| | 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
|
| |
|
| |
|
| | _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", [])
|
| |
|
| |
|
| | 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,
|
| | }
|
| |
|
| |
|
| | 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,
|
| | }
|
| |
|
| |
|
| | _current_plan = todos
|
| |
|
| |
|
| | if self.session:
|
| | await self.session.send_event(
|
| | Event(
|
| | event_type="plan_update",
|
| | data={"plan": todos},
|
| | )
|
| | )
|
| |
|
| |
|
| | 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
|
| |
|
| |
|
| |
|
| | 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)
|
| |
|