refactor(agent): extract run_conversation prologue into agent/turn_context.py

Phase 1 of the god-file decomposition plan. run_conversation's ~470-line
once-per-turn setup block (stdio guarding, retry-counter resets, user-message
sanitization, todo/nudge hydration, system-prompt restore-or-build,
crash-resilience persistence, preflight compression, the pre_llm_call hook, and
external-memory prefetch) is moved verbatim into build_turn_context(), which
returns a TurnContext dataclass the loop unpacks.

Behavior-neutral move-and-name refactor: the builder mutates `agent` exactly as
the inline code did; only the locals the loop reads back are returned.

- run_conversation: 4602 -> 4217 LOC (-385)
- agent/conversation_loop.py: 4965 -> ~4580 LOC
- new agent/turn_context.py: focused, dependency-injected, unit-tested in isolation

Tests: tests/run_agent/ 1570 passed / 0 failed under per-file process isolation.
Relocation follow-ups: 413_compression mocks now patch both module references;
nudge/on_turn_start source-inspection guards point at the extracted module.
This commit is contained in:
teknium1
2026-06-07 22:17:35 -07:00
committed by Teknium
parent 86c537d209
commit 54870847cb
6 changed files with 648 additions and 446 deletions
+4
View File
@@ -553,6 +553,7 @@ class TestPreflightCompression:
agent.status_callback = lambda ev, msg: status_messages.append((ev, msg))
with (
patch("agent.turn_context.estimate_request_tokens_rough", return_value=114_000),
patch("agent.conversation_loop.estimate_request_tokens_rough", return_value=114_000),
patch.object(agent, "_compress_context") as mock_compress,
patch.object(agent, "_persist_session"),
@@ -604,6 +605,7 @@ class TestPreflightCompression:
return 125_000 if _rough_calls["n"] == 1 else 40_000
with (
patch("agent.turn_context.estimate_request_tokens_rough", side_effect=_rough_estimate),
patch("agent.conversation_loop.estimate_request_tokens_rough", side_effect=_rough_estimate),
patch.object(agent, "_compress_context") as mock_compress,
patch.object(agent, "_persist_session"),
@@ -728,6 +730,7 @@ class TestPreflightCompression:
agent.client.chat.completions.create.side_effect = [ok_resp]
with (
patch("agent.turn_context.estimate_request_tokens_rough", return_value=144_669),
patch("agent.conversation_loop.estimate_request_tokens_rough", return_value=144_669),
# Compression no-ops (returns input unchanged) — mirrors an aux
# summary-model timeout where the messages can't be reduced.
@@ -760,6 +763,7 @@ class TestPreflightCompression:
agent.client.chat.completions.create.side_effect = [ok_resp]
with (
patch("agent.turn_context.estimate_request_tokens_rough", return_value=144_669),
patch("agent.conversation_loop.estimate_request_tokens_rough", return_value=144_669),
patch.object(agent, "_compress_context", side_effect=lambda msgs, *a, **k: (msgs, agent._cached_system_prompt)),
patch.object(agent, "_persist_session"),