""" Challenge tool - Encourages critical thinking and thoughtful disagreement This tool takes a user's statement and returns it wrapped in instructions that encourage the CLI agent to challenge ideas and think critically before agreeing. It helps avoid reflexive agreement by prompting deeper analysis and genuine evaluation. This is a simple, self-contained tool that doesn't require AI model access. """ from typing import TYPE_CHECKING, Any, Optional from pydantic import Field if TYPE_CHECKING: from tools.models import ToolModelCategory from config import TEMPERATURE_ANALYTICAL from tools.shared.base_models import ToolRequest from .simple.base import SimpleTool # Field descriptions for the Challenge tool CHALLENGE_FIELD_DESCRIPTIONS = { "prompt": ( "The statement, question, or assertion the user wants to challenge critically. " "This may be a claim, suggestion, or idea that requires thoughtful reconsideration, not automatic agreement." ), } class ChallengeRequest(ToolRequest): """Request model for Challenge tool""" prompt: str = Field(..., description=CHALLENGE_FIELD_DESCRIPTIONS["prompt"]) class ChallengeTool(SimpleTool): """ Challenge tool for encouraging critical thinking and avoiding automatic agreement. This tool wraps user statements in instructions that encourage the CLI agent to: - Challenge ideas and think critically before responding - Evaluate whether they actually agree or disagree - Provide thoughtful analysis rather than reflexive agreement The tool is self-contained and doesn't require AI model access - it simply transforms the input prompt into a structured critical thinking challenge. """ def get_name(self) -> str: return "challenge" def get_description(self) -> str: return ( "CRITICAL CHALLENGE PROMPT – Use this to frame your statement in a way that prompts " "the CLI agent to challenge it thoughtfully instead of agreeing by default. Ideal for " "challenging assumptions, validating ideas, and seeking honest, analytical feedback as part of an ongoing " "task. The tool wraps your input with instructions explicitly telling the agent to think critically " "and disagree if warranted." ) def get_system_prompt(self) -> str: # Challenge tool doesn't need a system prompt since it doesn't call AI return "" def get_default_temperature(self) -> float: return TEMPERATURE_ANALYTICAL def get_model_category(self) -> "ToolModelCategory": """Challenge doesn't need a model category since it doesn't use AI""" from tools.models import ToolModelCategory return ToolModelCategory.FAST_RESPONSE # Default, but not used def requires_model(self) -> bool: """ Challenge tool doesn't require model resolution at the MCP boundary. Like the planner tool, this is a pure data processing tool that transforms the input without calling external AI models. Returns: bool: False - challenge doesn't need AI model access """ return False def get_request_model(self): """Return the Challenge-specific request model""" return ChallengeRequest def get_input_schema(self) -> dict[str, Any]: """ Generate input schema for the challenge tool. Since this tool doesn't require a model, we exclude model-related fields. """ schema = { "type": "object", "properties": { "prompt": { "type": "string", "description": CHALLENGE_FIELD_DESCRIPTIONS["prompt"], }, }, "required": ["prompt"], } return schema async def execute(self, arguments: dict[str, Any]) -> list: """ Execute the challenge tool by wrapping the prompt in critical thinking instructions. This is the main execution method that transforms the user's statement into a structured challenge that encourages thoughtful re-evaluation. """ import json from mcp.types import TextContent try: # Validate request request = self.get_request_model()(**arguments) # Wrap the prompt in challenge instructions wrapped_prompt = self._wrap_prompt_for_challenge(request.prompt) # Return the wrapped prompt as the response response_data = { "status": "challenge_created", "original_statement": request.prompt, "challenge_prompt": wrapped_prompt, "instructions": ( "Present the challenge_prompt to yourself and follow its instructions. " "Challenge the statement critically before forming your response. " "If you disagree after careful reconsideration, explain why." ), } return [TextContent(type="text", text=json.dumps(response_data, indent=2, ensure_ascii=False))] except Exception as e: import logging logger = logging.getLogger(__name__) logger.error(f"Error in challenge tool execution: {e}", exc_info=True) error_data = { "status": "error", "error": str(e), "content": f"Failed to create challenge prompt: {str(e)}", } return [TextContent(type="text", text=json.dumps(error_data, ensure_ascii=False))] def _wrap_prompt_for_challenge(self, prompt: str) -> str: """ Wrap the user's statement in instructions that encourage critical challenge. Args: prompt: The original user statement to wrap Returns: The statement wrapped in challenge instructions """ return ( f"CHALLENGE THIS STATEMENT - Do not automatically agree:\n\n" f'"{prompt}"\n\n' f"Is this actually correct? Check carefully. If it's wrong, incomplete, misleading or incorrect, " f"you must say so. Provide your honest assessment, not automatic agreement. If you " f"feel there is merit in what the user is saying, explain WHY you agree." ) # Required method implementations from SimpleTool async def prepare_prompt(self, request: ChallengeRequest) -> str: """Not used since challenge doesn't call AI models""" return "" def format_response(self, response: str, request: ChallengeRequest, model_info: Optional[dict] = None) -> str: """Not used since challenge doesn't call AI models""" return response def get_tool_fields(self) -> dict[str, dict[str, Any]]: """Tool-specific field definitions for Challenge""" return { "prompt": { "type": "string", "description": CHALLENGE_FIELD_DESCRIPTIONS["prompt"], }, } def get_required_fields(self) -> list[str]: """Required fields for Challenge tool""" return ["prompt"]