from __future__ import annotations from typing import ClassVar from .base import BaseAgent, AgentInput, AgentOutput from .manifest import AgentManifest MANIFEST = AgentManifest( id="overdue-task", version="1.0.0", description="Reports the user's overdue tasks by count and age.", pref_schema={ "type": "object", "additionalProperties": False, "properties": { "lateness_tolerance_days": { "type": "integer", "minimum": 0, "default": 0, "description": "Days past due before a task is considered overdue. 0 = the moment it's late.", }, }, }, context_schema=["todoist.tasks"], required_consents=["data:core", "data:todoist", "agent:overdue-task"], output_contract={"type": "snippet", "format": "free_text"}, ttl_sec=3600, silenced_in_contexts=["vacation"], ) class OverdueTaskAgent(BaseAgent): """Reports the user's overdue tasks by count and age.""" agent_id: ClassVar[str] = MANIFEST.id ttl_seconds: ClassVar[int] = MANIFEST.ttl_sec version: ClassVar[str] = MANIFEST.version def compute(self, inp: AgentInput) -> AgentOutput: overdue = [t for t in inp.tasks if t.get("is_overdue")] top = sorted(overdue, key=lambda t: -t.get("task_age_days", 0))[:3] if not overdue: prompt = "The user has no overdue tasks at this time." elif len(overdue) == 1: t = top[0] age = round(t.get("task_age_days", 0)) prompt = ( f'The user has 1 overdue task: "{t["content"]}" ' f"({age} day{'s' if age != 1 else ''} overdue)." ) else: items = ", ".join( f'"{t["content"]}" ({round(t.get("task_age_days", 0))}d)' for t in top ) prompt = ( f"The user has {len(overdue)} overdue tasks. " f"Top {len(top)}: {items}." ) snapshot = { "overdue_count": len(overdue), "top_overdue": [ {"content": t["content"], "task_age_days": t.get("task_age_days", 0)} for t in top ], } return self._make_output(inp, prompt, snapshot)