Compact TodoWrite observations
- SHA
746eb3219e90c66e28b67e1e972098fc86e747fc- Parents
-
a608f28 - Tree
0d12fdb
746eb32
746eb3219e90c66e28b67e1e972098fc86e747fca608f28
0d12fdb| Status | File | + | - |
|---|---|---|---|
| M |
src/loader/runtime/parsing.py
|
39 | 0 |
| M |
tests/test_parsing.py
|
36 | 0 |
src/loader/runtime/parsing.pymodified@@ -407,5 +407,44 @@ def parse_tool_calls( | |||
| 407 | def format_tool_result(tool_name: str, result: str, is_error: bool = False) -> str: | 407 | def format_tool_result(tool_name: str, result: str, is_error: bool = False) -> str: |
| 408 | """Format a tool result for inclusion in conversation.""" | 408 | """Format a tool result for inclusion in conversation.""" |
| 409 | 409 | ||
| 410 | + if tool_name == "TodoWrite" and not is_error: | ||
| 411 | + try: | ||
| 412 | + payload = json.loads(result) | ||
| 413 | + except json.JSONDecodeError: | ||
| 414 | + payload = None | ||
| 415 | + if isinstance(payload, dict): | ||
| 416 | + todos = payload.get("new_todos", []) | ||
| 417 | + if isinstance(todos, list): | ||
| 418 | + completed = 0 | ||
| 419 | + in_progress = 0 | ||
| 420 | + pending = 0 | ||
| 421 | + next_pending: str | None = None | ||
| 422 | + for item in todos: | ||
| 423 | + if not isinstance(item, dict): | ||
| 424 | + continue | ||
| 425 | + status = str(item.get("status", "")).strip().lower() | ||
| 426 | + content = str(item.get("content", "")).strip() | ||
| 427 | + if status == "completed": | ||
| 428 | + completed += 1 | ||
| 429 | + elif status == "in_progress": | ||
| 430 | + in_progress += 1 | ||
| 431 | + if next_pending is None and content: | ||
| 432 | + next_pending = content | ||
| 433 | + else: | ||
| 434 | + pending += 1 | ||
| 435 | + if next_pending is None and content: | ||
| 436 | + next_pending = content | ||
| 437 | + summary_parts = [ | ||
| 438 | + "updated todo list", | ||
| 439 | + f"{completed} completed", | ||
| 440 | + f"{in_progress} in progress", | ||
| 441 | + f"{pending} pending", | ||
| 442 | + ] | ||
| 443 | + if next_pending: | ||
| 444 | + summary_parts.append(f"next pending: {next_pending}") | ||
| 445 | + if payload.get("verification_nudge_needed") is True: | ||
| 446 | + summary_parts.append("verification should be reviewed next") | ||
| 447 | + result = "; ".join(summary_parts) | ||
| 448 | + | ||
| 410 | prefix = "Error" if is_error else "Result" | 449 | prefix = "Error" if is_error else "Result" |
| 411 | return f"Observation [{tool_name}]: {prefix}: {result}" | 450 | return f"Observation [{tool_name}]: {prefix}: {result}" |
tests/test_parsing.pymodified@@ -274,3 +274,39 @@ class TestFormatToolResult: | |||
| 274 | assert "write" in result | 274 | assert "write" in result |
| 275 | assert "Error" in result | 275 | assert "Error" in result |
| 276 | assert "Permission denied" in result | 276 | assert "Permission denied" in result |
| 277 | + | ||
| 278 | + def test_format_todowrite_compacts_payload(self): | ||
| 279 | + result = format_tool_result( | ||
| 280 | + "TodoWrite", | ||
| 281 | + json.dumps( | ||
| 282 | + { | ||
| 283 | + "old_todos": [ | ||
| 284 | + { | ||
| 285 | + "content": "Create index.html", | ||
| 286 | + "active_form": "Creating index.html", | ||
| 287 | + "status": "completed", | ||
| 288 | + } | ||
| 289 | + ], | ||
| 290 | + "new_todos": [ | ||
| 291 | + { | ||
| 292 | + "content": "Create index.html", | ||
| 293 | + "active_form": "Creating index.html", | ||
| 294 | + "status": "completed", | ||
| 295 | + }, | ||
| 296 | + { | ||
| 297 | + "content": "Create installation chapter (02-installation.html)", | ||
| 298 | + "active_form": "Creating installation chapter", | ||
| 299 | + "status": "pending", | ||
| 300 | + }, | ||
| 301 | + ], | ||
| 302 | + "verification_nudge_needed": False, | ||
| 303 | + "store_path": "/tmp/.loader/todos/active.json", | ||
| 304 | + } | ||
| 305 | + ), | ||
| 306 | + ) | ||
| 307 | + assert "Observation [TodoWrite]: Result: updated todo list" in result | ||
| 308 | + assert "1 completed" in result | ||
| 309 | + assert "1 pending" in result | ||
| 310 | + assert "next pending: Create installation chapter (02-installation.html)" in result | ||
| 311 | + assert "old_todos" not in result | ||
| 312 | + assert "new_todos" not in result | ||