From e85d30af5ce2de0d05665e52d5e8c1dad074e726 Mon Sep 17 00:00:00 2001 From: Arnau Gris Date: Tue, 15 Sep 2026 08:41:51 +0200 Subject: [PATCH 1/2] Fix JSON serialization of contexts in external postprocessors --- .../external/src/hyperforge_external/agent.py | 2 +- agents/external/tests/test_external.py | 55 ++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/agents/external/src/hyperforge_external/agent.py b/agents/external/src/hyperforge_external/agent.py index 4d9e8d3f..c0aa93e8 100644 --- a/agents/external/src/hyperforge_external/agent.py +++ b/agents/external/src/hyperforge_external/agent.py @@ -94,7 +94,7 @@ async def __call__( request = client.build_request( method=self.config.method.value, url=self.config.url, - json=memory.contexts, + json=[context.model_dump(mode="json") for context in memory.contexts], headers=self.config.headers, ) else: diff --git a/agents/external/tests/test_external.py b/agents/external/tests/test_external.py index a44555ab..afdc6711 100644 --- a/agents/external/tests/test_external.py +++ b/agents/external/tests/test_external.py @@ -1,10 +1,16 @@ +import json import os -from unittest.mock import AsyncMock +from types import SimpleNamespace +from unittest.mock import AsyncMock, MagicMock import httpx import pytest from hyperforge.engine import main as arag_main from hyperforge.minimal_fixtures import cassette_nua_key +from hyperforge.models import Context + +from hyperforge_external.agent import ExternalCallAgent +from hyperforge_external.config import ExternalCallAgentConfig NUA_KEY = os.environ.get( "NUA_KEY", @@ -66,7 +72,7 @@ async def test_external(mocker): mock_client.__aexit__ = AsyncMock(return_value=None) mocker.patch( - "hyperforge.utils.http.safe_http_client", + "hyperforge_external.agent.safe_http_client", return_value=mock_client, ) @@ -89,3 +95,48 @@ async def test_external(mocker): or "Peugeot" in question_memory.steps[-2].reason ) assert mock_client.send.called + + +@pytest.mark.asyncio +async def test_external_with_context_payload(mocker): + config = ExternalCallAgentConfig( + context=True, + url="https://example.com/aaa", + ) + external_agent = ExternalCallAgent(config) + memory = SimpleNamespace( + original_question="Question", + final_answer="Answer", + contexts=[ + Context( + original_question_uuid=None, + actual_question_uuid=None, + question="Question", + source="static", + agent="static", + ) + ], + contexts_minimal=lambda: "Context", + add_step=AsyncMock(), + ) + + mock_response = httpx.Response( + 200, + content=b"oki doki", + request=httpx.Request("POST", config.url), + ) + mock_client = MagicMock() + mock_client.build_request.side_effect = httpx.Request + mock_client.send = AsyncMock(return_value=mock_response) + mock_client.__aenter__ = AsyncMock(return_value=mock_client) + mock_client.__aexit__ = AsyncMock(return_value=None) + mocker.patch( + "hyperforge_external.agent.safe_http_client", + return_value=mock_client, + ) + + await external_agent(memory, manager=None) + + request = mock_client.send.call_args.args[0] + assert request.headers["content-type"] == "application/json" + assert json.loads(request.content)[0]["source"] == "static" From 341294bcb3722047b12d3fed29c95ea083b92ff6 Mon Sep 17 00:00:00 2001 From: Arnau Gris Date: Tue, 15 Sep 2026 08:46:47 +0200 Subject: [PATCH 2/2] fix lint --- agents/external/src/hyperforge_external/agent.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/agents/external/src/hyperforge_external/agent.py b/agents/external/src/hyperforge_external/agent.py index c0aa93e8..f8481aa0 100644 --- a/agents/external/src/hyperforge_external/agent.py +++ b/agents/external/src/hyperforge_external/agent.py @@ -94,7 +94,9 @@ async def __call__( request = client.build_request( method=self.config.method.value, url=self.config.url, - json=[context.model_dump(mode="json") for context in memory.contexts], + json=[ + context.model_dump(mode="json") for context in memory.contexts + ], headers=self.config.headers, ) else: