diff --git a/agent/conversation_loop.py b/agent/conversation_loop.py index 41eb2d730f1..caac0d3e8f2 100644 --- a/agent/conversation_loop.py +++ b/agent/conversation_loop.py @@ -1454,7 +1454,6 @@ def run_conversation( } messages.append(continue_msg) agent._session_messages = messages - agent._save_session_log(messages) restart_with_length_continuation = True break @@ -3086,7 +3085,6 @@ def run_conversation( if not agent.quiet_mode: agent._vprint(f"{agent.log_prefix}↻ Codex response incomplete; continuing turn ({agent._codex_incomplete_retries}/3)") agent._session_messages = messages - agent._save_session_log(messages) continue agent._codex_incomplete_retries = 0 @@ -3411,7 +3409,6 @@ def run_conversation( # Save session log incrementally (so progress is visible even if interrupted) agent._session_messages = messages - agent._save_session_log(messages) # Continue loop for next response continue @@ -3578,7 +3575,6 @@ def run_conversation( interim_msg["_thinking_prefill"] = True messages.append(interim_msg) agent._session_messages = messages - agent._save_session_log(messages) continue # ── Empty response retry ────────────────────── @@ -3712,7 +3708,6 @@ def run_conversation( } messages.append(continue_msg) agent._session_messages = messages - agent._save_session_log(messages) continue codex_ack_continuations = 0 diff --git a/run_agent.py b/run_agent.py index f842ce6936c..99fb5a1563a 100644 --- a/run_agent.py +++ b/run_agent.py @@ -1176,7 +1176,6 @@ class AIAgent: self._drop_trailing_empty_response_scaffolding(messages) self._apply_persist_user_message_override(messages) self._session_messages = messages - self._save_session_log(messages) self._flush_messages_to_session_db(messages, conversation_history) def _drop_trailing_empty_response_scaffolding(self, messages: List[Dict]) -> None: @@ -1516,71 +1515,6 @@ class AIAgent: content = re.sub(r'()\n+', r'\1\n', content) return content.strip() - def _save_session_log(self, messages: List[Dict[str, Any]] = None): - """ - Save the full raw session to a JSON file. - - Stores every message exactly as the agent sees it: user messages, - assistant messages (with reasoning, finish_reason, tool_calls), - tool responses (with tool_call_id, tool_name), and injected system - messages (compression summaries, todo snapshots, etc.). - - REASONING_SCRATCHPAD tags are converted to blocks for consistency. - Overwritten after each turn so it always reflects the latest state. - """ - messages = messages or self._session_messages - if not messages: - return - - try: - # Clean assistant content for session logs - cleaned = [] - for msg in messages: - if msg.get("role") == "assistant" and msg.get("content"): - msg = dict(msg) - msg["content"] = self._clean_session_content(msg["content"]) - cleaned.append(msg) - - # Guard: never overwrite a larger session log with fewer messages. - # This protects against data loss when --resume loads a session whose - # messages weren't fully written to SQLite — the resumed agent starts - # with partial history and would otherwise clobber the full JSON log. - if self.session_log_file.exists(): - try: - existing = json.loads(self.session_log_file.read_text(encoding="utf-8")) - existing_count = existing.get("message_count", len(existing.get("messages", []))) - if existing_count > len(cleaned): - logging.debug( - "Skipping session log overwrite: existing has %d messages, current has %d", - existing_count, len(cleaned), - ) - return - except Exception: - pass # corrupted existing file — allow the overwrite - - entry = { - "session_id": self.session_id, - "model": self.model, - "base_url": self.base_url, - "platform": self.platform, - "session_start": self.session_start.isoformat(), - "last_updated": datetime.now().isoformat(), - "system_prompt": self._cached_system_prompt or "", - "tools": self.tools or [], - "message_count": len(cleaned), - "messages": cleaned, - } - - atomic_json_write( - self.session_log_file, - entry, - indent=2, - default=str, - ) - - except Exception as e: - if self.verbose_logging: - logging.warning(f"Failed to save session log: {e}") def interrupt(self, message: str = None) -> None: """ diff --git a/tests/cron/test_codex_execution_paths.py b/tests/cron/test_codex_execution_paths.py index 65526f4a8ce..5c3e5cf060b 100644 --- a/tests/cron/test_codex_execution_paths.py +++ b/tests/cron/test_codex_execution_paths.py @@ -74,7 +74,6 @@ class _Codex401ThenSuccessAgent(run_agent.AIAgent): self._cleanup_task_resources = lambda task_id: None self._persist_session = lambda messages, history=None: None self._save_trajectory = lambda messages, user_message, completed: None - self._save_session_log = lambda messages: None def _try_refresh_codex_client_credentials(self, *, force: bool = True) -> bool: type(self).refresh_attempts += 1 diff --git a/tests/run_agent/test_860_dedup.py b/tests/run_agent/test_860_dedup.py index cf9b8e745ca..6349595e894 100644 --- a/tests/run_agent/test_860_dedup.py +++ b/tests/run_agent/test_860_dedup.py @@ -110,8 +110,6 @@ class TestFlushDeduplication: db = SessionDB(db_path=db_path) agent = self._make_agent(db) - # Stub out _save_session_log to avoid file I/O - agent._save_session_log = MagicMock() conversation_history = [{"role": "user", "content": "old"}] messages = list(conversation_history) + [ diff --git a/tests/run_agent/test_context_token_tracking.py b/tests/run_agent/test_context_token_tracking.py index 772dfa89b16..4f9dac0fa3a 100644 --- a/tests/run_agent/test_context_token_tracking.py +++ b/tests/run_agent/test_context_token_tracking.py @@ -52,7 +52,7 @@ def _make_agent(monkeypatch, api_mode, provider, response_fn): kw.update(skip_context_files=True, skip_memory=True, max_iterations=4) super().__init__(*a, **kw) self._cleanup_task_resources = self._persist_session = lambda *a, **k: None - self._save_trajectory = self._save_session_log = lambda *a, **k: None + self._save_trajectory = lambda *a, **k: None def run_conversation(self, msg, conversation_history=None, task_id=None): self._interruptible_api_call = lambda kw: response_fn() diff --git a/tests/run_agent/test_empty_response_recovery_persistence.py b/tests/run_agent/test_empty_response_recovery_persistence.py index 24c637a2fee..27e6c23d2d4 100644 --- a/tests/run_agent/test_empty_response_recovery_persistence.py +++ b/tests/run_agent/test_empty_response_recovery_persistence.py @@ -9,11 +9,7 @@ def _agent_with_stubbed_persistence(): agent._persist_user_message_override = None agent._session_db = None agent._session_messages = [] - agent.saved_session_logs = [] agent.flushed_session_db_messages = [] - agent._save_session_log = lambda messages: agent.saved_session_logs.append( - [m.copy() for m in messages] - ) agent._flush_messages_to_session_db = lambda messages, conversation_history=None: ( agent.flushed_session_db_messages.append([m.copy() for m in messages]) ) @@ -60,7 +56,7 @@ def test_persist_session_strips_trailing_empty_recovery_scaffolding(): assert messages == [ {"role": "user", "content": "run the task"}, ] - assert agent.saved_session_logs[-1] == messages + assert agent.flushed_session_db_messages[-1] == messages assert all(not msg.get("_empty_recovery_synthetic") for msg in messages) @@ -77,7 +73,7 @@ def test_persist_session_keeps_unmarked_terminal_empty_response(): {"role": "user", "content": "run the task"}, {"role": "assistant", "content": "(empty)"}, ] - assert agent.saved_session_logs[-1] == messages + assert agent.flushed_session_db_messages[-1] == messages def test_persist_session_strips_marked_terminal_empty_sentinel(): @@ -94,5 +90,5 @@ def test_persist_session_strips_marked_terminal_empty_sentinel(): AIAgent._persist_session(agent, messages, conversation_history=[]) assert messages == [{"role": "user", "content": "continue"}] - assert agent.saved_session_logs[-1] == messages + assert agent.flushed_session_db_messages[-1] == messages assert all(not msg.get("_empty_terminal_sentinel") for msg in messages) diff --git a/tests/run_agent/test_run_agent.py b/tests/run_agent/test_run_agent.py index 69682804d47..9cdf16feb2e 100644 --- a/tests/run_agent/test_run_agent.py +++ b/tests/run_agent/test_run_agent.py @@ -1901,7 +1901,6 @@ class TestExecuteToolCalls: agent._interruptible_api_call = _fake_api_call agent._persist_session = lambda *args, **kwargs: None agent._save_trajectory = lambda *args, **kwargs: None - agent._save_session_log = lambda *args, **kwargs: None captured = io.StringIO() agent._print_fn = lambda *args, **kw: print(*args, file=captured, **kw) @@ -4300,22 +4299,6 @@ class TestSafeWriter: assert inner.getvalue() == "test" -class TestSaveSessionLogAtomicWrite: - def test_uses_shared_atomic_json_helper(self, agent, tmp_path): - agent.session_log_file = tmp_path / "session.json" - messages = [{"role": "user", "content": "hello"}] - - with patch("run_agent.atomic_json_write", create=True) as mock_atomic_write: - agent._save_session_log(messages) - - mock_atomic_write.assert_called_once() - call_args = mock_atomic_write.call_args - assert call_args.args[0] == agent.session_log_file - payload = call_args.args[1] - assert payload["session_id"] == agent.session_id - assert payload["messages"] == messages - assert call_args.kwargs["indent"] == 2 - assert call_args.kwargs["default"] is str # =================================================================== @@ -5103,12 +5086,9 @@ class TestPersistUserMessageOverride: {"role": "assistant", "content": "Hi!"}, ] - with patch.object(agent, "_save_session_log") as mock_save: - agent._persist_session(messages, []) + agent._persist_session(messages, []) assert messages[0]["content"] == "Hello there" - saved_messages = mock_save.call_args.args[0] - assert saved_messages[0]["content"] == "Hello there" first_db_write = agent._session_db.append_message.call_args_list[0].kwargs assert first_db_write["content"] == "Hello there" diff --git a/tests/run_agent/test_run_agent_codex_responses.py b/tests/run_agent/test_run_agent_codex_responses.py index 5652281eb42..163dbd0033b 100644 --- a/tests/run_agent/test_run_agent_codex_responses.py +++ b/tests/run_agent/test_run_agent_codex_responses.py @@ -54,7 +54,6 @@ def _build_agent(monkeypatch): agent._cleanup_task_resources = lambda task_id: None agent._persist_session = lambda messages, history=None: None agent._save_trajectory = lambda messages, user_message, completed: None - agent._save_session_log = lambda messages: None return agent @@ -75,7 +74,6 @@ def _build_copilot_agent(monkeypatch, *, model="gpt-5.4"): agent._cleanup_task_resources = lambda task_id: None agent._persist_session = lambda messages, history=None: None agent._save_trajectory = lambda messages, user_message, completed: None - agent._save_session_log = lambda messages: None return agent @@ -335,7 +333,6 @@ def test_build_api_kwargs_codex_clamps_minimal_effort(monkeypatch): agent._cleanup_task_resources = lambda task_id: None agent._persist_session = lambda messages, history=None: None agent._save_trajectory = lambda messages, user_message, completed: None - agent._save_session_log = lambda messages: None kwargs = agent._build_api_kwargs( [ @@ -365,8 +362,7 @@ def test_build_api_kwargs_codex_preserves_supported_efforts(monkeypatch): agent._cleanup_task_resources = lambda task_id: None agent._persist_session = lambda messages, history=None: None agent._save_trajectory = lambda messages, user_message, completed: None - agent._save_session_log = lambda messages: None - + kwargs = agent._build_api_kwargs( [ {"role": "system", "content": "sys"}, @@ -594,7 +590,6 @@ def _build_xai_oauth_agent(monkeypatch): agent._cleanup_task_resources = lambda task_id: None agent._persist_session = lambda messages, history=None: None agent._save_trajectory = lambda messages, user_message, completed: None - agent._save_session_log = lambda messages: None return agent