diff --git a/tools/analyze.py b/tools/analyze.py index 401ca5929..6e2629dd8 100644 --- a/tools/analyze.py +++ b/tools/analyze.py @@ -140,6 +140,8 @@ class AnalyzeTool(WorkflowTool): including architectural review, performance analysis, security assessment, and maintainability evaluation. """ + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} + def __init__(self): super().__init__() self.initial_request = None @@ -155,6 +157,10 @@ def get_description(self) -> str: "Guides through structured code review and strategic planning." ) + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only analysis tool.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: return ANALYZE_PROMPT diff --git a/tools/apilookup.py b/tools/apilookup.py index f097fe759..69b436338 100644 --- a/tools/apilookup.py +++ b/tools/apilookup.py @@ -70,6 +70,8 @@ class LookupRequest(ToolRequest): class LookupTool(SimpleTool): """Simple tool that wraps user queries with API lookup instructions.""" + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True, "openWorldHint": True} + def get_name(self) -> str: return "apilookup" @@ -79,6 +81,10 @@ def get_description(self) -> str: "This tool searches authoritative sources (official docs, GitHub, package registries) to ensure up-to-date accuracy." ) + def get_annotations(self) -> dict[str, Any] | None: + """Return tool annotations indicating this searches external sources.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: return "" diff --git a/tools/challenge.py b/tools/challenge.py index a63463d57..f8c88f5b3 100644 --- a/tools/challenge.py +++ b/tools/challenge.py @@ -49,6 +49,8 @@ class ChallengeTool(SimpleTool): transforms the input prompt into a structured critical thinking challenge. """ + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} + def get_name(self) -> str: return "challenge" @@ -58,6 +60,10 @@ def get_description(self) -> str: "Trigger automatically when a user critically questions, disagrees or appears to push back on earlier answers, and use it manually to sanity-check contentious claims." ) + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only analysis tool.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: # Challenge tool doesn't need a system prompt since it doesn't call AI return "" diff --git a/tools/codereview.py b/tools/codereview.py index 921765ec0..22045bcbb 100644 --- a/tools/codereview.py +++ b/tools/codereview.py @@ -125,6 +125,8 @@ class CodeReviewTool(WorkflowTool): including security audits, performance analysis, architectural review, and maintainability assessment. """ + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} + def __init__(self): super().__init__() self.initial_request = None @@ -140,6 +142,10 @@ def get_description(self) -> str: "Guides through structured investigation to ensure thoroughness." ) + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only code review tool.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: return CODEREVIEW_PROMPT diff --git a/tools/consensus.py b/tools/consensus.py index 1bd324987..fc7e0aff8 100644 --- a/tools/consensus.py +++ b/tools/consensus.py @@ -135,6 +135,8 @@ class ConsensusTool(WorkflowTool): and finally synthesizes all perspectives into a unified recommendation. """ + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} + def __init__(self): super().__init__() self.initial_prompt: str | None = None @@ -153,6 +155,10 @@ def get_description(self) -> str: "Consults multiple models with different stances to synthesize comprehensive recommendations." ) + def get_annotations(self) -> dict[str, Any] | None: + """Return tool annotations indicating this is a read-only consensus analysis tool.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: # For the CLI agent's initial analysis, use a neutral version of the consensus prompt return CONSENSUS_PROMPT.replace( diff --git a/tools/debug.py b/tools/debug.py index e8a64290c..30fc8eb7f 100644 --- a/tools/debug.py +++ b/tools/debug.py @@ -110,6 +110,8 @@ class DebugIssueTool(WorkflowTool): including race conditions, memory leaks, performance issues, and integration problems. """ + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} + def __init__(self): super().__init__() self.initial_issue = None @@ -124,6 +126,10 @@ def get_description(self) -> str: "Guides through structured investigation with hypothesis testing and expert analysis." ) + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only debugging tool.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: return DEBUG_ISSUE_PROMPT diff --git a/tools/docgen.py b/tools/docgen.py index db238e654..365105534 100644 --- a/tools/docgen.py +++ b/tools/docgen.py @@ -95,6 +95,8 @@ class DocgenTool(WorkflowTool): - Modern documentation style appropriate for the language/platform """ + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} + def __init__(self): super().__init__() self.initial_request = None @@ -109,6 +111,10 @@ def get_description(self) -> str: "Analyzes code structure and patterns to create thorough documentation." ) + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only documentation tool.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: return DOCGEN_PROMPT diff --git a/tools/planner.py b/tools/planner.py index c5440918e..feeec4ad0 100644 --- a/tools/planner.py +++ b/tools/planner.py @@ -21,7 +21,7 @@ """ import logging -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Optional from pydantic import Field, field_validator @@ -119,6 +119,8 @@ class PlannerTool(WorkflowTool): - Self-contained operation (no expert analysis) """ + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} + def __init__(self): super().__init__() self.branches = {} @@ -133,6 +135,10 @@ def get_description(self) -> str: "Builds plans incrementally with deep reflection for complex scenarios." ) + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only planning tool.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: return PLANNER_PROMPT diff --git a/tools/precommit.py b/tools/precommit.py index 29a2bd235..e0dac262e 100644 --- a/tools/precommit.py +++ b/tools/precommit.py @@ -126,6 +126,8 @@ class PrecommitTool(WorkflowTool): multi-repository analysis, security review, performance validation, and integration testing. """ + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} + def __init__(self): super().__init__() self.initial_request = None @@ -141,6 +143,10 @@ def get_description(self) -> str: "Guides through structured investigation with expert analysis." ) + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only validation tool.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: return PRECOMMIT_PROMPT diff --git a/tools/refactor.py b/tools/refactor.py index 715914328..649cbde3d 100644 --- a/tools/refactor.py +++ b/tools/refactor.py @@ -149,6 +149,8 @@ class RefactorTool(WorkflowTool): opportunities, and organization improvements. """ + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} + def __init__(self): super().__init__() self.initial_request = None @@ -164,6 +166,10 @@ def get_description(self) -> str: "Guides through structured analysis with expert validation." ) + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only refactoring analysis tool.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: return REFACTOR_PROMPT diff --git a/tools/secaudit.py b/tools/secaudit.py index 56415c804..f0e7072e4 100644 --- a/tools/secaudit.py +++ b/tools/secaudit.py @@ -126,6 +126,8 @@ class SecauditTool(WorkflowTool): security-specific capabilities. """ + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} + def __init__(self): super().__init__() self.initial_request = None @@ -143,6 +145,10 @@ def get_description(self) -> str: "Guides through structured security investigation with expert validation." ) + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only security audit tool.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: """Return the system prompt for expert security analysis.""" return SECAUDIT_PROMPT diff --git a/tools/testgen.py b/tools/testgen.py index 705168382..557127e59 100644 --- a/tools/testgen.py +++ b/tools/testgen.py @@ -103,6 +103,7 @@ class TestGenTool(WorkflowTool): """ __test__ = False # Prevent pytest from collecting this class as a test + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} def __init__(self): super().__init__() @@ -118,6 +119,10 @@ def get_description(self) -> str: "Be specific about scope - target particular components rather than testing everything." ) + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only test generation tool.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: return TESTGEN_PROMPT diff --git a/tools/thinkdeep.py b/tools/thinkdeep.py index 948375170..fc791230c 100644 --- a/tools/thinkdeep.py +++ b/tools/thinkdeep.py @@ -108,6 +108,7 @@ class ThinkDeepTool(WorkflowTool): "Use for architecture decisions, complex bugs, performance challenges, and security analysis. " "Provides systematic hypothesis testing, evidence-based investigation, and expert validation." ) + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} def __init__(self): """Initialize the ThinkDeep workflow tool""" @@ -123,6 +124,10 @@ def get_description(self) -> str: """Return the tool description""" return self.description + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only deep thinking tool.""" + return self._ANNOTATIONS + def get_model_category(self) -> "ToolModelCategory": """Return the model category for this tool""" from tools.models import ToolModelCategory diff --git a/tools/tracer.py b/tools/tracer.py index c81cf3942..ade1bfab5 100644 --- a/tools/tracer.py +++ b/tools/tracer.py @@ -145,6 +145,8 @@ class TracerTool(WorkflowTool): both precision tracing (execution flow) and dependencies tracing (structural relationships). """ + _ANNOTATIONS: dict[str, Any] = {"readOnlyHint": True} + def __init__(self): super().__init__() self.initial_request = None @@ -160,6 +162,10 @@ def get_description(self) -> str: "Supports precision mode (execution flow) and dependencies mode (structural relationships)." ) + def get_annotations(self) -> Optional[dict[str, Any]]: + """Return tool annotations indicating this is a read-only code tracing tool.""" + return self._ANNOTATIONS + def get_system_prompt(self) -> str: return TRACER_PROMPT