Spaces:
Running
Running
| from typing import Any, Dict, List | |
| from agent.core.session import Event | |
| from agent.utils.terminal_display import format_plan_tool_output | |
| from .types import ToolResult | |
| # In-memory storage for the current plan (raw structure from agent) | |
| _current_plan: List[Dict[str, str]] = [] | |
| class PlanTool: | |
| """Tool for managing a list of todos with status tracking.""" | |
| def __init__(self, session: Any = None): | |
| self.session = session | |
| async def execute(self, params: Dict[str, Any]) -> ToolResult: | |
| """ | |
| Execute the WritePlan operation. | |
| Args: | |
| params: Dictionary containing: | |
| - todos: List of todo items, each with id, content, and status | |
| Returns: | |
| ToolResult with formatted output | |
| """ | |
| global _current_plan | |
| todos = params.get("todos", []) | |
| # Validate todos structure | |
| for todo in todos: | |
| if not isinstance(todo, dict): | |
| return { | |
| "formatted": "Error: Each todo must be an object. Re call the tool with correct format (mandatory).", | |
| "isError": True, | |
| } | |
| required_fields = ["id", "content", "status"] | |
| for field in required_fields: | |
| if field not in todo: | |
| return { | |
| "formatted": f"Error: Todo missing required field '{field}'. Re call the tool with correct format (mandatory).", | |
| "isError": True, | |
| } | |
| # Validate status | |
| valid_statuses = ["pending", "in_progress", "completed"] | |
| if todo["status"] not in valid_statuses: | |
| return { | |
| "formatted": f"Error: Invalid status '{todo['status']}'. Must be one of: {', '.join(valid_statuses)}. Re call the tool with correct format (mandatory).", | |
| "isError": True, | |
| } | |
| # Store the raw todos structure in memory | |
| _current_plan = todos | |
| # Emit plan update event if session is available | |
| if self.session: | |
| await self.session.send_event( | |
| Event( | |
| event_type="plan_update", | |
| data={"plan": todos}, | |
| ) | |
| ) | |
| # Format only for display using terminal_display utility | |
| formatted_output = format_plan_tool_output(todos) | |
| return { | |
| "formatted": formatted_output, | |
| "totalResults": len(todos), | |
| "isError": False, | |
| } | |
| def get_current_plan() -> List[Dict[str, str]]: | |
| """Get the current plan (raw structure).""" | |
| return _current_plan | |
| # Tool specification | |
| PLAN_TOOL_SPEC = { | |
| "name": "plan_tool", | |
| "description": ( | |
| "Manage task planning and progress tracking with todo list (pending/in_progress/completed statuses). " | |
| "⚠️ CRITICAL: ALWAYS use for multi-step tasks (3+ steps) and MUST update frequently to show progress. " | |
| "**Use when:** (1) User provides multiple tasks, (2) Complex workflows (training, evaluation, data processing), " | |
| "(3) Tasks requiring multiple tool calls, (4) Need to communicate progress clearly to user, " | |
| "(5) Breaking down ambiguous requests into concrete steps. " | |
| "**Pattern:** Create plan at start → Mark in_progress when starting task → Mark completed immediately after finishing → User sees clear progress. " | |
| "Each call replaces entire plan (full list required). " | |
| "**Critical for reliability:** Exactly ONE task in_progress at a time (not zero, not multiple). " | |
| "Mark tasks completed IMMEDIATELY after finishing - don't batch completions. " | |
| "**For long-running tasks:** Update plan after each major step to keep user informed. " | |
| "**Only mark completed when:** Task fully accomplished, no errors, all requirements met. " | |
| "Keep tasks pending if blocked/errors occur - create new task to resolve blockers." | |
| ), | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "todos": { | |
| "type": "array", | |
| "description": "List of todo items", | |
| "items": { | |
| "type": "object", | |
| "properties": { | |
| "id": { | |
| "type": "string", | |
| "description": "Unique identifier for the todo", | |
| }, | |
| "content": { | |
| "type": "string", | |
| "description": "Description of the todo task", | |
| }, | |
| "status": { | |
| "type": "string", | |
| "enum": ["pending", "in_progress", "completed"], | |
| "description": "Current status of the todo", | |
| }, | |
| }, | |
| "required": ["id", "content", "status"], | |
| }, | |
| } | |
| }, | |
| "required": ["todos"], | |
| }, | |
| } | |
| async def plan_tool_handler( | |
| arguments: Dict[str, Any], session: Any = None | |
| ) -> tuple[str, bool]: | |
| tool = PlanTool(session=session) | |
| result = await tool.execute(arguments) | |
| return result["formatted"], not result.get("isError", False) | |