Skip to content

Commit 8916dfe

Browse files
committed
add ChecklistTool; implement stateful checklist for task management and progress tracking
1 parent 8bf8b2e commit 8916dfe

1 file changed

Lines changed: 102 additions & 0 deletions

File tree

argus/tools/checklist.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
from __future__ import annotations
2+
3+
from typing import Any
4+
5+
from argus.data.content import Content
6+
from argus.tools.base import Tool
7+
8+
9+
class ChecklistTool(Tool):
10+
"""Stateful checklist tool for tracking task progress across a run."""
11+
12+
name = "checklist"
13+
description = (
14+
"Manage a task checklist to plan and track your progress. "
15+
"Use action='init' at the start to list all planned steps, "
16+
"'complete' to mark a step done by its index, "
17+
"'add' to append a new step discovered mid-task, "
18+
"and 'view' to see current state."
19+
)
20+
parameters: dict[str, Any] = {
21+
"type": "object",
22+
"properties": {
23+
"action": {
24+
"type": "string",
25+
"enum": ["init", "complete", "add", "view"],
26+
"description": (
27+
"'init': create a new checklist (replaces any existing one); "
28+
"'complete': mark the item at the given index as done; "
29+
"'add': append a new item; "
30+
"'view': display current checklist state."
31+
),
32+
},
33+
"items": {
34+
"type": "array",
35+
"items": {"type": "string"},
36+
"description": "Ordered list of step descriptions. Required for action='init'.",
37+
},
38+
"index": {
39+
"type": "integer",
40+
"description": "0-based index of the item to complete. Required for action='complete'.",
41+
},
42+
"item": {
43+
"type": "string",
44+
"description": "Description of the new step to append. Required for action='add'.",
45+
},
46+
},
47+
"required": ["action"],
48+
}
49+
50+
def __init__(self) -> None:
51+
self._items: list[dict[str, Any]] = [] # {"text": str, "done": bool}
52+
53+
def reset(self) -> None:
54+
"""Clear checklist state at the start of a new run."""
55+
self._items = []
56+
57+
def render(self) -> str:
58+
if not self._items:
59+
return "Checklist is empty."
60+
lines = ["=== Task Checklist ==="]
61+
for i, it in enumerate(self._items):
62+
mark = "x" if it["done"] else " "
63+
lines.append(f" [{mark}] {i}. {it['text']}")
64+
done = sum(1 for it in self._items if it["done"])
65+
lines.append(f"\nProgress: {done}/{len(self._items)} completed")
66+
return "\n".join(lines)
67+
68+
def execute(
69+
self,
70+
action: str,
71+
items: list[str] | None = None,
72+
index: int | None = None,
73+
item: str | None = None,
74+
) -> Content:
75+
if action == "init":
76+
if not items:
77+
return Content(text="[error: 'items' is required for action='init']")
78+
self._items = [{"text": t, "done": False} for t in items]
79+
return Content(
80+
text=f"Checklist initialized with {len(self._items)} items.\n\n{self.render()}"
81+
)
82+
83+
if action == "complete":
84+
if index is None:
85+
return Content(text="[error: 'index' is required for action='complete']")
86+
if index < 0 or index >= len(self._items):
87+
return Content(
88+
text=f"[error: index {index} out of range (valid: 0–{len(self._items) - 1})]"
89+
)
90+
self._items[index]["done"] = True
91+
return Content(text=f"Item {index} marked as done.\n\n{self.render()}")
92+
93+
if action == "add":
94+
if not item:
95+
return Content(text="[error: 'item' is required for action='add']")
96+
self._items.append({"text": item, "done": False})
97+
return Content(text=f"Item added at index {len(self._items) - 1}.\n\n{self.render()}")
98+
99+
if action == "view":
100+
return Content(text=self.render())
101+
102+
return Content(text=f"[error: unknown action '{action}']")

0 commit comments

Comments
 (0)