diff --git a/packages/types/src/codebase-index.ts b/packages/types/src/codebase-index.ts index e86c17627f..7263068415 100644 --- a/packages/types/src/codebase-index.ts +++ b/packages/types/src/codebase-index.ts @@ -10,6 +10,7 @@ export const codebaseIndexConfigSchema = z.object({ codebaseIndexEmbedderProvider: z.enum(["openai", "ollama", "openai-compatible"]).optional(), codebaseIndexEmbedderBaseUrl: z.string().optional(), codebaseIndexEmbedderModelId: z.string().optional(), + codebaseIndexSearchMinScore: z.number().min(0).max(1).optional(), }) export type CodebaseIndexConfig = z.infer diff --git a/src/services/code-index/__tests__/config-manager.spec.ts b/src/services/code-index/__tests__/config-manager.spec.ts index f5a759c158..2da19a6a1e 100644 --- a/src/services/code-index/__tests__/config-manager.spec.ts +++ b/src/services/code-index/__tests__/config-manager.spec.ts @@ -709,6 +709,153 @@ describe("CodeIndexConfigManager", () => { const result = await configManager.loadConfiguration() expect(result.requiresRestart).toBe(false) }) + + describe("currentSearchMinScore priority system", () => { + it("should return user-configured score when set", async () => { + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai", + codebaseIndexEmbedderModelId: "text-embedding-3-small", + codebaseIndexSearchMinScore: 0.8, // User setting + }) + mockContextProxy.getSecret.mockImplementation((key: string) => { + if (key === "codeIndexOpenAiKey") return "test-key" + return undefined + }) + + await configManager.loadConfiguration() + expect(configManager.currentSearchMinScore).toBe(0.8) + }) + + it("should fall back to model-specific threshold when user setting is undefined", async () => { + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "ollama", + codebaseIndexEmbedderModelId: "nomic-embed-code", + // No codebaseIndexSearchMinScore - user hasn't configured it + }) + + await configManager.loadConfiguration() + // nomic-embed-code has a specific threshold of 0.15 + expect(configManager.currentSearchMinScore).toBe(0.15) + }) + + it("should fall back to default SEARCH_MIN_SCORE when neither user setting nor model threshold exists", async () => { + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai", + codebaseIndexEmbedderModelId: "unknown-model", // Model not in profiles + // No codebaseIndexSearchMinScore + }) + mockContextProxy.getSecret.mockImplementation((key: string) => { + if (key === "codeIndexOpenAiKey") return "test-key" + return undefined + }) + + await configManager.loadConfiguration() + // Should fall back to default SEARCH_MIN_SCORE (0.4) + expect(configManager.currentSearchMinScore).toBe(0.4) + }) + + it("should respect user setting of 0 (edge case)", async () => { + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "ollama", + codebaseIndexEmbedderModelId: "nomic-embed-code", + codebaseIndexSearchMinScore: 0, // User explicitly sets 0 + }) + + await configManager.loadConfiguration() + // Should return 0, not fall back to model threshold (0.15) + expect(configManager.currentSearchMinScore).toBe(0) + }) + + it("should use model-specific threshold with openai-compatible provider", async () => { + mockContextProxy.getGlobalState.mockImplementation((key: string) => { + if (key === "codebaseIndexConfig") { + return { + codebaseIndexEnabled: true, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai-compatible", + codebaseIndexEmbedderModelId: "nomic-embed-code", + // No codebaseIndexSearchMinScore + } + } + if (key === "codebaseIndexOpenAiCompatibleBaseUrl") return "https://api.example.com/v1" + return undefined + }) + mockContextProxy.getSecret.mockImplementation((key: string) => { + if (key === "codebaseIndexOpenAiCompatibleApiKey") return "test-api-key" + return undefined + }) + + await configManager.loadConfiguration() + // openai-compatible provider also has nomic-embed-code with 0.15 threshold + expect(configManager.currentSearchMinScore).toBe(0.15) + }) + + it("should use default model ID when modelId is not specified", async () => { + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai", + // No modelId specified + // No codebaseIndexSearchMinScore + }) + mockContextProxy.getSecret.mockImplementation((key: string) => { + if (key === "codeIndexOpenAiKey") return "test-key" + return undefined + }) + + await configManager.loadConfiguration() + // Should use default model (text-embedding-3-small) threshold (0.4) + expect(configManager.currentSearchMinScore).toBe(0.4) + }) + + it("should handle priority correctly: user > model > default", async () => { + // Test 1: User setting takes precedence + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "ollama", + codebaseIndexEmbedderModelId: "nomic-embed-code", // Has 0.15 threshold + codebaseIndexSearchMinScore: 0.9, // User overrides + }) + + await configManager.loadConfiguration() + expect(configManager.currentSearchMinScore).toBe(0.9) // User setting wins + + // Test 2: Model threshold when no user setting + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "ollama", + codebaseIndexEmbedderModelId: "nomic-embed-code", + // No user setting + }) + + const newManager = new CodeIndexConfigManager(mockContextProxy) + await newManager.loadConfiguration() + expect(newManager.currentSearchMinScore).toBe(0.15) // Model threshold + + // Test 3: Default when neither exists + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai", + codebaseIndexEmbedderModelId: "custom-unknown-model", + // No user setting, unknown model + }) + + const anotherManager = new CodeIndexConfigManager(mockContextProxy) + await anotherManager.loadConfiguration() + expect(anotherManager.currentSearchMinScore).toBe(0.4) // Default + }) + }) }) describe("empty/missing API key handling", () => { diff --git a/src/services/code-index/config-manager.ts b/src/services/code-index/config-manager.ts index 678cec36a1..d0eb9268b2 100644 --- a/src/services/code-index/config-manager.ts +++ b/src/services/code-index/config-manager.ts @@ -3,7 +3,7 @@ import { ContextProxy } from "../../core/config/ContextProxy" import { EmbedderProvider } from "./interfaces/manager" import { CodeIndexConfig, PreviousConfigSnapshot } from "./interfaces/config" import { SEARCH_MIN_SCORE } from "./constants" -import { getDefaultModelId, getModelDimension } from "../../shared/embeddingModels" +import { getDefaultModelId, getModelDimension, getModelScoreThreshold } from "../../shared/embeddingModels" /** * Manages configuration state and validation for the code indexing feature. @@ -34,10 +34,10 @@ export class CodeIndexConfigManager { const codebaseIndexConfig = this.contextProxy?.getGlobalState("codebaseIndexConfig") ?? { codebaseIndexEnabled: false, codebaseIndexQdrantUrl: "http://localhost:6333", - codebaseIndexSearchMinScore: 0.4, codebaseIndexEmbedderProvider: "openai", codebaseIndexEmbedderBaseUrl: "", codebaseIndexEmbedderModelId: "", + codebaseIndexSearchMinScore: undefined, } const { @@ -46,6 +46,7 @@ export class CodeIndexConfigManager { codebaseIndexEmbedderProvider, codebaseIndexEmbedderBaseUrl, codebaseIndexEmbedderModelId, + codebaseIndexSearchMinScore, } = codebaseIndexConfig const openAiKey = this.contextProxy?.getSecret("codeIndexOpenAiKey") ?? "" @@ -60,8 +61,8 @@ export class CodeIndexConfigManager { this.isEnabled = codebaseIndexEnabled || false this.qdrantUrl = codebaseIndexQdrantUrl this.qdrantApiKey = qdrantApiKey ?? "" + this.searchMinScore = codebaseIndexSearchMinScore this.openAiOptions = { openAiNativeApiKey: openAiKey } - this.searchMinScore = SEARCH_MIN_SCORE // Set embedder provider with support for openai-compatible if (codebaseIndexEmbedderProvider === "ollama") { @@ -139,7 +140,7 @@ export class CodeIndexConfigManager { openAiCompatibleOptions: this.openAiCompatibleOptions, qdrantUrl: this.qdrantUrl, qdrantApiKey: this.qdrantApiKey, - searchMinScore: this.searchMinScore, + searchMinScore: this.currentSearchMinScore, }, requiresRestart, } @@ -294,7 +295,7 @@ export class CodeIndexConfigManager { openAiCompatibleOptions: this.openAiCompatibleOptions, qdrantUrl: this.qdrantUrl, qdrantApiKey: this.qdrantApiKey, - searchMinScore: this.searchMinScore, + searchMinScore: this.currentSearchMinScore, } } @@ -337,9 +338,18 @@ export class CodeIndexConfigManager { } /** - * Gets the configured minimum search score. + * Gets the configured minimum search score based on user setting, model-specific threshold, or fallback. + * Priority: 1) User setting, 2) Model-specific threshold, 3) Default SEARCH_MIN_SCORE constant. */ - public get currentSearchMinScore(): number | undefined { - return this.searchMinScore + public get currentSearchMinScore(): number { + // First check if user has configured a custom score threshold + if (this.searchMinScore !== undefined) { + return this.searchMinScore + } + + // Fall back to model-specific threshold + const currentModelId = this.modelId ?? getDefaultModelId(this.embedderProvider) + const modelSpecificThreshold = getModelScoreThreshold(this.embedderProvider, currentModelId) + return modelSpecificThreshold ?? SEARCH_MIN_SCORE } } diff --git a/src/services/code-index/embedders/ollama.ts b/src/services/code-index/embedders/ollama.ts index 748ed188a4..2f212c7745 100644 --- a/src/services/code-index/embedders/ollama.ts +++ b/src/services/code-index/embedders/ollama.ts @@ -1,5 +1,7 @@ import { ApiHandlerOptions } from "../../../shared/api" import { EmbedderInfo, EmbeddingResponse, IEmbedder } from "../interfaces" +import { getModelQueryPrefix } from "../../../shared/embeddingModels" +import { MAX_ITEM_TOKENS } from "../constants" import { t } from "../../../i18n" /** @@ -25,6 +27,31 @@ export class CodeIndexOllamaEmbedder implements IEmbedder { const modelToUse = model || this.defaultModelId const url = `${this.baseUrl}/api/embed` // Endpoint as specified + // Apply model-specific query prefix if required + const queryPrefix = getModelQueryPrefix("ollama", modelToUse) + const processedTexts = queryPrefix + ? texts.map((text, index) => { + // Prevent double-prefixing + if (text.startsWith(queryPrefix)) { + return text + } + const prefixedText = `${queryPrefix}${text}` + const estimatedTokens = Math.ceil(prefixedText.length / 4) + if (estimatedTokens > MAX_ITEM_TOKENS) { + console.warn( + t("embeddings:textWithPrefixExceedsTokenLimit", { + index, + estimatedTokens, + maxTokens: MAX_ITEM_TOKENS, + }), + ) + // Return original text if adding prefix would exceed limit + return text + } + return prefixedText + }) + : texts + try { // Note: Standard Ollama API uses 'prompt' for single text, not 'input' for array. // Implementing based on user's specific request structure. @@ -35,7 +62,7 @@ export class CodeIndexOllamaEmbedder implements IEmbedder { }, body: JSON.stringify({ model: modelToUse, - input: texts, // Using 'input' as requested + input: processedTexts, // Using 'input' as requested }), }) diff --git a/src/services/code-index/embedders/openai-compatible.ts b/src/services/code-index/embedders/openai-compatible.ts index 0983cc297f..8bf35eea24 100644 --- a/src/services/code-index/embedders/openai-compatible.ts +++ b/src/services/code-index/embedders/openai-compatible.ts @@ -6,7 +6,7 @@ import { MAX_BATCH_RETRIES as MAX_RETRIES, INITIAL_RETRY_DELAY_MS as INITIAL_DELAY_MS, } from "../constants" -import { getDefaultModelId } from "../../../shared/embeddingModels" +import { getDefaultModelId, getModelQueryPrefix } from "../../../shared/embeddingModels" import { t } from "../../../i18n" interface EmbeddingItem { @@ -59,9 +59,35 @@ export class OpenAICompatibleEmbedder implements IEmbedder { */ async createEmbeddings(texts: string[], model?: string): Promise { const modelToUse = model || this.defaultModelId + + // Apply model-specific query prefix if required + const queryPrefix = getModelQueryPrefix("openai-compatible", modelToUse) + const processedTexts = queryPrefix + ? texts.map((text, index) => { + // Prevent double-prefixing + if (text.startsWith(queryPrefix)) { + return text + } + const prefixedText = `${queryPrefix}${text}` + const estimatedTokens = Math.ceil(prefixedText.length / 4) + if (estimatedTokens > MAX_ITEM_TOKENS) { + console.warn( + t("embeddings:textWithPrefixExceedsTokenLimit", { + index, + estimatedTokens, + maxTokens: MAX_ITEM_TOKENS, + }), + ) + // Return original text if adding prefix would exceed limit + return text + } + return prefixedText + }) + : texts + const allEmbeddings: number[][] = [] const usage = { promptTokens: 0, totalTokens: 0 } - const remainingTexts = [...texts] + const remainingTexts = [...processedTexts] while (remainingTexts.length > 0) { const currentBatch: string[] = [] diff --git a/src/services/code-index/embedders/openai.ts b/src/services/code-index/embedders/openai.ts index d0dc132df7..667c2f46d4 100644 --- a/src/services/code-index/embedders/openai.ts +++ b/src/services/code-index/embedders/openai.ts @@ -8,6 +8,7 @@ import { MAX_BATCH_RETRIES as MAX_RETRIES, INITIAL_RETRY_DELAY_MS as INITIAL_DELAY_MS, } from "../constants" +import { getModelQueryPrefix } from "../../../shared/embeddingModels" import { t } from "../../../i18n" /** @@ -36,9 +37,35 @@ export class OpenAiEmbedder extends OpenAiNativeHandler implements IEmbedder { */ async createEmbeddings(texts: string[], model?: string): Promise { const modelToUse = model || this.defaultModelId + + // Apply model-specific query prefix if required + const queryPrefix = getModelQueryPrefix("openai", modelToUse) + const processedTexts = queryPrefix + ? texts.map((text, index) => { + // Prevent double-prefixing + if (text.startsWith(queryPrefix)) { + return text + } + const prefixedText = `${queryPrefix}${text}` + const estimatedTokens = Math.ceil(prefixedText.length / 4) + if (estimatedTokens > MAX_ITEM_TOKENS) { + console.warn( + t("embeddings:textWithPrefixExceedsTokenLimit", { + index, + estimatedTokens, + maxTokens: MAX_ITEM_TOKENS, + }), + ) + // Return original text if adding prefix would exceed limit + return text + } + return prefixedText + }) + : texts + const allEmbeddings: number[][] = [] const usage = { promptTokens: 0, totalTokens: 0 } - const remainingTexts = [...texts] + const remainingTexts = [...processedTexts] while (remainingTexts.length > 0) { const currentBatch: string[] = [] diff --git a/src/shared/embeddingModels.ts b/src/shared/embeddingModels.ts index cd7c1d4e6b..c78dc6c487 100644 --- a/src/shared/embeddingModels.ts +++ b/src/shared/embeddingModels.ts @@ -6,6 +6,8 @@ export type EmbedderProvider = "openai" | "ollama" | "openai-compatible" // Add export interface EmbeddingModelProfile { dimension: number + scoreThreshold?: number // Model-specific minimum score threshold for semantic search + queryPrefix?: string // Optional prefix required by the model for queries // Add other model-specific properties if needed, e.g., context window size } @@ -18,21 +20,31 @@ export type EmbeddingModelProfiles = { // Example profiles - expand this list as needed export const EMBEDDING_MODEL_PROFILES: EmbeddingModelProfiles = { openai: { - "text-embedding-3-small": { dimension: 1536 }, - "text-embedding-3-large": { dimension: 3072 }, - "text-embedding-ada-002": { dimension: 1536 }, + "text-embedding-3-small": { dimension: 1536, scoreThreshold: 0.4 }, + "text-embedding-3-large": { dimension: 3072, scoreThreshold: 0.4 }, + "text-embedding-ada-002": { dimension: 1536, scoreThreshold: 0.4 }, }, ollama: { - "nomic-embed-text": { dimension: 768 }, - "mxbai-embed-large": { dimension: 1024 }, - "all-minilm": { dimension: 384 }, + "nomic-embed-text": { dimension: 768, scoreThreshold: 0.4 }, + "nomic-embed-code": { + dimension: 3584, + scoreThreshold: 0.15, + queryPrefix: "Represent this query for searching relevant code: ", + }, + "mxbai-embed-large": { dimension: 1024, scoreThreshold: 0.4 }, + "all-minilm": { dimension: 384, scoreThreshold: 0.4 }, // Add default Ollama model if applicable, e.g.: // 'default': { dimension: 768 } // Assuming a default dimension }, "openai-compatible": { - "text-embedding-3-small": { dimension: 1536 }, - "text-embedding-3-large": { dimension: 3072 }, - "text-embedding-ada-002": { dimension: 1536 }, + "text-embedding-3-small": { dimension: 1536, scoreThreshold: 0.4 }, + "text-embedding-3-large": { dimension: 3072, scoreThreshold: 0.4 }, + "text-embedding-ada-002": { dimension: 1536, scoreThreshold: 0.4 }, + "nomic-embed-code": { + dimension: 3584, + scoreThreshold: 0.15, + queryPrefix: "Represent this query for searching relevant code: ", + }, }, } @@ -59,6 +71,38 @@ export function getModelDimension(provider: EmbedderProvider, modelId: string): return modelProfile.dimension } +/** + * Retrieves the score threshold for a given provider and model ID. + * @param provider The embedder provider (e.g., "openai"). + * @param modelId The specific model ID (e.g., "text-embedding-3-small"). + * @returns The score threshold or undefined if the model is not found. + */ +export function getModelScoreThreshold(provider: EmbedderProvider, modelId: string): number | undefined { + const providerProfiles = EMBEDDING_MODEL_PROFILES[provider] + if (!providerProfiles) { + return undefined + } + + const modelProfile = providerProfiles[modelId] + return modelProfile?.scoreThreshold +} + +/** + * Retrieves the query prefix for a given provider and model ID. + * @param provider The embedder provider (e.g., "openai"). + * @param modelId The specific model ID (e.g., "nomic-embed-code"). + * @returns The query prefix or undefined if the model doesn't require one. + */ +export function getModelQueryPrefix(provider: EmbedderProvider, modelId: string): string | undefined { + const providerProfiles = EMBEDDING_MODEL_PROFILES[provider] + if (!providerProfiles) { + return undefined + } + + const modelProfile = providerProfiles[modelId] + return modelProfile?.queryPrefix +} + /** * Gets the default *specific* embedding model ID based on the provider. * Does not include the provider prefix. diff --git a/webview-ui/src/components/chat/CodebaseSearchResult.tsx b/webview-ui/src/components/chat/CodebaseSearchResult.tsx index 4a2ced6178..4d48749ecd 100644 --- a/webview-ui/src/components/chat/CodebaseSearchResult.tsx +++ b/webview-ui/src/components/chat/CodebaseSearchResult.tsx @@ -1,4 +1,5 @@ import React from "react" +import { useTranslation } from "react-i18next" import { vscode } from "@src/utils/vscode" import { StandardTooltip } from "@/components/ui" @@ -12,6 +13,8 @@ interface CodebaseSearchResultProps { } const CodebaseSearchResult: React.FC = ({ filePath, score, startLine, endLine }) => { + const { t } = useTranslation("chat") + const handleClick = () => { console.log(filePath) vscode.postMessage({ @@ -24,7 +27,7 @@ const CodebaseSearchResult: React.FC = ({ filePath, s } return ( - +
@@ -35,6 +38,9 @@ const CodebaseSearchResult: React.FC = ({ filePath, s {filePath.split("/").slice(0, -1).join("/")} + + {score.toFixed(3)} +
diff --git a/webview-ui/src/components/settings/CodeIndexSettings.tsx b/webview-ui/src/components/settings/CodeIndexSettings.tsx index 13c9524d9f..3712043931 100644 --- a/webview-ui/src/components/settings/CodeIndexSettings.tsx +++ b/webview-ui/src/components/settings/CodeIndexSettings.tsx @@ -7,6 +7,7 @@ import { Trans } from "react-i18next" import { CodebaseIndexConfig, CodebaseIndexModels, ProviderSettings } from "@roo-code/types" import { EmbedderProvider } from "@roo/embeddingModels" +import { SEARCH_MIN_SCORE } from "../../../../src/services/code-index/constants" import { vscode } from "@src/utils/vscode" import { useAppTranslation } from "@src/i18n/TranslationContext" @@ -27,6 +28,12 @@ import { AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, + Slider, + Button, + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, } from "@src/components/ui" import { SetCachedStateField } from "./types" @@ -58,6 +65,7 @@ export const CodeIndexSettings: React.FC = ({ totalItems: 0, currentItemUnit: "items", }) + const [advancedExpanded, setAdvancedExpanded] = useState(false) // Safely calculate available models for current provider const currentProvider = codebaseIndexConfig?.codebaseIndexEmbedderProvider @@ -495,6 +503,78 @@ export const CodeIndexSettings: React.FC = ({ )} + + {/* Advanced Configuration Section */} +
+ + + {advancedExpanded && ( +
+
+
+ + {t("settings:codeIndex.searchMinScoreLabel")} + +
+ + setCachedStateField("codebaseIndexConfig", { + ...codebaseIndexConfig, + codebaseIndexSearchMinScore: value, + }) + } + data-testid="search-min-score-slider" + aria-label={t("settings:codeIndex.searchMinScoreLabel")} + /> + + {( + codebaseIndexConfig.codebaseIndexSearchMinScore ?? SEARCH_MIN_SCORE + ).toFixed(2)} + + + + + + + +

{t("settings:codeIndex.searchMinScoreResetTooltip")}

+
+
+
+
+
+ {t("settings:codeIndex.searchMinScoreDescription")} +
+
+
+
+ )} +
)} diff --git a/webview-ui/src/components/settings/__tests__/CodeIndexSettings.spec.tsx b/webview-ui/src/components/settings/__tests__/CodeIndexSettings.spec.tsx index 3c3dae7956..802d5e8813 100644 --- a/webview-ui/src/components/settings/__tests__/CodeIndexSettings.spec.tsx +++ b/webview-ui/src/components/settings/__tests__/CodeIndexSettings.spec.tsx @@ -43,6 +43,11 @@ vi.mock("@src/i18n/TranslationContext", () => ({ "settings:codeIndex.clearDataDialog.description": "This will remove all indexed data", "settings:codeIndex.clearDataDialog.cancelButton": "Cancel", "settings:codeIndex.clearDataDialog.confirmButton": "Confirm", + "settings:codeIndex.searchMinScoreLabel": "Search Score Threshold", + "settings:codeIndex.searchMinScoreDescription": + "Minimum similarity score (0.0-1.0) required for search results. Lower values return more results but may be less relevant. Higher values return fewer but more relevant results.", + "settings:codeIndex.searchMinScoreResetTooltip": "Reset to default value (0.4)", + "settings:codeIndex.advancedConfigLabel": "Advanced Configuration", } return translations[key] || key }, @@ -85,6 +90,24 @@ vi.mock("@src/components/ui", () => ({ AlertDialogHeader: ({ children }: any) =>
{children}
, AlertDialogTitle: ({ children }: any) =>
{children}
, AlertDialogTrigger: ({ children }: any) =>
{children}
, + Slider: ({ value, onValueChange, "data-testid": dataTestId }: any) => ( + onValueChange && onValueChange([parseFloat(e.target.value)])} + data-testid={dataTestId} + role="slider" + /> + ), + Button: ({ children, onClick, "data-testid": dataTestId, ...props }: any) => ( + + ), + Tooltip: ({ children }: any) =>
{children}
, + TooltipContent: ({ children }: any) =>
{children}
, + TooltipProvider: ({ children }: any) =>
{children}
, + TooltipTrigger: ({ children }: any) =>
{children}
, })) vi.mock("@vscode/webview-ui-toolkit/react", () => ({ @@ -158,6 +181,7 @@ describe("CodeIndexSettings", () => { codebaseIndexEmbedderProvider: "openai" as const, codebaseIndexEmbedderModelId: "text-embedding-3-small", codebaseIndexQdrantUrl: "http://localhost:6333", + codebaseIndexSearchMinScore: 0.4, }, apiConfiguration: { codeIndexOpenAiKey: "", @@ -204,7 +228,7 @@ describe("CodeIndexSettings", () => { expect(screen.getByText("Base URL")).toBeInTheDocument() expect(screen.getByText("API Key")).toBeInTheDocument() - expect(screen.getAllByTestId("vscode-textfield")).toHaveLength(6) // Base URL, API Key, Embedding Dimension, Model ID, Qdrant URL, Qdrant Key + expect(screen.getAllByTestId("vscode-textfield")).toHaveLength(6) // Base URL, API Key, Embedding Dimension, Model ID, Qdrant URL, Qdrant Key (Search Min Score is now a slider) }) it("should hide OpenAI Compatible fields when different provider is selected", () => { @@ -817,6 +841,113 @@ describe("CodeIndexSettings", () => { }) }) + describe("Search Minimum Score Slider", () => { + const expandAdvancedConfig = () => { + const advancedButton = screen.getByRole("button", { name: /Advanced Configuration/i }) + fireEvent.click(advancedButton) + } + + it("should render advanced configuration toggle button", () => { + render() + + expect(screen.getByRole("button", { name: /Advanced Configuration/i })).toBeInTheDocument() + expect(screen.getByText("Advanced Configuration")).toBeInTheDocument() + }) + + it("should render search minimum score slider with reset button when expanded", () => { + render() + + expandAdvancedConfig() + + expect(screen.getByTestId("search-min-score-slider")).toBeInTheDocument() + expect(screen.getByTestId("search-min-score-reset-button")).toBeInTheDocument() + expect(screen.getByText("Search Score Threshold")).toBeInTheDocument() + }) + + it("should display current search minimum score value when expanded", () => { + const propsWithScore = { + ...defaultProps, + codebaseIndexConfig: { + ...defaultProps.codebaseIndexConfig, + codebaseIndexSearchMinScore: 0.65, + }, + } + + render() + + expandAdvancedConfig() + + expect(screen.getByText("0.65")).toBeInTheDocument() + }) + + it("should call setCachedStateField when slider value changes", () => { + render() + + expandAdvancedConfig() + + const slider = screen.getByTestId("search-min-score-slider") + fireEvent.change(slider, { target: { value: "0.8" } }) + + expect(mockSetCachedStateField).toHaveBeenCalledWith("codebaseIndexConfig", { + ...defaultProps.codebaseIndexConfig, + codebaseIndexSearchMinScore: 0.8, + }) + }) + + it("should reset to default value when reset button is clicked", () => { + const propsWithScore = { + ...defaultProps, + codebaseIndexConfig: { + ...defaultProps.codebaseIndexConfig, + codebaseIndexSearchMinScore: 0.8, + }, + } + + render() + + expandAdvancedConfig() + + const resetButton = screen.getByTestId("search-min-score-reset-button") + fireEvent.click(resetButton) + + expect(mockSetCachedStateField).toHaveBeenCalledWith("codebaseIndexConfig", { + ...defaultProps.codebaseIndexConfig, + codebaseIndexSearchMinScore: 0.4, + }) + }) + + it("should use default value when no score is set", () => { + const propsWithoutScore = { + ...defaultProps, + codebaseIndexConfig: { + ...defaultProps.codebaseIndexConfig, + codebaseIndexSearchMinScore: undefined, + }, + } + + render() + + expandAdvancedConfig() + + expect(screen.getByText("0.40")).toBeInTheDocument() + }) + + it("should toggle advanced section visibility", () => { + render() + + // Initially collapsed - should not see slider + expect(screen.queryByTestId("search-min-score-slider")).not.toBeInTheDocument() + + // Expand advanced section + expandAdvancedConfig() + expect(screen.getByTestId("search-min-score-slider")).toBeInTheDocument() + + // Collapse again + expandAdvancedConfig() + expect(screen.queryByTestId("search-min-score-slider")).not.toBeInTheDocument() + }) + }) + describe("Error Handling", () => { it("should handle invalid provider gracefully", () => { const propsWithInvalidProvider = { diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index 4db48e40f3..ae4e45c913 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo vol cercar a la base de codi {{query}}:", "wantsToSearchWithPath": "Roo vol cercar a la base de codi {{query}} a {{path}}:", - "didSearch": "S'han trobat {{count}} resultat(s) per a {{query}}:" + "didSearch": "S'han trobat {{count}} resultat(s) per a {{query}}:", + "resultTooltip": "Puntuació de similitud: {{score}} (fes clic per obrir el fitxer)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index b3906fb50e..a4ce4a19e3 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "URL d'Ollama:", "qdrantUrlLabel": "URL de Qdrant", "qdrantKeyLabel": "Clau de Qdrant:", + "advancedConfigLabel": "Configuració avançada", + "searchMinScoreLabel": "Llindar de puntuació de cerca", + "searchMinScoreDescription": "Puntuació mínima de similitud (0.0-1.0) requerida per als resultats de la cerca. Valors més baixos retornen més resultats però poden ser menys rellevants. Valors més alts retornen menys resultats però més rellevants.", + "searchMinScoreResetTooltip": "Restablir al valor per defecte (0.4)", "startIndexingButton": "Iniciar indexació", "clearIndexDataButton": "Esborrar dades d'índex", "unsavedSettingsMessage": "Si us plau, deseu la configuració abans d'iniciar el procés d'indexació.", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index 3ee69f9ae4..0e5d28c12d 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo möchte den Codebase nach {{query}} durchsuchen:", "wantsToSearchWithPath": "Roo möchte den Codebase nach {{query}} in {{path}} durchsuchen:", - "didSearch": "{{count}} Ergebnis(se) für {{query}} gefunden:" + "didSearch": "{{count}} Ergebnis(se) für {{query}} gefunden:", + "resultTooltip": "Ähnlichkeitswert: {{score}} (klicken zum Öffnen der Datei)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index ad78931d81..57adfc229f 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "Ollama-URL:", "qdrantUrlLabel": "Qdrant-URL", "qdrantKeyLabel": "Qdrant-Schlüssel:", + "advancedConfigLabel": "Erweiterte Konfiguration", + "searchMinScoreLabel": "Suchergebnis-Schwellenwert", + "searchMinScoreDescription": "Mindestähnlichkeitswert (0.0-1.0), der für Suchergebnisse erforderlich ist. Niedrigere Werte liefern mehr Ergebnisse, die jedoch möglicherweise weniger relevant sind. Höhere Werte liefern weniger, aber relevantere Ergebnisse.", + "searchMinScoreResetTooltip": "Auf Standardwert zurücksetzen (0.4)", "startIndexingButton": "Indexierung starten", "clearIndexDataButton": "Indexdaten löschen", "unsavedSettingsMessage": "Bitte speichere deine Einstellungen, bevor du den Indexierungsprozess startest.", diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index 9ee8e167bd..65375ba913 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -201,7 +201,8 @@ "codebaseSearch": { "wantsToSearch": "Roo wants to search the codebase for {{query}}:", "wantsToSearchWithPath": "Roo wants to search the codebase for {{query}} in {{path}}:", - "didSearch": "Found {{count}} result(s) for {{query}}:" + "didSearch": "Found {{count}} result(s) for {{query}}:", + "resultTooltip": "Similarity score: {{score}} (click to open file)" }, "commandOutput": "Command Output", "response": "Response", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 9083d4a204..145f2258f6 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "Ollama URL:", "qdrantUrlLabel": "Qdrant URL", "qdrantKeyLabel": "Qdrant Key:", + "advancedConfigLabel": "Advanced Configuration", + "searchMinScoreLabel": "Search Score Threshold", + "searchMinScoreDescription": "Minimum similarity score (0.0-1.0) required for search results. Lower values return more results but may be less relevant. Higher values return fewer but more relevant results.", + "searchMinScoreResetTooltip": "Reset to default value (0.4)", "startIndexingButton": "Start Indexing", "clearIndexDataButton": "Clear Index Data", "unsavedSettingsMessage": "Please save your settings before starting the indexing process.", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index 7072d0ea16..48fbfbc442 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo quiere buscar en la base de código {{query}}:", "wantsToSearchWithPath": "Roo quiere buscar en la base de código {{query}} en {{path}}:", - "didSearch": "Se encontraron {{count}} resultado(s) para {{query}}:" + "didSearch": "Se encontraron {{count}} resultado(s) para {{query}}:", + "resultTooltip": "Puntuación de similitud: {{score}} (haz clic para abrir el archivo)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index c83237d4f3..2263a03a42 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "URL de Ollama:", "qdrantUrlLabel": "URL de Qdrant", "qdrantKeyLabel": "Clave de Qdrant:", + "advancedConfigLabel": "Configuración avanzada", + "searchMinScoreLabel": "Umbral de puntuación de búsqueda", + "searchMinScoreDescription": "Puntuación mínima de similitud (0.0-1.0) requerida para los resultados de búsqueda. Valores más bajos devuelven más resultados pero pueden ser menos relevantes. Valores más altos devuelven menos resultados pero más relevantes.", + "searchMinScoreResetTooltip": "Restablecer al valor predeterminado (0.4)", "startIndexingButton": "Iniciar indexación", "clearIndexDataButton": "Borrar datos de índice", "unsavedSettingsMessage": "Por favor guarda tus ajustes antes de iniciar el proceso de indexación.", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index 25d5074f45..666204ebff 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo veut rechercher dans la base de code {{query}} :", "wantsToSearchWithPath": "Roo veut rechercher dans la base de code {{query}} dans {{path}} :", - "didSearch": "{{count}} résultat(s) trouvé(s) pour {{query}} :" + "didSearch": "{{count}} résultat(s) trouvé(s) pour {{query}} :", + "resultTooltip": "Score de similarité : {{score}} (cliquer pour ouvrir le fichier)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 681d95be98..7662e93113 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "URL Ollama :", "qdrantUrlLabel": "URL Qdrant", "qdrantKeyLabel": "Clé Qdrant :", + "advancedConfigLabel": "Configuration avancée", + "searchMinScoreLabel": "Seuil de score de recherche", + "searchMinScoreDescription": "Score de similarité minimum (0.0-1.0) requis pour les résultats de recherche. Des valeurs plus faibles renvoient plus de résultats mais peuvent être moins pertinents. Des valeurs plus élevées renvoient moins de résultats mais plus pertinents.", + "searchMinScoreResetTooltip": "Réinitialiser à la valeur par défaut (0.4)", "startIndexingButton": "Démarrer l'indexation", "clearIndexDataButton": "Effacer les données d'index", "unsavedSettingsMessage": "Merci d'enregistrer tes paramètres avant de démarrer le processus d'indexation.", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index e67068d090..814fa913c6 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo कोडबेस में {{query}} खोजना चाहता है:", "wantsToSearchWithPath": "Roo {{path}} में कोडबेस में {{query}} खोजना चाहता है:", - "didSearch": "{{query}} के लिए {{count}} परिणाम मिले:" + "didSearch": "{{query}} के लिए {{count}} परिणाम मिले:", + "resultTooltip": "समानता स्कोर: {{score}} (फ़ाइल खोलने के लिए क्लिक करें)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 9d8bef3711..5466e5383c 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "Ollama URL:", "qdrantUrlLabel": "Qdrant URL", "qdrantKeyLabel": "Qdrant कुंजी:", + "advancedConfigLabel": "उन्नत कॉन्फ़िगरेशन", + "searchMinScoreLabel": "खोज स्कोर थ्रेसहोल्ड", + "searchMinScoreDescription": "खोज परिणामों के लिए आवश्यक न्यूनतम समानता स्कोर (0.0-1.0)। कम मान अधिक परिणाम लौटाते हैं लेकिन कम प्रासंगिक हो सकते हैं। उच्च मान कम लेकिन अधिक प्रासंगिक परिणाम लौटाते हैं।", + "searchMinScoreResetTooltip": "डिफ़ॉल्ट मान पर रीसेट करें (0.4)", "startIndexingButton": "इंडेक्सिंग शुरू करें", "clearIndexDataButton": "इंडेक्स डेटा साफ़ करें", "unsavedSettingsMessage": "इंडेक्सिंग प्रक्रिया शुरू करने से पहले कृपया अपनी सेटिंग्स सहेजें।", diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json index 259665a406..6bd11ce03b 100644 --- a/webview-ui/src/i18n/locales/id/chat.json +++ b/webview-ui/src/i18n/locales/id/chat.json @@ -207,7 +207,8 @@ "codebaseSearch": { "wantsToSearch": "Roo ingin mencari codebase untuk {{query}}:", "wantsToSearchWithPath": "Roo ingin mencari codebase untuk {{query}} di {{path}}:", - "didSearch": "Ditemukan {{count}} hasil untuk {{query}}:" + "didSearch": "Ditemukan {{count}} hasil untuk {{query}}:", + "resultTooltip": "Skor kemiripan: {{score}} (klik untuk membuka file)" }, "commandOutput": "Output Perintah", "response": "Respons", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index c5e3abf45c..d7fa28aa4e 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "Ollama URL:", "qdrantUrlLabel": "Qdrant URL", "qdrantKeyLabel": "Qdrant Key:", + "advancedConfigLabel": "Konfigurasi Lanjutan", + "searchMinScoreLabel": "Ambang Batas Skor Pencarian", + "searchMinScoreDescription": "Skor kesamaan minimum (0.0-1.0) yang diperlukan untuk hasil pencarian. Nilai yang lebih rendah mengembalikan lebih banyak hasil tetapi mungkin kurang relevan. Nilai yang lebih tinggi mengembalikan lebih sedikit hasil tetapi lebih relevan.", + "searchMinScoreResetTooltip": "Reset ke nilai default (0.4)", "startIndexingButton": "Mulai Pengindeksan", "clearIndexDataButton": "Hapus Data Indeks", "unsavedSettingsMessage": "Silakan simpan pengaturan kamu sebelum memulai proses pengindeksan.", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index bbf8c8be6a..95f3fc98ed 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo vuole cercare nella base di codice {{query}}:", "wantsToSearchWithPath": "Roo vuole cercare nella base di codice {{query}} in {{path}}:", - "didSearch": "Trovato {{count}} risultato/i per {{query}}:" + "didSearch": "Trovato {{count}} risultato/i per {{query}}:", + "resultTooltip": "Punteggio di somiglianza: {{score}} (clicca per aprire il file)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index fefdcd2ca2..1e77010dd5 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "URL Ollama:", "qdrantUrlLabel": "URL Qdrant", "qdrantKeyLabel": "Chiave Qdrant:", + "advancedConfigLabel": "Configurazione avanzata", + "searchMinScoreLabel": "Soglia punteggio di ricerca", + "searchMinScoreDescription": "Punteggio minimo di somiglianza (0.0-1.0) richiesto per i risultati della ricerca. Valori più bassi restituiscono più risultati ma potrebbero essere meno pertinenti. Valori più alti restituiscono meno risultati ma più pertinenti.", + "searchMinScoreResetTooltip": "Ripristina al valore predefinito (0.4)", "startIndexingButton": "Avvia indicizzazione", "clearIndexDataButton": "Cancella dati indice", "unsavedSettingsMessage": "Per favore salva le tue impostazioni prima di avviare il processo di indicizzazione.", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index 0278edd4b6..abcb89c4a5 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Rooはコードベースで {{query}} を検索したい:", "wantsToSearchWithPath": "Rooは {{path}} 内のコードベースで {{query}} を検索したい:", - "didSearch": "{{query}} の検索結果: {{count}} 件" + "didSearch": "{{query}} の検索結果: {{count}} 件", + "resultTooltip": "類似度スコア: {{score}} (クリックしてファイルを開く)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index f5d198a8d4..1027eaed67 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "Ollama URL:", "qdrantUrlLabel": "Qdrant URL", "qdrantKeyLabel": "Qdrantキー:", + "advancedConfigLabel": "詳細設定", + "searchMinScoreLabel": "検索スコアのしきい値", + "searchMinScoreDescription": "検索結果に必要な最小類似度スコア(0.0-1.0)。値を低くするとより多くの結果が返されますが、関連性が低くなる可能性があります。値を高くすると返される結果は少なくなりますが、より関連性が高くなります。", + "searchMinScoreResetTooltip": "デフォルト値(0.4)にリセット", "startIndexingButton": "インデックス作成を開始", "clearIndexDataButton": "インデックスデータをクリア", "unsavedSettingsMessage": "インデックス作成プロセスを開始する前に設定を保存してください。", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index 5373831426..896f4de3d6 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo가 코드베이스에서 {{query}}을(를) 검색하고 싶어합니다:", "wantsToSearchWithPath": "Roo가 {{path}}에서 {{query}}을(를) 검색하고 싶어합니다:", - "didSearch": "{{query}}에 대한 검색 결과 {{count}}개 찾음:" + "didSearch": "{{query}}에 대한 검색 결과 {{count}}개 찾음:", + "resultTooltip": "유사도 점수: {{score}} (클릭하여 파일 열기)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 5476b044bf..ab3c79424a 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "Ollama URL:", "qdrantUrlLabel": "Qdrant URL", "qdrantKeyLabel": "Qdrant 키:", + "advancedConfigLabel": "고급 구성", + "searchMinScoreLabel": "검색 점수 임계값", + "searchMinScoreDescription": "검색 결과에 필요한 최소 유사도 점수(0.0-1.0). 값이 낮을수록 더 많은 결과가 반환되지만 관련성이 떨어질 수 있습니다. 값이 높을수록 결과는 적지만 관련성이 높은 결과가 반환됩니다.", + "searchMinScoreResetTooltip": "기본값(0.4)으로 재설정", "startIndexingButton": "인덱싱 시작", "clearIndexDataButton": "인덱스 데이터 지우기", "unsavedSettingsMessage": "인덱싱 프로세스를 시작하기 전에 설정을 저장해 주세요.", diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json index 2dc60da09e..84efa4da0a 100644 --- a/webview-ui/src/i18n/locales/nl/chat.json +++ b/webview-ui/src/i18n/locales/nl/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo wil de codebase doorzoeken op {{query}}:", "wantsToSearchWithPath": "Roo wil de codebase doorzoeken op {{query}} in {{path}}:", - "didSearch": "{{count}} resultaat/resultaten gevonden voor {{query}}:" + "didSearch": "{{count}} resultaat/resultaten gevonden voor {{query}}:", + "resultTooltip": "Gelijkenisscore: {{score}} (klik om bestand te openen)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 88a66c0d5f..84b4290e91 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "Ollama URL:", "qdrantUrlLabel": "Qdrant URL", "qdrantKeyLabel": "Qdrant-sleutel:", + "advancedConfigLabel": "Geavanceerde configuratie", + "searchMinScoreLabel": "Zoekscore drempel", + "searchMinScoreDescription": "Minimale overeenkomstscore (0.0-1.0) vereist voor zoekresultaten. Lagere waarden leveren meer resultaten op, maar zijn mogelijk minder relevant. Hogere waarden leveren minder, maar relevantere resultaten op.", + "searchMinScoreResetTooltip": "Reset naar standaardwaarde (0.4)", "startIndexingButton": "Indexering starten", "clearIndexDataButton": "Indexgegevens wissen", "unsavedSettingsMessage": "Sla je instellingen op voordat je het indexeringsproces start.", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index 0af70c595b..10dd4b1519 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo chce przeszukać bazę kodu w poszukiwaniu {{query}}:", "wantsToSearchWithPath": "Roo chce przeszukać bazę kodu w poszukiwaniu {{query}} w {{path}}:", - "didSearch": "Znaleziono {{count}} wynik(ów) dla {{query}}:" + "didSearch": "Znaleziono {{count}} wynik(ów) dla {{query}}:", + "resultTooltip": "Wynik podobieństwa: {{score}} (kliknij, aby otworzyć plik)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 4a446f7095..0c1412b3d3 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "URL Ollama:", "qdrantUrlLabel": "URL Qdrant", "qdrantKeyLabel": "Klucz Qdrant:", + "advancedConfigLabel": "Konfiguracja zaawansowana", + "searchMinScoreLabel": "Próg wyniku wyszukiwania", + "searchMinScoreDescription": "Minimalny wynik podobieństwa (0.0-1.0) wymagany dla wyników wyszukiwania. Niższe wartości zwracają więcej wyników, ale mogą być mniej trafne. Wyższe wartości zwracają mniej wyników, ale bardziej trafnych.", + "searchMinScoreResetTooltip": "Zresetuj do wartości domyślnej (0.4)", "startIndexingButton": "Rozpocznij indeksowanie", "clearIndexDataButton": "Wyczyść dane indeksu", "unsavedSettingsMessage": "Zapisz swoje ustawienia przed rozpoczęciem procesu indeksowania.", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index a09f8174f6..a0eae11699 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo quer pesquisar na base de código por {{query}}:", "wantsToSearchWithPath": "Roo quer pesquisar na base de código por {{query}} em {{path}}:", - "didSearch": "Encontrado {{count}} resultado(s) para {{query}}:" + "didSearch": "Encontrado {{count}} resultado(s) para {{query}}:", + "resultTooltip": "Pontuação de similaridade: {{score}} (clique para abrir o arquivo)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index b4ae11c2ac..996d031dd3 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "URL Ollama:", "qdrantUrlLabel": "URL Qdrant", "qdrantKeyLabel": "Chave Qdrant:", + "advancedConfigLabel": "Configuração Avançada", + "searchMinScoreLabel": "Limite de pontuação de busca", + "searchMinScoreDescription": "Pontuação mínima de similaridade (0.0-1.0) necessária para os resultados da busca. Valores mais baixos retornam mais resultados, mas podem ser menos relevantes. Valores mais altos retornam menos resultados, mas mais relevantes.", + "searchMinScoreResetTooltip": "Redefinir para o valor padrão (0.4)", "startIndexingButton": "Iniciar Indexação", "clearIndexDataButton": "Limpar Dados de Índice", "unsavedSettingsMessage": "Por favor, salve suas configurações antes de iniciar o processo de indexação.", diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index 89d35f322a..47b0a42557 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo хочет выполнить поиск в кодовой базе по {{query}}:", "wantsToSearchWithPath": "Roo хочет выполнить поиск в кодовой базе по {{query}} в {{path}}:", - "didSearch": "Найдено {{count}} результат(ов) для {{query}}:" + "didSearch": "Найдено {{count}} результат(ов) для {{query}}:", + "resultTooltip": "Оценка схожести: {{score}} (нажмите, чтобы открыть файл)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 79c13741da..c7b3521da0 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "URL Ollama:", "qdrantUrlLabel": "URL Qdrant", "qdrantKeyLabel": "Ключ Qdrant:", + "advancedConfigLabel": "Расширенная конфигурация", + "searchMinScoreLabel": "Порог оценки поиска", + "searchMinScoreDescription": "Минимальный балл сходства (0.0-1.0), необходимый для результатов поиска. Более низкие значения возвращают больше результатов, но они могут быть менее релевантными. Более высокие значения возвращают меньше результатов, но более релевантных.", + "searchMinScoreResetTooltip": "Сбросить к значению по умолчанию (0.4)", "startIndexingButton": "Начать индексацию", "clearIndexDataButton": "Очистить данные индекса", "unsavedSettingsMessage": "Пожалуйста, сохрани настройки перед запуском процесса индексации.", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index f12fa62bbb..9bcdd420f8 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo kod tabanında {{query}} aramak istiyor:", "wantsToSearchWithPath": "Roo {{path}} içinde kod tabanında {{query}} aramak istiyor:", - "didSearch": "{{query}} için {{count}} sonuç bulundu:" + "didSearch": "{{query}} için {{count}} sonuç bulundu:", + "resultTooltip": "Benzerlik puanı: {{score}} (dosyayı açmak için tıklayın)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index e6335c6dad..17391bd02e 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "Ollama URL:", "qdrantUrlLabel": "Qdrant URL", "qdrantKeyLabel": "Qdrant Anahtarı:", + "advancedConfigLabel": "Gelişmiş Yapılandırma", + "searchMinScoreLabel": "Arama Skoru Eşiği", + "searchMinScoreDescription": "Arama sonuçları için gereken minimum benzerlik puanı (0.0-1.0). Düşük değerler daha fazla sonuç döndürür ancak daha az alakalı olabilir. Yüksek değerler daha az ancak daha alakalı sonuçlar döndürür.", + "searchMinScoreResetTooltip": "Varsayılan değere sıfırla (0.4)", "startIndexingButton": "İndekslemeyi Başlat", "clearIndexDataButton": "İndeks Verilerini Temizle", "unsavedSettingsMessage": "İndeksleme işlemini başlatmadan önce lütfen ayarlarını kaydet.", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index c2338e33aa..e8cce0309f 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo muốn tìm kiếm trong cơ sở mã cho {{query}}:", "wantsToSearchWithPath": "Roo muốn tìm kiếm trong cơ sở mã cho {{query}} trong {{path}}:", - "didSearch": "Đã tìm thấy {{count}} kết quả cho {{query}}:" + "didSearch": "Đã tìm thấy {{count}} kết quả cho {{query}}:", + "resultTooltip": "Điểm tương tự: {{score}} (nhấp để mở tệp)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index f860292e02..1ba2508c34 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "URL Ollama:", "qdrantUrlLabel": "URL Qdrant", "qdrantKeyLabel": "Khóa Qdrant:", + "advancedConfigLabel": "Cấu hình nâng cao", + "searchMinScoreLabel": "Ngưỡng điểm tìm kiếm", + "searchMinScoreDescription": "Điểm tương đồng tối thiểu (0.0-1.0) cần thiết cho kết quả tìm kiếm. Giá trị thấp hơn trả về nhiều kết quả hơn nhưng có thể kém liên quan hơn. Giá trị cao hơn trả về ít kết quả hơn nhưng có liên quan hơn.", + "searchMinScoreResetTooltip": "Đặt lại về giá trị mặc định (0.4)", "startIndexingButton": "Bắt đầu lập chỉ mục", "clearIndexDataButton": "Xóa dữ liệu chỉ mục", "unsavedSettingsMessage": "Vui lòng lưu cài đặt của bạn trước khi bắt đầu quá trình lập chỉ mục.", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index f3fb857f06..714bbfc79f 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo 需要搜索代码库: {{query}}", "wantsToSearchWithPath": "Roo 需要在 {{path}} 中搜索: {{query}}", - "didSearch": "找到 {{count}} 个结果: {{query}}" + "didSearch": "找到 {{count}} 个结果: {{query}}", + "resultTooltip": "相似度评分: {{score}} (点击打开文件)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index f2e80cee7f..7d7d2f6733 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "Ollama URL:", "qdrantUrlLabel": "Qdrant URL", "qdrantKeyLabel": "Qdrant 密钥:", + "advancedConfigLabel": "高级配置", + "searchMinScoreLabel": "搜索分数阈值", + "searchMinScoreDescription": "搜索结果所需的最低相似度分数(0.0-1.0)。较低的值返回更多结果,但可能不太相关。较高的值返回较少但更相关的结果。", + "searchMinScoreResetTooltip": "恢复默认值 (0.4)", "startIndexingButton": "开始索引", "clearIndexDataButton": "清除索引数据", "unsavedSettingsMessage": "请先保存设置再开始索引过程。", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index 9a20f129a3..017a6faf4a 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -294,7 +294,8 @@ "codebaseSearch": { "wantsToSearch": "Roo 想要搜尋程式碼庫:{{query}}", "wantsToSearchWithPath": "Roo 想要在 {{path}} 中搜尋:{{query}}", - "didSearch": "找到 {{count}} 個結果:{{query}}" + "didSearch": "找到 {{count}} 個結果:{{query}}", + "resultTooltip": "相似度評分:{{score}} (點擊開啟檔案)" }, "read-batch": { "approve": { diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 874fbe7a37..5a6d33e82a 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -56,6 +56,10 @@ "ollamaUrlLabel": "Ollama URL:", "qdrantUrlLabel": "Qdrant URL", "qdrantKeyLabel": "Qdrant 金鑰:", + "advancedConfigLabel": "進階設定", + "searchMinScoreLabel": "搜尋分數閾值", + "searchMinScoreDescription": "搜尋結果所需的最低相似度分數(0.0-1.0)。較低的值會傳回更多結果,但可能較不相關。較高的值會傳回較少但更相關的結果。", + "searchMinScoreResetTooltip": "重設為預設值 (0.4)", "startIndexingButton": "開始索引", "clearIndexDataButton": "清除索引資料", "unsavedSettingsMessage": "請先儲存設定再開始索引程序。",