From 041fc4ab6e01183512345d83887e9df5e4d58c17 Mon Sep 17 00:00:00 2001
From: Pim Hutting
Date: Thu, 15 Jan 2026 09:02:52 +0100
Subject: [PATCH] chore: cond_norms unachieve and via belief msg
---
.../user_interrupt/user_interrupt_agent.py | 140 ++++++++++--------
1 file changed, 80 insertions(+), 60 deletions(-)
diff --git a/src/control_backend/agents/user_interrupt/user_interrupt_agent.py b/src/control_backend/agents/user_interrupt/user_interrupt_agent.py
index deddbba..0bde563 100644
--- a/src/control_backend/agents/user_interrupt/user_interrupt_agent.py
+++ b/src/control_backend/agents/user_interrupt/user_interrupt_agent.py
@@ -26,7 +26,7 @@ class UserInterruptAgent(BaseAgent):
- Send a prioritized message to the `RobotSpeechAgent`
- Send a prioritized gesture to the `RobotGestureAgent`
- - Send a belief override to the `BDIProgramManager`in order to activate a
+ - Send a belief override to the `BDI Core` in order to activate a
trigger/conditional norm or complete a goal.
Prioritized actions clear the current RI queue before inserting the new item,
@@ -75,7 +75,9 @@ class UserInterruptAgent(BaseAgent):
These are the different types and contexts:
- type: "speech", context: string that the robot has to say.
- type: "gesture", context: single gesture name that the robot has to perform.
- - type: "override", context: belief_id that overrides the goal/trigger/conditional norm.
+ - type: "override", context: id that belongs to the goal/trigger/conditional norm.
+ - type: "override_unachieve", context: id that belongs to the conditional norm to unachieve.
+ - type: "next_phase", context: None, indicates to the BDI Core to
- type: "pause", context: boolean indicating whether to pause
- type: "reset_phase", context: None, indicates to the BDI Core to
- type: "reset_experiment", context: None, indicates to the BDI Core to
@@ -93,68 +95,82 @@ class UserInterruptAgent(BaseAgent):
self.logger.debug("Received event type %s", event_type)
- if event_type == "speech":
- await self._send_to_speech_agent(event_context)
- self.logger.info(
- "Forwarded button press (speech) with context '%s' to RobotSpeechAgent.",
- event_context,
- )
- elif event_type == "gesture":
- await self._send_to_gesture_agent(event_context)
- self.logger.info(
- "Forwarded button press (gesture) with context '%s' to RobotGestureAgent.",
- event_context,
- )
- elif event_type == "override":
- ui_id = str(event_context)
- if asl_trigger := self._trigger_map.get(ui_id):
- await self._send_to_bdi("force_trigger", asl_trigger)
+ match event_type:
+ case "speech":
+ await self._send_to_speech_agent(event_context)
self.logger.info(
- "Forwarded button press (override) with context '%s' to BDI Core.",
+ "Forwarded button press (speech) with context '%s' to RobotSpeechAgent.",
event_context,
)
- elif asl_cond_norm := self._cond_norm_map.get(ui_id):
- await self._send_to_bdi("force_norm", asl_cond_norm)
+ case "gesture":
+ await self._send_to_gesture_agent(event_context)
self.logger.info(
- "Forwarded button press (override) with context '%s' to BDIProgramManager.",
+ "Forwarded button press (gesture) with context '%s' to RobotGestureAgent.",
event_context,
)
- elif asl_goal := self._goal_map.get(ui_id):
- await self._send_to_bdi_belief(asl_goal)
- self.logger.info(
- "Forwarded button press (override) with context '%s' to BDI Core.",
+ case "override":
+ ui_id = str(event_context)
+ if asl_trigger := self._trigger_map.get(ui_id):
+ await self._send_to_bdi("force_trigger", asl_trigger)
+ self.logger.info(
+ "Forwarded button press (override) with context '%s' to BDI Core.",
+ event_context,
+ )
+ elif asl_cond_norm := self._cond_norm_map.get(ui_id):
+ await self._send_to_bdi_belief(asl_cond_norm)
+ self.logger.info(
+ "Forwarded button press (override) with context '%s' to BDI Core.",
+ event_context,
+ )
+ elif asl_goal := self._goal_map.get(ui_id):
+ await self._send_to_bdi_belief(asl_goal)
+ self.logger.info(
+ "Forwarded button press (override) with context '%s' to BDI Core.",
+ event_context,
+ )
+ # Send achieve_goal to program manager to update semantic belief extractor
+ goal_achieve_msg = InternalMessage(
+ to=settings.agent_settings.bdi_program_manager_name,
+ thread="achieve_goal",
+ body=ui_id,
+ )
+
+ await self.send(goal_achieve_msg)
+ else:
+ self.logger.warning("Could not determine which element to override.")
+ case "override_unachieve":
+ ui_id = str(event_context)
+ if asl_cond_norm := self._cond_norm_map.get(ui_id):
+ await self._send_to_bdi_belief(asl_cond_norm, True)
+ self.logger.info(
+ "Forwarded button press (override_unachieve)"
+ "with context '%s' to BDI Core.",
+ event_context,
+ )
+ else:
+ self.logger.warning(
+ "Could not determine which conditional norm to unachieve."
+ )
+
+ case "pause":
+ self.logger.debug(
+ "Received pause/resume button press with context '%s'.", event_context
+ )
+ await self._send_pause_command(event_context)
+ if event_context:
+ self.logger.info("Sent pause command.")
+ else:
+ self.logger.info("Sent resume command.")
+
+ case "next_phase" | "reset_phase" | "reset_experiment":
+ await self._send_experiment_control_to_bdi_core(event_type)
+ case _:
+ self.logger.warning(
+ "Received button press with unknown type '%s' (context: '%s').",
+ event_type,
event_context,
)
- goal_achieve_msg = InternalMessage(
- to=settings.agent_settings.bdi_program_manager_name,
- thread="achieve_goal",
- body=ui_id,
- )
-
- await self.send(goal_achieve_msg)
- else:
- self.logger.warning("Could not determine which element to override.")
-
- elif event_type == "pause":
- self.logger.debug(
- "Received pause/resume button press with context '%s'.", event_context
- )
- await self._send_pause_command(event_context)
- if event_context:
- self.logger.info("Sent pause command.")
- else:
- self.logger.info("Sent resume command.")
-
- elif event_type in ["next_phase", "reset_phase", "reset_experiment"]:
- await self._send_experiment_control_to_bdi_core(event_type)
- else:
- self.logger.warning(
- "Received button press with unknown type '%s' (context: '%s').",
- event_type,
- event_context,
- )
-
async def handle_message(self, msg: InternalMessage):
"""
Handle commands received from other internal Python agents.
@@ -195,9 +211,10 @@ class UserInterruptAgent(BaseAgent):
await self._send_experiment_update(payload)
self.logger.info(f"UI Update: Goal {goal_name} started (ID: {ui_id})")
case "active_norms_update":
- norm_list = [s.strip("() '\",") for s in msg.body.split(",") if s.strip("() '\",")]
-
- await self._broadcast_cond_norms(norm_list)
+ active_norms_asl = [
+ s.strip("() '\",") for s in msg.body.split(",") if s.strip("() '\",")
+ ]
+ await self._broadcast_cond_norms(active_norms_asl)
case _:
self.logger.debug(f"Received internal message on unhandled thread: {msg.thread}")
@@ -308,12 +325,15 @@ class UserInterruptAgent(BaseAgent):
await self.send(msg)
self.logger.info(f"Directly forced {thread} in BDI: {body}")
- async def _send_to_bdi_belief(self, asl_goal: str):
+ async def _send_to_bdi_belief(self, asl_goal: str, unachieve: bool = False):
"""Send belief to BDI Core"""
belief_name = f"achieved_{asl_goal}"
belief = Belief(name=belief_name, arguments=None)
self.logger.debug(f"Sending belief to BDI Core: {belief_name}")
- belief_message = BeliefMessage(create=[belief])
+ # Conditional norms are unachieved by removing the belief
+ belief_message = (
+ BeliefMessage(delete=[belief]) if unachieve else BeliefMessage(create=[belief])
+ )
msg = InternalMessage(
to=settings.agent_settings.bdi_core_name,
thread="beliefs",