Files
my-pal-mcp-server/tools/debug.py
Fahad eb388ab2f2 Categorize tools into 'model capabilities categories' to help determine which type of model to pick when in auto mode
Encourage Claude to pick the best model for the job automatically in auto mode
Lots of new tests to ensure automatic model picking works reliably based on user preference or when a matching model is not found or ambiguous
Improved error reporting when bogus model is requested and is not configured or available
2025-06-14 02:17:06 +04:00

217 lines
9.4 KiB
Python

"""
Debug Issue tool - Root cause analysis and debugging assistance
"""
from typing import TYPE_CHECKING, Any, Optional
from mcp.types import TextContent
from pydantic import Field
if TYPE_CHECKING:
from tools.models import ToolModelCategory
from config import TEMPERATURE_ANALYTICAL
from prompts import DEBUG_ISSUE_PROMPT
from .base import BaseTool, ToolRequest
from .models import ToolOutput
class DebugIssueRequest(ToolRequest):
"""Request model for debug tool"""
prompt: str = Field(..., description="Error message, symptoms, or issue description")
error_context: Optional[str] = Field(None, description="Stack trace, logs, or additional error context")
files: Optional[list[str]] = Field(
None,
description="Files or directories that might be related to the issue (must be absolute paths)",
)
runtime_info: Optional[str] = Field(None, description="Environment, versions, or runtime information")
previous_attempts: Optional[str] = Field(None, description="What has been tried already")
class DebugIssueTool(BaseTool):
"""Advanced debugging and root cause analysis tool"""
def get_name(self) -> str:
return "debug"
def get_description(self) -> str:
return (
"DEBUG & ROOT CAUSE ANALYSIS - Expert debugging for complex issues with 1M token capacity. "
"Use this when you need to debug code, find out why something is failing, identify root causes, "
"trace errors, or diagnose issues. "
"IMPORTANT: Share diagnostic files liberally! The model can handle up to 1M tokens, so include: "
"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. "
"Claude should proactively use this tool whenever debugging is needed and share comprehensive "
"file paths rather than snippets. Include error messages, stack traces, logs, and ALL relevant "
"code files as absolute paths. The more context, the better the debugging analysis. "
"Choose thinking_mode based on issue complexity: 'low' for simple errors, "
"'medium' for standard debugging (default), 'high' for complex system issues, "
"'max' for extremely challenging bugs requiring deepest analysis."
)
def get_input_schema(self) -> dict[str, Any]:
schema = {
"type": "object",
"properties": {
"prompt": {
"type": "string",
"description": "Error message, symptoms, or issue description",
},
"model": self.get_model_field_schema(),
"error_context": {
"type": "string",
"description": "Stack trace, logs, or additional error context",
},
"files": {
"type": "array",
"items": {"type": "string"},
"description": "Files or directories that might be related to the issue (must be absolute paths)",
},
"runtime_info": {
"type": "string",
"description": "Environment, versions, or runtime information",
},
"previous_attempts": {
"type": "string",
"description": "What has been tried already",
},
"temperature": {
"type": "number",
"description": "Temperature (0-1, default 0.2 for accuracy)",
"minimum": 0,
"maximum": 1,
},
"thinking_mode": {
"type": "string",
"enum": ["minimal", "low", "medium", "high", "max"],
"description": "Thinking depth: minimal (0.5% of model max), low (8%), medium (33%), high (67%), max (100% of model max)",
},
"use_websearch": {
"type": "boolean",
"description": "Enable web search for documentation, best practices, and current information. Particularly useful for: brainstorming sessions, architectural design discussions, exploring industry best practices, working with specific frameworks/technologies, researching solutions to complex problems, or when current documentation and community insights would enhance the analysis.",
"default": True,
},
"continuation_id": {
"type": "string",
"description": "Thread continuation ID for multi-turn conversations. Can be used to continue conversations across different tools. Only provide this if continuing a previous conversation thread.",
},
},
"required": ["prompt"] + (["model"] if self.is_effective_auto_mode() else []),
}
return schema
def get_system_prompt(self) -> str:
return DEBUG_ISSUE_PROMPT
def get_default_temperature(self) -> float:
return TEMPERATURE_ANALYTICAL
def get_model_category(self) -> "ToolModelCategory":
"""Debug requires deep analysis and reasoning"""
from tools.models import ToolModelCategory
return ToolModelCategory.EXTENDED_REASONING
def get_request_model(self):
return DebugIssueRequest
async def execute(self, arguments: dict[str, Any]) -> list[TextContent]:
"""Override execute to check error_description and error_context size before processing"""
# First validate request
request_model = self.get_request_model()
request = request_model(**arguments)
# Check prompt size
size_check = self.check_prompt_size(request.prompt)
if size_check:
return [TextContent(type="text", text=ToolOutput(**size_check).model_dump_json())]
# Check error_context size if provided
if request.error_context:
size_check = self.check_prompt_size(request.error_context)
if size_check:
return [TextContent(type="text", text=ToolOutput(**size_check).model_dump_json())]
# Continue with normal execution
return await super().execute(arguments)
async def prepare_prompt(self, request: DebugIssueRequest) -> str:
"""Prepare the debugging prompt"""
# Check for prompt.txt in files
prompt_content, updated_files = self.handle_prompt_file(request.files)
# If prompt.txt was found, use it as prompt or error_context
if prompt_content:
if not request.prompt or request.prompt == "":
request.prompt = prompt_content
else:
request.error_context = prompt_content
# Update request files list
if updated_files is not None:
request.files = updated_files
# Build context sections
context_parts = [f"=== ISSUE DESCRIPTION ===\n{request.prompt}\n=== END DESCRIPTION ==="]
if request.error_context:
context_parts.append(f"\n=== ERROR CONTEXT/STACK TRACE ===\n{request.error_context}\n=== END CONTEXT ===")
if request.runtime_info:
context_parts.append(f"\n=== RUNTIME INFORMATION ===\n{request.runtime_info}\n=== END RUNTIME ===")
if request.previous_attempts:
context_parts.append(f"\n=== PREVIOUS ATTEMPTS ===\n{request.previous_attempts}\n=== END ATTEMPTS ===")
# Add relevant files if provided
if request.files:
# Use centralized file processing logic
continuation_id = getattr(request, "continuation_id", None)
file_content = self._prepare_file_content_for_prompt(request.files, continuation_id, "Code")
if file_content:
context_parts.append(f"\n=== RELEVANT CODE ===\n{file_content}\n=== END CODE ===")
full_context = "\n".join(context_parts)
# Check token limits
self._validate_token_limit(full_context, "Context")
# Add web search instruction if enabled
websearch_instruction = self.get_websearch_instruction(
request.use_websearch,
"""When debugging issues, consider if searches for these would help:
- The exact error message to find known solutions
- Framework-specific error codes and their meanings
- Similar issues in forums, GitHub issues, or Stack Overflow
- Workarounds and patches for known bugs
- Version-specific issues and compatibility problems""",
)
# Combine everything
full_prompt = f"""{self.get_system_prompt()}{websearch_instruction}
{full_context}
Please debug this issue following the structured format in the system prompt.
Focus on finding the root cause and providing actionable solutions."""
return full_prompt
def format_response(self, response: str, request: DebugIssueRequest, model_info: Optional[dict] = None) -> str:
"""Format the debugging response"""
# Get the friendly model name
model_name = "the model"
if model_info and model_info.get("model_response"):
model_name = model_info["model_response"].friendly_name or "the model"
return f"""{response}
---
**Next Steps:** Evaluate {model_name}'s recommendations, synthesize the best fix considering potential regressions, and if the root cause has been clearly identified, proceed with implementing the potential fixes."""