Skip to content

Commit c394d03

Browse files
committed
Keep plan file after session close and auto-clean test plan dirs
AgentSession.close no longer removes the per-session PLAN.md so the plan stays available for later reference. Tests create real plan files but rarely call close(), leaking python-agent-plans-* dirs into /tmp; tests/plan_cleanup.py now tracks them and removes them after each test (with an atexit safety net).
1 parent 40cd767 commit c394d03

10 files changed

Lines changed: 87 additions & 5 deletions

File tree

python_agent_harness/agent_session.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,6 @@ def _conversation_text(self, messages: list) -> str:
539539
def close(self) -> None:
540540
self.cancel()
541541
self.alive = False
542-
self.plan_mode.cleanup_plan_file()
543542
cleanup_spooled_files()
544543
# MCP server connections + event-loop thread (no-op when no MCP
545544
# servers are configured or none connected)

tests/plan_cleanup.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""Automatic cleanup of /tmp plan dirs created by the test suite.
2+
3+
``PlanMode.ensure_plan_file()`` puts PLAN.md in a fresh
4+
``python-agent-plans-*`` dir under the temp dir (usually /tmp).
5+
Production ``AgentSession.close()`` intentionally keeps the plan file
6+
(one unique file per session), so tests must clean up their own:
7+
this module is imported (for its side effects) by the test files that
8+
can create plan files — it records every plan file created by
9+
``ensure_plan_file`` and removes them after each test (via a
10+
``unittest.TestCase.run`` hook) with an atexit safety net.
11+
"""
12+
13+
import atexit
14+
import os
15+
import unittest
16+
17+
from python_agent_harness.planmode import PlanMode
18+
19+
_created: list[str] = []
20+
21+
_orig_ensure = PlanMode.ensure_plan_file
22+
23+
24+
def _tracked_ensure(self) -> str:
25+
path = _orig_ensure(self)
26+
_created.append(path)
27+
return path
28+
29+
30+
def _cleanup_plan_files() -> None:
31+
for path in _created:
32+
try:
33+
os.remove(path)
34+
d = os.path.dirname(path)
35+
if os.path.isdir(d) and not os.listdir(d):
36+
os.rmdir(d)
37+
except OSError:
38+
pass
39+
_created.clear()
40+
41+
42+
_orig_run = unittest.TestCase.run
43+
44+
45+
def _run(self, result=None):
46+
try:
47+
return _orig_run(self, result)
48+
finally:
49+
_cleanup_plan_files()
50+
51+
52+
PlanMode.ensure_plan_file = _tracked_ensure
53+
unittest.TestCase.run = _run
54+
atexit.register(_cleanup_plan_files)

tests/test_agent.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
sys.path.insert(0, os.path.dirname(__file__)) # sibling fake server import
1414

15+
import plan_cleanup # noqa: F401,E402 (side-effect: auto-remove /tmp plan dirs)
16+
1517
from python_agent_harness.agent import AgentLoop, Supervisor, sanitize_tool_result
1618
from python_agent_harness.agent_session import AgentSession
1719
from python_agent_harness.models import Message, ToolCall, Usage

tests/test_agent_session.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
sys.path.insert(0, os.path.dirname(__file__))
1111

12+
import plan_cleanup # noqa: F401,E402 (side-effect: auto-remove /tmp plan dirs)
1213
from test_agent import FakeClient, RecordingSession
1314

1415
from python_agent_harness import config
@@ -655,10 +656,11 @@ def test_switch_to_plan_registers_plan_exit(self):
655656

656657

657658
class TestClose(unittest.TestCase):
658-
"""close() cancels the run, marks the session dead, cleans up the
659-
plan file and closes the client."""
659+
"""close() cancels the run, marks the session dead and closes the
660+
client; the plan file is kept (one per session) for later
661+
reference."""
660662

661-
def test_close_cancels_and_cleans_up(self):
663+
def test_close_cancels_and_keeps_plan_file(self):
662664
session = RecordingSession()
663665
session.switch_to_plan() # creates a real plan file
664666
plan_file = session.plan_mode.plan_file
@@ -674,7 +676,7 @@ def close(self):
674676
session.close()
675677
self.assertFalse(session.alive)
676678
self.assertTrue(session.cancel_event.is_set())
677-
self.assertFalse(os.path.exists(plan_file))
679+
self.assertTrue(os.path.exists(plan_file))
678680
self.assertTrue(ClosableClient.closed)
679681

680682
def test_close_closes_subagent_client_too(self):

tests/test_cli.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33
from __future__ import annotations
44

55
import os
6+
import sys
67
import tempfile
78
import unittest
89
from pathlib import Path
910

11+
sys.path.insert(0, os.path.dirname(__file__))
12+
13+
import plan_cleanup # noqa: F401,E402 (side-effect: auto-remove /tmp plan dirs)
14+
1015
from python_agent_harness import cli, config
1116

1217

tests/test_invariants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353

5454
sys.path.insert(0, os.path.dirname(__file__)) # sibling test helpers
5555

56+
import plan_cleanup # noqa: F401,E402 (side-effect: auto-remove /tmp plan dirs)
5657
from test_agent import ParallelToolSession, RecordingSession, agent_call # noqa: E402
5758

5859
from python_agent_harness import config # noqa: E402

tests/test_planmode.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import os
22
import re
3+
import sys
34
import tempfile
45
import unittest
56
from unittest import mock
67

8+
sys.path.insert(0, os.path.dirname(__file__))
9+
10+
import plan_cleanup # noqa: F401,E402 (side-effect: auto-remove /tmp plan dirs)
11+
712
from python_agent_harness.models import AgentMode
813
from python_agent_harness.planmode import PlanMode, _plan_temp_dir
914

tests/test_scenarios.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
2121
from unittest import mock
2222

23+
sys.path.insert(0, os.path.dirname(__file__))
24+
25+
import plan_cleanup # noqa: F401,E402 (side-effect: auto-remove /tmp plan dirs)
26+
2327
from python_agent_harness import config
2428
from python_agent_harness.agent import AgentLoop
2529
from python_agent_harness.agent_session import AgentSession

tests/test_subagent.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22

33
from __future__ import annotations
44

5+
import os
6+
import sys
57
import tempfile
68
import unittest
79

10+
sys.path.insert(0, os.path.dirname(__file__))
11+
12+
import plan_cleanup # noqa: F401,E402 (side-effect: auto-remove /tmp plan dirs)
13+
814
from python_agent_harness.agent_session import AgentSession
915
from python_agent_harness.models import Message, Usage
1016
from python_agent_harness.session_store import SessionStore

tests/test_tui.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22

33
import io
44
import os
5+
import sys
56
import tempfile
67
import unittest
78
import unittest.mock as mock
89

10+
sys.path.insert(0, os.path.dirname(__file__))
11+
12+
import plan_cleanup # noqa: F401,E402 (side-effect: auto-remove /tmp plan dirs)
913
from rich.console import Console
1014
from rich.live import Live
1115

0 commit comments

Comments
 (0)