refactor: rename review tools for clarity and consistency
- Renamed `review_code` tool to `codereview` for better naming convention - Renamed `review_changes` tool to `precommit` to better reflect its purpose - Updated all tool descriptions to remove "Triggers:" sections and improve clarity - Updated all imports and references throughout the codebase - Renamed test files to match new tool names - Updated server.py tool registrations - All existing functionality preserved with improved naming This refactoring improves code organization and makes tool purposes clearer. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
12
README.md
12
README.md
@@ -19,8 +19,8 @@ The ultimate development partner for Claude - a Model Context Protocol server th
|
|||||||
- **Tools Reference**
|
- **Tools Reference**
|
||||||
- [`chat`](#1-chat---general-development-chat--collaborative-thinking) - Collaborative thinking
|
- [`chat`](#1-chat---general-development-chat--collaborative-thinking) - Collaborative thinking
|
||||||
- [`think_deeper`](#2-think_deeper---extended-reasoning-partner) - Extended reasoning
|
- [`think_deeper`](#2-think_deeper---extended-reasoning-partner) - Extended reasoning
|
||||||
- [`review_code`](#3-review_code---professional-code-review) - Code review
|
- [`codereview`](#3-codereview---professional-code-review) - Code review
|
||||||
- [`review_changes`](#4-review_changes---pre-commit-validation) - Pre-commit validation
|
- [`precommit`](#4-precommit---pre-commit-validation) - Pre-commit validation
|
||||||
- [`debug`](#5-debug---expert-debugging-assistant) - Debugging help
|
- [`debug`](#5-debug---expert-debugging-assistant) - Debugging help
|
||||||
- [`analyze`](#6-analyze---smart-file-analysis) - File analysis
|
- [`analyze`](#6-analyze---smart-file-analysis) - File analysis
|
||||||
|
|
||||||
@@ -42,8 +42,8 @@ The ultimate development partner for Claude - a Model Context Protocol server th
|
|||||||
Claude is brilliant, but sometimes you need:
|
Claude is brilliant, but sometimes you need:
|
||||||
- **A senior developer partner** to validate and extend ideas ([`chat`](#1-chat---general-development-chat--collaborative-thinking))
|
- **A senior developer partner** to validate and extend ideas ([`chat`](#1-chat---general-development-chat--collaborative-thinking))
|
||||||
- **A second opinion** on complex architectural decisions - augment Claude's extended thinking with Gemini's perspective ([`think_deeper`](#2-think_deeper---extended-reasoning-partner))
|
- **A second opinion** on complex architectural decisions - augment Claude's extended thinking with Gemini's perspective ([`think_deeper`](#2-think_deeper---extended-reasoning-partner))
|
||||||
- **Professional code reviews** with actionable feedback across entire repositories ([`review_code`](#3-review_code---professional-code-review))
|
- **Professional code reviews** with actionable feedback across entire repositories ([`codereview`](#3-codereview---professional-code-review))
|
||||||
- **Pre-commit validation** with deep analysis that finds edge cases, validates your implementation against original requirements, and catches subtle bugs Claude might miss ([`review_changes`](#4-review_changes---pre-commit-validation))
|
- **Pre-commit validation** with deep analysis that finds edge cases, validates your implementation against original requirements, and catches subtle bugs Claude might miss ([`precommit`](#4-precommit---pre-commit-validation))
|
||||||
- **Expert debugging** for tricky issues with full system context ([`debug`](#5-debug---expert-debugging-assistant))
|
- **Expert debugging** for tricky issues with full system context ([`debug`](#5-debug---expert-debugging-assistant))
|
||||||
- **Massive context window** (1M tokens) - Gemini 2.5 Pro can analyze entire codebases, read hundreds of files at once, and provide comprehensive insights ([`analyze`](#6-analyze---smart-file-analysis))
|
- **Massive context window** (1M tokens) - Gemini 2.5 Pro can analyze entire codebases, read hundreds of files at once, and provide comprehensive insights ([`analyze`](#6-analyze---smart-file-analysis))
|
||||||
- **Deep code analysis** across massive codebases that exceed Claude's context limits ([`analyze`](#6-analyze---smart-file-analysis))
|
- **Deep code analysis** across massive codebases that exceed Claude's context limits ([`analyze`](#6-analyze---smart-file-analysis))
|
||||||
@@ -562,7 +562,7 @@ about event ordering and failure scenarios. Then integrate gemini's insights and
|
|||||||
|
|
||||||
**Triggers:** think deeper, ultrathink, extend my analysis, validate my approach
|
**Triggers:** think deeper, ultrathink, extend my analysis, validate my approach
|
||||||
|
|
||||||
### 3. `review_code` - Professional Code Review
|
### 3. `codereview` - Professional Code Review
|
||||||
**Comprehensive code analysis with prioritized feedback**
|
**Comprehensive code analysis with prioritized feedback**
|
||||||
|
|
||||||
**Thinking Mode:** Default is `medium` (8,192 tokens). Use `high` for security-critical code (worth the extra tokens) or `low` for quick style checks (saves ~6k tokens).
|
**Thinking Mode:** Default is `medium` (8,192 tokens). Use `high` for security-critical code (worth the extra tokens) or `low` for quick style checks (saves ~6k tokens).
|
||||||
@@ -607,7 +607,7 @@ make any necessary adjustments and show me the final secure implementation."
|
|||||||
|
|
||||||
**Triggers:** review code, check for issues, find bugs, security check
|
**Triggers:** review code, check for issues, find bugs, security check
|
||||||
|
|
||||||
### 4. `review_changes` - Pre-Commit Validation
|
### 4. `precommit` - Pre-Commit Validation
|
||||||
**Comprehensive review of staged/unstaged git changes across multiple repositories**
|
**Comprehensive review of staged/unstaged git changes across multiple repositories**
|
||||||
|
|
||||||
**Thinking Mode:** Default is `medium` (8,192 tokens). Use `high` or `max` for critical releases when thorough validation justifies the token cost.
|
**Thinking Mode:** Default is `medium` (8,192 tokens). Use `high` or `max` for critical releases when thorough validation justifies the token cost.
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ System prompts for Gemini tools
|
|||||||
from .tool_prompts import (
|
from .tool_prompts import (
|
||||||
ANALYZE_PROMPT,
|
ANALYZE_PROMPT,
|
||||||
CHAT_PROMPT,
|
CHAT_PROMPT,
|
||||||
|
CODEREVIEW_PROMPT,
|
||||||
DEBUG_ISSUE_PROMPT,
|
DEBUG_ISSUE_PROMPT,
|
||||||
REVIEW_CODE_PROMPT,
|
|
||||||
THINK_DEEPER_PROMPT,
|
THINK_DEEPER_PROMPT,
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"THINK_DEEPER_PROMPT",
|
"THINK_DEEPER_PROMPT",
|
||||||
"REVIEW_CODE_PROMPT",
|
"CODEREVIEW_PROMPT",
|
||||||
"DEBUG_ISSUE_PROMPT",
|
"DEBUG_ISSUE_PROMPT",
|
||||||
"ANALYZE_PROMPT",
|
"ANALYZE_PROMPT",
|
||||||
"CHAT_PROMPT",
|
"CHAT_PROMPT",
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ Be direct and technical. Assume Claude and the user are experienced developers w
|
|||||||
deep, nuanced analysis rather than basic explanations. Your goal is to be the perfect
|
deep, nuanced analysis rather than basic explanations. Your goal is to be the perfect
|
||||||
development partner that extends Claude's capabilities."""
|
development partner that extends Claude's capabilities."""
|
||||||
|
|
||||||
REVIEW_CODE_PROMPT = """You are an expert code reviewer with deep knowledge of software engineering best practices.
|
CODEREVIEW_PROMPT = """You are an expert code reviewer with deep knowledge of software engineering best practices.
|
||||||
Your expertise spans security, performance, maintainability, and architectural patterns.
|
Your expertise spans security, performance, maintainability, and architectural patterns.
|
||||||
|
|
||||||
IMPORTANT: If you need additional context (e.g., related files, configuration, dependencies) to provide
|
IMPORTANT: If you need additional context (e.g., related files, configuration, dependencies) to provide
|
||||||
@@ -171,7 +171,7 @@ the ideal thinking partner who helps explore ideas deeply, validates approaches,
|
|||||||
insights that might be missed in solo analysis. Think step by step through complex problems
|
insights that might be missed in solo analysis. Think step by step through complex problems
|
||||||
and don't hesitate to explore tangential but relevant considerations."""
|
and don't hesitate to explore tangential but relevant considerations."""
|
||||||
|
|
||||||
REVIEW_CHANGES_PROMPT = """You are an expert code change analyst specializing in pre-commit review of git diffs.
|
PRECOMMIT_PROMPT = """You are an expert code change analyst specializing in pre-commit review of git diffs.
|
||||||
Your role is to act as a seasoned senior developer performing a final review before code is committed.
|
Your role is to act as a seasoned senior developer performing a final review before code is committed.
|
||||||
|
|
||||||
IMPORTANT: If you need additional context (e.g., related files not in the diff, test files, configuration)
|
IMPORTANT: If you need additional context (e.g., related files not in the diff, test files, configuration)
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ from config import (
|
|||||||
from tools import (
|
from tools import (
|
||||||
AnalyzeTool,
|
AnalyzeTool,
|
||||||
ChatTool,
|
ChatTool,
|
||||||
|
CodeReviewTool,
|
||||||
DebugIssueTool,
|
DebugIssueTool,
|
||||||
ReviewChanges,
|
Precommit,
|
||||||
ReviewCodeTool,
|
|
||||||
ThinkDeeperTool,
|
ThinkDeeperTool,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -60,11 +60,11 @@ server: Server = Server("gemini-server")
|
|||||||
# Tools are instantiated once and reused across requests (stateless design)
|
# Tools are instantiated once and reused across requests (stateless design)
|
||||||
TOOLS = {
|
TOOLS = {
|
||||||
"think_deeper": ThinkDeeperTool(), # Extended reasoning for complex problems
|
"think_deeper": ThinkDeeperTool(), # Extended reasoning for complex problems
|
||||||
"review_code": ReviewCodeTool(), # Comprehensive code review and quality analysis
|
"codereview": CodeReviewTool(), # Comprehensive code review and quality analysis
|
||||||
"debug": DebugIssueTool(), # Root cause analysis and debugging assistance
|
"debug": DebugIssueTool(), # Root cause analysis and debugging assistance
|
||||||
"analyze": AnalyzeTool(), # General-purpose file and code analysis
|
"analyze": AnalyzeTool(), # General-purpose file and code analysis
|
||||||
"chat": ChatTool(), # Interactive development chat and brainstorming
|
"chat": ChatTool(), # Interactive development chat and brainstorming
|
||||||
"review_changes": ReviewChanges(), # Pre-commit review of git changes
|
"precommit": Precommit(), # Pre-commit validation of git changes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -156,10 +156,10 @@ def test_review_changes_docker_path_translation():
|
|||||||
utils.file_utils.CONTAINER_WORKSPACE = container_workspace
|
utils.file_utils.CONTAINER_WORKSPACE = container_workspace
|
||||||
|
|
||||||
# Import after reloading to get updated environment
|
# Import after reloading to get updated environment
|
||||||
from tools.review_changes import ReviewChanges
|
from tools.precommit import Precommit
|
||||||
|
|
||||||
# Create tool instance
|
# Create tool instance
|
||||||
tool = ReviewChanges()
|
tool = Precommit()
|
||||||
|
|
||||||
# Test path translation in prepare_prompt
|
# Test path translation in prepare_prompt
|
||||||
request = tool.get_request_model()(
|
request = tool.get_request_model()(
|
||||||
@@ -209,10 +209,10 @@ def test_review_changes_docker_path_error():
|
|||||||
utils.file_utils.CONTAINER_WORKSPACE = container_workspace
|
utils.file_utils.CONTAINER_WORKSPACE = container_workspace
|
||||||
|
|
||||||
# Import after reloading to get updated environment
|
# Import after reloading to get updated environment
|
||||||
from tools.review_changes import ReviewChanges
|
from tools.precommit import Precommit
|
||||||
|
|
||||||
# Create tool instance
|
# Create tool instance
|
||||||
tool = ReviewChanges()
|
tool = Precommit()
|
||||||
|
|
||||||
# Test path translation with an inaccessible path
|
# Test path translation with an inaccessible path
|
||||||
request = tool.get_request_model()(
|
request = tool.get_request_model()(
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ from mcp.types import TextContent
|
|||||||
from config import MCP_PROMPT_SIZE_LIMIT
|
from config import MCP_PROMPT_SIZE_LIMIT
|
||||||
from tools.analyze import AnalyzeTool
|
from tools.analyze import AnalyzeTool
|
||||||
from tools.chat import ChatTool
|
from tools.chat import ChatTool
|
||||||
|
from tools.codereview import CodeReviewTool
|
||||||
from tools.debug import DebugIssueTool
|
from tools.debug import DebugIssueTool
|
||||||
from tools.review_changes import ReviewChanges
|
from tools.precommit import Precommit
|
||||||
from tools.review_code import ReviewCodeTool
|
|
||||||
from tools.think_deeper import ThinkDeeperTool
|
from tools.think_deeper import ThinkDeeperTool
|
||||||
|
|
||||||
|
|
||||||
@@ -141,9 +141,9 @@ class TestLargePromptHandling:
|
|||||||
assert output["status"] == "requires_file_prompt"
|
assert output["status"] == "requires_file_prompt"
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_review_code_large_focus(self, large_prompt):
|
async def test_codereview_large_focus(self, large_prompt):
|
||||||
"""Test that review_code tool detects large focus_on field."""
|
"""Test that codereview tool detects large focus_on field."""
|
||||||
tool = ReviewCodeTool()
|
tool = CodeReviewTool()
|
||||||
result = await tool.execute(
|
result = await tool.execute(
|
||||||
{
|
{
|
||||||
"files": ["/some/file.py"],
|
"files": ["/some/file.py"],
|
||||||
@@ -159,7 +159,7 @@ class TestLargePromptHandling:
|
|||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_review_changes_large_original_request(self, large_prompt):
|
async def test_review_changes_large_original_request(self, large_prompt):
|
||||||
"""Test that review_changes tool detects large original_request."""
|
"""Test that review_changes tool detects large original_request."""
|
||||||
tool = ReviewChanges()
|
tool = Precommit()
|
||||||
result = await tool.execute({"path": "/some/path", "original_request": large_prompt})
|
result = await tool.execute({"path": "/some/path", "original_request": large_prompt})
|
||||||
|
|
||||||
assert len(result) == 1
|
assert len(result) == 1
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Tests for the review_changes tool
|
Tests for the precommit tool
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
@@ -7,22 +7,22 @@ from unittest.mock import Mock, patch
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tools.review_changes import ReviewChanges, ReviewChangesRequest
|
from tools.precommit import Precommit, PrecommitRequest
|
||||||
|
|
||||||
|
|
||||||
class TestReviewChangesTool:
|
class TestPrecommitTool:
|
||||||
"""Test the review_changes tool"""
|
"""Test the precommit tool"""
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def tool(self):
|
def tool(self):
|
||||||
"""Create tool instance"""
|
"""Create tool instance"""
|
||||||
return ReviewChanges()
|
return Precommit()
|
||||||
|
|
||||||
def test_tool_metadata(self, tool):
|
def test_tool_metadata(self, tool):
|
||||||
"""Test tool metadata"""
|
"""Test tool metadata"""
|
||||||
assert tool.get_name() == "review_changes"
|
assert tool.get_name() == "precommit"
|
||||||
assert "REVIEW PENDING GIT CHANGES" in tool.get_description()
|
assert "PRECOMMIT VALIDATION" in tool.get_description()
|
||||||
assert "pre-commit review" in tool.get_description()
|
assert "pre-commit" in tool.get_description()
|
||||||
|
|
||||||
# Check schema
|
# Check schema
|
||||||
schema = tool.get_input_schema()
|
schema = tool.get_input_schema()
|
||||||
@@ -34,7 +34,7 @@ class TestReviewChangesTool:
|
|||||||
|
|
||||||
def test_request_model_defaults(self):
|
def test_request_model_defaults(self):
|
||||||
"""Test request model default values"""
|
"""Test request model default values"""
|
||||||
request = ReviewChangesRequest(path="/some/absolute/path")
|
request = PrecommitRequest(path="/some/absolute/path")
|
||||||
assert request.path == "/some/absolute/path"
|
assert request.path == "/some/absolute/path"
|
||||||
assert request.original_request is None
|
assert request.original_request is None
|
||||||
assert request.compare_to is None
|
assert request.compare_to is None
|
||||||
@@ -56,21 +56,21 @@ class TestReviewChangesTool:
|
|||||||
assert "./relative/path" in response["content"]
|
assert "./relative/path" in response["content"]
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@patch("tools.review_changes.find_git_repositories")
|
@patch("tools.precommit.find_git_repositories")
|
||||||
async def test_no_repositories_found(self, mock_find_repos, tool):
|
async def test_no_repositories_found(self, mock_find_repos, tool):
|
||||||
"""Test when no git repositories are found"""
|
"""Test when no git repositories are found"""
|
||||||
mock_find_repos.return_value = []
|
mock_find_repos.return_value = []
|
||||||
|
|
||||||
request = ReviewChangesRequest(path="/absolute/path/no-git")
|
request = PrecommitRequest(path="/absolute/path/no-git")
|
||||||
result = await tool.prepare_prompt(request)
|
result = await tool.prepare_prompt(request)
|
||||||
|
|
||||||
assert result == "No git repositories found in the specified path."
|
assert result == "No git repositories found in the specified path."
|
||||||
mock_find_repos.assert_called_once_with("/absolute/path/no-git", 5)
|
mock_find_repos.assert_called_once_with("/absolute/path/no-git", 5)
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@patch("tools.review_changes.find_git_repositories")
|
@patch("tools.precommit.find_git_repositories")
|
||||||
@patch("tools.review_changes.get_git_status")
|
@patch("tools.precommit.get_git_status")
|
||||||
@patch("tools.review_changes.run_git_command")
|
@patch("tools.precommit.run_git_command")
|
||||||
async def test_no_changes_found(self, mock_run_git, mock_status, mock_find_repos, tool):
|
async def test_no_changes_found(self, mock_run_git, mock_status, mock_find_repos, tool):
|
||||||
"""Test when repositories have no changes"""
|
"""Test when repositories have no changes"""
|
||||||
mock_find_repos.return_value = ["/test/repo"]
|
mock_find_repos.return_value = ["/test/repo"]
|
||||||
@@ -89,15 +89,15 @@ class TestReviewChangesTool:
|
|||||||
(True, ""), # unstaged files (empty)
|
(True, ""), # unstaged files (empty)
|
||||||
]
|
]
|
||||||
|
|
||||||
request = ReviewChangesRequest(path="/absolute/repo/path")
|
request = PrecommitRequest(path="/absolute/repo/path")
|
||||||
result = await tool.prepare_prompt(request)
|
result = await tool.prepare_prompt(request)
|
||||||
|
|
||||||
assert result == "No pending changes found in any of the git repositories."
|
assert result == "No pending changes found in any of the git repositories."
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@patch("tools.review_changes.find_git_repositories")
|
@patch("tools.precommit.find_git_repositories")
|
||||||
@patch("tools.review_changes.get_git_status")
|
@patch("tools.precommit.get_git_status")
|
||||||
@patch("tools.review_changes.run_git_command")
|
@patch("tools.precommit.run_git_command")
|
||||||
async def test_staged_changes_review(
|
async def test_staged_changes_review(
|
||||||
self,
|
self,
|
||||||
mock_run_git,
|
mock_run_git,
|
||||||
@@ -126,7 +126,7 @@ class TestReviewChangesTool:
|
|||||||
(True, ""), # unstaged files (empty)
|
(True, ""), # unstaged files (empty)
|
||||||
]
|
]
|
||||||
|
|
||||||
request = ReviewChangesRequest(
|
request = PrecommitRequest(
|
||||||
path="/absolute/repo/path",
|
path="/absolute/repo/path",
|
||||||
original_request="Add hello message",
|
original_request="Add hello message",
|
||||||
review_type="security",
|
review_type="security",
|
||||||
@@ -143,9 +143,9 @@ class TestReviewChangesTool:
|
|||||||
assert "## Git Diffs" in result
|
assert "## Git Diffs" in result
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@patch("tools.review_changes.find_git_repositories")
|
@patch("tools.precommit.find_git_repositories")
|
||||||
@patch("tools.review_changes.get_git_status")
|
@patch("tools.precommit.get_git_status")
|
||||||
@patch("tools.review_changes.run_git_command")
|
@patch("tools.precommit.run_git_command")
|
||||||
async def test_compare_to_invalid_ref(self, mock_run_git, mock_status, mock_find_repos, tool):
|
async def test_compare_to_invalid_ref(self, mock_run_git, mock_status, mock_find_repos, tool):
|
||||||
"""Test comparing to an invalid git ref"""
|
"""Test comparing to an invalid git ref"""
|
||||||
mock_find_repos.return_value = ["/test/repo"]
|
mock_find_repos.return_value = ["/test/repo"]
|
||||||
@@ -156,14 +156,14 @@ class TestReviewChangesTool:
|
|||||||
(False, "fatal: not a valid ref"), # rev-parse fails
|
(False, "fatal: not a valid ref"), # rev-parse fails
|
||||||
]
|
]
|
||||||
|
|
||||||
request = ReviewChangesRequest(path="/absolute/repo/path", compare_to="invalid-branch")
|
request = PrecommitRequest(path="/absolute/repo/path", compare_to="invalid-branch")
|
||||||
result = await tool.prepare_prompt(request)
|
result = await tool.prepare_prompt(request)
|
||||||
|
|
||||||
# When all repos have errors and no changes, we get this message
|
# When all repos have errors and no changes, we get this message
|
||||||
assert "No pending changes found in any of the git repositories." in result
|
assert "No pending changes found in any of the git repositories." in result
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@patch("tools.review_changes.ReviewChanges.execute")
|
@patch("tools.precommit.Precommit.execute")
|
||||||
async def test_execute_integration(self, mock_execute, tool):
|
async def test_execute_integration(self, mock_execute, tool):
|
||||||
"""Test execute method integration"""
|
"""Test execute method integration"""
|
||||||
# Mock the execute to return a standardized response
|
# Mock the execute to return a standardized response
|
||||||
@@ -183,9 +183,9 @@ class TestReviewChangesTool:
|
|||||||
assert tool.get_default_temperature() == TEMPERATURE_ANALYTICAL
|
assert tool.get_default_temperature() == TEMPERATURE_ANALYTICAL
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@patch("tools.review_changes.find_git_repositories")
|
@patch("tools.precommit.find_git_repositories")
|
||||||
@patch("tools.review_changes.get_git_status")
|
@patch("tools.precommit.get_git_status")
|
||||||
@patch("tools.review_changes.run_git_command")
|
@patch("tools.precommit.run_git_command")
|
||||||
async def test_mixed_staged_unstaged_changes(
|
async def test_mixed_staged_unstaged_changes(
|
||||||
self,
|
self,
|
||||||
mock_run_git,
|
mock_run_git,
|
||||||
@@ -211,7 +211,7 @@ class TestReviewChangesTool:
|
|||||||
(True, "diff --git a/file2.py..."), # diff for file2.py
|
(True, "diff --git a/file2.py..."), # diff for file2.py
|
||||||
]
|
]
|
||||||
|
|
||||||
request = ReviewChangesRequest(
|
request = PrecommitRequest(
|
||||||
path="/absolute/repo/path",
|
path="/absolute/repo/path",
|
||||||
focus_on="error handling",
|
focus_on="error handling",
|
||||||
severity_filter="high",
|
severity_filter="high",
|
||||||
@@ -225,10 +225,10 @@ class TestReviewChangesTool:
|
|||||||
assert "Reviewing: staged and unstaged changes" in result
|
assert "Reviewing: staged and unstaged changes" in result
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@patch("tools.review_changes.find_git_repositories")
|
@patch("tools.precommit.find_git_repositories")
|
||||||
@patch("tools.review_changes.get_git_status")
|
@patch("tools.precommit.get_git_status")
|
||||||
@patch("tools.review_changes.run_git_command")
|
@patch("tools.precommit.run_git_command")
|
||||||
@patch("tools.review_changes.read_files")
|
@patch("tools.precommit.read_files")
|
||||||
async def test_files_parameter_with_context(
|
async def test_files_parameter_with_context(
|
||||||
self,
|
self,
|
||||||
mock_read_files,
|
mock_read_files,
|
||||||
@@ -257,7 +257,7 @@ class TestReviewChangesTool:
|
|||||||
# Mock read_files
|
# Mock read_files
|
||||||
mock_read_files.return_value = "=== FILE: config.py ===\nCONFIG_VALUE = 42\n=== END FILE ==="
|
mock_read_files.return_value = "=== FILE: config.py ===\nCONFIG_VALUE = 42\n=== END FILE ==="
|
||||||
|
|
||||||
request = ReviewChangesRequest(
|
request = PrecommitRequest(
|
||||||
path="/absolute/repo/path",
|
path="/absolute/repo/path",
|
||||||
files=["/absolute/repo/path/config.py"],
|
files=["/absolute/repo/path/config.py"],
|
||||||
)
|
)
|
||||||
@@ -271,9 +271,9 @@ class TestReviewChangesTool:
|
|||||||
assert "CONFIG_VALUE = 42" in result
|
assert "CONFIG_VALUE = 42" in result
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@patch("tools.review_changes.find_git_repositories")
|
@patch("tools.precommit.find_git_repositories")
|
||||||
@patch("tools.review_changes.get_git_status")
|
@patch("tools.precommit.get_git_status")
|
||||||
@patch("tools.review_changes.run_git_command")
|
@patch("tools.precommit.run_git_command")
|
||||||
async def test_files_request_instruction(
|
async def test_files_request_instruction(
|
||||||
self,
|
self,
|
||||||
mock_run_git,
|
mock_run_git,
|
||||||
@@ -298,7 +298,7 @@ class TestReviewChangesTool:
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Request without files
|
# Request without files
|
||||||
request = ReviewChangesRequest(path="/absolute/repo/path")
|
request = PrecommitRequest(path="/absolute/repo/path")
|
||||||
result = await tool.prepare_prompt(request)
|
result = await tool.prepare_prompt(request)
|
||||||
|
|
||||||
# Should include instruction for requesting files
|
# Should include instruction for requesting files
|
||||||
@@ -306,7 +306,7 @@ class TestReviewChangesTool:
|
|||||||
assert "standardized JSON response format" in result
|
assert "standardized JSON response format" in result
|
||||||
|
|
||||||
# Request with files - should not include instruction
|
# Request with files - should not include instruction
|
||||||
request_with_files = ReviewChangesRequest(path="/absolute/repo/path", files=["/some/file.py"])
|
request_with_files = PrecommitRequest(path="/absolute/repo/path", files=["/some/file.py"])
|
||||||
|
|
||||||
# Need to reset mocks for second call
|
# Need to reset mocks for second call
|
||||||
mock_find_repos.return_value = ["/test/repo"]
|
mock_find_repos.return_value = ["/test/repo"]
|
||||||
@@ -317,7 +317,7 @@ class TestReviewChangesTool:
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Mock read_files to return empty (file not found)
|
# Mock read_files to return empty (file not found)
|
||||||
with patch("tools.review_changes.read_files") as mock_read:
|
with patch("tools.precommit.read_files") as mock_read:
|
||||||
mock_read.return_value = ""
|
mock_read.return_value = ""
|
||||||
result_with_files = await tool.prepare_prompt(request_with_files)
|
result_with_files = await tool.prepare_prompt(request_with_files)
|
||||||
|
|
||||||
@@ -12,9 +12,9 @@ import pytest
|
|||||||
|
|
||||||
from tools.analyze import AnalyzeTool
|
from tools.analyze import AnalyzeTool
|
||||||
from tools.chat import ChatTool
|
from tools.chat import ChatTool
|
||||||
|
from tools.codereview import CodeReviewTool
|
||||||
from tools.debug import DebugIssueTool
|
from tools.debug import DebugIssueTool
|
||||||
from tools.review_changes import ReviewChanges
|
from tools.precommit import Precommit
|
||||||
from tools.review_code import ReviewCodeTool
|
|
||||||
from tools.think_deeper import ThinkDeeperTool
|
from tools.think_deeper import ThinkDeeperTool
|
||||||
|
|
||||||
|
|
||||||
@@ -105,9 +105,9 @@ class TestPromptRegression:
|
|||||||
assert "deeper analysis" in output["content"]
|
assert "deeper analysis" in output["content"]
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_review_code_normal_review(self, mock_model_response):
|
async def test_codereview_normal_review(self, mock_model_response):
|
||||||
"""Test review_code tool with normal inputs."""
|
"""Test codereview tool with normal inputs."""
|
||||||
tool = ReviewCodeTool()
|
tool = CodeReviewTool()
|
||||||
|
|
||||||
with patch.object(tool, "create_model") as mock_create_model:
|
with patch.object(tool, "create_model") as mock_create_model:
|
||||||
mock_model = MagicMock()
|
mock_model = MagicMock()
|
||||||
@@ -117,7 +117,7 @@ class TestPromptRegression:
|
|||||||
mock_create_model.return_value = mock_model
|
mock_create_model.return_value = mock_model
|
||||||
|
|
||||||
# Mock file reading
|
# Mock file reading
|
||||||
with patch("tools.review_code.read_files") as mock_read_files:
|
with patch("tools.codereview.read_files") as mock_read_files:
|
||||||
mock_read_files.return_value = "def main(): pass"
|
mock_read_files.return_value = "def main(): pass"
|
||||||
|
|
||||||
result = await tool.execute(
|
result = await tool.execute(
|
||||||
@@ -137,7 +137,7 @@ class TestPromptRegression:
|
|||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_review_changes_normal_request(self, mock_model_response):
|
async def test_review_changes_normal_request(self, mock_model_response):
|
||||||
"""Test review_changes tool with normal original_request."""
|
"""Test review_changes tool with normal original_request."""
|
||||||
tool = ReviewChanges()
|
tool = Precommit()
|
||||||
|
|
||||||
with patch.object(tool, "create_model") as mock_create_model:
|
with patch.object(tool, "create_model") as mock_create_model:
|
||||||
mock_model = MagicMock()
|
mock_model = MagicMock()
|
||||||
@@ -147,8 +147,8 @@ class TestPromptRegression:
|
|||||||
mock_create_model.return_value = mock_model
|
mock_create_model.return_value = mock_model
|
||||||
|
|
||||||
# Mock git operations
|
# Mock git operations
|
||||||
with patch("tools.review_changes.find_git_repositories") as mock_find_repos:
|
with patch("tools.precommit.find_git_repositories") as mock_find_repos:
|
||||||
with patch("tools.review_changes.get_git_status") as mock_git_status:
|
with patch("tools.precommit.get_git_status") as mock_git_status:
|
||||||
mock_find_repos.return_value = ["/path/to/repo"]
|
mock_find_repos.return_value = ["/path/to/repo"]
|
||||||
mock_git_status.return_value = {
|
mock_git_status.return_value = {
|
||||||
"modified": ["file.py"],
|
"modified": ["file.py"],
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ class TestServerTools:
|
|||||||
|
|
||||||
# Check all core tools are present
|
# Check all core tools are present
|
||||||
assert "think_deeper" in tool_names
|
assert "think_deeper" in tool_names
|
||||||
assert "review_code" in tool_names
|
assert "codereview" in tool_names
|
||||||
assert "debug" in tool_names
|
assert "debug" in tool_names
|
||||||
assert "analyze" in tool_names
|
assert "analyze" in tool_names
|
||||||
assert "chat" in tool_names
|
assert "chat" in tool_names
|
||||||
assert "review_changes" in tool_names
|
assert "precommit" in tool_names
|
||||||
assert "get_version" in tool_names
|
assert "get_version" in tool_names
|
||||||
|
|
||||||
# Should have exactly 7 tools
|
# Should have exactly 7 tools
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ from unittest.mock import Mock, patch
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tools.analyze import AnalyzeTool
|
from tools.analyze import AnalyzeTool
|
||||||
|
from tools.codereview import CodeReviewTool
|
||||||
from tools.debug import DebugIssueTool
|
from tools.debug import DebugIssueTool
|
||||||
from tools.review_code import ReviewCodeTool
|
|
||||||
from tools.think_deeper import ThinkDeeperTool
|
from tools.think_deeper import ThinkDeeperTool
|
||||||
|
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ class TestThinkingModes:
|
|||||||
tools = [
|
tools = [
|
||||||
(ThinkDeeperTool(), "high"),
|
(ThinkDeeperTool(), "high"),
|
||||||
(AnalyzeTool(), "medium"),
|
(AnalyzeTool(), "medium"),
|
||||||
(ReviewCodeTool(), "medium"),
|
(CodeReviewTool(), "medium"),
|
||||||
(DebugIssueTool(), "medium"),
|
(DebugIssueTool(), "medium"),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ class TestThinkingModes:
|
|||||||
)
|
)
|
||||||
mock_create_model.return_value = mock_model
|
mock_create_model.return_value = mock_model
|
||||||
|
|
||||||
tool = ReviewCodeTool()
|
tool = CodeReviewTool()
|
||||||
result = await tool.execute(
|
result = await tool.execute(
|
||||||
{
|
{
|
||||||
"files": ["/absolute/path/test.py"],
|
"files": ["/absolute/path/test.py"],
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from unittest.mock import Mock, patch
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tools import AnalyzeTool, ChatTool, DebugIssueTool, ReviewCodeTool, ThinkDeeperTool
|
from tools import AnalyzeTool, ChatTool, CodeReviewTool, DebugIssueTool, ThinkDeeperTool
|
||||||
|
|
||||||
|
|
||||||
class TestThinkDeeperTool:
|
class TestThinkDeeperTool:
|
||||||
@@ -54,16 +54,16 @@ class TestThinkDeeperTool:
|
|||||||
assert "Extended analysis" in output["content"]
|
assert "Extended analysis" in output["content"]
|
||||||
|
|
||||||
|
|
||||||
class TestReviewCodeTool:
|
class TestCodeReviewTool:
|
||||||
"""Test the review_code tool"""
|
"""Test the codereview tool"""
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def tool(self):
|
def tool(self):
|
||||||
return ReviewCodeTool()
|
return CodeReviewTool()
|
||||||
|
|
||||||
def test_tool_metadata(self, tool):
|
def test_tool_metadata(self, tool):
|
||||||
"""Test tool metadata"""
|
"""Test tool metadata"""
|
||||||
assert tool.get_name() == "review_code"
|
assert tool.get_name() == "codereview"
|
||||||
assert "PROFESSIONAL CODE REVIEW" in tool.get_description()
|
assert "PROFESSIONAL CODE REVIEW" in tool.get_description()
|
||||||
assert tool.get_default_temperature() == 0.2
|
assert tool.get_default_temperature() == 0.2
|
||||||
|
|
||||||
@@ -214,9 +214,9 @@ class TestAbsolutePathValidation:
|
|||||||
assert "./relative/path.py" in response["content"]
|
assert "./relative/path.py" in response["content"]
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_review_code_tool_relative_path_rejected(self):
|
async def test_codereview_tool_relative_path_rejected(self):
|
||||||
"""Test that review_code tool rejects relative paths"""
|
"""Test that codereview tool rejects relative paths"""
|
||||||
tool = ReviewCodeTool()
|
tool = CodeReviewTool()
|
||||||
result = await tool.execute(
|
result = await tool.execute(
|
||||||
{
|
{
|
||||||
"files": ["../parent/file.py"],
|
"files": ["../parent/file.py"],
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ Tool implementations for Gemini MCP Server
|
|||||||
|
|
||||||
from .analyze import AnalyzeTool
|
from .analyze import AnalyzeTool
|
||||||
from .chat import ChatTool
|
from .chat import ChatTool
|
||||||
|
from .codereview import CodeReviewTool
|
||||||
from .debug import DebugIssueTool
|
from .debug import DebugIssueTool
|
||||||
from .review_changes import ReviewChanges
|
from .precommit import Precommit
|
||||||
from .review_code import ReviewCodeTool
|
|
||||||
from .think_deeper import ThinkDeeperTool
|
from .think_deeper import ThinkDeeperTool
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"ThinkDeeperTool",
|
"ThinkDeeperTool",
|
||||||
"ReviewCodeTool",
|
"CodeReviewTool",
|
||||||
"DebugIssueTool",
|
"DebugIssueTool",
|
||||||
"AnalyzeTool",
|
"AnalyzeTool",
|
||||||
"ChatTool",
|
"ChatTool",
|
||||||
"ReviewChanges",
|
"Precommit",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -37,8 +37,7 @@ class AnalyzeTool(BaseTool):
|
|||||||
return (
|
return (
|
||||||
"ANALYZE FILES & CODE - General-purpose analysis for understanding code. "
|
"ANALYZE FILES & CODE - General-purpose analysis for understanding code. "
|
||||||
"Supports both individual files and entire directories. "
|
"Supports both individual files and entire directories. "
|
||||||
"Use this for examining files, understanding architecture, or investigating specific aspects. "
|
"Use this when you need to analyze files, examine code, or understand specific aspects of a codebase. "
|
||||||
"Triggers: 'analyze these files', 'examine this code', 'understand this'. "
|
|
||||||
"Perfect for: codebase exploration, dependency analysis, pattern detection. "
|
"Perfect for: codebase exploration, dependency analysis, pattern detection. "
|
||||||
"Always uses file paths for clean terminal output."
|
"Always uses file paths for clean terminal output."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ class ChatTool(BaseTool):
|
|||||||
"Perfect for: bouncing ideas during your own analysis, getting second opinions on your plans, "
|
"Perfect for: bouncing ideas during your own analysis, getting second opinions on your plans, "
|
||||||
"collaborative brainstorming, validating your checklists and approaches, exploring alternatives. "
|
"collaborative brainstorming, validating your checklists and approaches, exploring alternatives. "
|
||||||
"Also great for: explanations, comparisons, general development questions. "
|
"Also great for: explanations, comparisons, general development questions. "
|
||||||
"Triggers: 'ask gemini', 'brainstorm with gemini', 'get gemini's opinion', 'discuss with gemini', "
|
"Use this when you want to ask Gemini questions, brainstorm ideas, get opinions, discuss topics, "
|
||||||
"'share my thinking with gemini', 'explain', 'what is', 'how do I'."
|
"share your thinking, or need explanations about concepts and approaches."
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_input_schema(self) -> dict[str, Any]:
|
def get_input_schema(self) -> dict[str, Any]:
|
||||||
|
|||||||
@@ -20,14 +20,14 @@ from mcp.types import TextContent
|
|||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
|
|
||||||
from config import TEMPERATURE_ANALYTICAL
|
from config import TEMPERATURE_ANALYTICAL
|
||||||
from prompts import REVIEW_CODE_PROMPT
|
from prompts import CODEREVIEW_PROMPT
|
||||||
from utils import read_files
|
from utils import read_files
|
||||||
|
|
||||||
from .base import BaseTool, ToolRequest
|
from .base import BaseTool, ToolRequest
|
||||||
from .models import ToolOutput
|
from .models import ToolOutput
|
||||||
|
|
||||||
|
|
||||||
class ReviewCodeRequest(ToolRequest):
|
class CodeReviewRequest(ToolRequest):
|
||||||
"""
|
"""
|
||||||
Request model for the code review tool.
|
Request model for the code review tool.
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ class ReviewCodeRequest(ToolRequest):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ReviewCodeTool(BaseTool):
|
class CodeReviewTool(BaseTool):
|
||||||
"""
|
"""
|
||||||
Professional code review tool implementation.
|
Professional code review tool implementation.
|
||||||
|
|
||||||
@@ -63,14 +63,13 @@ class ReviewCodeTool(BaseTool):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def get_name(self) -> str:
|
def get_name(self) -> str:
|
||||||
return "review_code"
|
return "codereview"
|
||||||
|
|
||||||
def get_description(self) -> str:
|
def get_description(self) -> str:
|
||||||
return (
|
return (
|
||||||
"PROFESSIONAL CODE REVIEW - Comprehensive analysis for bugs, security, and quality. "
|
"PROFESSIONAL CODE REVIEW - Comprehensive analysis for bugs, security, and quality. "
|
||||||
"Supports both individual files and entire directories/projects. "
|
"Supports both individual files and entire directories/projects. "
|
||||||
"Use this for thorough code review with actionable feedback. "
|
"Use this when you need to review code, check for issues, find bugs, or perform security audits. "
|
||||||
"Triggers: 'review this code', 'check for issues', 'find bugs', 'security audit'. "
|
|
||||||
"I'll identify issues by severity (Critical→High→Medium→Low) with specific fixes. "
|
"I'll identify issues by severity (Critical→High→Medium→Low) with specific fixes. "
|
||||||
"Supports focused reviews: security, performance, or quick checks. "
|
"Supports focused reviews: security, performance, or quick checks. "
|
||||||
"Choose thinking_mode based on review scope: 'low' for small code snippets, "
|
"Choose thinking_mode based on review scope: 'low' for small code snippets, "
|
||||||
@@ -132,13 +131,13 @@ class ReviewCodeTool(BaseTool):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def get_system_prompt(self) -> str:
|
def get_system_prompt(self) -> str:
|
||||||
return REVIEW_CODE_PROMPT
|
return CODEREVIEW_PROMPT
|
||||||
|
|
||||||
def get_default_temperature(self) -> float:
|
def get_default_temperature(self) -> float:
|
||||||
return TEMPERATURE_ANALYTICAL
|
return TEMPERATURE_ANALYTICAL
|
||||||
|
|
||||||
def get_request_model(self):
|
def get_request_model(self):
|
||||||
return ReviewCodeRequest
|
return CodeReviewRequest
|
||||||
|
|
||||||
async def execute(self, arguments: dict[str, Any]) -> list[TextContent]:
|
async def execute(self, arguments: dict[str, Any]) -> list[TextContent]:
|
||||||
"""Override execute to check focus_on size before processing"""
|
"""Override execute to check focus_on size before processing"""
|
||||||
@@ -155,7 +154,7 @@ class ReviewCodeTool(BaseTool):
|
|||||||
# Continue with normal execution
|
# Continue with normal execution
|
||||||
return await super().execute(arguments)
|
return await super().execute(arguments)
|
||||||
|
|
||||||
async def prepare_prompt(self, request: ReviewCodeRequest) -> str:
|
async def prepare_prompt(self, request: CodeReviewRequest) -> str:
|
||||||
"""
|
"""
|
||||||
Prepare the code review prompt with customized instructions.
|
Prepare the code review prompt with customized instructions.
|
||||||
|
|
||||||
@@ -239,7 +238,7 @@ Please provide a code review aligned with the user's context and expectations, f
|
|||||||
|
|
||||||
return full_prompt
|
return full_prompt
|
||||||
|
|
||||||
def format_response(self, response: str, request: ReviewCodeRequest) -> str:
|
def format_response(self, response: str, request: CodeReviewRequest) -> str:
|
||||||
"""
|
"""
|
||||||
Format the review response with appropriate headers.
|
Format the review response with appropriate headers.
|
||||||
|
|
||||||
@@ -37,8 +37,8 @@ class DebugIssueTool(BaseTool):
|
|||||||
def get_description(self) -> str:
|
def get_description(self) -> str:
|
||||||
return (
|
return (
|
||||||
"DEBUG & ROOT CAUSE ANALYSIS - Expert debugging for complex issues with 1M token capacity. "
|
"DEBUG & ROOT CAUSE ANALYSIS - Expert debugging for complex issues with 1M token capacity. "
|
||||||
"Use this when you need help tracking down bugs or understanding errors. "
|
"Use this when you need to debug code, find out why something is failing, identify root causes, "
|
||||||
"Triggers: 'debug this', 'why is this failing', 'root cause', 'trace error', 'diagnose issue'. "
|
"trace errors, or diagnose issues. "
|
||||||
"IMPORTANT: Share diagnostic files liberally! Gemini can handle up to 1M tokens, so include: "
|
"IMPORTANT: Share diagnostic files liberally! Gemini can handle up to 1M tokens, so include: "
|
||||||
"large log files, full stack traces, memory dumps, diagnostic outputs, multiple related files, "
|
"large log files, full stack traces, memory dumps, diagnostic outputs, multiple related files, "
|
||||||
"entire modules, test results, configuration files - anything that might help debug the issue. "
|
"entire modules, test results, configuration files - anything that might help debug the issue. "
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Tool for reviewing pending git changes across multiple repositories.
|
Tool for pre-commit validation of git changes across multiple repositories.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -9,7 +9,7 @@ from mcp.types import TextContent
|
|||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
|
|
||||||
from config import MAX_CONTEXT_TOKENS
|
from config import MAX_CONTEXT_TOKENS
|
||||||
from prompts.tool_prompts import REVIEW_CHANGES_PROMPT
|
from prompts.tool_prompts import PRECOMMIT_PROMPT
|
||||||
from utils.file_utils import read_files, translate_file_paths, translate_path_for_environment
|
from utils.file_utils import read_files, translate_file_paths, translate_path_for_environment
|
||||||
from utils.git_utils import find_git_repositories, get_git_status, run_git_command
|
from utils.git_utils import find_git_repositories, get_git_status, run_git_command
|
||||||
from utils.token_utils import estimate_tokens
|
from utils.token_utils import estimate_tokens
|
||||||
@@ -18,8 +18,8 @@ from .base import BaseTool, ToolRequest
|
|||||||
from .models import ToolOutput
|
from .models import ToolOutput
|
||||||
|
|
||||||
|
|
||||||
class ReviewChangesRequest(ToolRequest):
|
class PrecommitRequest(ToolRequest):
|
||||||
"""Request model for review_changes tool"""
|
"""Request model for precommit tool"""
|
||||||
|
|
||||||
path: str = Field(
|
path: str = Field(
|
||||||
...,
|
...,
|
||||||
@@ -71,21 +71,21 @@ class ReviewChangesRequest(ToolRequest):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ReviewChanges(BaseTool):
|
class Precommit(BaseTool):
|
||||||
"""Tool for reviewing git changes across multiple repositories."""
|
"""Tool for pre-commit validation of git changes across multiple repositories."""
|
||||||
|
|
||||||
def get_name(self) -> str:
|
def get_name(self) -> str:
|
||||||
return "review_changes"
|
return "precommit"
|
||||||
|
|
||||||
def get_description(self) -> str:
|
def get_description(self) -> str:
|
||||||
return (
|
return (
|
||||||
"REVIEW PENDING GIT CHANGES BEFORE COMMITTING - ALWAYS use this tool before creating any git commit! "
|
"PRECOMMIT VALIDATION FOR GIT CHANGES - ALWAYS use this tool before creating any git commit! "
|
||||||
"Comprehensive pre-commit validation that catches bugs, security issues, incomplete implementations, "
|
"Comprehensive pre-commit validation that catches bugs, security issues, incomplete implementations, "
|
||||||
"and ensures changes match the original requirements. Searches all git repositories recursively and "
|
"and ensures changes match the original requirements. Searches all git repositories recursively and "
|
||||||
"provides deep analysis of staged/unstaged changes. Essential for code quality and preventing bugs. "
|
"provides deep analysis of staged/unstaged changes. Essential for code quality and preventing bugs. "
|
||||||
"Triggers: 'before commit', 'review changes', 'check my changes', 'validate changes', 'pre-commit review', "
|
"Use this before committing, when reviewing changes, checking your changes, validating changes, "
|
||||||
"'about to commit', 'ready to commit'. Claude should proactively suggest using this tool whenever "
|
"or when you're about to commit or ready to commit. Claude should proactively suggest using this tool "
|
||||||
"the user mentions committing or when changes are complete. "
|
"whenever the user mentions committing or when changes are complete. "
|
||||||
"Choose thinking_mode based on changeset size: 'low' for small focused changes, "
|
"Choose thinking_mode based on changeset size: 'low' for small focused changes, "
|
||||||
"'medium' for standard commits (default), 'high' for large feature branches or complex refactoring, "
|
"'medium' for standard commits (default), 'high' for large feature branches or complex refactoring, "
|
||||||
"'max' for critical releases or when reviewing extensive changes across multiple systems."
|
"'max' for critical releases or when reviewing extensive changes across multiple systems."
|
||||||
@@ -103,10 +103,10 @@ class ReviewChanges(BaseTool):
|
|||||||
return schema
|
return schema
|
||||||
|
|
||||||
def get_system_prompt(self) -> str:
|
def get_system_prompt(self) -> str:
|
||||||
return REVIEW_CHANGES_PROMPT
|
return PRECOMMIT_PROMPT
|
||||||
|
|
||||||
def get_request_model(self):
|
def get_request_model(self):
|
||||||
return ReviewChangesRequest
|
return PrecommitRequest
|
||||||
|
|
||||||
def get_default_temperature(self) -> float:
|
def get_default_temperature(self) -> float:
|
||||||
"""Use analytical temperature for code review."""
|
"""Use analytical temperature for code review."""
|
||||||
@@ -129,7 +129,7 @@ class ReviewChanges(BaseTool):
|
|||||||
# Continue with normal execution
|
# Continue with normal execution
|
||||||
return await super().execute(arguments)
|
return await super().execute(arguments)
|
||||||
|
|
||||||
async def prepare_prompt(self, request: ReviewChangesRequest) -> str:
|
async def prepare_prompt(self, request: PrecommitRequest) -> str:
|
||||||
"""Prepare the prompt with git diff information."""
|
"""Prepare the prompt with git diff information."""
|
||||||
# Check for prompt.txt in files
|
# Check for prompt.txt in files
|
||||||
prompt_content, updated_files = self.handle_prompt_file(request.files)
|
prompt_content, updated_files = self.handle_prompt_file(request.files)
|
||||||
@@ -409,6 +409,6 @@ class ReviewChanges(BaseTool):
|
|||||||
|
|
||||||
return full_prompt
|
return full_prompt
|
||||||
|
|
||||||
def format_response(self, response: str, request: ReviewChangesRequest) -> str:
|
def format_response(self, response: str, request: PrecommitRequest) -> str:
|
||||||
"""Format the response with commit guidance"""
|
"""Format the response with commit guidance"""
|
||||||
return f"{response}\n\n---\n\n**Commit Status:** If no critical issues found, changes are ready for commit. Otherwise, address issues first and re-run review. Check with user before proceeding with any commit."
|
return f"{response}\n\n---\n\n**Commit Status:** If no critical issues found, changes are ready for commit. Otherwise, address issues first and re-run review. Check with user before proceeding with any commit."
|
||||||
@@ -39,9 +39,8 @@ class ThinkDeeperTool(BaseTool):
|
|||||||
def get_description(self) -> str:
|
def get_description(self) -> str:
|
||||||
return (
|
return (
|
||||||
"EXTENDED THINKING & REASONING - Your deep thinking partner for complex problems. "
|
"EXTENDED THINKING & REASONING - Your deep thinking partner for complex problems. "
|
||||||
"Use this when you need to extend your analysis, explore alternatives, or validate approaches. "
|
"Use this when you need to think deeper about a problem, extend your analysis, explore alternatives, or validate approaches. "
|
||||||
"Perfect for: architecture decisions, complex bugs, performance challenges, security analysis. "
|
"Perfect for: architecture decisions, complex bugs, performance challenges, security analysis. "
|
||||||
"Triggers: 'think deeper', 'ultrathink', 'extend my analysis', 'explore alternatives'. "
|
|
||||||
"I'll challenge assumptions, find edge cases, and provide alternative solutions. "
|
"I'll challenge assumptions, find edge cases, and provide alternative solutions. "
|
||||||
"IMPORTANT: Choose the appropriate thinking_mode based on task complexity - "
|
"IMPORTANT: Choose the appropriate thinking_mode based on task complexity - "
|
||||||
"'low' for quick analysis, 'medium' for standard problems, 'high' for complex issues (default), "
|
"'low' for quick analysis, 'medium' for standard problems, 'high' for complex issues (default), "
|
||||||
|
|||||||
Reference in New Issue
Block a user