diff --git a/src/core/prompts/tools/__tests__/index.spec.ts b/src/core/prompts/tools/__tests__/index.spec.ts new file mode 100644 index 00000000000..32289b2fe92 --- /dev/null +++ b/src/core/prompts/tools/__tests__/index.spec.ts @@ -0,0 +1,185 @@ +import { describe, it, expect, vi, beforeEach } from "vitest" +import { getToolDescriptionsForMode } from "../index" +import { CodeIndexManager } from "../../../../services/code-index/manager" + +// Mock dependencies +vi.mock("../../../../services/code-index/manager") +vi.mock("../../../../services/mcp/McpHub") +vi.mock("../../../config/ContextProxy", () => ({ + ContextProxy: { + instance: { + getSettings: vi.fn(() => ({ todoListEnabled: true })), + }, + }, +})) + +describe("getToolDescriptionsForMode", () => { + let mockCodeIndexManager: any + + beforeEach(() => { + vi.clearAllMocks() + + // Setup mock CodeIndexManager + mockCodeIndexManager = { + isFeatureEnabled: true, + isFeatureConfigured: true, + isInitialized: true, + state: "Indexed", + } + + vi.mocked(CodeIndexManager).getInstance = vi.fn((_context: any) => mockCodeIndexManager as any) + }) + + describe("codebase_search tool availability", () => { + it("should include codebase_search when feature is enabled, configured, and indexing is complete", () => { + mockCodeIndexManager.isFeatureEnabled = true + mockCodeIndexManager.isFeatureConfigured = true + mockCodeIndexManager.state = "Indexed" + + const result = getToolDescriptionsForMode( + "code", + "/test/path", + false, + mockCodeIndexManager, + undefined, + undefined, + undefined, + [], + {}, + false, + { todoListEnabled: true }, + ) + + expect(result).toContain("codebase_search") + expect(result).toContain("Find files most relevant to the search query") + }) + + it("should exclude codebase_search when feature is disabled", () => { + mockCodeIndexManager.isFeatureEnabled = false + mockCodeIndexManager.isFeatureConfigured = true + mockCodeIndexManager.state = "Indexed" + + const result = getToolDescriptionsForMode( + "code", + "/test/path", + false, + mockCodeIndexManager, + undefined, + undefined, + undefined, + [], + {}, + false, + { todoListEnabled: true }, + ) + + expect(result).not.toContain("codebase_search") + }) + + it("should exclude codebase_search when feature is not configured", () => { + mockCodeIndexManager.isFeatureEnabled = true + mockCodeIndexManager.isFeatureConfigured = false + mockCodeIndexManager.state = "Indexed" + + const result = getToolDescriptionsForMode( + "code", + "/test/path", + false, + mockCodeIndexManager, + undefined, + undefined, + undefined, + [], + {}, + false, + { todoListEnabled: true }, + ) + + expect(result).not.toContain("codebase_search") + }) + + it("should exclude codebase_search when indexing is in Standby state", () => { + mockCodeIndexManager.isFeatureEnabled = true + mockCodeIndexManager.isFeatureConfigured = true + mockCodeIndexManager.state = "Standby" + + const result = getToolDescriptionsForMode( + "code", + "/test/path", + false, + mockCodeIndexManager, + undefined, + undefined, + undefined, + [], + {}, + false, + { todoListEnabled: true }, + ) + + expect(result).not.toContain("codebase_search") + }) + + it("should exclude codebase_search when indexing is in progress", () => { + mockCodeIndexManager.isFeatureEnabled = true + mockCodeIndexManager.isFeatureConfigured = true + mockCodeIndexManager.state = "Indexing" + + const result = getToolDescriptionsForMode( + "code", + "/test/path", + false, + mockCodeIndexManager, + undefined, + undefined, + undefined, + [], + {}, + false, + { todoListEnabled: true }, + ) + + expect(result).not.toContain("codebase_search") + }) + + it("should exclude codebase_search when indexing is in Error state", () => { + mockCodeIndexManager.isFeatureEnabled = true + mockCodeIndexManager.isFeatureConfigured = true + mockCodeIndexManager.state = "Error" + + const result = getToolDescriptionsForMode( + "code", + "/test/path", + false, + mockCodeIndexManager, + undefined, + undefined, + undefined, + [], + {}, + false, + { todoListEnabled: true }, + ) + + expect(result).not.toContain("codebase_search") + }) + + it("should exclude codebase_search when codeIndexManager is undefined", () => { + const result = getToolDescriptionsForMode( + "code", + "/test/path", + false, + undefined, + undefined, + undefined, + undefined, + [], + {}, + false, + { todoListEnabled: true }, + ) + + expect(result).not.toContain("codebase_search") + }) + }) +}) diff --git a/src/core/prompts/tools/index.ts b/src/core/prompts/tools/index.ts index 9f4af7f312c..561aadaf508 100644 --- a/src/core/prompts/tools/index.ts +++ b/src/core/prompts/tools/index.ts @@ -101,10 +101,12 @@ export function getToolDescriptionsForMode( // Add always available tools ALWAYS_AVAILABLE_TOOLS.forEach((tool) => tools.add(tool)) - // Conditionally exclude codebase_search if feature is disabled or not configured + // Conditionally exclude codebase_search if feature is disabled, not configured, or indexing is not complete if ( !codeIndexManager || - !(codeIndexManager.isFeatureEnabled && codeIndexManager.isFeatureConfigured && codeIndexManager.isInitialized) + !codeIndexManager.isFeatureEnabled || + !codeIndexManager.isFeatureConfigured || + codeIndexManager.state !== "Indexed" ) { tools.delete("codebase_search") } diff --git a/src/core/tools/__tests__/codebaseSearchTool.spec.ts b/src/core/tools/__tests__/codebaseSearchTool.spec.ts new file mode 100644 index 00000000000..aabcfb39aa4 --- /dev/null +++ b/src/core/tools/__tests__/codebaseSearchTool.spec.ts @@ -0,0 +1,363 @@ +import { describe, it, expect, vi, beforeEach } from "vitest" +import { codebaseSearchTool } from "../codebaseSearchTool" +import { CodeIndexManager } from "../../../services/code-index/manager" +import { Task } from "../../task/Task" +import { ToolUse } from "../../../shared/tools" +import { TelemetryService } from "@roo-code/telemetry" +import { TelemetryEventName } from "@roo-code/types" + +// Mock dependencies +vi.mock("../../../services/code-index/manager") +vi.mock("../../../utils/path", () => ({ + getWorkspacePath: vi.fn(() => "/test/workspace"), +})) +vi.mock("../../prompts/responses", () => ({ + formatResponse: { + toolDenied: vi.fn(() => "Tool denied"), + }, +})) +vi.mock("vscode", () => ({ + workspace: { + asRelativePath: vi.fn((path: string) => path.replace("/test/workspace/", "")), + }, +})) +vi.mock("@roo-code/telemetry", () => ({ + TelemetryService: { + instance: { + captureEvent: vi.fn(), + }, + }, +})) + +describe("codebaseSearchTool", () => { + let mockTask: Task + let mockAskApproval: any + let mockHandleError: any + let mockPushToolResult: any + let mockRemoveClosingTag: any + let mockCodeIndexManager: any + + beforeEach(() => { + vi.clearAllMocks() + + // Setup mock task + mockTask = { + ask: vi.fn().mockResolvedValue(undefined), + sayAndCreateMissingParamError: vi.fn().mockResolvedValue("Missing parameter error"), + consecutiveMistakeCount: 0, + providerRef: { + deref: vi.fn(() => ({ + context: {}, + })), + }, + say: vi.fn().mockResolvedValue(undefined), + } as any + + // Setup mock functions + mockAskApproval = vi.fn().mockResolvedValue(true) + mockHandleError = vi.fn() + mockPushToolResult = vi.fn() + mockRemoveClosingTag = vi.fn((tag, value) => value) + + // Setup mock CodeIndexManager + mockCodeIndexManager = { + isFeatureEnabled: true, + isFeatureConfigured: true, + isInitialized: true, + state: "Indexed", + searchIndex: vi.fn().mockResolvedValue([ + { + score: 0.9, + payload: { + filePath: "/test/workspace/src/file.ts", + startLine: 10, + endLine: 20, + codeChunk: "test code", + }, + }, + ]), + } + + vi.mocked(CodeIndexManager).getInstance = vi.fn((_context: any) => mockCodeIndexManager as any) + }) + + describe("codebase search functionality", () => { + it("should perform search when tool is available (feature enabled, configured, and indexed)", async () => { + mockCodeIndexManager.state = "Indexed" + + const block: ToolUse = { + type: "tool_use", + name: "codebase_search", + params: { query: "test query" }, + partial: false, + } + + await codebaseSearchTool( + mockTask, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + expect(mockCodeIndexManager.searchIndex).toHaveBeenCalledWith("test query", undefined) + // Check that say was called with the search results + expect(mockTask.say).toHaveBeenCalledWith("codebase_search_result", expect.stringContaining("test code")) + // Check that pushToolResult was called with the formatted output + expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Query: test query")) + expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("test code")) + expect(mockPushToolResult).not.toHaveBeenCalledWith( + expect.stringContaining("Semantic search is not available"), + ) + }) + }) + + describe("feature configuration checks", () => { + it("should throw error when feature is disabled", async () => { + mockCodeIndexManager.isFeatureEnabled = false + + const block: ToolUse = { + type: "tool_use", + name: "codebase_search", + params: { query: "test query" }, + partial: false, + } + + await codebaseSearchTool( + mockTask, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + expect(mockHandleError).toHaveBeenCalledWith( + "codebase_search", + expect.objectContaining({ + message: "Code Indexing is disabled in the settings.", + }), + ) + }) + + it("should throw error when feature is not configured", async () => { + mockCodeIndexManager.isFeatureConfigured = false + + const block: ToolUse = { + type: "tool_use", + name: "codebase_search", + params: { query: "test query" }, + partial: false, + } + + await codebaseSearchTool( + mockTask, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + expect(mockHandleError).toHaveBeenCalledWith( + "codebase_search", + expect.objectContaining({ + message: "Code Indexing is not configured (Missing OpenAI Key or Qdrant URL).", + }), + ) + }) + + it("should be available when enabled and configured but not initialized", async () => { + // This test verifies that the tool is available even when indexing is not complete + // The tool itself will handle the state checking + mockCodeIndexManager.isFeatureEnabled = true + mockCodeIndexManager.isFeatureConfigured = true + mockCodeIndexManager.isInitialized = false + mockCodeIndexManager.state = "Standby" + + const block: ToolUse = { + type: "tool_use", + name: "codebase_search", + params: { query: "test query" }, + partial: false, + } + + await codebaseSearchTool( + mockTask, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + // Should not throw an error, but should provide feedback about the state + expect(mockHandleError).not.toHaveBeenCalled() + expect(mockPushToolResult).toHaveBeenCalledWith( + expect.stringContaining("Semantic search is not available yet (currently Standby)"), + ) + }) + }) + + describe("telemetry tracking", () => { + it("should track telemetry for successful searches", async () => { + mockCodeIndexManager.state = "Indexed" + mockCodeIndexManager.searchIndex.mockResolvedValue([ + { + score: 0.9, + payload: { + filePath: "/test/workspace/src/file.ts", + startLine: 10, + endLine: 20, + codeChunk: "test code", + }, + }, + ]) + + const block: ToolUse = { + type: "tool_use", + name: "codebase_search", + params: { query: "test query" }, + partial: false, + } + + await codebaseSearchTool( + mockTask, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + // Should not capture telemetry event for non-indexed states + expect(TelemetryService.instance.captureEvent).not.toHaveBeenCalledWith( + TelemetryEventName.TOOL_USED, + expect.objectContaining({ + result: "unavailable_not_indexed", + }), + ) + }) + + it("should track telemetry with hasQuery false when query is missing", async () => { + mockCodeIndexManager.state = "Standby" + + const block: ToolUse = { + type: "tool_use", + name: "codebase_search", + params: {}, + partial: false, + } + + await codebaseSearchTool( + mockTask, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + // Even though query is missing, telemetry should still be tracked before parameter validation + expect(mockTask.sayAndCreateMissingParamError).toHaveBeenCalledWith("codebase_search", "query") + }) + }) + + describe("parameter validation", () => { + it("should handle missing query parameter", async () => { + const block: ToolUse = { + type: "tool_use", + name: "codebase_search", + params: {}, + partial: false, + } + + await codebaseSearchTool( + mockTask, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + expect(mockTask.sayAndCreateMissingParamError).toHaveBeenCalledWith("codebase_search", "query") + expect(mockPushToolResult).toHaveBeenCalledWith("Missing parameter error") + }) + + it("should handle partial tool use", async () => { + const block: ToolUse = { + type: "tool_use", + name: "codebase_search", + params: { query: "test" }, + partial: true, + } + + await codebaseSearchTool( + mockTask, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + // Should not track telemetry for non-indexed states since the tool won't be available + expect(TelemetryService.instance.captureEvent).not.toHaveBeenCalled() + }) + }) + + describe("search results handling", () => { + it("should handle empty search results", async () => { + mockCodeIndexManager.searchIndex.mockResolvedValue([]) + + const block: ToolUse = { + type: "tool_use", + name: "codebase_search", + params: { query: "test query" }, + partial: false, + } + + await codebaseSearchTool( + mockTask, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + expect(mockPushToolResult).toHaveBeenCalledWith( + 'No relevant code snippets found for the query: "test query"', + ) + }) + + it("should format search results correctly", async () => { + const block: ToolUse = { + type: "tool_use", + name: "codebase_search", + params: { query: "test query" }, + partial: false, + } + + await codebaseSearchTool( + mockTask, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + // The tool should call pushToolResult with a single formatted string containing all results + expect(mockPushToolResult).toHaveBeenCalledTimes(1) + const resultString = mockPushToolResult.mock.calls[0][0] + expect(resultString).toContain("Query: test query") + expect(resultString).toContain("File path: src/file.ts") + expect(resultString).toContain("Score: 0.9") + expect(resultString).toContain("Lines: 10-20") + expect(resultString).toContain("Code Chunk: test code") + }) + }) +}) diff --git a/src/core/tools/codebaseSearchTool.ts b/src/core/tools/codebaseSearchTool.ts index 236b066306d..70c7e16cf78 100644 --- a/src/core/tools/codebaseSearchTool.ts +++ b/src/core/tools/codebaseSearchTool.ts @@ -7,6 +7,28 @@ import { formatResponse } from "../prompts/responses" import { VectorStoreSearchResult } from "../../services/code-index/interfaces" import { AskApproval, HandleError, PushToolResult, RemoveClosingTag, ToolUse } from "../../shared/tools" import path from "path" +import { TelemetryService } from "@roo-code/telemetry" +import { TelemetryEventName } from "@roo-code/types" + +type IndexingState = "Standby" | "Indexing" | "Indexed" | "Error" + +/** + * Get a user-friendly message for the current indexing state + * @param state The current indexing state + * @returns A descriptive message for the user + */ +function getIndexingStateMessage(state: IndexingState): string { + switch (state) { + case "Standby": + return "Code indexing has not started yet. Please wait for the initial indexing to complete." + case "Indexing": + return "Code indexing is currently in progress. Semantic search will be available once indexing is complete." + case "Error": + return "Code indexing encountered an error. Please check your configuration and try again." + default: + return `Code indexing is in an unexpected state: ${state}` + } +} export async function codebaseSearchTool( cline: Task, @@ -82,6 +104,29 @@ export async function codebaseSearchTool( throw new Error("Code Indexing is not configured (Missing OpenAI Key or Qdrant URL).") } + // Check indexing state at runtime + const indexingState = manager.state as IndexingState + + // Track telemetry for non-indexed states + if (indexingState !== "Indexed") { + TelemetryService.instance.captureEvent(TelemetryEventName.TOOL_USED, { + tool: toolName, + codeIndexState: indexingState, + hasQuery: query ? true : false, + result: "unavailable_not_indexed", + }) + } + + if (indexingState !== "Indexed") { + const stateMessage = getIndexingStateMessage(indexingState) + + // Return informative message instead of throwing error + pushToolResult( + `Semantic search is not available yet (currently ${indexingState}).\n\n${stateMessage}\n\nPlease use file reading tools (read_file, search_files) for now.`, + ) + return + } + const searchResults: VectorStoreSearchResult[] = await manager.searchIndex(query, directoryPrefix) // 3. Format and push results diff --git a/src/i18n/locales/ca/embeddings.json b/src/i18n/locales/ca/embeddings.json index 651bc2b80fe..3e81a30b7cc 100644 --- a/src/i18n/locales/ca/embeddings.json +++ b/src/i18n/locales/ca/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "No s'ha pogut determinar la dimensió del vector per al model '{{modelId}}' amb el proveïdor '{{provider}}'. Comprova els perfils del model o la configuració.", "qdrantUrlMissing": "Falta l'URL de Qdrant per crear l'emmagatzematge de vectors", "codeIndexingNotConfigured": "No es poden crear serveis: La indexació de codi no està configurada correctament" + }, + "codeIndex": { + "errorState": "L'índex de codi està en estat d'error. Si us plau, comproveu la vostra configuració." } } diff --git a/src/i18n/locales/de/embeddings.json b/src/i18n/locales/de/embeddings.json index 167abc516cf..3bcd5e1c2a3 100644 --- a/src/i18n/locales/de/embeddings.json +++ b/src/i18n/locales/de/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "Konnte die Vektordimension für Modell '{{modelId}}' mit Anbieter '{{provider}}' nicht bestimmen. Überprüfe die Modellprofile oder Konfiguration.", "qdrantUrlMissing": "Qdrant-URL fehlt für die Erstellung des Vektorspeichers", "codeIndexingNotConfigured": "Kann keine Dienste erstellen: Code-Indizierung ist nicht richtig konfiguriert" + }, + "codeIndex": { + "errorState": "Der Code-Index befindet sich in einem Fehlerzustand. Bitte überprüfe deine Konfiguration." } } diff --git a/src/i18n/locales/en/embeddings.json b/src/i18n/locales/en/embeddings.json index 270a8d193b7..d37323a0e7a 100644 --- a/src/i18n/locales/en/embeddings.json +++ b/src/i18n/locales/en/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "Could not determine vector dimension for model '{{modelId}}' with provider '{{provider}}'. Check model profiles or configuration.", "qdrantUrlMissing": "Qdrant URL missing for vector store creation", "codeIndexingNotConfigured": "Cannot create services: Code indexing is not properly configured" + }, + "codeIndex": { + "errorState": "Code index is in error state. Please check your configuration." } } diff --git a/src/i18n/locales/es/embeddings.json b/src/i18n/locales/es/embeddings.json index 06478f1d506..2d5faaae4ca 100644 --- a/src/i18n/locales/es/embeddings.json +++ b/src/i18n/locales/es/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "No se pudo determinar la dimensión del vector para el modelo '{{modelId}}' con el proveedor '{{provider}}'. Verifica los perfiles del modelo o la configuración.", "qdrantUrlMissing": "Falta la URL de Qdrant para crear el almacén de vectores", "codeIndexingNotConfigured": "No se pueden crear servicios: La indexación de código no está configurada correctamente" + }, + "codeIndex": { + "errorState": "El índice de código está en estado de error. Por favor, comprueba tu configuración." } } diff --git a/src/i18n/locales/fr/embeddings.json b/src/i18n/locales/fr/embeddings.json index 167d093e7ac..e6500fb59e9 100644 --- a/src/i18n/locales/fr/embeddings.json +++ b/src/i18n/locales/fr/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "Impossible de déterminer la dimension du vecteur pour le modèle '{{modelId}}' avec le fournisseur '{{provider}}'. Vérifie les profils du modèle ou la configuration.", "qdrantUrlMissing": "URL Qdrant manquante pour la création du stockage de vecteurs", "codeIndexingNotConfigured": "Impossible de créer les services : L'indexation du code n'est pas correctement configurée" + }, + "codeIndex": { + "errorState": "L'index de code est en état d'erreur. Veuillez vérifier votre configuration." } } diff --git a/src/i18n/locales/hi/embeddings.json b/src/i18n/locales/hi/embeddings.json index ad24cfe9d17..cd63c936769 100644 --- a/src/i18n/locales/hi/embeddings.json +++ b/src/i18n/locales/hi/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "प्रदाता '{{provider}}' के साथ मॉडल '{{modelId}}' के लिए वेक्टर आयाम निर्धारित नहीं कर सका। मॉडल प्रोफ़ाइल या कॉन्फ़िगरेशन की जांच करें।", "qdrantUrlMissing": "वेक्टर स्टोर बनाने के लिए Qdrant URL गायब है", "codeIndexingNotConfigured": "सेवाएं नहीं बना सकते: कोड इंडेक्सिंग ठीक से कॉन्फ़िगर नहीं है" + }, + "codeIndex": { + "errorState": "कोड इंडेक्स त्रुटि स्थिति में है। कृपया अपनी कॉन्फ़िगरेशन जांचें।" } } diff --git a/src/i18n/locales/id/embeddings.json b/src/i18n/locales/id/embeddings.json index 997c6e80186..93c1198ace0 100644 --- a/src/i18n/locales/id/embeddings.json +++ b/src/i18n/locales/id/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "Tidak dapat menentukan dimensi vektor untuk model '{{modelId}}' dengan penyedia '{{provider}}'. Periksa profil model atau konfigurasi.", "qdrantUrlMissing": "URL Qdrant tidak ada untuk membuat penyimpanan vektor", "codeIndexingNotConfigured": "Tidak dapat membuat layanan: Pengindeksan kode tidak dikonfigurasi dengan benar" + }, + "codeIndex": { + "errorState": "Indeks kode dalam status kesalahan. Silakan periksa konfigurasi Anda." } } diff --git a/src/i18n/locales/it/embeddings.json b/src/i18n/locales/it/embeddings.json index 1bc406aecb7..f1d72a3554b 100644 --- a/src/i18n/locales/it/embeddings.json +++ b/src/i18n/locales/it/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "Impossibile determinare la dimensione del vettore per il modello '{{modelId}}' con il provider '{{provider}}'. Controlla i profili del modello o la configurazione.", "qdrantUrlMissing": "URL Qdrant mancante per la creazione dello storage vettoriale", "codeIndexingNotConfigured": "Impossibile creare i servizi: L'indicizzazione del codice non è configurata correttamente" + }, + "codeIndex": { + "errorState": "L'indice del codice è in stato di errore. Controlla la tua configurazione." } } diff --git a/src/i18n/locales/ja/embeddings.json b/src/i18n/locales/ja/embeddings.json index 7152eb52dfd..f8e40513fff 100644 --- a/src/i18n/locales/ja/embeddings.json +++ b/src/i18n/locales/ja/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "プロバイダー '{{provider}}' のモデル '{{modelId}}' の埋め込み次元を決定できませんでした。モデルプロファイルまたは設定を確認してください。", "qdrantUrlMissing": "ベクターストア作成のためのQdrant URLがありません", "codeIndexingNotConfigured": "サービスを作成できません: コードインデックスが正しく設定されていません" + }, + "codeIndex": { + "errorState": "コードインデックスがエラー状態です。設定を確認してください。" } } diff --git a/src/i18n/locales/ko/embeddings.json b/src/i18n/locales/ko/embeddings.json index f1c40f66bce..53c2eff901d 100644 --- a/src/i18n/locales/ko/embeddings.json +++ b/src/i18n/locales/ko/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "프로바이더 '{{provider}}'의 모델 '{{modelId}}'에 대한 벡터 차원을 결정할 수 없습니다. 모델 프로필 또는 구성을 확인하세요.", "qdrantUrlMissing": "벡터 저장소 생성을 위한 Qdrant URL이 누락되었습니다", "codeIndexingNotConfigured": "서비스를 생성할 수 없습니다: 코드 인덱싱이 올바르게 구성되지 않았습니다" + }, + "codeIndex": { + "errorState": "코드 인덱스가 오류 상태입니다. 구성을 확인하십시오." } } diff --git a/src/i18n/locales/nl/embeddings.json b/src/i18n/locales/nl/embeddings.json index 19b7bfeaa22..e7840acf89a 100644 --- a/src/i18n/locales/nl/embeddings.json +++ b/src/i18n/locales/nl/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "Kan de vectordimensie voor model '{{modelId}}' met provider '{{provider}}' niet bepalen. Controleer modelprofielen of configuratie.", "qdrantUrlMissing": "Qdrant URL ontbreekt voor het maken van vectoropslag", "codeIndexingNotConfigured": "Kan geen services maken: Code-indexering is niet correct geconfigureerd" + }, + "codeIndex": { + "errorState": "De code-index heeft een foutstatus. Controleer uw configuratie." } } diff --git a/src/i18n/locales/pl/embeddings.json b/src/i18n/locales/pl/embeddings.json index 46e761cb8b6..0db5d139a04 100644 --- a/src/i18n/locales/pl/embeddings.json +++ b/src/i18n/locales/pl/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "Nie można określić wymiaru wektora dla modelu '{{modelId}}' z dostawcą '{{provider}}'. Sprawdź profile modelu lub konfigurację.", "qdrantUrlMissing": "Brak adresu URL Qdrant do utworzenia magazynu wektorów", "codeIndexingNotConfigured": "Nie można utworzyć usług: Indeksowanie kodu nie jest poprawnie skonfigurowane" + }, + "codeIndex": { + "errorState": "Indeks kodu jest w stanie błędu. Sprawdź swoją konfigurację." } } diff --git a/src/i18n/locales/pt-BR/embeddings.json b/src/i18n/locales/pt-BR/embeddings.json index 816b1ecded4..6956ad17402 100644 --- a/src/i18n/locales/pt-BR/embeddings.json +++ b/src/i18n/locales/pt-BR/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "Não foi possível determinar a dimensão do vetor para o modelo '{{modelId}}' com o provedor '{{provider}}'. Verifique os perfis do modelo ou a configuração.", "qdrantUrlMissing": "URL do Qdrant ausente para criação do armazenamento de vetores", "codeIndexingNotConfigured": "Não é possível criar serviços: A indexação de código não está configurada corretamente" + }, + "codeIndex": { + "errorState": "O índice de código está em estado de erro. Verifique sua configuração." } } diff --git a/src/i18n/locales/ru/embeddings.json b/src/i18n/locales/ru/embeddings.json index fb1688e2ca4..5750bab7ba3 100644 --- a/src/i18n/locales/ru/embeddings.json +++ b/src/i18n/locales/ru/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "Не удалось определить размерность вектора для модели '{{modelId}}' с провайдером '{{provider}}'. Проверьте профили модели или конфигурацию.", "qdrantUrlMissing": "Отсутствует URL Qdrant для создания векторного хранилища", "codeIndexingNotConfigured": "Невозможно создать сервисы: Индексация кода не настроена должным образом" + }, + "codeIndex": { + "errorState": "Индекс кода находится в состоянии ошибки. Проверьте свою конфигурацию." } } diff --git a/src/i18n/locales/tr/embeddings.json b/src/i18n/locales/tr/embeddings.json index 5023190929a..e84855929e5 100644 --- a/src/i18n/locales/tr/embeddings.json +++ b/src/i18n/locales/tr/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "'{{provider}}' sağlayıcısı ile '{{modelId}}' modeli için vektör boyutu belirlenemedi. Model profillerini veya yapılandırmayı kontrol et.", "qdrantUrlMissing": "Vektör deposu oluşturmak için Qdrant URL'si eksik", "codeIndexingNotConfigured": "Hizmetler oluşturulamıyor: Kod indeksleme düzgün yapılandırılmamış" + }, + "codeIndex": { + "errorState": "Kod dizini hata durumunda. Lütfen yapılandırmanızı kontrol edin." } } diff --git a/src/i18n/locales/vi/embeddings.json b/src/i18n/locales/vi/embeddings.json index 626f0f68624..71a9f93f8f7 100644 --- a/src/i18n/locales/vi/embeddings.json +++ b/src/i18n/locales/vi/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "Không thể xác định kích thước vector cho mô hình '{{modelId}}' với nhà cung cấp '{{provider}}'. Kiểm tra hồ sơ mô hình hoặc cấu hình.", "qdrantUrlMissing": "Thiếu URL Qdrant để tạo kho lưu trữ vector", "codeIndexingNotConfigured": "Không thể tạo dịch vụ: Lập chỉ mục mã không được cấu hình đúng cách" + }, + "codeIndex": { + "errorState": "Chỉ mục mã đang ở trạng thái lỗi. Vui lòng kiểm tra cấu hình của bạn." } } diff --git a/src/i18n/locales/zh-CN/embeddings.json b/src/i18n/locales/zh-CN/embeddings.json index 3247631bb24..db1c2a106a6 100644 --- a/src/i18n/locales/zh-CN/embeddings.json +++ b/src/i18n/locales/zh-CN/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "无法确定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量维度。请检查模型配置文件或配置。", "qdrantUrlMissing": "创建向量存储缺少 Qdrant URL", "codeIndexingNotConfigured": "无法创建服务:代码索引未正确配置" + }, + "codeIndex": { + "errorState": "代码索引处于错误状态。请检查您的配置。" } } diff --git a/src/i18n/locales/zh-TW/embeddings.json b/src/i18n/locales/zh-TW/embeddings.json index b3b3231d4ab..cd6a7215898 100644 --- a/src/i18n/locales/zh-TW/embeddings.json +++ b/src/i18n/locales/zh-TW/embeddings.json @@ -52,5 +52,8 @@ "vectorDimensionNotDetermined": "無法確定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量維度。請檢查模型設定檔或設定。", "qdrantUrlMissing": "建立向量儲存缺少 Qdrant URL", "codeIndexingNotConfigured": "無法建立服務:程式碼索引未正確設定" + }, + "codeIndex": { + "errorState": "程式碼索引處於錯誤狀態。請檢查您的設定。" } } diff --git a/src/services/code-index/search-service.ts b/src/services/code-index/search-service.ts index a56f5cc6744..238b49dd3a1 100644 --- a/src/services/code-index/search-service.ts +++ b/src/services/code-index/search-service.ts @@ -6,6 +6,7 @@ import { CodeIndexConfigManager } from "./config-manager" import { CodeIndexStateManager } from "./state-manager" import { TelemetryService } from "@roo-code/telemetry" import { TelemetryEventName } from "@roo-code/types" +import { t } from "../../i18n" /** * Service responsible for searching the code index. @@ -34,10 +35,11 @@ export class CodeIndexSearchService { const minScore = this.configManager.currentSearchMinScore const maxResults = this.configManager.currentSearchMaxResults + // Note: State checking is now handled in the codebaseSearchTool + // This allows the tool to provide more user-friendly feedback const currentState = this.stateManager.getCurrentStatus().systemStatus - if (currentState !== "Indexed" && currentState !== "Indexing") { - // Allow search during Indexing too - throw new Error(`Code index is not ready for search. Current state: ${currentState}`) + if (currentState === "Error") { + throw new Error(t("embeddings:codeIndex.errorState")) } try {