From 77ec309c0fee08480a0033ebad5e88ec03d7c9fd Mon Sep 17 00:00:00 2001 From: fluffy314 Date: Mon, 20 Jul 2026 18:13:43 +0800 Subject: [PATCH] fix(agents): close transcript streams cleanly Restore standard streams before closing the transcript log so one-shot GAN runs exit successfully instead of crashing the AutoResearch supervisor during interpreter shutdown. Co-authored-by: Cursor --- scripts/agent_gan_repl.py | 11 ++++++++++- .../bridge/test_agent_gan_repl.py | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/scripts/agent_gan_repl.py b/scripts/agent_gan_repl.py index 130094e..4148154 100644 --- a/scripts/agent_gan_repl.py +++ b/scripts/agent_gan_repl.py @@ -60,6 +60,8 @@ def write(self, text: str) -> int: return 0 with self._lock: self.terminal.write(text) + if self.log.closed: + return len(text) for part in text.splitlines(keepends=True): if self._line_start: self.log.write(f"[{self.timestamp_fn()}] ") @@ -71,10 +73,13 @@ def write(self, text: str) -> int: def flush(self) -> None: with self._lock: self.terminal.flush() - self.log.flush() + if not self.log.closed: + self.log.flush() def log_only(self, event: str) -> None: with self._lock: + if self.log.closed: + return if not self._line_start: self.log.write("\n") self.log.write(f"[{self.timestamp_fn()}] {event.rstrip()}\n") @@ -83,6 +88,10 @@ def log_only(self, event: str) -> None: def close_log(self) -> None: with self._lock: + if sys.stdout is self: + sys.stdout = self.terminal + if sys.stderr is self: + sys.stderr = self.terminal if not self.log.closed: self.log.flush() self.log.close() diff --git a/tests/inference_engine/bridge/test_agent_gan_repl.py b/tests/inference_engine/bridge/test_agent_gan_repl.py index ee74f03..18bc0fe 100644 --- a/tests/inference_engine/bridge/test_agent_gan_repl.py +++ b/tests/inference_engine/bridge/test_agent_gan_repl.py @@ -1,6 +1,7 @@ import io import json import signal +import sys import time from pathlib import Path @@ -63,6 +64,22 @@ def test_timestamped_tee_preserves_terminal_and_flushes_log(tmp_path): ) +def test_timestamped_tee_shutdown_restores_streams_and_flush_is_safe( + tmp_path, + monkeypatch, +): + terminal = io.StringIO() + tee = TimestampedTee(terminal, tmp_path / "agent.log") + monkeypatch.setattr(sys, "stdout", tee) + monkeypatch.setattr(sys, "stderr", tee) + tee.close_log() + assert sys.stdout is terminal + assert sys.stderr is terminal + tee.flush() + tee.write("after-close") + assert terminal.getvalue() == "after-close" + + def test_token_printer_streams_only_new_suffix(capsys): printer = TokenPrinter(Tokenizer(), "generator") printer([1])