From 069bfd6545f618a1c5d3c617908ea82ad4556e8e Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sat, 13 Jun 2026 14:08:11 -0700 Subject: [PATCH] fix(agent): keep Codex reasoning replay on Codex path --- agent/agent_runtime_helpers.py | 10 +++++++++- agent/conversation_loop.py | 5 ++++- run_agent.py | 15 ++++++++++++--- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/agent/agent_runtime_helpers.py b/agent/agent_runtime_helpers.py index ea71cb93946..cae1a685a53 100644 --- a/agent/agent_runtime_helpers.py +++ b/agent/agent_runtime_helpers.py @@ -881,6 +881,8 @@ def try_recover_primary_transport( def drop_thinking_only_and_merge_users( messages: List[Dict[str, Any]], + *, + drop_codex_reasoning_items: bool = True, ) -> List[Dict[str, Any]]: """Drop thinking-only assistant turns; merge any adjacent user messages left behind. @@ -902,7 +904,13 @@ def drop_thinking_only_and_merge_users( return messages # Pass 1: drop thinking-only assistant turns. - kept = [m for m in messages if not _ra().AIAgent._is_thinking_only_assistant(m)] + kept = [ + m for m in messages + if not _ra().AIAgent._is_thinking_only_assistant( + m, + drop_codex_reasoning_items=drop_codex_reasoning_items, + ) + ] dropped = len(messages) - len(kept) if dropped == 0: return messages diff --git a/agent/conversation_loop.py b/agent/conversation_loop.py index 05d19772d9c..1d8384aa8a7 100644 --- a/agent/conversation_loop.py +++ b/agent/conversation_loop.py @@ -707,7 +707,10 @@ def run_conversation( # a thinking-only turn. Runs on the per-call copy only — the # stored conversation history keeps the reasoning block for the # UI transcript and session persistence. - api_messages = agent._drop_thinking_only_and_merge_users(api_messages) + api_messages = agent._drop_thinking_only_and_merge_users( + api_messages, + drop_codex_reasoning_items=agent.api_mode != "codex_responses", + ) # Normalize message whitespace and tool-call JSON for consistent # prefix matching. Ensures bit-perfect prefixes across turns, diff --git a/run_agent.py b/run_agent.py index b793f0e6b5d..ffcf2abf171 100644 --- a/run_agent.py +++ b/run_agent.py @@ -3246,7 +3246,11 @@ class AIAgent: return sanitize_api_messages(messages) @staticmethod - def _is_thinking_only_assistant(msg: Dict[str, Any]) -> bool: + def _is_thinking_only_assistant( + msg: Dict[str, Any], + *, + drop_codex_reasoning_items: bool = True, + ) -> bool: """Return True if ``msg`` is an assistant turn whose only payload is reasoning. "Thinking-only" means the model emitted reasoning (``reasoning`` or @@ -3302,7 +3306,7 @@ class AIAgent: # thinking-only; empty/junk lists should fall through to the generic # empty-turn handling instead of being dropped here. codex_items = msg.get("codex_reasoning_items") - if isinstance(codex_items, list): + if drop_codex_reasoning_items and isinstance(codex_items, list): return any( isinstance(item, dict) and item.get("type") == "reasoning" for item in codex_items @@ -3312,10 +3316,15 @@ class AIAgent: @staticmethod def _drop_thinking_only_and_merge_users( messages: List[Dict[str, Any]], + *, + drop_codex_reasoning_items: bool = True, ) -> List[Dict[str, Any]]: """Forwarder — see ``agent.agent_runtime_helpers.drop_thinking_only_and_merge_users``.""" from agent.agent_runtime_helpers import drop_thinking_only_and_merge_users - return drop_thinking_only_and_merge_users(messages) + return drop_thinking_only_and_merge_users( + messages, + drop_codex_reasoning_items=drop_codex_reasoning_items, + ) @staticmethod def _cap_delegate_task_calls(tool_calls: list) -> list: