Performance improvements when embedding files:

- Exit early at MCP boundary if files won't fit within given context of chosen model
- Encourage claude to re-run with better context
- Check file sizes before embedding
- Drop files from older conversations when building continuations and give priority to newer files
- List and mention excluded files to Claude on return
- Improved tests
- Improved precommit prompt
- Added a new Low severity to precommit
- Improved documentation of file embedding strategy
- Refactor
This commit is contained in:
Fahad
2025-06-16 05:51:52 +04:00
parent 56333cbd86
commit 91077e3810
16 changed files with 1557 additions and 308 deletions

View File

@@ -135,6 +135,14 @@ class AnalyzeTool(BaseTool):
if updated_files is not None:
request.files = updated_files
# MCP boundary check - STRICT REJECTION
if request.files:
file_size_check = self.check_total_file_size(request.files)
if file_size_check:
from tools.models import ToolOutput
raise ValueError(f"MCP_SIZE_CHECK:{ToolOutput(**file_size_check).model_dump_json()}")
# Use centralized file processing logic
continuation_id = getattr(request, "continuation_id", None)
file_content, processed_files = self._prepare_file_content_for_prompt(request.files, continuation_id, "Files")

View File

@@ -936,6 +936,49 @@ When recommending searches, be specific about what information you need and why
}
return None
def estimate_tokens_smart(self, file_path: str) -> int:
"""
Estimate tokens for a file using file-type aware ratios.
Args:
file_path: Path to the file
Returns:
int: Estimated token count
"""
from utils.file_utils import estimate_file_tokens
return estimate_file_tokens(file_path)
def check_total_file_size(self, files: list[str]) -> Optional[dict[str, Any]]:
"""
Check if total file sizes would exceed token threshold before embedding.
IMPORTANT: This performs STRICT REJECTION at MCP boundary.
No partial inclusion - either all files fit or request is rejected.
This forces Claude to make better file selection decisions.
Args:
files: List of file paths to check
Returns:
Dict with MCP_CODE_TOO_LARGE response if too large, None if acceptable
"""
if not files:
return None
# Get current model name for context-aware thresholds
model_name = getattr(self, "_current_model_name", None)
if not model_name:
from config import DEFAULT_MODEL
model_name = DEFAULT_MODEL
# Use centralized file size checking with model context
from utils.file_utils import check_total_file_size as check_file_size_utility
return check_file_size_utility(files, model_name)
def handle_prompt_file(self, files: Optional[list[str]]) -> tuple[Optional[str], Optional[list[str]]]:
"""
Check for and handle prompt.txt in the files list.

View File

@@ -178,6 +178,14 @@ class CodeReviewTool(BaseTool):
if updated_files is not None:
request.files = updated_files
# MCP boundary check - STRICT REJECTION
if request.files:
file_size_check = self.check_total_file_size(request.files)
if file_size_check:
from tools.models import ToolOutput
raise ValueError(f"MCP_SIZE_CHECK:{ToolOutput(**file_size_check).model_dump_json()}")
# Check user input size at MCP transport boundary (before adding internal content)
user_content = request.prompt
size_check = self.check_prompt_size(user_content)

View File

@@ -150,6 +150,14 @@ class DebugIssueTool(BaseTool):
if updated_files is not None:
request.files = updated_files
# MCP boundary check - STRICT REJECTION
if request.files:
file_size_check = self.check_total_file_size(request.files)
if file_size_check:
from tools.models import ToolOutput
raise ValueError(f"MCP_SIZE_CHECK:{ToolOutput(**file_size_check).model_dump_json()}")
# Build context sections
context_parts = [f"=== ISSUE DESCRIPTION ===\n{request.prompt}\n=== END DESCRIPTION ==="]

View File

@@ -43,6 +43,7 @@ class ToolOutput(BaseModel):
"refactor_analysis_complete",
"trace_complete",
"resend_prompt",
"code_too_large",
"continuation_available",
] = "success"
content: Optional[str] = Field(None, description="The main content/response from the tool")
@@ -142,6 +143,15 @@ class RefactorAnalysisComplete(BaseModel):
next_actions_for_claude: list[RefactorAction] = Field(..., description="Specific actions for Claude to implement")
class CodeTooLargeRequest(BaseModel):
"""Request to reduce file selection due to size constraints"""
status: Literal["code_too_large"] = "code_too_large"
content: str = Field(..., description="Message explaining the size constraint")
content_type: Literal["text"] = "text"
metadata: dict[str, Any] = Field(default_factory=dict)
class ResendPromptRequest(BaseModel):
"""Request to resend prompt via file due to size limits"""
@@ -284,6 +294,7 @@ SPECIAL_STATUS_MODELS = {
"refactor_analysis_complete": RefactorAnalysisComplete,
"trace_complete": TraceComplete,
"resend_prompt": ResendPromptRequest,
"code_too_large": CodeTooLargeRequest,
}

View File

@@ -36,7 +36,7 @@ class PrecommitRequest(ToolRequest):
)
prompt: Optional[str] = Field(
None,
description="The original user request description for the changes. Provides critical context for the review. If original request is limited or not available, Claude MUST study the changes carefully, think deeply about the implementation intent, analyze patterns across all modifications, infer the logic and requirements from the code changes and provide a thorough starting point.",
description="The original user request description for the changes. Provides critical context for the review. If original request is limited or not available, you MUST study the changes carefully, think deeply about the implementation intent, analyze patterns across all modifications, infer the logic and requirements from the code changes and provide a thorough starting point.",
)
compare_to: Optional[str] = Field(
None,
@@ -57,7 +57,7 @@ class PrecommitRequest(ToolRequest):
review_type: Literal["full", "security", "performance", "quick"] = Field(
"full", description="Type of review to perform on the changes."
)
severity_filter: Literal["critical", "high", "medium", "all"] = Field(
severity_filter: Literal["critical", "high", "medium", "low", "all"] = Field(
"all",
description="Minimum severity level to report on the changes.",
)
@@ -117,7 +117,7 @@ class Precommit(BaseTool):
"model": self.get_model_field_schema(),
"prompt": {
"type": "string",
"description": "The original user request description for the changes. Provides critical context for the review. If original request is limited or not available, Claude MUST study the changes carefully, think deeply about the implementation intent, analyze patterns across all modifications, infer the logic and requirements from the code changes and provide a thorough starting point.",
"description": "The original user request description for the changes. Provides critical context for the review. If original request is limited or not available, you MUST study the changes carefully, think deeply about the implementation intent, analyze patterns across all modifications, infer the logic and requirements from the code changes and provide a thorough starting point.",
},
"compare_to": {
"type": "string",
@@ -145,7 +145,7 @@ class Precommit(BaseTool):
},
"severity_filter": {
"type": "string",
"enum": ["critical", "high", "medium", "all"],
"enum": ["critical", "high", "medium", "low", "all"],
"default": "all",
"description": "Minimum severity level to report on the changes.",
},
@@ -227,6 +227,14 @@ class Precommit(BaseTool):
translated_path = translate_path_for_environment(request.path)
translated_files = translate_file_paths(request.files)
# MCP boundary check - STRICT REJECTION (check original files before translation)
if request.files:
file_size_check = self.check_total_file_size(request.files)
if file_size_check:
from tools.models import ToolOutput
raise ValueError(f"MCP_SIZE_CHECK:{ToolOutput(**file_size_check).model_dump_json()}")
# Check if the path translation resulted in an error path
if translated_path.startswith("/inaccessible/"):
raise ValueError(
@@ -540,4 +548,20 @@ class Precommit(BaseTool):
def format_response(self, response: str, request: PrecommitRequest, model_info: Optional[dict] = None) -> str:
"""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."
# Base response
formatted_response = response
# Add footer separator
formatted_response += "\n\n---\n\n"
# Add commit status instruction
formatted_response += (
"COMMIT STATUS: You MUST provide a clear summary of ALL issues found to the user. "
"If no critical or high severity issues found, changes are ready for commit. "
"If critical issues are found, you MUST fix them first and then run the precommit tool again "
"to validate the fixes before proceeding. "
"Medium to low severity issues should be addressed but may not block commit. "
"You MUST always CONFIRM with user and show them a CLEAR summary of ALL issues before proceeding with any commit."
)
return formatted_response

View File

@@ -143,6 +143,14 @@ class ThinkDeepTool(BaseTool):
if updated_files is not None:
request.files = updated_files
# MCP boundary check - STRICT REJECTION
if request.files:
file_size_check = self.check_total_file_size(request.files)
if file_size_check:
from tools.models import ToolOutput
raise ValueError(f"MCP_SIZE_CHECK:{ToolOutput(**file_size_check).model_dump_json()}")
# Build context parts
context_parts = [f"=== CLAUDE'S CURRENT ANALYSIS ===\n{current_analysis}\n=== END ANALYSIS ==="]