Quiet setup handoffs
Authored by
mfwolffe <wolffemf@dukes.jmu.edu>
- SHA
2a6f1423728d9d7b24edebe0ea6055e34950ef6c- Parents
-
4a458e4 - Tree
222c875
2a6f142
2a6f1423728d9d7b24edebe0ea6055e34950ef6c4a458e4
222c875| Status | File | + | - |
|---|---|---|---|
| M |
src/loader/runtime/tool_batches.py
|
21 | 0 |
| M |
tests/test_tool_batches.py
|
2 | 11 |
src/loader/runtime/tool_batches.pymodified@@ -2,6 +2,7 @@ | ||
| 2 | 2 | |
| 3 | 3 | from __future__ import annotations |
| 4 | 4 | |
| 5 | +import shlex | |
| 5 | 6 | from collections.abc import Awaitable, Callable |
| 6 | 7 | from dataclasses import dataclass, field |
| 7 | 8 | from pathlib import Path |
@@ -1106,6 +1107,11 @@ class ToolBatchRunner: | ||
| 1106 | 1107 | dod, |
| 1107 | 1108 | project_root=self.context.project_root, |
| 1108 | 1109 | ) |
| 1110 | + if ( | |
| 1111 | + not has_file_artifact_progress | |
| 1112 | + and _is_pure_directory_creation_tool_call(tool_call) | |
| 1113 | + ): | |
| 1114 | + return | |
| 1109 | 1115 | resume_target = _preferred_resume_target_path( |
| 1110 | 1116 | dod, |
| 1111 | 1117 | next_pending=next_pending, |
@@ -2112,6 +2118,21 @@ def _current_mutation_label(tool_call: ToolCall) -> str: | ||
| 2112 | 2118 | return f"the successful `{tool_call.name}` result" |
| 2113 | 2119 | |
| 2114 | 2120 | |
| 2121 | +def _is_pure_directory_creation_tool_call(tool_call: ToolCall) -> bool: | |
| 2122 | + if tool_call.name != "bash": | |
| 2123 | + return False | |
| 2124 | + command = str(tool_call.arguments.get("command", "")).strip() | |
| 2125 | + if not command or any( | |
| 2126 | + operator in command for operator in ("&&", "||", ";", "|", "$(", ">", "<") | |
| 2127 | + ): | |
| 2128 | + return False | |
| 2129 | + try: | |
| 2130 | + parts = shlex.split(command) | |
| 2131 | + except ValueError: | |
| 2132 | + return False | |
| 2133 | + return bool(parts) and parts[0] == "mkdir" | |
| 2134 | + | |
| 2135 | + | |
| 2115 | 2136 | def _tool_call_label(tool_call: ToolCall) -> str: |
| 2116 | 2137 | """Human-readable label for one tool call.""" |
| 2117 | 2138 | name = tool_call.name |
tests/test_tool_batches.pymodified@@ -2024,7 +2024,7 @@ async def test_tool_batch_runner_discovery_completion_handoff_stays_persistent( | ||
| 2024 | 2024 | |
| 2025 | 2025 | |
| 2026 | 2026 | @pytest.mark.asyncio |
| 2027 | -async def test_tool_batch_runner_missing_artifact_nudge_prefers_pending_index_after_mkdir( | |
| 2027 | +async def test_tool_batch_runner_missing_artifact_nudge_stays_quiet_after_setup_mkdir( | |
| 2028 | 2028 | temp_dir: Path, |
| 2029 | 2029 | ) -> None: |
| 2030 | 2030 | async def assess_confidence( |
@@ -2119,16 +2119,7 @@ async def test_tool_batch_runner_missing_artifact_nudge_prefers_pending_index_af | ||
| 2119 | 2119 | consecutive_errors=0, |
| 2120 | 2120 | ) |
| 2121 | 2121 | |
| 2122 | - assert persistent_messages | |
| 2123 | - message = persistent_messages[-1] | |
| 2124 | - assert "Next step: create `index.html`." in message | |
| 2125 | - assert ( | |
| 2126 | - f"Prefer one `write(file_path=..., content=...)` call for `{(nginx_root / 'index.html').resolve(strict=False)}` now." | |
| 2127 | - in message | |
| 2128 | - ) | |
| 2129 | - assert "One declared output artifact is still missing." not in message | |
| 2130 | - assert "Do not reread reference material or spend the next turn on bookkeeping." in message | |
| 2131 | - assert "Resume by creating the next output file under `chapters/` now." not in message | |
| 2122 | + assert persistent_messages == [] | |
| 2132 | 2123 | assert ephemeral_messages == [] |
| 2133 | 2124 | |
| 2134 | 2125 | |