From efaaed9f7381f7d9d1d027193b870cf0596adb4e Mon Sep 17 00:00:00 2001 From: MuriloFP Date: Thu, 3 Jul 2025 15:26:24 -0300 Subject: [PATCH 1/6] feat: add Issue Fixer Orchestrator mode --- .../1_Workflow.xml | 402 +++++++++++++----- .../2_best_practices.xml | 31 +- .roomodes | 3 +- 3 files changed, 315 insertions(+), 121 deletions(-) diff --git a/.roo/rules-issue-fixer-orchestrator/1_Workflow.xml b/.roo/rules-issue-fixer-orchestrator/1_Workflow.xml index 2ad4bf65fc7..3e6619993ec 100644 --- a/.roo/rules-issue-fixer-orchestrator/1_Workflow.xml +++ b/.roo/rules-issue-fixer-orchestrator/1_Workflow.xml @@ -27,7 +27,7 @@ Delegate: Analyze Requirements & Explore Codebase - Launch a subtask in `code` mode to perform a detailed analysis of the issue and the codebase. The subtask will be responsible for identifying affected files and creating an implementation plan. + Launch a subtask in `architect` mode to perform a detailed analysis of the issue and the codebase. The subtask will be responsible for identifying affected files and creating an implementation plan. The context file `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/issue_context.json` will be the input for this subtask. The subtask should write its findings (the implementation plan) to a new file: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/implementation_plan.md`. @@ -36,19 +36,50 @@ **Task: Analyze Issue and Create Implementation Plan** - You are an expert software architect. Your task is to analyze the provided GitHub issue and the current codebase to create a detailed implementation plan. + You are an expert software architect. Your task is to analyze the provided GitHub issue and the current codebase to create a detailed implementation plan with a focus on understanding component interactions and dependencies. 1. **Read Issue Context**: The full issue details and comments are in `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/issue_context.json`. Read this file to understand all requirements, acceptance criteria, and technical discussions. - 2. **Explore Codebase**: Use `codebase_search`, `read_file`, and other tools to explore the codebase. Identify all files that will need to be modified or created to address the issue. Analyze existing patterns and conventions. - - 3. **Create Implementation Plan**: Based on your analysis, create a comprehensive implementation plan. The plan should be detailed enough for another developer to execute. It must include: - - A summary of the issue and the proposed solution. - - A list of all files to be created or modified. - - A step-by-step guide for the code changes required in each file. - - A plan for writing or updating tests. - - 4. **Save the Plan**: Write the complete implementation plan to `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/implementation_plan.md`. + 2. **Perform Architectural Analysis**: + - **Map Component Interactions**: Trace the complete data flow from entry points to outputs + - **Identify Paired Operations**: For any operation (e.g., export), find its counterpart (e.g., import) + - **Find Similar Patterns**: Search for existing implementations of similar features + - **Analyze Dependencies**: Identify all consumers of the functionality being modified + - **Assess Impact**: Determine how changes will affect other parts of the system + + 3. **Explore Codebase Systematically**: + - Use `codebase_search` FIRST to find all related functionality + - Search for paired operations (if modifying export, search for import) + - Find all files that consume or depend on the affected functionality + - Identify configuration files, tests, and documentation that need updates + - Study similar features to understand established patterns + + 4. **Create Comprehensive Implementation Plan**: The plan must include: + - **Issue Summary**: Clear description of the problem and proposed solution + - **Architectural Context**: + - Data flow diagram showing component interactions + - List of paired operations that must be updated together + - Dependencies and consumers of the affected functionality + - **Impact Analysis**: + - All files that will be affected (directly and indirectly) + - Potential breaking changes + - Performance implications + - **Implementation Steps**: + - Detailed, ordered steps for each file modification + - Specific code changes with context + - Validation and error handling requirements + - **Testing Strategy**: + - Unit tests for individual components + - Integration tests for component interactions + - Edge cases and error scenarios + + 5. **Save the Plan**: Write the complete implementation plan to `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/implementation_plan.md`. + + **Critical Requirements:** + - Always search for and analyze paired operations (import/export, save/load, etc.) + - Map the complete data flow before proposing changes + - Identify all integration points and dependencies + - Consider backward compatibility and migration needs **Completion Protocol:** - This is your only task. Do not deviate from these instructions. @@ -110,19 +141,43 @@ **Task: Implement Code Changes Based on Plan** - You are an expert software developer. Your task is to implement the code changes exactly as described in the provided implementation plan. + You are an expert software developer. Your task is to implement the code changes with full awareness of system interactions and dependencies. - 1. **Read the Plan**: The implementation plan is located at `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/implementation_plan.md`. Follow its instructions carefully. + 1. **Read the Plan**: The implementation plan is located at `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/implementation_plan.md`. Pay special attention to: + - The architectural context section + - Component interaction diagrams + - Identified dependencies and related operations + - Impact analysis - 2. **Implement Changes**: Use `apply_diff` and `write_to_file` to make the specified code changes. Adhere to all coding standards and patterns mentioned in the plan. + 2. **Validate Understanding**: Before coding, ensure you understand: + - How data flows through the system + - All related operations that must be updated together + - Dependencies that could be affected + - Integration points with other components - 3. **Implement Tests**: Write new unit and integration tests as specified in the plan to ensure quality and prevent regressions. + 3. **Implement Holistically**: + - **Update Related Operations Together**: If modifying one operation, update all related operations + - **Maintain Consistency**: Ensure data structures, validation, and error handling are consistent + - **Consider Side Effects**: Account for how changes propagate through the system + - **Follow Existing Patterns**: Use established patterns from similar features - 4. **Track Modified Files**: As you modify or create files, keep a running list. + 4. **Implement Tests**: + - Write tests that verify component interactions + - Test related operations together + - Include edge cases and error scenarios + - Verify data consistency across operations - 5. **Save Modified Files List**: After all changes are implemented and tested, save the list of all file paths you created or modified to `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/modified_files.json`. The format should be a JSON array of strings. + 5. **Track Modified Files**: As you modify or create files, keep a running list. + + 6. **Save Modified Files List**: After all changes are implemented and tested, save the list of all file paths you created or modified to `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/modified_files.json`. The format should be a JSON array of strings. Example: `["src/components/NewFeature.tsx", "src/__tests__/NewFeature.spec.ts"]` + **Critical Reminders:** + - Never implement changes in isolation - consider the full system impact + - Always update related operations together to maintain consistency + - Test component interactions, not just individual functions + - Follow the architectural analysis from the planning phase + Once the `modified_files.json` file is saved, your task is complete. @@ -325,122 +380,233 @@ - Create Pull Request + Delegate: Review Changes Before PR - This is the final step where the orchestrator takes all the prepared materials and creates the pull request. + Before creating the pull request, delegate to the PR reviewer mode to get feedback on the implementation and proposed changes. - 1. **Read PR Summary**: - - - - .roo/temp/issue-fixer-orchestrator/[TASK_ID]/pr_summary.json - - - - - 2. **Get Final Approval**: Present the PR title and body to the user for final approval, providing an option to request changes. + + pr-reviewer + + **Task: Review Implementation Before PR Creation** - - - I have prepared the pull request. Please review and confirm. + You are an expert code reviewer. Your task is to review the implementation for issue #[issue-number] and provide feedback before a pull request is created. - **Title**: [Insert title from pr_summary.json] + **Context Files:** + - **Issue Details**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/issue_context.json` + - **Implementation Plan**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/implementation_plan.md` + - **Modified Files**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/modified_files.json` + - **Verification Results**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/verification_results.md` + - **Translation Summary** (if exists): `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/translation_summary.md` + - **Draft PR Summary**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/pr_summary.json` + + **Your Review Focus:** + 1. **Code Quality**: Review the actual code changes for: + - Adherence to project coding standards + - Proper error handling and edge cases + - Performance considerations + - Security implications + - Maintainability and readability + + 2. **Implementation Completeness**: Verify that: + - All requirements from the issue are addressed + - The solution follows the implementation plan + - No critical functionality is missing + - Proper test coverage exists + + 3. **Integration Concerns**: Check for: + - Potential breaking changes + - Impact on other parts of the system + - Backward compatibility issues + - API consistency + + 4. **Documentation and Communication**: Assess: + - Code comments and documentation + - PR description clarity and completeness + - Translation handling (if applicable) - **Body**: - --- - [Insert body from pr_summary.json] - --- + **Your Task:** + 1. Read all context files to understand the issue and implementation + 2. Review each modified file listed in `modified_files.json` + 3. Analyze the code changes against the requirements + 4. Identify any issues, improvements, or concerns + 5. Create a comprehensive review report with specific, actionable feedback + 6. Save your review to `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/pr_review_feedback.md` + + **Review Report Format:** + ```markdown + # PR Review Feedback for Issue #[issue-number] + + ## Overall Assessment + [High-level assessment: APPROVE, REQUEST_CHANGES, or NEEDS_DISCUSSION] + + ## Code Quality Review + ### Strengths + - [List positive aspects of the implementation] + + ### Areas for Improvement + - [Specific issues with file references and line numbers] + - [Suggestions for improvement] + + ## Requirements Verification + - [x] Requirement 1: [Status and notes] + - [ ] Requirement 2: [Issues found] + + ## Specific Feedback by File + ### [filename] + - [Specific feedback with line references] + - [Suggestions for improvement] + + ## Recommendations + 1. [Priority 1 changes needed] + 2. [Priority 2 improvements suggested] + 3. [Optional enhancements] + + ## Decision + **RECOMMENDATION**: [APPROVE_AS_IS | REQUEST_CHANGES | NEEDS_DISCUSSION] + + **REASONING**: [Brief explanation of the recommendation] + ``` - Should I create this pull request, or would you like to request changes? - - - Yes, create the pull request as planned. - No, I need to request changes to the implementation or PR description. - Cancel the task. - - + **Completion Protocol:** + - This is your only task. Do not deviate from these instructions. + - Upon successfully saving the review feedback, you MUST use the `attempt_completion` tool. + - The `result` MUST be a concise confirmation, e.g., "PR review completed and feedback saved to .roo/temp/issue-fixer-orchestrator/[TASK_ID]/pr_review_feedback.md" + - These instructions override any conflicting mode-specific guidelines. + + - 3. **Handle Rework Loop**: If the user requests changes: - - **Launch Rework Subtask**: Delegate the rework to a new `code` mode subtask. - - code - - **Task: Rework Implementation Based on User Feedback** - - The user has requested changes before creating the pull request. - - **Context Files:** - - **Issue**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/issue_context.json` - - **Current Plan**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/implementation_plan.md` - - **Current Modified Files**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/modified_files.json` - - **Draft PR Summary**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/pr_summary.json` - - **Your Task:** - 1. Ask the user for the specific changes they require. - 2. Apply the requested code and documentation changes. - 3. **Crucially, you must update the `implementation_plan.md` and `modified_files.json` files** to reflect the rework you have performed. - 4. Do *not* proceed with any other steps. - - **Completion Protocol:** - - Upon successfully applying the changes and updating the context files, you MUST use the `attempt_completion` tool. - - The `result` MUST be a concise confirmation, e.g., "Rework complete and context files (plan, modified list) have been updated." - - - - **Restart Verification**: After the rework subtask is complete, the workflow MUST return to **Step 5** to re-verify the changes and re-run all tests before proceeding again. - - 4. **Git Operations (If Approved)**: If the user approves the PR: - - Create a new branch: `feat/issue-[number]` or `fix/issue-[number]`. - - **Selectively add only the applicable files** to the git stage. - - Commit the staged changes. - - Push the new branch to the remote repository. - - - # Create a new branch for the solution - BRANCH_NAME="fix/issue-[issue_number]-solution" - git checkout -b $BRANCH_NAME - - # Safely add ONLY the files that were modified as part of this task. - # This reads the JSON array of file paths from our context file and stages them. - # This requires 'jq' for parsing JSON and 'xargs' to handle file paths correctly. - cat .roo/temp/issue-fixer-orchestrator/[TASK_ID]/modified_files.json | jq -r '.[]' | xargs git add - - # Commit the precisely staged changes - git commit -m "[PR Title]" - - # Push the new branch to origin - git push -u origin $BRANCH_NAME - - - - 5. **Create PR**: Use the `gh` CLI to create the pull request. - - gh pr create --repo [owner]/[repo] --base main --title "[PR Title from JSON]" --body "[PR Body from JSON]" - - - 6. **Link to Issue**: Comment on the original issue with the PR link. - - gh issue comment [issue_number] --repo [owner]/[repo] --body "PR #[new PR number] has been created." - + After the review subtask completes, read and process the feedback. - Monitor PR Checks and Cleanup + Process Review Feedback and Decide Next Steps - After creating the PR, monitor the CI checks and then clean up the temporary files. + After the PR review is complete, read the feedback and decide whether to make changes or proceed with PR creation. + + 1. **Read Review Feedback**: + + + + .roo/temp/issue-fixer-orchestrator/[TASK_ID]/pr_review_feedback.md + + + + + 2. **Present Feedback to User**: Show the review feedback and ask for direction. + + + The PR review has been completed. Here is the feedback: + + --- + [Insert content of pr_review_feedback.md here] + --- + + Based on this review, how would you like to proceed? + + + Implement the suggested changes before creating the PR + Create the PR as-is, ignoring the review feedback + Discuss specific feedback points before deciding + Cancel the task + + + + 3. **Handle User Decision**: + + **If user chooses to implement changes:** + - Launch a rework subtask to address the review feedback + + code + + **Task: Address PR Review Feedback** + + The PR review has identified areas for improvement. Your task is to address the feedback before creating the pull request. + + **Context Files:** + - **Issue**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/issue_context.json` + - **Current Plan**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/implementation_plan.md` + - **Current Modified Files**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/modified_files.json` + - **Review Feedback**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/pr_review_feedback.md` + - **Draft PR Summary**: `.roo/temp/issue-fixer-orchestrator/[TASK_ID]/pr_summary.json` + + **Your Task:** + 1. Read the review feedback carefully + 2. Address each point raised by the reviewer + 3. Make the necessary code changes + 4. Update tests if needed + 5. **Update the `modified_files.json` file** to reflect any new or changed files + 6. **Update the `implementation_plan.md`** if the approach has changed significantly + + **Important Notes:** + - Focus on the specific issues identified in the review + - Maintain the overall solution approach unless the review suggests otherwise + - Ensure all changes are properly tested + - Do not proceed with any other workflow steps + + **Completion Protocol:** + - Upon successfully addressing the feedback and updating context files, you MUST use the `attempt_completion` tool. + - The `result` MUST be a concise confirmation, e.g., "Review feedback addressed and context files updated." + + + - **After rework completion**: Return to **Step 5** (Verify and Test) to re-verify the changes + + **If user chooses to proceed as-is:** + - Continue to the next step (Create Pull Request) + + **If user wants to discuss or cancel:** + - Handle accordingly based on user input + + - 1. **Monitor Checks**: Use `--watch` to monitor CI status in real-time. - - gh pr checks [PR URL or number] --repo [owner]/[repo] --watch - + + Prepare Branch and Present PR Template + + This step prepares the branch and commits, then presents the PR template to the user for confirmation before creating the actual pull request. + + 1. Read Issue Context for Issue Number: + Use read_file to get the issue context from .roo/temp/issue-fixer-orchestrator/[TASK_ID]/issue_context.json + + 2. Git Operations - Create branch and commit changes: + - Create a new branch: feat/issue-[number] or fix/issue-[number] + - Selectively add only the applicable files to the git stage + - Commit the staged changes + - Push the new branch to the remote repository + + Use execute_command with: + BRANCH_NAME="fix/issue-[issue_number]-solution" + git checkout -b $BRANCH_NAME + cat .roo/temp/issue-fixer-orchestrator/[TASK_ID]/modified_files.json | jq -r '.[]' | xargs git add + git commit -m "[PR Title]" + git push -u origin $BRANCH_NAME + + 3. Present PR Template - Instead of creating the PR automatically, present the standardized PR template to the user: + Use ask_followup_question to ask: "The branch has been created and changes have been committed. I have prepared a standardized PR template for this issue. Would you like me to create the pull request using the standard Roo Code PR template, or would you prefer to make changes first?" + + Provide these options: + - Yes, create the pull request with the standard template + - No, I want to make changes to the implementation first + - No, I want to customize the PR template before creating it + - Cancel the task + + 4. Handle User Decision: + If user chooses to create the PR: Use gh CLI to create the pull request with the standard template + If user chooses to make changes: Launch a rework subtask using new_task with code mode + If user wants to customize the template: Ask for their preferred PR title and body + + 5. Link to Issue - After PR creation, comment on the original issue with the PR link using gh issue comment + + - 2. **Report Status**: Inform the user of the final status of the checks. + + Monitor PR Checks and Cleanup + + After creating the PR (if created), monitor the CI checks and then clean up the temporary files. - 3. **Cleanup**: Remove the temporary task directory. - - rm -rf .roo/temp/issue-fixer-orchestrator/[TASK_ID] - - + 1. Monitor Checks - Use gh pr checks with --watch to monitor CI status in real-time + 2. Report Status - Inform the user of the final status of the checks + 3. Cleanup - Remove the temporary task directory using rm -rf .roo/temp/issue-fixer-orchestrator/[TASK_ID] + This concludes the orchestration workflow. diff --git a/.roo/rules-issue-fixer-orchestrator/2_best_practices.xml b/.roo/rules-issue-fixer-orchestrator/2_best_practices.xml index e6251d67b23..b9a9b52db78 100644 --- a/.roo/rules-issue-fixer-orchestrator/2_best_practices.xml +++ b/.roo/rules-issue-fixer-orchestrator/2_best_practices.xml @@ -27,6 +27,17 @@ Always use `codebase_search` FIRST to understand the codebase structure and find all related files before using other tools like `read_file`. + + Critical: Understand Component Interactions + + Map the complete data flow from input to output + Identify ALL paired operations (import/export, save/load, encode/decode) + Find all consumers and dependencies of the affected code + Trace how data transformations occur throughout the system + Understand error propagation and handling patterns + + + Investigation Checklist for Bug Fixes Search for the specific error message or broken functionality. @@ -34,6 +45,8 @@ Locate related test files to understand expected behavior. Identify all dependencies and import/export patterns for the affected code. Find similar, working patterns in the codebase to use as a reference. + **CRITICAL**: For any operation being fixed, find and analyze its paired operations + Trace the complete data flow to understand all affected components @@ -42,10 +55,26 @@ Find potential integration points (e.g., API routes, UI component registries). Locate relevant configuration files that may need to be updated. Identify common patterns, components, and utilities that should be reused. + **CRITICAL**: Design paired operations together (e.g., both import AND export) + Map all data transformations and state changes + Identify all downstream consumers of the new functionality + + Always Implement Paired Operations Together + + When fixing export, ALWAYS check and update import + When modifying save, ALWAYS verify load handles the changes + When changing serialization, ALWAYS update deserialization + When updating create, consider read/update/delete operations + + + Paired operations must maintain consistency. Changes to one without the other leads to data corruption, import failures, or broken functionality. + + + - Always read multiple related files together to understand the full context, including coding conventions, testing patterns, and error handling approaches. + Always read multiple related files together to understand the full context. Never assume a change is isolated - trace its impact through the entire system. \ No newline at end of file diff --git a/.roomodes b/.roomodes index 3b178f234fa..213d7b8314a 100644 --- a/.roomodes +++ b/.roomodes @@ -9,7 +9,7 @@ customModes: - Ensuring modes have appropriate tool group permissions - Crafting clear whenToUse descriptions for the Orchestrator - Following XML structuring best practices for clarity and parseability - + You help users create new modes by: - Gathering requirements about the mode's purpose and workflow - Defining appropriate roleDefinition and whenToUse descriptions @@ -182,4 +182,3 @@ customModes: - edit - command source: project - description: Issue Fixer mode ported into an orchestrator From 616cafc3a1e1a85d19970c997eb9bceb9ef7aede Mon Sep 17 00:00:00 2001 From: MuriloFP Date: Wed, 23 Jul 2025 11:10:48 -0300 Subject: [PATCH 2/6] fix: handle codebase search indexing state properly (#5662) - Always show codebase_search tool in the tool list - Add runtime state checking with user-friendly feedback - Provide clear messages for each indexing state (Standby, Indexing, Error) - Suggest alternative tools when semantic search is unavailable - Add comprehensive tests for the new behavior This ensures Roo doesn't try to use semantic search when indexing is incomplete and provides clear feedback to users about the current state. --- src/core/prompts/tools/index.ts | 9 +- .../__tests__/codebaseSearchTool.spec.ts | 344 ++++++++++++++++++ src/core/tools/codebaseSearchTool.ts | 27 ++ src/services/code-index/search-service.ts | 7 +- 4 files changed, 377 insertions(+), 10 deletions(-) create mode 100644 src/core/tools/__tests__/codebaseSearchTool.spec.ts diff --git a/src/core/prompts/tools/index.ts b/src/core/prompts/tools/index.ts index 9f4af7f312c..be3bb3ccd15 100644 --- a/src/core/prompts/tools/index.ts +++ b/src/core/prompts/tools/index.ts @@ -101,13 +101,8 @@ 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 - if ( - !codeIndexManager || - !(codeIndexManager.isFeatureEnabled && codeIndexManager.isFeatureConfigured && codeIndexManager.isInitialized) - ) { - tools.delete("codebase_search") - } + // Note: codebase_search is now always included in the tool list + // The tool itself will check the indexing state at runtime and provide appropriate feedback // Conditionally exclude update_todo_list if disabled in settings if (settings?.todoListEnabled === false) { diff --git a/src/core/tools/__tests__/codebaseSearchTool.spec.ts b/src/core/tools/__tests__/codebaseSearchTool.spec.ts new file mode 100644 index 00000000000..b3b5d0d8d96 --- /dev/null +++ b/src/core/tools/__tests__/codebaseSearchTool.spec.ts @@ -0,0 +1,344 @@ +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" + +// 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/", "")), + }, +})) + +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("indexing state checks", () => { + it("should provide feedback when indexing is in Standby state", async () => { + 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, + ) + + expect(mockPushToolResult).toHaveBeenCalledWith( + expect.stringContaining("Semantic search is not available yet (currently Standby)"), + ) + expect(mockPushToolResult).toHaveBeenCalledWith( + expect.stringContaining("Code indexing has not started yet"), + ) + expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Please use file reading tools")) + expect(mockCodeIndexManager.searchIndex).not.toHaveBeenCalled() + }) + + it("should provide feedback when indexing is in progress", async () => { + mockCodeIndexManager.state = "Indexing" + + 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( + expect.stringContaining("Semantic search is not available yet (currently Indexing)"), + ) + expect(mockPushToolResult).toHaveBeenCalledWith( + expect.stringContaining("Code indexing is currently in progress"), + ) + expect(mockCodeIndexManager.searchIndex).not.toHaveBeenCalled() + }) + + it("should provide feedback when indexing is in Error state", async () => { + mockCodeIndexManager.state = "Error" + + 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( + expect.stringContaining("Semantic search is not available yet (currently Error)"), + ) + expect(mockPushToolResult).toHaveBeenCalledWith( + expect.stringContaining("Code indexing encountered an error"), + ) + expect(mockCodeIndexManager.searchIndex).not.toHaveBeenCalled() + }) + + it("should perform search when indexing is complete (Indexed state)", 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).", + }), + ) + }) + }) + + 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, + ) + + expect(mockTask.ask).toHaveBeenCalled() + expect(mockCodeIndexManager.searchIndex).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..a5e2baaaeac 100644 --- a/src/core/tools/codebaseSearchTool.ts +++ b/src/core/tools/codebaseSearchTool.ts @@ -82,6 +82,33 @@ 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 + if (indexingState !== "Indexed") { + let stateMessage = "" + switch (indexingState) { + case "Standby": + stateMessage = + "Code indexing has not started yet. Please wait for the initial indexing to complete." + break + case "Indexing": + stateMessage = + "Code indexing is currently in progress. Semantic search will be available once indexing is complete." + break + case "Error": + stateMessage = "Code indexing encountered an error. Please check your configuration and try again." + break + default: + stateMessage = `Code indexing is in an unexpected state: ${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/services/code-index/search-service.ts b/src/services/code-index/search-service.ts index a56f5cc6744..a8361587dbb 100644 --- a/src/services/code-index/search-service.ts +++ b/src/services/code-index/search-service.ts @@ -34,10 +34,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(`Code index is in error state. Please check your configuration.`) } try { From 5ce9ea50f230826ad75d7bc995660a8928d6763f Mon Sep 17 00:00:00 2001 From: MuriloFP Date: Wed, 23 Jul 2025 11:18:22 -0300 Subject: [PATCH 3/6] fix: keep tool hidden when disabled/not configured - Only show codebase_search when feature is enabled AND configured - Tool is now visible during indexing (Standby/Indexing states) - Added test to verify tool availability during initialization --- src/core/prompts/tools/index.ts | 7 +++-- .../__tests__/codebaseSearchTool.spec.ts | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/core/prompts/tools/index.ts b/src/core/prompts/tools/index.ts index be3bb3ccd15..ea09280000a 100644 --- a/src/core/prompts/tools/index.ts +++ b/src/core/prompts/tools/index.ts @@ -101,8 +101,11 @@ export function getToolDescriptionsForMode( // Add always available tools ALWAYS_AVAILABLE_TOOLS.forEach((tool) => tools.add(tool)) - // Note: codebase_search is now always included in the tool list - // The tool itself will check the indexing state at runtime and provide appropriate feedback + // Conditionally exclude codebase_search if feature is disabled or not configured + // Note: We still show the tool when it's initialized but indexing is in progress + if (!codeIndexManager || !codeIndexManager.isFeatureEnabled || !codeIndexManager.isFeatureConfigured) { + tools.delete("codebase_search") + } // Conditionally exclude update_todo_list if disabled in settings if (settings?.todoListEnabled === false) { diff --git a/src/core/tools/__tests__/codebaseSearchTool.spec.ts b/src/core/tools/__tests__/codebaseSearchTool.spec.ts index b3b5d0d8d96..b6cd5092d82 100644 --- a/src/core/tools/__tests__/codebaseSearchTool.spec.ts +++ b/src/core/tools/__tests__/codebaseSearchTool.spec.ts @@ -243,6 +243,37 @@ describe("codebaseSearchTool", () => { }), ) }) + + 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("parameter validation", () => { From 7a68182a31ff1396391c2bd38958fca76f6cf8c4 Mon Sep 17 00:00:00 2001 From: MuriloFP Date: Wed, 23 Jul 2025 17:05:13 -0300 Subject: [PATCH 4/6] feat: implement Daniel's feedback on PR #6118 --- .../__tests__/codebaseSearchTool.spec.ts | 148 ++++++++++++++++++ src/core/tools/codebaseSearchTool.ts | 52 ++++-- src/i18n/locales/en/embeddings.json | 3 + src/services/code-index/search-service.ts | 3 +- 4 files changed, 188 insertions(+), 18 deletions(-) diff --git a/src/core/tools/__tests__/codebaseSearchTool.spec.ts b/src/core/tools/__tests__/codebaseSearchTool.spec.ts index b6cd5092d82..bb6297c7aac 100644 --- a/src/core/tools/__tests__/codebaseSearchTool.spec.ts +++ b/src/core/tools/__tests__/codebaseSearchTool.spec.ts @@ -3,6 +3,8 @@ 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") @@ -19,6 +21,13 @@ vi.mock("vscode", () => ({ asRelativePath: vi.fn((path: string) => path.replace("/test/workspace/", "")), }, })) +vi.mock("@roo-code/telemetry", () => ({ + TelemetryService: { + instance: { + captureEvent: vi.fn(), + }, + }, +})) describe("codebaseSearchTool", () => { let mockTask: Task @@ -274,6 +283,145 @@ describe("codebaseSearchTool", () => { expect.stringContaining("Semantic search is not available yet (currently Standby)"), ) }) + + it("should track telemetry when indexing is in Standby state", async () => { + 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, + ) + + expect(TelemetryService.instance.captureEvent).toHaveBeenCalledWith(TelemetryEventName.TOOL_USED, { + tool: "codebase_search", + codeIndexState: "Standby", + hasQuery: true, + result: "unavailable_not_indexed", + }) + }) + + it("should track telemetry when indexing is in progress", async () => { + mockCodeIndexManager.state = "Indexing" + + const block: ToolUse = { + type: "tool_use", + name: "codebase_search", + params: { query: "test query" }, + partial: false, + } + + await codebaseSearchTool( + mockTask, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + expect(TelemetryService.instance.captureEvent).toHaveBeenCalledWith(TelemetryEventName.TOOL_USED, { + tool: "codebase_search", + codeIndexState: "Indexing", + hasQuery: true, + result: "unavailable_not_indexed", + }) + expect(mockPushToolResult).toHaveBeenCalledWith( + expect.stringContaining("Code indexing is currently in progress"), + ) + }) + + it("should track telemetry when indexing is in error state", async () => { + mockCodeIndexManager.state = "Error" + + const block: ToolUse = { + type: "tool_use", + name: "codebase_search", + params: { query: "test query" }, + partial: false, + } + + await codebaseSearchTool( + mockTask, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + ) + + expect(TelemetryService.instance.captureEvent).toHaveBeenCalledWith(TelemetryEventName.TOOL_USED, { + tool: "codebase_search", + codeIndexState: "Error", + hasQuery: true, + result: "unavailable_not_indexed", + }) + expect(mockPushToolResult).toHaveBeenCalledWith( + expect.stringContaining("Code indexing encountered an error"), + ) + }) + + it("should not track telemetry when indexing is complete", async () => { + mockCodeIndexManager.state = "Indexed" + 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, + ) + + // 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", () => { diff --git a/src/core/tools/codebaseSearchTool.ts b/src/core/tools/codebaseSearchTool.ts index a5e2baaaeac..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, @@ -83,24 +105,20 @@ export async function codebaseSearchTool( } // Check indexing state at runtime - const indexingState = manager.state + 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") { - let stateMessage = "" - switch (indexingState) { - case "Standby": - stateMessage = - "Code indexing has not started yet. Please wait for the initial indexing to complete." - break - case "Indexing": - stateMessage = - "Code indexing is currently in progress. Semantic search will be available once indexing is complete." - break - case "Error": - stateMessage = "Code indexing encountered an error. Please check your configuration and try again." - break - default: - stateMessage = `Code indexing is in an unexpected state: ${indexingState}` - } + const stateMessage = getIndexingStateMessage(indexingState) // Return informative message instead of throwing error pushToolResult( 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/services/code-index/search-service.ts b/src/services/code-index/search-service.ts index a8361587dbb..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. @@ -38,7 +39,7 @@ export class CodeIndexSearchService { // This allows the tool to provide more user-friendly feedback const currentState = this.stateManager.getCurrentStatus().systemStatus if (currentState === "Error") { - throw new Error(`Code index is in error state. Please check your configuration.`) + throw new Error(t("embeddings:codeIndex.errorState")) } try { From f1f3234e1cecfc4c50bf5276b3e2fe444ba61f6a Mon Sep 17 00:00:00 2001 From: MuriloFP Date: Wed, 23 Jul 2025 17:25:14 -0300 Subject: [PATCH 5/6] fix: add missing translations for code index error message - Added translations for codeIndex.errorState to all 17 language files - Ensures consistent error messaging across all supported languages --- src/i18n/locales/ca/embeddings.json | 3 +++ src/i18n/locales/de/embeddings.json | 3 +++ src/i18n/locales/es/embeddings.json | 3 +++ src/i18n/locales/fr/embeddings.json | 3 +++ src/i18n/locales/hi/embeddings.json | 3 +++ src/i18n/locales/id/embeddings.json | 3 +++ src/i18n/locales/it/embeddings.json | 3 +++ src/i18n/locales/ja/embeddings.json | 3 +++ src/i18n/locales/ko/embeddings.json | 3 +++ src/i18n/locales/nl/embeddings.json | 3 +++ src/i18n/locales/pl/embeddings.json | 3 +++ src/i18n/locales/pt-BR/embeddings.json | 3 +++ src/i18n/locales/ru/embeddings.json | 3 +++ src/i18n/locales/tr/embeddings.json | 3 +++ src/i18n/locales/vi/embeddings.json | 3 +++ src/i18n/locales/zh-CN/embeddings.json | 3 +++ src/i18n/locales/zh-TW/embeddings.json | 3 +++ 17 files changed, 51 insertions(+) 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/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": "程式碼索引處於錯誤狀態。請檢查您的設定。" } } From 114dc76fbcfaf22415cdfda48482ca80af4c6d23 Mon Sep 17 00:00:00 2001 From: MuriloFP Date: Fri, 25 Jul 2025 13:18:57 -0300 Subject: [PATCH 6/6] fix: hide codebase_search tool when indexing is not complete - Updated tool availability logic to exclude codebase_search when state is not 'Indexed' - Added comprehensive tests for tool availability based on indexing state - Removed tests for runtime feedback since tool won't be available in non-indexed states - Addresses review feedback from @daniel-lxs --- .../prompts/tools/__tests__/index.spec.ts | 185 +++++++++++++++++ src/core/prompts/tools/index.ts | 10 +- .../__tests__/codebaseSearchTool.spec.ts | 196 ++---------------- 3 files changed, 210 insertions(+), 181 deletions(-) create mode 100644 src/core/prompts/tools/__tests__/index.spec.ts 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 ea09280000a..561aadaf508 100644 --- a/src/core/prompts/tools/index.ts +++ b/src/core/prompts/tools/index.ts @@ -101,9 +101,13 @@ 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 - // Note: We still show the tool when it's initialized but indexing is in progress - if (!codeIndexManager || !codeIndexManager.isFeatureEnabled || !codeIndexManager.isFeatureConfigured) { + // Conditionally exclude codebase_search if feature is disabled, not configured, or indexing is not complete + if ( + !codeIndexManager || + !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 index bb6297c7aac..aabcfb39aa4 100644 --- a/src/core/tools/__tests__/codebaseSearchTool.spec.ts +++ b/src/core/tools/__tests__/codebaseSearchTool.spec.ts @@ -81,93 +81,8 @@ describe("codebaseSearchTool", () => { vi.mocked(CodeIndexManager).getInstance = vi.fn((_context: any) => mockCodeIndexManager as any) }) - describe("indexing state checks", () => { - it("should provide feedback when indexing is in Standby state", async () => { - 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, - ) - - expect(mockPushToolResult).toHaveBeenCalledWith( - expect.stringContaining("Semantic search is not available yet (currently Standby)"), - ) - expect(mockPushToolResult).toHaveBeenCalledWith( - expect.stringContaining("Code indexing has not started yet"), - ) - expect(mockPushToolResult).toHaveBeenCalledWith(expect.stringContaining("Please use file reading tools")) - expect(mockCodeIndexManager.searchIndex).not.toHaveBeenCalled() - }) - - it("should provide feedback when indexing is in progress", async () => { - mockCodeIndexManager.state = "Indexing" - - 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( - expect.stringContaining("Semantic search is not available yet (currently Indexing)"), - ) - expect(mockPushToolResult).toHaveBeenCalledWith( - expect.stringContaining("Code indexing is currently in progress"), - ) - expect(mockCodeIndexManager.searchIndex).not.toHaveBeenCalled() - }) - - it("should provide feedback when indexing is in Error state", async () => { - mockCodeIndexManager.state = "Error" - - 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( - expect.stringContaining("Semantic search is not available yet (currently Error)"), - ) - expect(mockPushToolResult).toHaveBeenCalledWith( - expect.stringContaining("Code indexing encountered an error"), - ) - expect(mockCodeIndexManager.searchIndex).not.toHaveBeenCalled() - }) - - it("should perform search when indexing is complete (Indexed state)", async () => { + describe("codebase search functionality", () => { + it("should perform search when tool is available (feature enabled, configured, and indexed)", async () => { mockCodeIndexManager.state = "Indexed" const block: ToolUse = { @@ -283,97 +198,22 @@ describe("codebaseSearchTool", () => { expect.stringContaining("Semantic search is not available yet (currently Standby)"), ) }) + }) - it("should track telemetry when indexing is in Standby state", async () => { - 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, - ) - - expect(TelemetryService.instance.captureEvent).toHaveBeenCalledWith(TelemetryEventName.TOOL_USED, { - tool: "codebase_search", - codeIndexState: "Standby", - hasQuery: true, - result: "unavailable_not_indexed", - }) - }) - - it("should track telemetry when indexing is in progress", async () => { - mockCodeIndexManager.state = "Indexing" - - const block: ToolUse = { - type: "tool_use", - name: "codebase_search", - params: { query: "test query" }, - partial: false, - } - - await codebaseSearchTool( - mockTask, - block, - mockAskApproval, - mockHandleError, - mockPushToolResult, - mockRemoveClosingTag, - ) - - expect(TelemetryService.instance.captureEvent).toHaveBeenCalledWith(TelemetryEventName.TOOL_USED, { - tool: "codebase_search", - codeIndexState: "Indexing", - hasQuery: true, - result: "unavailable_not_indexed", - }) - expect(mockPushToolResult).toHaveBeenCalledWith( - expect.stringContaining("Code indexing is currently in progress"), - ) - }) - - it("should track telemetry when indexing is in error state", async () => { - mockCodeIndexManager.state = "Error" - - const block: ToolUse = { - type: "tool_use", - name: "codebase_search", - params: { query: "test query" }, - partial: false, - } - - await codebaseSearchTool( - mockTask, - block, - mockAskApproval, - mockHandleError, - mockPushToolResult, - mockRemoveClosingTag, - ) - - expect(TelemetryService.instance.captureEvent).toHaveBeenCalledWith(TelemetryEventName.TOOL_USED, { - tool: "codebase_search", - codeIndexState: "Error", - hasQuery: true, - result: "unavailable_not_indexed", - }) - expect(mockPushToolResult).toHaveBeenCalledWith( - expect.stringContaining("Code indexing encountered an error"), - ) - }) - - it("should not track telemetry when indexing is complete", async () => { + describe("telemetry tracking", () => { + it("should track telemetry for successful searches", async () => { mockCodeIndexManager.state = "Indexed" - mockCodeIndexManager.searchIndex.mockResolvedValue([]) + 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", @@ -463,8 +303,8 @@ describe("codebaseSearchTool", () => { mockRemoveClosingTag, ) - expect(mockTask.ask).toHaveBeenCalled() - expect(mockCodeIndexManager.searchIndex).not.toHaveBeenCalled() + // Should not track telemetry for non-indexed states since the tool won't be available + expect(TelemetryService.instance.captureEvent).not.toHaveBeenCalled() }) })