_run_dir_loop was ~160 lines holding four conceptual layers in one
function: pre-loop setup, budget check + partial-flush, API call +
response printing, and tool dispatch + done detection. Phase 3 dynamic
turn allocation will inject more state into the same code path, so
this debt is paid before that lands.
Three new helpers above _run_dir_loop:
- _build_dir_loop_context(): pure setup. Builds the dir context, child
summaries, survey block, filtered tool list, system prompt, and seed
user message. Returns a _DirLoopContext namedtuple.
- _flush_partial_dir_entry(): idempotent partial-cache writer for the
budget-exceeded path. Returns the partial summary string. Idempotent
via cache.has_entry() guard, so callers can call it without checking.
- _handle_turn_response(): per-turn response processing. Prints text
blocks and tool decisions, appends the assistant message, dispatches
tools (or nudges the agent to call submit_report), appends
tool_results. Returns (done, summary).
_run_dir_loop is now a ~25-line coordinator: build context, then
for-loop calls budget check, API, and turn handler in sequence.
No behavior change. 164 tests pass. Internals.md §4 updated for the
new structure and the file:line refs that drifted.