mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-29 06:31:32 +00:00
fix(run_agent): use safe attribute extraction instead of vars() on response objects
vars() raises TypeError on objects that don't expose __dict__ — this includes pydantic v2 models and certain OpenAI SDK response types. The crash occurred in the debug logging path when provider detection fell back to scanning response attributes. Replace vars(response) with a three-way fallback: check __dict__ first, then model_dump() for pydantic models, then an empty dict, wrapped in a try/except for any remaining edge cases. Fixes #6133
This commit is contained in:
parent
a521005fe5
commit
c1191e78cb
2 changed files with 46 additions and 1 deletions
11
run_agent.py
11
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}")
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue