diff --git a/run_agent.py b/run_agent.py index 8e1fbfed194..fa8c22d8455 100644 --- a/run_agent.py +++ b/run_agent.py @@ -9499,7 +9499,16 @@ class AIAgent: # Check for x-openrouter-provider or similar metadata if provider_name == "Unknown" and response: # Log all response attributes for debugging - resp_attrs = {k: str(v)[:100] for k, v in vars(response).items() if not k.startswith('_')} + try: + if hasattr(response, "__dict__"): + _resp_dict = response.__dict__ + elif hasattr(response, "model_dump"): + _resp_dict = response.model_dump() + else: + _resp_dict = {} + resp_attrs = {k: str(v)[:100] for k, v in _resp_dict.items() if not k.startswith('_')} + except (TypeError, AttributeError): + resp_attrs = {} if self.verbose_logging: logging.debug(f"Response attributes for invalid response: {resp_attrs}") diff --git a/tests/run_agent/test_run_agent_codex_responses.py b/tests/run_agent/test_run_agent_codex_responses.py index 81213aaf673..4b4d13e8279 100644 --- a/tests/run_agent/test_run_agent_codex_responses.py +++ b/tests/run_agent/test_run_agent_codex_responses.py @@ -1310,3 +1310,39 @@ def test_preflight_codex_input_deduplicates_reasoning_ids(monkeypatch): # IDs must be stripped — with store=False the API 404s on id lookups. for it in reasoning_items: assert "id" not in it + + +# --------------------------------------------------------------------------- +# Issue #6133 — vars() on response objects that lack __dict__ raises TypeError. +# The fix must use a safe fallback (hasattr __dict__ / model_dump) instead. +# --------------------------------------------------------------------------- + + +def test_run_conversation_slots_response_does_not_raise(monkeypatch): + """Response objects that define __slots__ (and therefore have no __dict__) + must not crash the invalid-response debug logging path.""" + + class _SlotsResponse: + __slots__ = ("output", "output_text", "status") + + def __init__(self): + self.output = [] + self.output_text = None + self.status = "completed" + + agent = _build_agent(monkeypatch) + calls = {"n": 0} + + def _fake_api(api_kwargs): + calls["n"] += 1 + if calls["n"] == 1: + return _SlotsResponse() + return _codex_message_response("Recovered") + + monkeypatch.setattr(agent, "_interruptible_api_call", _fake_api) + + result = agent.run_conversation("ping") + + assert calls["n"] >= 2 + assert result["completed"] is True + assert result["final_response"] == "Recovered"