feat(tools): add bulk operations support to todo tools

- update_todo: add `updates` param for bulk updates in one call
- mark_todo_done: add `todo_ids` param to mark multiple todos done
- mark_todo_pending: add `todo_ids` param to mark multiple pending
- delete_todo: add `todo_ids` param to delete multiple todos
- Increase todo renderer display limit from 10 to 25
- Maintains backward compatibility with single-ID usage
- Update prompts to keep todos short-horizon and dynamic
This commit is contained in:
0xallam
2025-12-14 20:31:33 -08:00
committed by Ahmed Allam
parent c29f13fd69
commit 37c8cffbe3
4 changed files with 327 additions and 106 deletions
@@ -20,7 +20,7 @@ def _truncate(text: str, length: int = 80) -> str:
def _format_todo_lines(
cls: type[BaseToolRenderer], result: dict[str, Any], limit: int = 10
cls: type[BaseToolRenderer], result: dict[str, Any], limit: int = 25
) -> list[str]:
todos = result.get("todos")
if not isinstance(todos, list) or not todos:
@@ -67,7 +67,7 @@ class CreateTodoRenderer(BaseToolRenderer):
if result and isinstance(result, dict):
if result.get("success"):
lines = [header]
lines.extend(_format_todo_lines(cls, result, limit=10))
lines.extend(_format_todo_lines(cls, result))
content_text = "\n".join(lines)
else:
error = result.get("error", "Failed to create todo")
@@ -92,7 +92,7 @@ class ListTodosRenderer(BaseToolRenderer):
if result and isinstance(result, dict):
if result.get("success"):
lines = [header]
lines.extend(_format_todo_lines(cls, result, limit=10))
lines.extend(_format_todo_lines(cls, result))
content_text = "\n".join(lines)
else:
error = result.get("error", "Unable to list todos")
@@ -117,7 +117,7 @@ class UpdateTodoRenderer(BaseToolRenderer):
if result and isinstance(result, dict):
if result.get("success"):
lines = [header]
lines.extend(_format_todo_lines(cls, result, limit=10))
lines.extend(_format_todo_lines(cls, result))
content_text = "\n".join(lines)
else:
error = result.get("error", "Failed to update todo")
@@ -142,7 +142,7 @@ class MarkTodoDoneRenderer(BaseToolRenderer):
if result and isinstance(result, dict):
if result.get("success"):
lines = [header]
lines.extend(_format_todo_lines(cls, result, limit=10))
lines.extend(_format_todo_lines(cls, result))
content_text = "\n".join(lines)
else:
error = result.get("error", "Failed to mark todo done")
@@ -167,7 +167,7 @@ class MarkTodoPendingRenderer(BaseToolRenderer):
if result and isinstance(result, dict):
if result.get("success"):
lines = [header]
lines.extend(_format_todo_lines(cls, result, limit=10))
lines.extend(_format_todo_lines(cls, result))
content_text = "\n".join(lines)
else:
error = result.get("error", "Failed to reopen todo")
@@ -192,7 +192,7 @@ class DeleteTodoRenderer(BaseToolRenderer):
if result and isinstance(result, dict):
if result.get("success"):
lines = [header]
lines.extend(_format_todo_lines(cls, result, limit=10))
lines.extend(_format_todo_lines(cls, result))
content_text = "\n".join(lines)
else:
error = result.get("error", "Failed to remove todo")