From 59ea881465950b9e3e9d55c95ff19b7cdb1e9efc Mon Sep 17 00:00:00 2001 From: Fahad Date: Sat, 21 Jun 2025 07:58:07 +0400 Subject: [PATCH] Improved tracer that uses a workflow --- systemprompts/__init__.py | 2 + systemprompts/tracer_prompt.py | 145 +++++++ tests/test_tracer.py | 224 +++-------- tools/tracer.py | 682 +++++++++++++++++++++++++-------- 4 files changed, 722 insertions(+), 331 deletions(-) create mode 100644 systemprompts/tracer_prompt.py diff --git a/systemprompts/__init__.py b/systemprompts/__init__.py index 1e5047d..31ab97d 100644 --- a/systemprompts/__init__.py +++ b/systemprompts/__init__.py @@ -12,6 +12,7 @@ from .precommit_prompt import PRECOMMIT_PROMPT from .refactor_prompt import REFACTOR_PROMPT from .testgen_prompt import TESTGEN_PROMPT from .thinkdeep_prompt import THINKDEEP_PROMPT +from .tracer_prompt import TRACER_PROMPT __all__ = [ "THINKDEEP_PROMPT", @@ -24,4 +25,5 @@ __all__ = [ "PRECOMMIT_PROMPT", "REFACTOR_PROMPT", "TESTGEN_PROMPT", + "TRACER_PROMPT", ] diff --git a/systemprompts/tracer_prompt.py b/systemprompts/tracer_prompt.py new file mode 100644 index 0000000..db9c5b4 --- /dev/null +++ b/systemprompts/tracer_prompt.py @@ -0,0 +1,145 @@ +""" +Tracer tool system prompts +""" + +TRACER_PROMPT = """ +You are an expert, seasoned software architect and code analysis specialist with deep expertise in code tracing, +execution flow analysis, and dependency mapping. You have extensive experience analyzing complex codebases, +tracing method calls, understanding data flow, and mapping structural relationships in software systems. +From microservices to monolithic applications, your ability to understand code structure, execution paths, +and dependencies is unmatched. There is nothing related to software architecture, design patterns, or code +analysis that you're not aware of. Your role is to systematically trace and analyze code to provide +comprehensive understanding of how software components interact and execute. + +CRITICAL LINE NUMBER INSTRUCTIONS +Code is presented with line number markers "LINE│ code". These markers are for reference ONLY and MUST NOT be +included in any code you generate. Always reference specific line numbers for Claude to locate +exact positions if needed to point to exact locations. Include a very short code excerpt alongside for clarity. +Include context_start_text and context_end_text as backup references. Never include "LINE│" markers in generated code +snippets. + +IF MORE INFORMATION IS NEEDED +If Claude is discussing specific code, functions, or project components that was not given as part of the context, +and you need additional context (e.g., related files, configuration, dependencies, test files) to provide meaningful +analysis, you MUST respond ONLY with this JSON format (and nothing else). Do NOT ask for the same file you've been +provided unless for some reason its content is missing or incomplete: +{ + "status": "files_required_to_continue", + "mandatory_instructions": "", + "files_needed": ["[file name here]", "[or some folder/]"] +} + +TRACING METHODOLOGY: + +1. PRECISION MODE (Execution Flow): + - Trace method/function execution paths and call chains + - Identify entry points and usage patterns + - Map conditional branches and control flow + - Document side effects and state changes + - Analyze parameter flow and return values + +2. DEPENDENCIES MODE (Structural Relationships): + - Map incoming and outgoing dependencies + - Identify type relationships (inheritance, composition, usage) + - Trace bidirectional connections between components + - Document interface contracts and protocols + - Analyze coupling and cohesion patterns + +ANALYSIS STRUCTURE: +Each tracing step MUST include: +- Step number and current findings +- Files examined and methods analyzed +- Concrete evidence from code examination +- Relationships discovered (calls, dependencies, usage) +- Execution paths or structural patterns identified +- Areas requiring deeper investigation + +TRACING PRINCIPLES: +- Start with target identification, then explore systematically +- Follow actual code paths, not assumed behavior +- Document concrete evidence with file:line references +- Consider edge cases, error handling, and conditional logic +- Map both direct and indirect relationships +- Verify assumptions with code examination + +STRUCTURED JSON OUTPUT FORMAT: +You MUST respond with a properly formatted JSON object following this exact schema. +Do NOT include any text before or after the JSON. The response must be valid JSON only. + +IF MORE INFORMATION IS NEEDED: +If you lack critical information to proceed with tracing, you MUST only respond with: +{ + "status": "files_required_to_continue", + "mandatory_instructions": "", + "files_needed": ["", ""] +} + +FOR NORMAL TRACING RESPONSES: + +{ + "status": "tracing_in_progress", + "step_number": , + "total_steps": , + "next_step_required": , + "step_content": "", + "metadata": { + "trace_mode": "", + "target_description": "", + "step_history_length": + }, + "tracing_status": { + "files_checked": , + "relevant_files": , + "relevant_context": , + "issues_found": 0, + "images_collected": , + "current_confidence": "", + "step_history_length": + }, + "continuation_id": "", + "tracing_complete": , + "trace_summary": "", + "next_steps": "", + "output": { + "instructions": "", + "format": "", + "rendering_instructions": "", + "presentation_guidelines": "" + } +} + +TRACING CONTENT GUIDELINES: +- step_content: Provide detailed analysis of current tracing investigation +- Include specific files examined, methods analyzed, and relationships discovered +- Reference exact line numbers and code snippets for evidence +- Document execution paths, call chains, or dependency relationships +- When completing tracing, provide comprehensive trace_summary +- next_steps: Always guide Claude on what to investigate next + +TRACE PRESENTATION GUIDELINES: +When tracing is complete (tracing_complete: true), Claude should present the final trace with: + +FOR PRECISION MODE: +- Vertical indented call flow diagrams with exact file:line references +- Branching and side effect tables with specific conditions +- Usage points with context descriptions +- Entry points with trigger scenarios +- Visual call chains using arrows and indentation + +FOR DEPENDENCIES MODE: +- Bidirectional arrow flow diagrams showing incoming/outgoing dependencies +- Type relationship mappings (inheritance, composition, usage) +- Dependency tables with file:line references +- Visual connection diagrams with proper arrow directions +- Structural relationship analysis + +IMPORTANT FORMATTING RULES: +- Use exact file paths and line numbers from actual codebase +- Adapt method naming to match project's programming language conventions +- Use proper indentation and visual alignment for call flows +- Show conditional execution with explicit condition descriptions +- Mark uncertain or ambiguous paths clearly +- Include comprehensive side effects categorization + +Be systematic, thorough, and provide concrete evidence. Your tracing should be detailed enough that someone could follow the exact execution paths or understand the complete dependency structure. +""" diff --git a/tests/test_tracer.py b/tests/test_tracer.py index debc6a2..2466492 100644 --- a/tests/test_tracer.py +++ b/tests/test_tracer.py @@ -23,113 +23,91 @@ class TestTracerTool: def test_get_description(self, tracer_tool): """Test that the tool returns a comprehensive description""" description = tracer_tool.get_description() - assert "ANALYSIS PROMPT GENERATOR" in description + assert "STEP-BY-STEP CODE TRACING WORKFLOW" in description assert "precision" in description assert "dependencies" in description - assert "static code analysis" in description + assert "guided investigation" in description def test_get_input_schema(self, tracer_tool): """Test that the input schema includes required fields""" schema = tracer_tool.get_input_schema() assert schema["type"] == "object" - assert "prompt" in schema["properties"] + assert "target_description" in schema["properties"] assert "trace_mode" in schema["properties"] + assert "step" in schema["properties"] + assert "step_number" in schema["properties"] # Check trace_mode enum values trace_enum = schema["properties"]["trace_mode"]["enum"] assert "precision" in trace_enum assert "dependencies" in trace_enum - # Check required fields - assert set(schema["required"]) == {"prompt", "trace_mode"} + # Check required fields include workflow fields + required_fields = set(schema["required"]) + assert "target_description" in required_fields + assert "trace_mode" in required_fields def test_get_model_category(self, tracer_tool): - """Test that the tracer tool uses FAST_RESPONSE category""" + """Test that the tracer tool uses EXTENDED_REASONING category""" category = tracer_tool.get_model_category() - assert category == ToolModelCategory.FAST_RESPONSE + assert category == ToolModelCategory.EXTENDED_REASONING def test_request_model_validation(self, tracer_tool): """Test TracerRequest model validation""" # Valid request request = TracerRequest( - prompt="BookingManager finalizeInvoice method", + step="Analyze BookingManager finalizeInvoice method execution flow", + step_number=1, + total_steps=3, + next_step_required=True, + findings="Initial investigation of booking finalization process", + target_description="BookingManager finalizeInvoice method", trace_mode="precision", ) - assert request.prompt == "BookingManager finalizeInvoice method" + assert request.target_description == "BookingManager finalizeInvoice method" assert request.trace_mode == "precision" + assert request.step_number == 1 # Test invalid trace_mode with pytest.raises(ValueError): TracerRequest( - prompt="Test", + step="Test step", + step_number=1, + total_steps=1, + next_step_required=False, + findings="Test findings", trace_mode="invalid_mode", ) - @pytest.mark.asyncio - async def test_execute_precision_mode(self, tracer_tool): - """Test executing tracer with precision mode""" - request_args = { - "prompt": "BookingManager finalizeInvoice method", - "trace_mode": "precision", - } + def test_get_required_actions(self, tracer_tool): + """Test that required actions are provided for each step""" + # Step 1 - initial investigation + actions = tracer_tool.get_required_actions(1, "exploring", "Initial findings", 3) + assert len(actions) > 0 + assert any("search" in action.lower() for action in actions) + assert any("locate" in action.lower() for action in actions) - result = await tracer_tool.execute(request_args) + # Later steps with low confidence + actions = tracer_tool.get_required_actions(2, "low", "Some findings", 3) + assert len(actions) > 0 + assert any("trace" in action.lower() for action in actions) - assert len(result) == 1 - output = result[0] - assert output.type == "text" + # High confidence steps + actions = tracer_tool.get_required_actions(3, "high", "Strong findings", 3) + assert len(actions) > 0 + assert any("verify" in action.lower() for action in actions) - # Check content includes expected sections - content = output.text - assert "STATIC CODE ANALYSIS REQUEST" in content - assert "Analysis Instructions" in content - assert "BookingManager finalizeInvoice method" in content - assert "precision" in content - assert "CALL FLOW DIAGRAM" in content + def test_workflow_tool_characteristics(self, tracer_tool): + """Test that tracer has proper workflow tool characteristics""" + # Should not require external expert analysis + assert not tracer_tool.requires_expert_analysis() - @pytest.mark.asyncio - async def test_execute_dependencies_mode(self, tracer_tool): - """Test executing tracer with dependencies mode""" - request_args = { - "prompt": "payment processing flow", - "trace_mode": "dependencies", - } + # Should return TracerRequest as the workflow model + assert tracer_tool.get_workflow_request_model() == TracerRequest - result = await tracer_tool.execute(request_args) - - assert len(result) == 1 - output = result[0] - assert output.type == "text" - - # Check content includes expected sections - content = output.text - assert "STATIC CODE ANALYSIS REQUEST" in content - assert "payment processing flow" in content - assert "dependencies" in content - assert "DEPENDENCY FLOW DIAGRAM" in content - - def test_create_enhanced_prompt_precision(self, tracer_tool): - """Test enhanced prompt creation for precision mode""" - prompt = tracer_tool._create_enhanced_prompt("BookingManager::finalizeInvoice", "precision") - - assert "TARGET:" in prompt - assert "BookingManager::finalizeInvoice" in prompt - assert "precision" in prompt - assert "execution path" in prompt - assert "method calls" in prompt - assert "line numbers" in prompt - - def test_create_enhanced_prompt_dependencies(self, tracer_tool): - """Test enhanced prompt creation for dependencies mode""" - prompt = tracer_tool._create_enhanced_prompt("validation function", "dependencies") - - assert "TARGET:" in prompt - assert "validation function" in prompt - assert "dependencies" in prompt - assert "bidirectional dependencies" in prompt - assert "incoming" in prompt - assert "outgoing" in prompt + # Should not require AI model at MCP boundary + assert not tracer_tool.requires_model() def test_get_rendering_instructions_precision(self, tracer_tool): """Test rendering instructions for precision mode""" @@ -153,28 +131,6 @@ class TestTracerTool: assert "←" in instructions assert "→" in instructions - def test_get_precision_rendering_instructions(self, tracer_tool): - """Test precision rendering instructions content""" - instructions = tracer_tool._get_precision_rendering_instructions() - - assert "MANDATORY RENDERING INSTRUCTIONS" in instructions - assert "ADDITIONAL ANALYSIS VIEWS" in instructions - assert "CALL FLOW DIAGRAM" in instructions - assert "line number" in instructions - assert "ambiguous branch" in instructions - assert "SIDE EFFECTS" in instructions - - def test_get_dependencies_rendering_instructions(self, tracer_tool): - """Test dependencies rendering instructions content""" - instructions = tracer_tool._get_dependencies_rendering_instructions() - - assert "MANDATORY RENDERING INSTRUCTIONS" in instructions - assert "Bidirectional Arrow Flow Style" in instructions - assert "CallerClass::callerMethod" in instructions - assert "FirstDependency::method" in instructions - assert "TYPE RELATIONSHIPS" in instructions - assert "DEPENDENCY TABLE" in instructions - def test_rendering_instructions_consistency(self, tracer_tool): """Test that rendering instructions are consistent between modes""" precision_instructions = tracer_tool._get_precision_rendering_instructions() @@ -192,97 +148,13 @@ class TestTracerTool: assert "ABSOLUTE REQUIREMENTS" in precision_instructions assert "ABSOLUTE REQUIREMENTS" in dependencies_instructions - def test_rendering_instructions_completeness(self, tracer_tool): - """Test that rendering instructions include all necessary elements""" - precision = tracer_tool._get_precision_rendering_instructions() - dependencies = tracer_tool._get_dependencies_rendering_instructions() - - # Precision mode should include call flow and additional analysis views - assert "CALL FLOW DIAGRAM" in precision - assert "ADDITIONAL ANALYSIS VIEWS" in precision - - # Dependencies mode should include flow diagram and table - assert "DEPENDENCY FLOW DIAGRAM" in dependencies - assert "DEPENDENCY TABLE" in dependencies - - def test_rendering_instructions_mode_specific_content(self, tracer_tool): - """Test that each mode has its specific content requirements""" - precision = tracer_tool._get_precision_rendering_instructions() - dependencies = tracer_tool._get_dependencies_rendering_instructions() - - # Precision-specific content - assert "USAGE POINTS" in precision - assert "ENTRY POINTS" in precision - - # Dependencies-specific content - assert "INCOMING DEPENDENCIES" in dependencies - assert "OUTGOING DEPENDENCIES" in dependencies - assert "Bidirectional Arrow" in dependencies - - @pytest.mark.asyncio - async def test_execute_returns_textcontent_format(self, tracer_tool): - """Test that execute returns proper TextContent format for MCP protocol""" - from mcp.types import TextContent - - request_args = { - "prompt": "test method analysis", - "trace_mode": "precision", - } - - result = await tracer_tool.execute(request_args) - - # Verify structure - assert isinstance(result, list) - assert len(result) == 1 - - # Verify TextContent format - output = result[0] - assert isinstance(output, TextContent) - assert hasattr(output, "type") - assert hasattr(output, "text") - assert output.type == "text" - assert isinstance(output.text, str) - assert len(output.text) > 0 - - @pytest.mark.asyncio - async def test_mcp_protocol_compatibility(self, tracer_tool): - """Test that the tool output is compatible with MCP protocol expectations""" - request_args = { - "prompt": "analyze method dependencies", - "trace_mode": "dependencies", - } - - result = await tracer_tool.execute(request_args) - - # Should return list of TextContent objects - assert isinstance(result, list) - - for item in result: - # Each item should be TextContent with required fields - assert hasattr(item, "type") - assert hasattr(item, "text") - - # Verify it can be serialized (MCP requirement) - serialized = item.model_dump() - assert "type" in serialized - assert "text" in serialized - assert serialized["type"] == "text" - def test_mode_selection_guidance(self, tracer_tool): """Test that the schema provides clear guidance on when to use each mode""" schema = tracer_tool.get_input_schema() trace_mode_desc = schema["properties"]["trace_mode"]["description"] # Should clearly indicate precision is for methods/functions - assert "methods/functions" in trace_mode_desc assert "execution flow" in trace_mode_desc - assert "usage patterns" in trace_mode_desc - # Should clearly indicate dependencies is for classes/modules/protocols - assert "classes/modules/protocols" in trace_mode_desc + # Should clearly indicate dependencies is for structural relationships assert "structural relationships" in trace_mode_desc - - # Should provide clear examples in prompt description - prompt_desc = schema["properties"]["prompt"]["description"] - assert "method" in prompt_desc and "precision mode" in prompt_desc - assert "class" in prompt_desc and "dependencies mode" in prompt_desc diff --git a/tools/tracer.py b/tools/tracer.py index 5e1b1d0..5618174 100644 --- a/tools/tracer.py +++ b/tools/tracer.py @@ -1,31 +1,97 @@ """ -Tracer tool - Prompt generator for static code analysis workflows +Tracer Workflow tool - Step-by-step code tracing and dependency analysis -This tool generates structured prompts and instructions for static code analysis. -It helps Claude create focused analysis requests and provides detailed rendering -instructions for visualizing call paths and dependency mappings. +This tool provides a structured workflow for comprehensive code tracing and analysis. +It guides Claude through systematic investigation steps with forced pauses between each step +to ensure thorough code examination, dependency mapping, and execution flow analysis before proceeding. + +The tracer guides users through sequential code analysis with full context awareness and +the ability to revise and adapt as understanding deepens. + +Key features: +- Sequential tracing with systematic investigation workflow +- Support for precision tracing (execution flow) and dependencies tracing (structural relationships) +- Self-contained completion with detailed output formatting instructions +- Context-aware analysis that builds understanding step by step +- No external expert analysis needed - provides comprehensive guidance internally + +Perfect for: method/function execution flow analysis, dependency mapping, call chain tracing, +structural relationship analysis, architectural understanding, and code comprehension. """ -from typing import Any, Literal +import logging +from typing import TYPE_CHECKING, Any, Literal, Optional -from pydantic import Field +from pydantic import Field, field_validator -from .base import BaseTool, ToolRequest +if TYPE_CHECKING: + from tools.models import ToolModelCategory -# Field descriptions to avoid duplication between Pydantic and JSON schema -TRACER_FIELD_DESCRIPTIONS = { - "prompt": ( - "Detailed description of what to trace and WHY you need this analysis. MUST include context about what " - "you're trying to understand, debug, analyze or find. For precision mode: describe the specific " - "method/function and what aspect of its execution flow you need to understand. For dependencies " - "mode: describe the class/module and what relationships you need to map. Example: 'I need to " - "understand how BookingManager.finalizeInvoice method is called throughout the system and what " - "side effects it has, as I'm debugging payment processing issues' rather than just " - "'BookingManager finalizeInvoice method'" +from config import TEMPERATURE_ANALYTICAL +from systemprompts import TRACER_PROMPT +from tools.shared.base_models import WorkflowRequest + +from .workflow.base import WorkflowTool + +logger = logging.getLogger(__name__) + +# Tool-specific field descriptions for tracer workflow +TRACER_WORKFLOW_FIELD_DESCRIPTIONS = { + "step": ( + "Describe what you're currently investigating for code tracing by thinking deeply about the code structure, " + "execution paths, and dependencies. In step 1, clearly state your tracing plan and begin forming a systematic " + "approach after thinking carefully about what needs to be analyzed. CRITICAL: For precision mode, focus on " + "execution flow, call chains, and usage patterns. For dependencies mode, focus on structural relationships " + "and bidirectional dependencies. Map out the code structure, understand the business logic, and identify " + "areas requiring deeper tracing. In all later steps, continue exploring with precision: trace dependencies, " + "verify call paths, and adapt your understanding as you uncover more evidence." ), - "trace_mode": ( - "Trace mode: 'precision' (for methods/functions - shows execution flow and usage patterns) or " - "'dependencies' (for classes/modules/protocols - shows structural relationships)" + "step_number": ( + "The index of the current step in the tracing sequence, beginning at 1. Each step should build upon or " + "revise the previous one." + ), + "total_steps": ( + "Your current estimate for how many steps will be needed to complete the tracing analysis. " + "Adjust as new findings emerge." + ), + "next_step_required": ( + "Set to true if you plan to continue the investigation with another step. False means you believe the " + "tracing analysis is complete and ready for final output formatting." + ), + "findings": ( + "Summarize everything discovered in this step about the code being traced. Include analysis of execution " + "paths, dependency relationships, call chains, structural patterns, and any discoveries about how the code " + "works. Be specific and avoid vague language—document what you now know about the code and how it affects " + "your tracing analysis. IMPORTANT: Document both the direct relationships (immediate calls, dependencies) " + "and indirect relationships (transitive dependencies, side effects). In later steps, confirm or update past " + "findings with additional evidence." + ), + "files_checked": ( + "List all files (as absolute paths, do not clip or shrink file names) examined during the tracing " + "investigation so far. Include even files ruled out or found to be unrelated, as this tracks your " + "exploration path." + ), + "relevant_files": ( + "Subset of files_checked (as full absolute paths) that contain code directly relevant to the tracing analysis. " + "Only list those that are directly tied to the target method/function/class/module being traced, its " + "dependencies, or its usage patterns. This could include implementation files, related modules, or files " + "demonstrating key relationships." + ), + "relevant_context": ( + "List methods, functions, classes, or modules that are central to the tracing analysis, in the format " + "'ClassName.methodName', 'functionName', or 'module.ClassName'. Prioritize those that are part of the " + "execution flow, dependency chain, or represent key relationships in the tracing analysis." + ), + "confidence": ( + "Indicate your current confidence in the tracing analysis completeness. Use: 'exploring' (starting analysis), " + "'low' (early investigation), 'medium' (some patterns identified), 'high' (comprehensive understanding), " + "'complete' (tracing analysis finished and ready for output). Do NOT use 'complete' unless the tracing " + "analysis is thoroughly finished and you have a comprehensive understanding of the code relationships." + ), + "trace_mode": "Type of tracing: 'precision' (execution flow) or 'dependencies' (structural relationships)", + "target_description": ( + "Detailed description of what to trace and WHY you need this analysis. MUST include context about what " + "you're trying to understand, debug, analyze or find." ), "images": ( "Optional images of system architecture diagrams, flow charts, or visual references to help " @@ -34,165 +100,417 @@ TRACER_FIELD_DESCRIPTIONS = { } -class TracerRequest(ToolRequest): - """ - Request model for the tracer tool. +class TracerRequest(WorkflowRequest): + """Request model for tracer workflow investigation steps""" - This model defines the parameters for generating analysis prompts. + # Required fields for each investigation step + step: str = Field(..., description=TRACER_WORKFLOW_FIELD_DESCRIPTIONS["step"]) + step_number: int = Field(..., description=TRACER_WORKFLOW_FIELD_DESCRIPTIONS["step_number"]) + total_steps: int = Field(..., description=TRACER_WORKFLOW_FIELD_DESCRIPTIONS["total_steps"]) + next_step_required: bool = Field(..., description=TRACER_WORKFLOW_FIELD_DESCRIPTIONS["next_step_required"]) + + # Investigation tracking fields + findings: str = Field(..., description=TRACER_WORKFLOW_FIELD_DESCRIPTIONS["findings"]) + files_checked: list[str] = Field( + default_factory=list, description=TRACER_WORKFLOW_FIELD_DESCRIPTIONS["files_checked"] + ) + relevant_files: list[str] = Field( + default_factory=list, description=TRACER_WORKFLOW_FIELD_DESCRIPTIONS["relevant_files"] + ) + relevant_context: list[str] = Field( + default_factory=list, description=TRACER_WORKFLOW_FIELD_DESCRIPTIONS["relevant_context"] + ) + confidence: Optional[str] = Field("exploring", description=TRACER_WORKFLOW_FIELD_DESCRIPTIONS["confidence"]) + + # Tracer-specific fields (used in step 1 to initialize) + trace_mode: Optional[Literal["precision", "dependencies"]] = Field( + None, description=TRACER_WORKFLOW_FIELD_DESCRIPTIONS["trace_mode"] + ) + target_description: Optional[str] = Field( + None, description=TRACER_WORKFLOW_FIELD_DESCRIPTIONS["target_description"] + ) + images: Optional[list[str]] = Field(default=None, description=TRACER_WORKFLOW_FIELD_DESCRIPTIONS["images"]) + + # Exclude fields not relevant to tracing workflow + issues_found: list[dict] = Field(default_factory=list, exclude=True, description="Tracing doesn't track issues") + hypothesis: Optional[str] = Field(default=None, exclude=True, description="Tracing doesn't use hypothesis") + backtrack_from_step: Optional[int] = Field( + default=None, exclude=True, description="Tracing doesn't use backtracking" + ) + + # Exclude other non-tracing fields + temperature: Optional[float] = Field(default=None, exclude=True) + thinking_mode: Optional[str] = Field(default=None, exclude=True) + use_websearch: Optional[bool] = Field(default=None, exclude=True) + use_assistant_model: Optional[bool] = Field(default=False, exclude=True, description="Tracing is self-contained") + + @field_validator("step_number") + @classmethod + def validate_step_number(cls, v): + if v < 1: + raise ValueError("step_number must be at least 1") + return v + + @field_validator("total_steps") + @classmethod + def validate_total_steps(cls, v): + if v < 1: + raise ValueError("total_steps must be at least 1") + return v + + +class TracerTool(WorkflowTool): + """ + Tracer workflow tool for step-by-step code tracing and dependency analysis. + + This tool implements a structured tracing workflow that guides users through + methodical investigation steps, ensuring thorough code examination, dependency + mapping, and execution flow analysis before reaching conclusions. It supports + both precision tracing (execution flow) and dependencies tracing (structural relationships). """ - prompt: str = Field(..., description=TRACER_FIELD_DESCRIPTIONS["prompt"]) - trace_mode: Literal["precision", "dependencies"] = Field(..., description=TRACER_FIELD_DESCRIPTIONS["trace_mode"]) - images: list[str] = Field(default_factory=list, description=TRACER_FIELD_DESCRIPTIONS["images"]) - - -class TracerTool(BaseTool): - """ - Tracer tool implementation. - - This tool generates structured prompts and instructions for static code analysis. - It creates detailed requests and provides rendering instructions for Claude. - """ + def __init__(self): + super().__init__() + self.initial_request = None + self.trace_config = {} def get_name(self) -> str: return "tracer" def get_description(self) -> str: return ( - "ANALYSIS PROMPT GENERATOR - Creates structured prompts for static code analysis. " - "Helps generate detailed analysis requests with specific method/function names, file paths, and " - "component context. " - "Type 'precision': For methods/functions - traces execution flow, call chains, call stacks, and " - "shows when/how they are used. " - "Type 'dependencies': For classes/modules/protocols - maps structural relationships and " - "bidirectional dependencies. " - "Returns detailed instructions on how to perform the analysis and format the results. " - "Use this to create focused analysis requests that can be fed back to Claude with the appropriate " - "code files. " + "STEP-BY-STEP CODE TRACING WORKFLOW - Systematic code analysis through guided investigation. " + "This tool guides you through a structured investigation process where you:\\n\\n" + "1. Start with step 1: describe your tracing plan and target\\n" + "2. STOP and investigate code structure, patterns, and relationships\\n" + "3. Report findings in step 2 with concrete evidence from actual code analysis\\n" + "4. Continue investigating between each step\\n" + "5. Track findings, relevant files, and code relationships throughout\\n" + "6. Build comprehensive understanding as analysis evolves\\n" + "7. Complete with detailed output formatted according to trace mode\\n\\n" + "IMPORTANT: This tool enforces investigation between steps:\\n" + "- After each call, you MUST investigate before calling again\\n" + "- Each step must include NEW evidence from code examination\\n" + "- No recursive calls without actual investigation work\\n" + "- The tool will specify which step number to use next\\n" + "- Follow the required_actions list for investigation guidance\\n\\n" + "TRACE MODES:\\n" + "- 'precision': For methods/functions - traces execution flow, call chains, and usage patterns\\n" + "- 'dependencies': For classes/modules - maps structural relationships and bidirectional dependencies\\n\\n" + "Perfect for: method execution flow analysis, dependency mapping, call chain tracing, " + "structural relationship analysis, architectural understanding, code comprehension." ) - def get_input_schema(self) -> dict[str, Any]: - return { - "type": "object", - "properties": { - "prompt": { - "type": "string", - "description": TRACER_FIELD_DESCRIPTIONS["prompt"], - }, - "trace_mode": { - "type": "string", - "enum": ["precision", "dependencies"], - "description": TRACER_FIELD_DESCRIPTIONS["trace_mode"], - }, - "images": { - "type": "array", - "items": {"type": "string"}, - "description": TRACER_FIELD_DESCRIPTIONS["images"], - }, - }, - "required": ["prompt", "trace_mode"], - } + def get_system_prompt(self) -> str: + return TRACER_PROMPT - def get_model_category(self): - """Tracer is a simple prompt generator""" + def get_default_temperature(self) -> float: + return TEMPERATURE_ANALYTICAL + + def get_model_category(self) -> "ToolModelCategory": + """Tracer requires analytical reasoning for code analysis""" from tools.models import ToolModelCategory - return ToolModelCategory.FAST_RESPONSE + return ToolModelCategory.EXTENDED_REASONING - def get_request_model(self): + def requires_model(self) -> bool: + """ + Tracer tool doesn't require model resolution at the MCP boundary. + + The tracer is a structured workflow tool that organizes tracing steps + and provides detailed output formatting guidance without calling external AI models. + + Returns: + bool: False - tracer doesn't need AI model access + """ + return False + + def get_workflow_request_model(self): + """Return the tracer-specific request model.""" return TracerRequest - def get_system_prompt(self) -> str: - """Not used in this simplified tool.""" - return "" - - async def prepare_prompt(self, request: TracerRequest) -> str: - """Not used in this simplified tool.""" - return "" - - async def execute(self, arguments: dict[str, Any]) -> list: - """Generate analysis prompt and instructions.""" - - request = TracerRequest(**arguments) - - # Create enhanced prompt with specific instructions - enhanced_prompt = self._create_enhanced_prompt(request.prompt, request.trace_mode) - - # Get rendering instructions - rendering_instructions = self._get_rendering_instructions(request.trace_mode) - - # Create response with both the enhanced prompt and instructions - response_content = f"""THIS IS A STATIC CODE ANALYSIS REQUEST: - -{enhanced_prompt} - -## Analysis Instructions - -{rendering_instructions} - -CRITICAL: Comprehensive Search and Call-Graph Generation: -First, think and identify and collect all relevant code, files, and declarations connected to the method, class, or module -in question: - -- If you are unable to find the code or mentioned files, look for the relevant code in subfolders. If unsure, ask the user -to confirm location of folder / filename -- You MUST carry this task using your own tools, do NOT delegate this to any other model -- DO NOT automatically use any zen tools (including zen:analyze, zen:debug, zen:chat, etc.) to perform this analysis. -- EXCEPTION: If files are very large or the codebase is too complex for direct analysis due to context limitations, -you may use zen tools with a larger context model to assist with analysis by passing only the relevant files -- Understand carefully and fully how this code is used, what it depends on, and what other parts of the system depend on it -- Think through what other components or services are affected by this code's execution — directly or indirectly. -- Consider what happens when the code succeeds or fails, and what ripple effects a change to it would cause. - - -Finally, present your output in a clearly structured format, following rendering guidelines exactly. - -IMPORTANT: If using this tool in conjunction with other work, another tool or another checklist item must be completed -immediately then do not stop after displaying your output, proceed directly to your next step. -""" - - from mcp.types import TextContent - - return [TextContent(type="text", text=response_content)] - - def _create_enhanced_prompt(self, original_prompt: str, trace_mode: str) -> str: - """Create an enhanced, specific prompt for analysis.""" - mode_guidance = { - "precision": "Follow the exact execution path from the specified method/function, including all method calls, branching logic, and side effects. Track the complete flow from entry point through all called functions. Show when and how this method/function is used throughout the codebase.", - "dependencies": "Map all bidirectional dependencies for the specified class/module/protocol: what calls this target (incoming) and what it calls (outgoing). Include imports, inheritance, state access, type relationships, and structural connections.", + def get_tool_fields(self) -> dict[str, dict[str, Any]]: + """Return tracing-specific field definitions beyond the standard workflow fields.""" + return { + # Tracer-specific fields + "trace_mode": { + "type": "string", + "enum": ["precision", "dependencies"], + "description": TRACER_WORKFLOW_FIELD_DESCRIPTIONS["trace_mode"], + }, + "target_description": { + "type": "string", + "description": TRACER_WORKFLOW_FIELD_DESCRIPTIONS["target_description"], + }, + "images": { + "type": "array", + "items": {"type": "string"}, + "description": TRACER_WORKFLOW_FIELD_DESCRIPTIONS["images"], + }, } - return f""" + def get_input_schema(self) -> dict[str, Any]: + """Generate input schema using WorkflowSchemaBuilder with field exclusion.""" + from .workflow.schema_builders import WorkflowSchemaBuilder -TARGET: {original_prompt} -MODE: {trace_mode} + # Exclude investigation-specific fields that tracing doesn't need + excluded_workflow_fields = [ + "issues_found", # Tracing doesn't track issues + "hypothesis", # Tracing doesn't use hypothesis + "backtrack_from_step", # Tracing doesn't use backtracking + ] -**Specific Instructions**: -{mode_guidance[trace_mode]} + # Exclude common fields that tracing doesn't need + excluded_common_fields = [ + "temperature", # Tracing doesn't need temperature control + "thinking_mode", # Tracing doesn't need thinking mode + "use_websearch", # Tracing doesn't need web search + "files", # Tracing uses relevant_files instead + ] -**CRITICAL: Comprehensive File Search Requirements**: -- If you are unable to find the code or mentioned files, look for the relevant code in subfolders. If unsure, ask the user -to confirm location of folder / filename -- DO NOT automatically use any zen tools (including zen:analyze, zen:debug, zen:chat, etc.) to perform this analysis -- EXCEPTION: If files are very large or the codebase is too complex for direct analysis due to context limitations, -you may use zen tools with a larger context model to assist with analysis by passing only the relevant files + return WorkflowSchemaBuilder.build_schema( + tool_specific_fields=self.get_tool_fields(), + required_fields=["target_description", "trace_mode"], # Step 1 requires these + model_field_schema=self.get_model_field_schema(), + auto_mode=self.is_effective_auto_mode(), + tool_name=self.get_name(), + excluded_workflow_fields=excluded_workflow_fields, + excluded_common_fields=excluded_common_fields, + ) -**What to identify** (works with any programming language/project): -- Exact method/function names with full signatures and parameter types -- Complete file paths and line numbers for all references -- Class/module context, namespace, and package relationships -- Conditional branches, their conditions, and execution paths -- Side effects (database, network, filesystem, state changes, logging) -- Type relationships, inheritance, polymorphic dispatch, and interfaces -- Cross-module/cross-service dependencies and API boundaries -- Configuration dependencies, environment variables, and external resources -- Error handling paths, exception propagation, and recovery mechanisms -- Async/concurrent execution patterns and synchronization points -- Memory allocation patterns and resource lifecycle management + # ================================================================================ + # Abstract Methods - Required Implementation from BaseWorkflowMixin + # ================================================================================ -**Analysis Focus**: -Provide concrete, code-based evidence for all findings. Reference specific line numbers and include exact method signatures. Identify uncertain paths where parameters or runtime context affects flow. Consider project scope and architectural patterns (monolith, microservices, layered, etc.). -""" + def get_required_actions(self, step_number: int, confidence: str, findings: str, total_steps: int) -> list[str]: + """Define required actions for each tracing phase.""" + if step_number == 1: + # Initial tracing investigation tasks + return [ + "Search for and locate the target method/function/class/module in the codebase", + "Read and understand the implementation of the target code", + "Identify the file location, complete signature, and basic structure", + "Begin mapping immediate relationships (what it calls, what calls it)", + "Understand the context and purpose of the target code", + ] + elif confidence in ["exploring", "low"]: + # Need deeper investigation + return [ + "Trace deeper into the execution flow or dependency relationships", + "Examine how the target code is used throughout the codebase", + "Map additional layers of dependencies or call chains", + "Look for conditional execution paths, error handling, and edge cases", + "Understand the broader architectural context and patterns", + ] + elif confidence in ["medium", "high"]: + # Close to completion - need final verification + return [ + "Verify completeness of the traced relationships and execution paths", + "Check for any missed dependencies, usage patterns, or execution branches", + "Confirm understanding of side effects, state changes, and external interactions", + "Validate that the tracing covers all significant code relationships", + "Prepare comprehensive findings for final output formatting", + ] + else: + # General investigation needed + return [ + "Continue systematic tracing of code relationships and execution paths", + "Gather more evidence using appropriate code analysis techniques", + "Test assumptions about code behavior and dependency relationships", + "Look for patterns that enhance understanding of the code structure", + "Focus on areas that haven't been thoroughly traced yet", + ] + + def should_call_expert_analysis(self, consolidated_findings, request=None) -> bool: + """Tracer is self-contained and doesn't need expert analysis.""" + return False + + def prepare_expert_analysis_context(self, consolidated_findings) -> str: + """Tracer doesn't use expert analysis.""" + return "" + + def requires_expert_analysis(self) -> bool: + """Tracer is self-contained like the planner tool.""" + return False + + # ================================================================================ + # Workflow Customization - Match Planner Behavior + # ================================================================================ + + def prepare_step_data(self, request) -> dict: + """ + Prepare step data from request with tracer-specific fields. + """ + step_data = { + "step": request.step, + "step_number": request.step_number, + "findings": request.findings, + "files_checked": request.files_checked, + "relevant_files": request.relevant_files, + "relevant_context": request.relevant_context, + "issues_found": [], # Tracer doesn't track issues + "confidence": request.confidence or "exploring", + "hypothesis": None, # Tracer doesn't use hypothesis + "images": request.images or [], + # Tracer-specific fields + "trace_mode": request.trace_mode, + "target_description": request.target_description, + } + return step_data + + def build_base_response(self, request, continuation_id: str = None) -> dict: + """ + Build the base response structure with tracer-specific fields. + """ + # Use work_history from workflow mixin for consistent step tracking + current_step_count = len(self.work_history) + 1 + + response_data = { + "status": f"{self.get_name()}_in_progress", + "step_number": request.step_number, + "total_steps": request.total_steps, + "next_step_required": request.next_step_required, + "step_content": request.step, + f"{self.get_name()}_status": { + "files_checked": len(self.consolidated_findings.files_checked), + "relevant_files": len(self.consolidated_findings.relevant_files), + "relevant_context": len(self.consolidated_findings.relevant_context), + "issues_found": len(self.consolidated_findings.issues_found), + "images_collected": len(self.consolidated_findings.images), + "current_confidence": self.get_request_confidence(request), + "step_history_length": current_step_count, + }, + "metadata": { + "trace_mode": self.trace_config.get("trace_mode", "unknown"), + "target_description": self.trace_config.get("target_description", ""), + "step_history_length": current_step_count, + }, + } + + if continuation_id: + response_data["continuation_id"] = continuation_id + + return response_data + + def handle_work_continuation(self, response_data: dict, request) -> dict: + """ + Handle work continuation with tracer-specific guidance. + """ + response_data["status"] = f"pause_for_{self.get_name()}" + response_data[f"{self.get_name()}_required"] = True + + # Get tracer-specific required actions + required_actions = self.get_required_actions( + request.step_number, request.confidence or "exploring", request.findings, request.total_steps + ) + response_data["required_actions"] = required_actions + + # Generate step-specific guidance + if request.step_number == 1: + response_data["next_steps"] = ( + f"MANDATORY: DO NOT call the {self.get_name()} tool again immediately. You MUST first investigate " + f"the codebase to understand the target code. CRITICAL AWARENESS: You need to find and understand " + f"the target method/function/class/module, examine its implementation, and begin mapping its " + f"relationships. Use file reading tools, code search, and systematic examination to gather " + f"comprehensive information about the target. Only call {self.get_name()} again AFTER completing " + f"your investigation. When you call {self.get_name()} next time, use step_number: {request.step_number + 1} " + f"and report specific files examined, code structure discovered, and initial relationship findings." + ) + elif request.confidence in ["exploring", "low"]: + next_step = request.step_number + 1 + response_data["next_steps"] = ( + f"STOP! Do NOT call {self.get_name()} again yet. Based on your findings, you've identified areas that need " + f"deeper tracing analysis. MANDATORY ACTIONS before calling {self.get_name()} step {next_step}:\\n" + + "\\n".join(f"{i+1}. {action}" for i, action in enumerate(required_actions)) + + f"\\n\\nOnly call {self.get_name()} again with step_number: {next_step} AFTER " + + "completing these tracing investigations." + ) + elif request.confidence in ["medium", "high"]: + next_step = request.step_number + 1 + response_data["next_steps"] = ( + f"WAIT! Your tracing analysis needs final verification. DO NOT call {self.get_name()} immediately. " + f"REQUIRED ACTIONS:\\n" + + "\\n".join(f"{i+1}. {action}" for i, action in enumerate(required_actions)) + + f"\\n\\nREMEMBER: Ensure you have traced all significant relationships and execution paths. " + f"Document findings with specific file references and method signatures, then call {self.get_name()} " + f"with step_number: {next_step}." + ) + else: + # General investigation needed + next_step = request.step_number + 1 + remaining_steps = request.total_steps - request.step_number + response_data["next_steps"] = ( + f"Continue systematic tracing with step {next_step}. Approximately {remaining_steps} steps remaining. " + f"Focus on deepening your understanding of the code relationships and execution patterns." + ) + + return response_data + + def customize_workflow_response(self, response_data: dict, request) -> dict: + """ + Customize response to match tracer tool format with output instructions. + """ + # Store trace configuration on first step + if request.step_number == 1: + self.initial_request = request.step + self.trace_config = { + "trace_mode": request.trace_mode, + "target_description": request.target_description, + } + + # Update metadata with trace configuration + if "metadata" in response_data: + response_data["metadata"]["trace_mode"] = request.trace_mode or "unknown" + response_data["metadata"]["target_description"] = request.target_description or "" + + # Add tracer-specific output instructions for final steps + if not request.next_step_required: + response_data["tracing_complete"] = True + response_data["trace_summary"] = f"TRACING COMPLETE: {request.step}" + + # Get mode-specific output instructions + trace_mode = self.trace_config.get("trace_mode", "precision") + rendering_instructions = self._get_rendering_instructions(trace_mode) + + response_data["output"] = { + "instructions": ( + "This is a structured tracing analysis response. Present the comprehensive tracing findings " + "using the specific rendering format for the trace mode. Follow the exact formatting guidelines " + "provided in rendering_instructions. Include all discovered relationships, execution paths, " + "and dependencies with precise file references and line numbers." + ), + "format": f"{trace_mode}_trace_analysis", + "rendering_instructions": rendering_instructions, + "presentation_guidelines": { + "completed_trace": ( + "Use the exact rendering format specified for the trace mode. Include comprehensive " + "diagrams, tables, and structured analysis. Reference specific file paths and line numbers. " + "Follow formatting rules precisely." + ), + "step_content": "Present as main analysis with clear structure and actionable insights.", + "continuation": "Use continuation_id for related tracing sessions or follow-up analysis", + }, + } + response_data["next_steps"] = ( + f"Tracing analysis complete. Present the comprehensive {trace_mode} trace analysis to the user " + f"using the exact rendering format specified in the output instructions. Follow the formatting " + f"guidelines precisely, including diagrams, tables, and file references. After presenting the " + f"analysis, offer to help with related tracing tasks or use the continuation_id for follow-up analysis." + ) + + # Convert generic status names to tracer-specific ones + tool_name = self.get_name() + status_mapping = { + f"{tool_name}_in_progress": "tracing_in_progress", + f"pause_for_{tool_name}": f"pause_for_{tool_name}", + f"{tool_name}_required": f"{tool_name}_required", + f"{tool_name}_complete": f"{tool_name}_complete", + } + + if response_data["status"] in status_mapping: + response_data["status"] = status_mapping[response_data["status"]] + + return response_data def _get_rendering_instructions(self, trace_mode: str) -> str: """ @@ -392,3 +710,57 @@ DTOClass ──uses──→ [TARGET_CLASS] ──uses──→ EntityClass - Maintain visual alignment and consistent spacing - Include type relationships section when applicable - Show clear directional flow with proper arrows""" + + # ================================================================================ + # Hook Method Overrides for Tracer-Specific Behavior + # ================================================================================ + + def get_completion_status(self) -> str: + """Tracer uses tracing-specific status.""" + return "tracing_complete" + + def get_completion_data_key(self) -> str: + """Tracer uses 'complete_tracing' key.""" + return "complete_tracing" + + def get_completion_message(self) -> str: + """Tracer-specific completion message.""" + return ( + "Tracing analysis complete. Present the comprehensive trace analysis to the user " + "using the specified rendering format and offer to help with related tracing tasks." + ) + + def get_skip_reason(self) -> str: + """Tracer-specific skip reason.""" + return "Tracer is self-contained and completes analysis without external assistance" + + def get_skip_expert_analysis_status(self) -> str: + """Tracer-specific expert analysis skip status.""" + return "skipped_by_tool_design" + + def store_initial_issue(self, step_description: str): + """Store initial tracing description.""" + self.initial_tracing_description = step_description + + def get_initial_request(self, fallback_step: str) -> str: + """Get initial tracing description.""" + try: + return self.initial_tracing_description + except AttributeError: + return fallback_step + + def get_request_confidence(self, request) -> str: + """Get confidence from request for tracer workflow.""" + try: + return request.confidence or "exploring" + except AttributeError: + return "exploring" + + # Required abstract methods from BaseTool + def get_request_model(self): + """Return the tracer-specific request model.""" + return TracerRequest + + async def prepare_prompt(self, request) -> str: + """Not used - workflow tools use execute_workflow().""" + return "" # Workflow tools use execute_workflow() directly