Compare commits

...

6 Commits

Author SHA1 Message Date
Pim Hutting
08812371fd chore: applied feedback and merged dev into branch
ref: N25B-355
2026-01-02 16:08:13 +01:00
Pim Hutting
6cf25cc587 Merge remote-tracking branch 'origin/dev' into feat/program-reset-llm 2026-01-02 16:06:14 +01:00
Pim Hutting
fb276133d9 chore: removed comment that was no longer needed
ref: N25B-355
2025-12-15 18:43:23 +01:00
Pim Hutting
35548f6864 chore: fixed test that wasn't passing
this was not my test
I stole the fix from Björn's cb2ri-gestures

ref: N25B-355
2025-12-15 18:40:24 +01:00
Pim Hutting
06503d568f Merge branch 'dev' of git.science.uu.nl:ics/sp/2025/n25b/pepperplus-cb into feat/program-reset-llm 2025-12-15 18:02:24 +01:00
Pim Hutting
cd0ca77af9 feat: made program reset LLM
also added test_bdi_program_manager back cause
it was somehow missing in my files

ref: N25B-355
2025-12-15 17:57:38 +01:00
4 changed files with 65 additions and 2 deletions

View File

@@ -60,24 +60,41 @@ class BDIProgramManager(BaseAgent):
await self.send(message) await self.send(message)
self.logger.debug("Sent new norms and goals to the BDI agent.") self.logger.debug("Sent new norms and goals to the BDI agent.")
async def _send_clear_llm_history(self):
"""
Clear the LLM Agent's conversation history.
Sends a message to the LLM Agent instructing it to clear its history.
"""
message = InternalMessage(
to=settings.agent_settings.llm_name,
sender=self.name,
body="clear_history",
threads="clear history message",
)
await self.send(message)
self.logger.debug("Sent message to LLM agent to clear history.")
async def _receive_programs(self): async def _receive_programs(self):
""" """
Continuous loop that receives program updates from the HTTP endpoint. Continuous loop that receives program updates from the HTTP endpoint.
It listens to the ``program`` topic on the internal ZMQ SUB socket. It listens to the ``program`` topic on the internal ZMQ SUB socket.
When a program is received, it is validated and forwarded to BDI via :meth:`_send_to_bdi`. When a program is received, it is validated and forwarded to BDI via :meth:`_send_to_bdi`.
Additionally, the LLM history is cleared via :meth:`_send_clear_llm_history`.
""" """
while True: while True:
topic, body = await self.sub_socket.recv_multipart() topic, body = await self.sub_socket.recv_multipart()
try: try:
program = Program.model_validate_json(body) program = Program.model_validate_json(body)
await self._send_to_bdi(program)
await self._send_clear_llm_history()
except ValidationError: except ValidationError:
self.logger.exception("Received an invalid program.") self.logger.exception("Received an invalid program.")
continue continue
await self._send_to_bdi(program)
async def setup(self): async def setup(self):
""" """
Initialize the agent. Initialize the agent.

View File

@@ -52,6 +52,10 @@ class LLMAgent(BaseAgent):
await self._process_bdi_message(prompt_message) await self._process_bdi_message(prompt_message)
except ValidationError: except ValidationError:
self.logger.debug("Prompt message from BDI core is invalid.") self.logger.debug("Prompt message from BDI core is invalid.")
elif msg.sender == settings.agent_settings.bdi_program_manager_name:
if msg.body == "clear_history":
self.logger.debug("Clearing conversation history.")
self.history.clear()
else: else:
self.logger.debug("Message ignored (not from BDI core.") self.logger.debug("Message ignored (not from BDI core.")

View File

@@ -63,6 +63,7 @@ async def test_receive_programs_valid_and_invalid():
manager = BDIProgramManager(name="program_manager_test") manager = BDIProgramManager(name="program_manager_test")
manager.sub_socket = sub manager.sub_socket = sub
manager._send_to_bdi = AsyncMock() manager._send_to_bdi = AsyncMock()
manager._send_clear_llm_history = AsyncMock()
try: try:
# Will give StopAsyncIteration when the predefined `sub.recv_multipart` side-effects run out # Will give StopAsyncIteration when the predefined `sub.recv_multipart` side-effects run out
@@ -75,3 +76,24 @@ async def test_receive_programs_valid_and_invalid():
forwarded: Program = manager._send_to_bdi.await_args[0][0] forwarded: Program = manager._send_to_bdi.await_args[0][0]
assert forwarded.phases[0].norms[0].norm == "N1" assert forwarded.phases[0].norms[0].norm == "N1"
assert forwarded.phases[0].goals[0].description == "G1" assert forwarded.phases[0].goals[0].description == "G1"
# Verify history clear was triggered
assert manager._send_clear_llm_history.await_count == 1
@pytest.mark.asyncio
async def test_send_clear_llm_history(mock_settings):
# Ensure the mock returns a string for the agent name (just like in your LLM tests)
mock_settings.agent_settings.llm_agent_name = "llm_agent"
manager = BDIProgramManager(name="program_manager_test")
manager.send = AsyncMock()
await manager._send_clear_llm_history()
assert manager.send.await_count == 1
msg: InternalMessage = manager.send.await_args[0][0]
# Verify the content and recipient
assert msg.body == "clear_history"
assert msg.to == "llm_agent"

View File

@@ -265,3 +265,23 @@ async def test_stream_query_llm_skips_non_data_lines(mock_httpx_client, mock_set
# Only the valid 'data:' line should yield content # Only the valid 'data:' line should yield content
assert tokens == ["Hi"] assert tokens == ["Hi"]
@pytest.mark.asyncio
async def test_clear_history_command(mock_settings):
"""Test that the 'clear_history' message clears the agent's memory."""
# setup LLM to have some history
mock_settings.agent_settings.bdi_program_manager_name = "bdi_program_manager_agent"
agent = LLMAgent("llm_agent")
agent.history = [
{"role": "user", "content": "Old conversation context"},
{"role": "assistant", "content": "Old response"},
]
assert len(agent.history) == 2
msg = InternalMessage(
to="llm_agent",
sender=mock_settings.agent_settings.bdi_program_manager_name,
body="clear_history",
)
await agent.handle_message(msg)
assert len(agent.history) == 0