refactor: move the Codex recovery rungs out of turn_recovery

turn_recovery.py crossed the 2,000-line gate once the reasoning-replay recovery
landed beside it. The stale-encrypted-reasoning rungs and the replay-verdict
reset are one topic; they move verbatim to agent/turn_recovery_codex.py.
This commit is contained in:
Teknium committed 2026-10-10 19:22:07 -07:00
1 parent 86aa201bba
commit 52ccae4740
4 files changed
+80 -68

No files matched your search

+1 -1
View File
@@ -2286,7 +2286,7 @@ def _swap_switch_runtime(agent, new_model, new_provider, api_key, base_url, api_
# New api_mode may need a different transport.
if hasattr(agent, "_transport_cache"):
agent._transport_cache.clear()
from agent.turn_recovery import reset_codex_reasoning_replay
from agent.turn_recovery_codex import reset_codex_reasoning_replay
reset_codex_reasoning_replay(agent)
if api_key:
agent.api_key = api_key
+2 -2
View File
@@ -69,7 +69,7 @@ def bind_route_entry(agent: Any, entry: dict[str, Any], provider: str, model: st
agent._reasoning_echo_flag = bool(entry.get("reasoning_echo", False))
if hasattr(agent, "_transport_cache"):
agent._transport_cache.clear()
from agent.turn_recovery import reset_codex_reasoning_replay
from agent.turn_recovery_codex import reset_codex_reasoning_replay
reset_codex_reasoning_replay(agent)
agent._fallback_activated = True
@@ -101,7 +101,7 @@ def reinstall_runtime_snapshot(agent: Any, rt: dict[str, Any]) -> None:
_apply_primary_runtime_fields, _rebuild_primary_client, _restore_runtime_capabilities,
)
_apply_primary_runtime_fields(agent, rt)
from agent.turn_recovery import reset_codex_reasoning_replay
from agent.turn_recovery_codex import reset_codex_reasoning_replay
reset_codex_reasoning_replay(agent)
_restore_runtime_capabilities(agent, rt)
agent._use_prompt_caching = rt["use_prompt_caching"]
+1 -65
View File
@@ -34,6 +34,7 @@ from agent.turn_failure_copy import (
provider_label_for, site_copy, stamp_failure,
)
from agent.turn_retry_state import TurnRetryState
from agent.turn_recovery_codex import _is_codex_token_expired, _recover_stale_codex_reasoning
from hermes_constants import display_hermes_home
from utils import base_url_host_matches
@@ -450,71 +451,6 @@ def _refresh_credentials_after_401(
return False
def _is_codex_token_expired(agent: Any, api_error: Exception) -> bool:
"""401 ``token_expired`` from the Codex backend (#88510). It rejects a stale replayed
``encrypted_content`` blob with this auth signature, so a persisted session loops on "sign
in again" while a fresh session on the same bearer works. The caller treats it like
``invalid_encrypted_content`` — but only while cached reasoning items remain to strip."""
if getattr(api_error, "status_code", None) != 401:
return False
reason = agent._extract_api_error_context(api_error).get("reason")
return isinstance(reason, str) and reason.strip().lower() == "token_expired"
def reset_codex_reasoning_replay(agent: Any) -> None:
"""The replay verdict belongs to the route that earned it: a ``/model`` switch, fallback
activation or primary restore starts the new route with replay on (#61552)."""
agent._codex_reasoning_replay_enabled = True
agent._codex_reasoning_replay_rejected = False
def _recover_stale_codex_reasoning(
agent: Any, _retry: TurnRetryState, messages: list[dict[str, Any]], api_messages: Any,
) -> bool:
"""Stale ``codex_reasoning_items`` blob rejected by the provider: strip cached items (mutates
persisted ``messages``) and retry once. The first rung drops only the replayed blobs not stamped by
exactly this endpoint+model (it consumes its own precondition, so it cannot loop); a repeat goes on
to strip every item. The first full strip keeps replay on, since blobs the
route mints from now on are sealed with its current key; a repeat rejection means the route
cannot round-trip its own blobs, so replay is disabled for the session."""
if (
_retry.invalid_encrypted_content_retry_attempted
or agent.api_mode != "codex_responses"
or not bool(getattr(agent, "_codex_reasoning_replay_enabled", True))
or not any(
isinstance(_m, dict)
and _m.get("role") == "assistant"
and isinstance(_m.get("codex_reasoning_items"), list)
and _m.get("codex_reasoning_items")
for _m in messages
)
):
return False
transport = agent._get_transport()
if transport is not None and (removed := transport.drop_unverified_replay(messages, api_messages)):
_vlines(agent, f"⚠️ Encrypted reasoning replay was rejected — dropped {removed} item(s) minted elsewhere, retrying...")
return True
_retry.invalid_encrypted_content_retry_attempted = True
keep_replay = not getattr(agent, "_codex_reasoning_replay_rejected", False)
agent._codex_reasoning_replay_rejected = True
replay_stats = agent._disable_codex_reasoning_replay(messages, keep_replay=keep_replay)
# The retry is rebuilt from the request copy; with replay kept on it would resend the stale blob.
for _m in api_messages if isinstance(api_messages, list) else []:
if isinstance(_m, dict):
_m.pop("codex_reasoning_items", None)
action = "stripped stale" if keep_replay else "disabled replay for this session and stripped"
_vlines(
agent,
f"⚠️ Encrypted reasoning replay was rejected by the provider — "
f"{action} {replay_stats['items']} item(s) from {replay_stats['messages']} message(s), retrying...",
)
logger.warning(
"%sInvalid encrypted reasoning recovery: %s %d items from %d messages",
agent.log_prefix, action, replay_stats["items"], replay_stats["messages"],
)
return True
def _recover_format_errors(
agent: Any, api_error: Exception, classified: Any, _retry: TurnRetryState,
messages: list[dict[str, Any]], api_messages: Any,
+76
View File
@@ -0,0 +1,76 @@
"""Codex Responses recovery rungs: stale encrypted-reasoning strip and the replay verdict reset."""
from __future__ import annotations
import logging
from typing import Any
from agent.turn_retry_state import TurnRetryState
logger = logging.getLogger(__name__)
def _is_codex_token_expired(agent: Any, api_error: Exception) -> bool:
"""401 ``token_expired`` from the Codex backend (#88510). It rejects a stale replayed
``encrypted_content`` blob with this auth signature, so a persisted session loops on "sign
in again" while a fresh session on the same bearer works. The caller treats it like
``invalid_encrypted_content`` — but only while cached reasoning items remain to strip."""
if getattr(api_error, "status_code", None) != 401:
return False
reason = agent._extract_api_error_context(api_error).get("reason")
return isinstance(reason, str) and reason.strip().lower() == "token_expired"
def reset_codex_reasoning_replay(agent: Any) -> None:
"""The replay verdict belongs to the route that earned it: a ``/model`` switch, fallback
activation or primary restore starts the new route with replay on (#61552)."""
agent._codex_reasoning_replay_enabled = True
agent._codex_reasoning_replay_rejected = False
def _recover_stale_codex_reasoning(
agent: Any, _retry: TurnRetryState, messages: list[dict[str, Any]], api_messages: Any,
) -> bool:
"""Stale ``codex_reasoning_items`` blob rejected by the provider: strip cached items (mutates
persisted ``messages``) and retry once. The first rung drops only the replayed blobs not stamped by
exactly this endpoint+model (it consumes its own precondition, so it cannot loop); a repeat goes on
to strip every item. The first full strip keeps replay on, since blobs the
route mints from now on are sealed with its current key; a repeat rejection means the route
cannot round-trip its own blobs, so replay is disabled for the session."""
if (
_retry.invalid_encrypted_content_retry_attempted
or agent.api_mode != "codex_responses"
or not bool(getattr(agent, "_codex_reasoning_replay_enabled", True))
or not any(
isinstance(_m, dict)
and _m.get("role") == "assistant"
and isinstance(_m.get("codex_reasoning_items"), list)
and _m.get("codex_reasoning_items")
for _m in messages
)
):
return False
from agent.turn_recovery import _vlines # facade owns the verbose printer; late import breaks the cycle
transport = agent._get_transport()
if transport is not None and (removed := transport.drop_unverified_replay(messages, api_messages)):
_vlines(agent, f"⚠️ Encrypted reasoning replay was rejected — dropped {removed} item(s) minted elsewhere, retrying...")
return True
_retry.invalid_encrypted_content_retry_attempted = True
keep_replay = not getattr(agent, "_codex_reasoning_replay_rejected", False)
agent._codex_reasoning_replay_rejected = True
replay_stats = agent._disable_codex_reasoning_replay(messages, keep_replay=keep_replay)
# The retry is rebuilt from the request copy; with replay kept on it would resend the stale blob.
for _m in api_messages if isinstance(api_messages, list) else []:
if isinstance(_m, dict):
_m.pop("codex_reasoning_items", None)
action = "stripped stale" if keep_replay else "disabled replay for this session and stripped"
_vlines(
agent,
f"⚠️ Encrypted reasoning replay was rejected by the provider — "
f"{action} {replay_stats['items']} item(s) from {replay_stats['messages']} message(s), retrying...",
)
logger.warning(
"%sInvalid encrypted reasoning recovery: %s %d items from %d messages",
agent.log_prefix, action, replay_stats["items"], replay_stats["messages"],
)
return True