feat: pydantic models and inter-process messaging

Moved `InternalMessage` into schemas and created a `BeliefMessage`
model. Also added the ability for agents to communicate via ZMQ to
agents on another process.

ref: N25B-316
This commit is contained in:
2025-11-24 14:03:34 +01:00
parent 47a20413c4
commit ef00c03ec5
9 changed files with 113 additions and 37 deletions

View File

@@ -1,10 +1,13 @@
import json
from unittest.mock import AsyncMock, MagicMock, mock_open, patch
import agentspeak
import pytest
from control_backend.agents.bdi.bdi_core_agent.bdi_core_agent import BDICoreAgent
from control_backend.core.agent_system import InternalMessage
from control_backend.core.config import settings
from control_backend.schemas.belief_message import BeliefMessage
@pytest.fixture
@@ -40,23 +43,43 @@ async def test_setup_no_asl(mock_agentspeak_env, agent):
@pytest.mark.asyncio
async def test_handle_belief_collector_message(agent):
async def test_handle_belief_collector_message(agent, mock_settings):
"""Test that incoming beliefs are added to the BDI agent"""
# Simulate message from belief collector
import json
beliefs = {"user_said": ["Hello"]}
msg = InternalMessage(
to="bdi_agent",
sender=settings.agent_settings.bdi_belief_collector_name,
body=json.dumps(beliefs),
sender=mock_settings.agent_settings.bdi_belief_collector_name,
body=BeliefMessage(beliefs=beliefs).model_dump_json(),
thread="beliefs",
)
await agent.handle_message(msg)
# Expect bdi_agent.call to be triggered to add belief
assert agent.bdi_agent.call.called
args = agent.bdi_agent.call.call_args.args
assert args[0] == agentspeak.Trigger.addition
assert args[1] == agentspeak.GoalType.belief
assert args[2] == agentspeak.Literal("user_said", (agentspeak.Literal("Hello"),))
@pytest.mark.asyncio
async def test_incorrect_belief_collector_message(agent, mock_settings):
"""Test that incorrect message format triggers an exception."""
msg = InternalMessage(
to="bdi_agent",
sender=mock_settings.agent_settings.bdi_belief_collector_name,
body=json.dumps({"bad_format": "bad_format"}),
thread="beliefs",
)
await agent.handle_message(msg)
agent.bdi_agent.call.assert_not_called() # did not set belief
@pytest.mark.asyncio
async def test():
pass
@pytest.mark.asyncio

View File

@@ -84,4 +84,4 @@ async def test_send_beliefs_to_bdi(agent):
sent: InternalMessage = agent.send.call_args.args[0]
assert sent.to == settings.agent_settings.bdi_core_name
assert sent.thread == "beliefs"
assert json.loads(sent.body) == beliefs
assert json.loads(sent.body)["beliefs"] == beliefs

View File

@@ -2,6 +2,7 @@
import asyncio
import logging
from unittest.mock import AsyncMock
import pytest
@@ -39,7 +40,7 @@ async def test_agent_lifecycle():
# Wait for task to finish
await asyncio.sleep(0.02)
assert len(agent._tasks) == 1 # _process_inbox is still running
assert len(agent._tasks) == 2 # message handling tasks are running
await agent.stop()
assert agent._running is False
@@ -51,14 +52,15 @@ async def test_agent_lifecycle():
@pytest.mark.asyncio
async def test_send_unknown_agent(caplog):
async def test_send_unknown_agent():
agent = ConcreteTestAgent("sender")
msg = InternalMessage(to="unknown_sender", sender="sender", body="boo")
msg = InternalMessage(to="unknown_receiver", sender="sender", body="boo")
with caplog.at_level(logging.WARNING):
await agent.send(msg)
agent._internal_pub_socket = AsyncMock()
assert "Attempted to send message to unknown agent: unknown_sender" in caplog.text
await agent.send(msg)
agent._internal_pub_socket.send_multipart.assert_called()
@pytest.mark.asyncio