mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-09 08:21:50 +00:00
fix(agent): import SimpleNamespace for hook payload sanitization
_hook_jsonable() referenced SimpleNamespace without importing it, so sanitizing any hook payload that contained one raised NameError: name 'SimpleNamespace' is not defined. Bedrock, Codex-responses, and the auxiliary client build their response / message / tool_call objects as SimpleNamespace and hand the raw objects to the post_api_request hook. The hook call sites swallow exceptions (except Exception: pass), so the crash silently dropped the observability hook for those providers. Add the missing `from types import SimpleNamespace` and a regression test covering the SimpleNamespace sanitization path.
This commit is contained in:
parent
bb53edc773
commit
40cea4d58d
2 changed files with 47 additions and 0 deletions
|
|
@ -60,6 +60,7 @@ from typing import List, Dict, Any, Optional
|
|||
# ModuleNotFoundError on broken/partial installs where `fire` isn't present.
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
from hermes_constants import get_hermes_home
|
||||
|
||||
|
|
|
|||
|
|
@ -4545,6 +4545,52 @@ class TestRunConversation:
|
|||
)
|
||||
|
||||
|
||||
class TestHookPayloadSanitizesSimpleNamespace:
|
||||
"""Regression: ``_hook_jsonable`` referenced ``SimpleNamespace`` without
|
||||
importing it, so sanitizing any hook payload that contained one raised
|
||||
``NameError: name 'SimpleNamespace' is not defined``.
|
||||
|
||||
The non-OpenAI providers (Bedrock, Codex responses, the auxiliary client,
|
||||
and the chat-completion stream stub) build their response / message /
|
||||
tool_call objects as ``types.SimpleNamespace`` — see
|
||||
``agent/bedrock_adapter.py``, ``agent/codex_responses_adapter.py``, and
|
||||
``agent/auxiliary_client.py``. Those raw objects are handed straight to
|
||||
``_api_response_payload_for_hook`` for the ``post_api_request`` hook, so the
|
||||
crash silently killed observability hooks for every one of those providers
|
||||
(the call sites swallow the exception with ``except Exception: pass``).
|
||||
"""
|
||||
|
||||
def test_hook_jsonable_normalizes_simplenamespace(self):
|
||||
ns = SimpleNamespace(id="call_1", value=42, nested=SimpleNamespace(name="x"))
|
||||
result = AIAgent._sanitize_hook_payload(ns)
|
||||
assert result == {"id": "call_1", "value": 42, "nested": {"name": "x"}}
|
||||
|
||||
def test_api_response_payload_for_hook_normalizes_simplenamespace_tool_calls(self, agent):
|
||||
# Shape mirrors agent/bedrock_adapter.py::normalize_converse_response and
|
||||
# agent/codex_responses_adapter.py — raw SDK objects are SimpleNamespace.
|
||||
tool_call = SimpleNamespace(
|
||||
id="call_1",
|
||||
type="function",
|
||||
function=SimpleNamespace(name="web_search", arguments='{"q": "hi"}'),
|
||||
)
|
||||
assistant_message = SimpleNamespace(
|
||||
role="assistant",
|
||||
content="",
|
||||
tool_calls=[tool_call],
|
||||
)
|
||||
response = SimpleNamespace(model="anthropic.claude-3", usage=None)
|
||||
|
||||
payload = agent._api_response_payload_for_hook(
|
||||
response, assistant_message, finish_reason="tool_calls"
|
||||
)
|
||||
|
||||
assert payload["model"] == "anthropic.claude-3"
|
||||
assert payload["finish_reason"] == "tool_calls"
|
||||
normalized_call = payload["assistant_message"]["tool_calls"][0]
|
||||
assert normalized_call["id"] == "call_1"
|
||||
assert normalized_call["function"]["name"] == "web_search"
|
||||
|
||||
|
||||
class TestRetryExhaustion:
|
||||
"""Regression: retry_count > max_retries was dead code (off-by-one).
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue