From 98d087417f54b35afd5efd18ffed39f3224dac3b Mon Sep 17 00:00:00 2001 From: Kasper Date: Fri, 21 Nov 2025 13:28:37 +0100 Subject: [PATCH] docs: document how to use agents ref: N25B-300 --- src/control_backend/agents/base.py | 3 ++- .../bdi/bdi_core_agent/bdi_core_agent.py | 12 ++++----- src/control_backend/core/agent_system.py | 27 +++++++++++++++++-- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/control_backend/agents/base.py b/src/control_backend/agents/base.py index 3960b51..389c894 100644 --- a/src/control_backend/agents/base.py +++ b/src/control_backend/agents/base.py @@ -5,7 +5,8 @@ from control_backend.core.agent_system import BaseAgent as CoreBaseAgent class BaseAgent(CoreBaseAgent): """ - Base agent class for our agents to inherit from. + Base agent class for our agents to inherit from. This just ensures + all agents have a logger. """ logger: logging.Logger diff --git a/src/control_backend/agents/bdi/bdi_core_agent/bdi_core_agent.py b/src/control_backend/agents/bdi/bdi_core_agent/bdi_core_agent.py index 73d187a..ccefb11 100644 --- a/src/control_backend/agents/bdi/bdi_core_agent/bdi_core_agent.py +++ b/src/control_backend/agents/bdi/bdi_core_agent/bdi_core_agent.py @@ -85,8 +85,6 @@ class BDICoreAgent(BaseAgent): new_args = (agentspeak.Literal(arg) for arg in args) term = agentspeak.Literal(name, new_args) - assert self.bdi_agent is not None - self.bdi_agent.call( agentspeak.Trigger.addition, agentspeak.GoalType.belief, @@ -102,8 +100,6 @@ class BDICoreAgent(BaseAgent): new_args = (agentspeak.Literal(arg) for arg in args) term = agentspeak.Literal(name, new_args) - assert self.bdi_agent is not None - result = self.bdi_agent.call( agentspeak.Trigger.removal, agentspeak.GoalType.belief, @@ -121,8 +117,6 @@ class BDICoreAgent(BaseAgent): """ Removes all beliefs that match the given `name`. """ - assert self.bdi_agent is not None - relevant_groups = [] for key in self.bdi_agent.beliefs: if key[0] == name: @@ -142,7 +136,11 @@ class BDICoreAgent(BaseAgent): self.logger.debug(f"Removed {removed_count} beliefs.") def _add_custom_actions(self) -> None: - """Add any custom actions here.""" + """ + Add any custom actions here. Inside `@self.actions.add()`, the first argument is + the name of the function in the ASL file, and the second the amount of arguments + the function expects (which will be located in `term.args`). + """ @self.actions.add(".reply", 1) def _reply(agent, term, intention): diff --git a/src/control_backend/core/agent_system.py b/src/control_backend/core/agent_system.py index 37ca9c8..e308b4c 100644 --- a/src/control_backend/core/agent_system.py +++ b/src/control_backend/core/agent_system.py @@ -9,6 +9,10 @@ _agent_directory: dict[str, "BaseAgent"] = {} @dataclass class InternalMessage: + """ + Represents a message to an agent. + """ + to: str sender: str body: str @@ -16,6 +20,11 @@ class InternalMessage: class AgentDirectory: + """ + Helper class to keep track of which agents are registered. + Used for handling message routing. + """ + @staticmethod def register(name: str, agent: "BaseAgent"): _agent_directory[name] = agent @@ -26,6 +35,17 @@ class AgentDirectory: class BaseAgent(ABC): + """ + Abstract base class for all agents. To make a new agent, inherit from + `control_backend.agents.BaseAgent`, not this class. That ensures that a + logger is present with the correct name pattern. + + When subclassing, the `setup()` method needs to be overwritten. To handle + messages from other agents, overwrite the `handle_message()` method. To + send messages to other agents, use the `send()` method. To add custom + behaviors/tasks to the agent, use the `add_background_task()` method. + """ + logger: logging.Logger def __init__(self, name: str): @@ -39,7 +59,7 @@ class BaseAgent(ABC): @abstractmethod async def setup(self): - """Override this to initialize resources.""" + """Overwrite this to initialize resources.""" pass async def start(self): @@ -59,6 +79,9 @@ class BaseAgent(ABC): self.logger.info(f"Agent {self.name} stopped") async def send(self, message: InternalMessage): + """ + Sends a message to another agent. + """ target = AgentDirectory.get(message.to) if target: await target.inbox.put(message) @@ -76,7 +99,7 @@ class BaseAgent(ABC): raise NotImplementedError async def add_background_task(self, coro): - """Helper to run cyclic behaviors.""" + """Helper to add a behavior to the agent.""" task = asyncio.create_task(coro) self._tasks.add(task) task.add_done_callback(self._tasks.discard)