"""UI-only task progress tool. The tool gives the model a structured way to publish a short user-visible plan. Its result is intentionally tiny; the full plan stays in the assistant tool_call arguments for Web rendering and is compacted out of older LLM context. """ from __future__ import annotations import json from typing import Any, ClassVar from .base import Tool class TaskProgressTool(Tool): name = "task_progress" description = ( "Publish the complete current user-visible progress checklist for this run. " "Use only for meaningful multi-step work. Every call must include the full checklist, " "including unchanged steps; never send a partial step patch. Keep stable step ids while " "revising the plan, allow at most one in_progress step, and mark every step completed " "before a successful final answer. This is a UI progress signal, not a work product." ) parameters: ClassVar[dict[str, Any]] = { "type": "object", "additionalProperties": False, "properties": { "explanation": { "type": "string", "description": "Optional short reason when the plan materially changes.", }, "steps": { "type": "array", "description": "The complete current checklist. Keep to 3-7 user-meaningful steps.", "items": { "type": "object", "additionalProperties": False, "properties": { "id": {"type": "string", "description": "Stable short id, e.g. s1."}, "title": {"type": "string", "description": "Short user-visible step title."}, "status": { "type": "string", "enum": ["pending", "in_progress", "completed"], }, }, "required": ["id", "title", "status"], }, }, }, "required": ["steps"], } def execute(self, **kwargs: Any) -> str: steps = kwargs.get("steps") out: dict[str, Any] = { "ok": True, "step_count": len(steps) if isinstance(steps, list) else 0, } return json.dumps(out, ensure_ascii=False, separators=(",", ":"))