From d43cb9394a3c04db7cecd4f4eadb3506878af6a2 Mon Sep 17 00:00:00 2001 From: Kasper Date: Sun, 2 Nov 2025 11:32:21 +0100 Subject: [PATCH] refactor: improve logging and module structure Changed some folders to not be modules and organized some `__init__.py` files. ref: N25B-223 --- .vscode/settings.json | 7 - src/control_backend/agents/__init__.py | 4 + src/control_backend/agents/bdi/__init__.py | 2 + src/control_backend/agents/bdi/bdi_core.py | 14 +- .../agents/bdi/behaviours/__init__.py | 0 .../agents/bdi/behaviours/belief_setter.py | 48 ++++-- .../behaviours/receive_llm_resp_behaviour.py | 8 +- .../bdi/behaviours/text_belief_extractor.py | 22 ++- .../agents/bdi/text_extractor.py | 7 +- .../agents/belief_collector/__init__.py | 0 .../behaviours/continuous_collect.py | 51 ++---- src/control_backend/agents/llm/llm.py | 11 +- .../agents/mock_agents/__init__.py | 0 .../agents/ri_communication_agent.py | 4 +- .../agents/transcription/__init__.py | 2 - .../transcription/transcription_agent.py | 2 +- src/control_backend/agents/vad_agent.py | 2 +- src/control_backend/main.py | 149 +++++++++++------- 18 files changed, 179 insertions(+), 154 deletions(-) delete mode 100644 .vscode/settings.json delete mode 100644 src/control_backend/agents/bdi/behaviours/__init__.py delete mode 100644 src/control_backend/agents/belief_collector/__init__.py delete mode 100644 src/control_backend/agents/mock_agents/__init__.py delete mode 100644 src/control_backend/agents/transcription/__init__.py diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index b2b8866..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "python.testing.pytestArgs": [ - "test" - ], - "python.testing.unittestEnabled": false, - "python.testing.pytestEnabled": true -} \ No newline at end of file diff --git a/src/control_backend/agents/__init__.py b/src/control_backend/agents/__init__.py index e69de29..1d5ec09 100644 --- a/src/control_backend/agents/__init__.py +++ b/src/control_backend/agents/__init__.py @@ -0,0 +1,4 @@ +from .belief_collector.belief_collector import BeliefCollectorAgent +from .llm.llm import LLMAgent +from .ri_communication_agent import RICommunicationAgent +from .vad_agent import VADAgent \ No newline at end of file diff --git a/src/control_backend/agents/bdi/__init__.py b/src/control_backend/agents/bdi/__init__.py index e69de29..23135d6 100644 --- a/src/control_backend/agents/bdi/__init__.py +++ b/src/control_backend/agents/bdi/__init__.py @@ -0,0 +1,2 @@ +from .bdi_core import BDICoreAgent +from .text_extractor import TBeliefExtractorAgent \ No newline at end of file diff --git a/src/control_backend/agents/bdi/bdi_core.py b/src/control_backend/agents/bdi/bdi_core.py index 06c7b01..955a587 100644 --- a/src/control_backend/agents/bdi/bdi_core.py +++ b/src/control_backend/agents/bdi/bdi_core.py @@ -5,10 +5,8 @@ from spade.behaviour import OneShotBehaviour from spade.message import Message from spade_bdi.bdi import BDIAgent -from control_backend.agents.bdi.behaviours.belief_setter import BeliefSetterBehaviour -from control_backend.agents.bdi.behaviours.receive_llm_resp_behaviour import ( - ReceiveLLMResponseBehaviour, -) +from .behaviours.belief_setter import BeliefSetterBehaviour +from .behaviours.receive_llm_resp_behaviour import ReceiveLLMResponseBehaviour from control_backend.core.config import settings @@ -26,12 +24,12 @@ class BDICoreAgent(BDIAgent): """ Initializes belief behaviors and message routing. """ - self.logger.info("BDICoreAgent setup started") + self.logger.info("BDICoreAgent setup started.") self.add_behaviour(BeliefSetterBehaviour()) self.add_behaviour(ReceiveLLMResponseBehaviour()) - self.logger.info("BDICoreAgent setup complete") + self.logger.info("BDICoreAgent setup complete.") def add_custom_actions(self, actions) -> None: """ @@ -45,7 +43,7 @@ class BDICoreAgent(BDIAgent): Example: .reply("Hello LLM!") """ message_text = agentspeak.grounded(term.args[0], intention.scope) - self.logger.info("Reply action sending: %s", message_text) + self.logger.debug("Reply action sending: %s", message_text) self._send_to_llm(str(message_text)) yield @@ -63,6 +61,6 @@ class BDICoreAgent(BDIAgent): ) await self.send(msg) - self.agent.logger.info("Message sent to LLM: %s", text) + self.agent.logger.info("Message sent to LLM agent: %s", text) self.add_behaviour(SendBehaviour()) \ No newline at end of file diff --git a/src/control_backend/agents/bdi/behaviours/__init__.py b/src/control_backend/agents/bdi/behaviours/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/control_backend/agents/bdi/behaviours/belief_setter.py b/src/control_backend/agents/bdi/behaviours/belief_setter.py index 961288d..f0b1c14 100644 --- a/src/control_backend/agents/bdi/behaviours/belief_setter.py +++ b/src/control_backend/agents/bdi/behaviours/belief_setter.py @@ -3,7 +3,7 @@ import logging from spade.agent import Message from spade.behaviour import CyclicBehaviour -from spade_bdi.bdi import BDIAgent, BeliefNotInitiated +from spade_bdi.bdi import BDIAgent from control_backend.core.config import settings @@ -11,26 +11,32 @@ from control_backend.core.config import settings class BeliefSetterBehaviour(CyclicBehaviour): """ This is the behaviour that the BDI agent runs. This behaviour waits for incoming - message and processes it based on sender. + message and updates the agent's beliefs accordingly. """ agent: BDIAgent - logger = logging.getLogger("BDI/Belief Setter") + logger = logging.getLogger(__name__) async def run(self): - msg = await self.receive(timeout=0.1) - if msg: - self.logger.info(f"Received message {msg.body}") - self._process_message(msg) + """Polls for messages and processes them.""" + msg = await self.receive() + self.logger.debug( + "Received message from %s with thread '%s' and body: %s", + msg.sender, + msg.thread, + msg.body, + ) + self._process_message(msg) def _process_message(self, message: Message): + """Routes the message to the correct processing function based on the sender.""" sender = message.sender.node # removes host from jid and converts to str - self.logger.debug("Sender: %s", sender) + self.logger.debug("Processing message from sender: %s", sender) match sender: case settings.agent_settings.belief_collector_agent_name: - self.logger.debug("Processing message from belief collector.") + self.logger.debug("Message is from the belief collector agent. Processing as belief message.") self._process_belief_message(message) case _: self.logger.debug("Not the belief agent, discarding message") @@ -38,6 +44,7 @@ class BeliefSetterBehaviour(CyclicBehaviour): def _process_belief_message(self, message: Message): if not message.body: + self.logger.debug("Ignoring message with empty body from %s", message.sender.node) return match message.thread: @@ -45,22 +52,33 @@ class BeliefSetterBehaviour(CyclicBehaviour): try: beliefs: dict[str, list[str]] = json.loads(message.body) self._set_beliefs(beliefs) - except json.JSONDecodeError as e: - self.logger.error("Could not decode beliefs into JSON format: %s", e) + except json.JSONDecodeError: + self.logger.error( + "Could not decode beliefs from JSON. Message body: '%s'", + message.body, + exc_info=True + ) case _: pass def _set_beliefs(self, beliefs: dict[str, list[str]]): - """Remove previous values for beliefs and update them with the provided values.""" + """Removes previous values for beliefs and updates them with the provided values.""" if self.agent.bdi is None: - self.logger.warning("Cannot set beliefs, since agent's BDI is not yet initialized.") + self.logger.warning("Cannot set beliefs; agent's BDI is not yet initialized.") + return + + if not beliefs: + self.logger.debug("Received an empty set of beliefs. No beliefs were updated.") return # Set new beliefs (outdated beliefs are automatically removed) for belief, arguments in beliefs.items(): + self.logger.debug("Setting belief %s with arguments %s", belief, arguments) self.agent.bdi.set_belief(belief, *arguments) # Special case: if there's a new user message, flag that we haven't responded yet - if belief == "user_said": self.agent.bdi.set_belief("new_message") + if belief == "user_said": + self.agent.bdi.set_belief("new_message") + self.logger.debug("Detected 'user_said' belief, also setting 'new_message' belief.") - self.logger.info("Set belief %s with arguments %s", belief, arguments) + self.logger.info("Successfully updated %d beliefs.", len(beliefs)) \ No newline at end of file diff --git a/src/control_backend/agents/bdi/behaviours/receive_llm_resp_behaviour.py b/src/control_backend/agents/bdi/behaviours/receive_llm_resp_behaviour.py index 747ab4c..1def978 100644 --- a/src/control_backend/agents/bdi/behaviours/receive_llm_resp_behaviour.py +++ b/src/control_backend/agents/bdi/behaviours/receive_llm_resp_behaviour.py @@ -9,11 +9,9 @@ class ReceiveLLMResponseBehaviour(CyclicBehaviour): """ Adds behavior to receive responses from the LLM Agent. """ - logger = logging.getLogger("BDI/LLM Reciever") + logger = logging.getLogger(__name__) async def run(self): - msg = await self.receive(timeout=2) - if not msg: - return + msg = await self.receive() sender = msg.sender.node match sender: @@ -22,5 +20,5 @@ class ReceiveLLMResponseBehaviour(CyclicBehaviour): self.logger.info("Received LLM response: %s", content) #Here the BDI can pass the message back as a response case _: - self.logger.debug("Not from the llm, discarding message") + self.logger.debug("Discarding message from %s", sender) pass \ No newline at end of file diff --git a/src/control_backend/agents/bdi/behaviours/text_belief_extractor.py b/src/control_backend/agents/bdi/behaviours/text_belief_extractor.py index c75e66c..75f8841 100644 --- a/src/control_backend/agents/bdi/behaviours/text_belief_extractor.py +++ b/src/control_backend/agents/bdi/behaviours/text_belief_extractor.py @@ -37,17 +37,15 @@ class BeliefFromText(CyclicBehaviour): } async def run(self): - msg = await self.receive(timeout=0.1) - if msg: - sender = msg.sender.node - match sender: - case settings.agent_settings.transcription_agent_name: - self.logger.info("Received text from transcriber.") - await self._process_transcription_demo(msg.body) - case _: - self.logger.info("Received message from other agent.") - pass - await asyncio.sleep(1) + msg = await self.receive() + sender = msg.sender.node + match sender: + case settings.agent_settings.transcription_agent_name: + self.logger.debug("Received text from transcriber: %s", msg.body) + await self._process_transcription_demo(msg.body) + case _: + self.logger.info("Discarding message from %s", sender) + pass async def _process_transcription(self, text: str): text_prompt = f"Text: {text}" @@ -91,4 +89,4 @@ class BeliefFromText(CyclicBehaviour): belief_msg.thread = "beliefs" await self.send(belief_msg) - self.logger.info("Sent beliefs to Belief Collector.") + self.logger.info("Sent %d beliefs to the belief collector.", len(belief["beliefs"])) diff --git a/src/control_backend/agents/bdi/text_extractor.py b/src/control_backend/agents/bdi/text_extractor.py index 596a3fe..559dc71 100644 --- a/src/control_backend/agents/bdi/text_extractor.py +++ b/src/control_backend/agents/bdi/text_extractor.py @@ -1,9 +1,8 @@ from spade.agent import Agent -from control_backend.agents.bdi.behaviours.text_belief_extractor import BeliefFromText +from .behaviours.text_belief_extractor import BeliefFromText -class TBeliefExtractor(Agent): +class TBeliefExtractorAgent(Agent): async def setup(self): - self.b = BeliefFromText() - self.add_behaviour(self.b) \ No newline at end of file + self.add_behaviour(BeliefFromText()) \ No newline at end of file diff --git a/src/control_backend/agents/belief_collector/__init__.py b/src/control_backend/agents/belief_collector/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/control_backend/agents/belief_collector/behaviours/continuous_collect.py b/src/control_backend/agents/belief_collector/behaviours/continuous_collect.py index 5dcf59d..5dd7188 100644 --- a/src/control_backend/agents/belief_collector/behaviours/continuous_collect.py +++ b/src/control_backend/agents/belief_collector/behaviours/continuous_collect.py @@ -1,32 +1,32 @@ import json import logging +from json import JSONDecodeError + from spade.behaviour import CyclicBehaviour from spade.agent import Message from control_backend.core.config import settings -logger = logging.getLogger(__name__) - class ContinuousBeliefCollector(CyclicBehaviour): """ Continuously collects beliefs/emotions from extractor agents: Then we send a unified belief packet to the BDI agent. """ + logger = logging.getLogger(__name__) async def run(self): - msg = await self.receive(timeout=0.1) # Wait for 0.1s - if msg: - await self._process_message(msg) + msg = await self.receive() + await self._process_message(msg) async def _process_message(self, msg: Message): - sender_node = self._sender_node(msg) + sender_node = msg.sender.node # Parse JSON payload try: payload = json.loads(msg.body) - except Exception as e: - logger.warning( - "BeliefCollector: failed to parse JSON from %s. Body=%r Error=%s", + except JSONDecodeError as e: + self.logger.warning( + "Failed to parse JSON from %s. Body=%r Error=%s", sender_node, msg.body, e ) return @@ -35,27 +35,18 @@ class ContinuousBeliefCollector(CyclicBehaviour): # Prefer explicit 'type' field if msg_type == "belief_extraction_text" or sender_node == "belief_text_agent_mock": - logger.info("BeliefCollector: message routed to _handle_belief_text (sender=%s)", sender_node) + self.logger.debug("Message routed to _handle_belief_text (sender=%s)", sender_node) await self._handle_belief_text(payload, sender_node) #This is not implemented yet, but we keep the structure for future use elif msg_type == "emotion_extraction_text" or sender_node == "emo_text_agent_mock": - logger.info("BeliefCollector: message routed to _handle_emo_text (sender=%s)", sender_node) + self.logger.debug("Message routed to _handle_emo_text (sender=%s)", sender_node) await self._handle_emo_text(payload, sender_node) else: - logger.info( - "BeliefCollector: unrecognized message (sender=%s, type=%r). Ignoring.", + self.logger.warning( + "Unrecognized message (sender=%s, type=%r). Ignoring.", sender_node, msg_type ) - @staticmethod - def _sender_node(msg: Message) -> str: - """ - Extracts the 'node' (localpart) of the sender JID. - E.g., 'agent@host/resource' -> 'agent' - """ - s = str(msg.sender) if msg.sender is not None else "no_sender" - return s.split("@", 1)[0] if "@" in s else s - async def _handle_belief_text(self, payload: dict, origin: str): """ @@ -70,21 +61,13 @@ class ContinuousBeliefCollector(CyclicBehaviour): beliefs = payload.get("beliefs", {}) if not beliefs: - logger.info("BeliefCollector: no beliefs to process.") - return - - if not isinstance(beliefs, dict): - logger.warning("BeliefCollector: 'beliefs' is not a dict: %r", beliefs) - return - - if not all(isinstance(v, list) for v in beliefs.values()): - logger.warning("BeliefCollector: 'beliefs' values are not all lists: %r", beliefs) + self.logger.debug("Received empty beliefs set.") return - logger.info("BeliefCollector: forwarding %d beliefs.", len(beliefs)) + self.logger.debug("Forwarding %d beliefs.", len(beliefs)) for belief_name, belief_list in beliefs.items(): for belief in belief_list: - logger.info(" - %s %s", belief_name,str(belief)) + self.logger.debug(" - %s %s", belief_name,str(belief)) await self._send_beliefs_to_bdi(beliefs, origin=origin) @@ -109,4 +92,4 @@ class ContinuousBeliefCollector(CyclicBehaviour): await self.send(msg) - logger.info("BeliefCollector: sent %d belief(s) to BDI at %s", len(beliefs), to_jid) + self.logger.info("Sent %d belief(s) to BDI core.", len(beliefs)) diff --git a/src/control_backend/agents/llm/llm.py b/src/control_backend/agents/llm/llm.py index 0f78095..88036b7 100644 --- a/src/control_backend/agents/llm/llm.py +++ b/src/control_backend/agents/llm/llm.py @@ -11,7 +11,7 @@ from spade.agent import Agent from spade.behaviour import CyclicBehaviour from spade.message import Message -from control_backend.agents.llm.llm_instructions import LLMInstructions +from .llm_instructions import LLMInstructions from control_backend.core.config import settings @@ -35,12 +35,10 @@ class LLMAgent(Agent): Receives SPADE messages and processes only those originating from the configured BDI agent. """ - msg = await self.receive(timeout=1) - if not msg: - return + msg = await self.receive() sender = msg.sender.node - self.agent.logger.info( + self.agent.logger.debug( "Received message: %s from %s", msg.body, sender, @@ -121,7 +119,6 @@ class LLMAgent(Agent): Sets up the SPADE behaviour to filter and process messages from the BDI Core Agent. """ - self.logger.info("LLMAgent setup complete") - behaviour = self.ReceiveMessageBehaviour() self.add_behaviour(behaviour) + self.logger.info("LLMAgent setup complete") diff --git a/src/control_backend/agents/mock_agents/__init__.py b/src/control_backend/agents/mock_agents/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/control_backend/agents/ri_communication_agent.py b/src/control_backend/agents/ri_communication_agent.py index 504c707..2ae91a9 100644 --- a/src/control_backend/agents/ri_communication_agent.py +++ b/src/control_backend/agents/ri_communication_agent.py @@ -1,5 +1,4 @@ import asyncio -import json import logging from spade.agent import Agent from spade.behaviour import CyclicBehaviour @@ -7,8 +6,7 @@ import zmq from control_backend.core.config import settings from control_backend.core.zmq_context import context -from control_backend.schemas.message import Message -from control_backend.agents.ri_command_agent import RICommandAgent +from .ri_command_agent import RICommandAgent logger = logging.getLogger(__name__) diff --git a/src/control_backend/agents/transcription/__init__.py b/src/control_backend/agents/transcription/__init__.py deleted file mode 100644 index fd3c8c5..0000000 --- a/src/control_backend/agents/transcription/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .speech_recognizer import SpeechRecognizer as SpeechRecognizer -from .transcription_agent import TranscriptionAgent as TranscriptionAgent diff --git a/src/control_backend/agents/transcription/transcription_agent.py b/src/control_backend/agents/transcription/transcription_agent.py index a2c8e2b..fe5914e 100644 --- a/src/control_backend/agents/transcription/transcription_agent.py +++ b/src/control_backend/agents/transcription/transcription_agent.py @@ -8,7 +8,7 @@ from spade.agent import Agent from spade.behaviour import CyclicBehaviour from spade.message import Message -from control_backend.agents.transcription.speech_recognizer import SpeechRecognizer +from .speech_recognizer import SpeechRecognizer from control_backend.core.config import settings from control_backend.core.zmq_context import context as zmq_context diff --git a/src/control_backend/agents/vad_agent.py b/src/control_backend/agents/vad_agent.py index a228135..89c14c5 100644 --- a/src/control_backend/agents/vad_agent.py +++ b/src/control_backend/agents/vad_agent.py @@ -7,7 +7,7 @@ import zmq.asyncio as azmq from spade.agent import Agent from spade.behaviour import CyclicBehaviour -from control_backend.agents.transcription import TranscriptionAgent +from .transcription.transcription_agent import TranscriptionAgent from control_backend.core.config import settings from control_backend.core.zmq_context import context as zmq_context diff --git a/src/control_backend/main.py b/src/control_backend/main.py index 5f6a2f2..93b0d79 100644 --- a/src/control_backend/main.py +++ b/src/control_backend/main.py @@ -1,6 +1,3 @@ -# Standard library imports - -# External imports import contextlib import logging @@ -8,74 +5,116 @@ import zmq from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -from control_backend.agents.bdi.bdi_core import BDICoreAgent -from control_backend.agents.bdi.text_extractor import TBeliefExtractor -from control_backend.agents.belief_collector.belief_collector import BeliefCollectorAgent -from control_backend.agents.llm.llm import LLMAgent - -# Internal imports -from control_backend.agents.ri_communication_agent import RICommunicationAgent -from control_backend.agents.vad_agent import VADAgent +from control_backend.agents import ( + BeliefCollectorAgent, + LLMAgent, + RICommunicationAgent, + VADAgent, +) +from control_backend.agents.bdi import BDICoreAgent, TBeliefExtractorAgent from control_backend.api.v1.router import api_router from control_backend.core.config import settings from control_backend.core.zmq_context import context from control_backend.logging import setup_logging +logger = logging.getLogger(__name__) + @contextlib.asynccontextmanager async def lifespan(app: FastAPI): + """ + Application lifespan context manager to handle startup and shutdown events. + """ + # --- APPLICATION STARTUP --- setup_logging() - logger = logging.getLogger(__name__) + logger.info("%s is starting up.", app.title) - logger.info("%s starting up.", app.title) + # --- Initialize Sockets --- + logger.info("Initializing ZeroMQ sockets.") + try: + internal_comm_socket = context.socket(zmq.PUB) + internal_comm_address = settings.zmq_settings.internal_comm_address + logger.debug("Binding internal PUB socket to address: %s", internal_comm_address) + internal_comm_socket.bind(internal_comm_address) + app.state.internal_comm_socket = internal_comm_socket + logger.info("Internal communication socket bound successfully.") + except Exception as e: + logger.error("Failed to bind internal communication socket: %s", e, exc_info=True) + raise - # Initiate sockets - internal_comm_socket = context.socket(zmq.PUB) - internal_comm_address = settings.zmq_settings.internal_comm_address - internal_comm_socket.bind(internal_comm_address) - app.state.internal_comm_socket = internal_comm_socket - logger.info("Internal publishing socket bound to %s", internal_comm_socket) + # --- Initialize Agents --- + logger.info("Initializing and starting agents.") + agents_to_start = { + "RICommunicationAgent": ( + RICommunicationAgent, + { + "name": settings.agent_settings.ri_communication_agent_name, + "jid": f"{settings.agent_settings.ri_communication_agent_name}@{settings.agent_settings.host}", + "password": settings.agent_settings.ri_communication_agent_name, + "address": "tcp://*:5555", + "bind": True, + }, + ), + "LLMAgent": ( + LLMAgent, + { + "name": settings.agent_settings.llm_agent_name, + "jid": f"{settings.agent_settings.llm_agent_name}@{settings.agent_settings.host}", + "password": settings.agent_settings.llm_agent_name, + }, + ), + "BDICoreAgent": ( + BDICoreAgent, + { + "name": settings.agent_settings.bdi_core_agent_name, + "jid": f"{settings.agent_settings.bdi_core_agent_name}@{settings.agent_settings.host}", + "password": settings.agent_settings.bdi_core_agent_name, + "asl": "src/control_backend/agents/bdi/rules.asl", + }, + ), + "BeliefCollectorAgent": ( + BeliefCollectorAgent, + { + "name": settings.agent_settings.belief_collector_agent_name, + "jid": f"{settings.agent_settings.belief_collector_agent_name}@{settings.agent_settings.host}", + "password": settings.agent_settings.belief_collector_agent_name, + }, + ), + "TBeliefExtractor": ( + TBeliefExtractorAgent, + { + "name": settings.agent_settings.text_belief_extractor_agent_name, + "jid": f"{settings.agent_settings.text_belief_extractor_agent_name}@{settings.agent_settings.host}", + "password": settings.agent_settings.text_belief_extractor_agent_name, + }, + ), + "VADAgent": ( + VADAgent, + {"audio_in_address": "tcp://localhost:5558", "audio_in_bind": False}, + ), + } - # Initiate agents - ri_communication_agent = RICommunicationAgent( - settings.agent_settings.ri_communication_agent_name + "@" + settings.agent_settings.host, - settings.agent_settings.ri_communication_agent_name, - address="tcp://*:5555", - bind=True, - ) - await ri_communication_agent.start() + for name, (agent_class, kwargs) in agents_to_start.items(): + try: + logger.debug("Starting agent: %s", name) + agent_instance = agent_class(**{k: v for k, v in kwargs.items() if k != "name"}) + await agent_instance.start() + logger.info("Agent '%s' started successfully.", name) + except Exception as e: + logger.error("Failed to start agent '%s': %s", name, e, exc_info=True) + # Consider if the application should continue if an agent fails to start. + raise - llm_agent = LLMAgent( - settings.agent_settings.llm_agent_name + '@' + settings.agent_settings.host, - settings.agent_settings.llm_agent_name, - ) - await llm_agent.start() - - bdi_core = BDICoreAgent( - settings.agent_settings.bdi_core_agent_name + '@' + settings.agent_settings.host, - settings.agent_settings.bdi_core_agent_name, - "src/control_backend/agents/bdi/rules.asl", - ) - await bdi_core.start() - - belief_collector = BeliefCollectorAgent( - settings.agent_settings.belief_collector_agent_name + '@' + settings.agent_settings.host, - settings.agent_settings.belief_collector_agent_name, - ) - await belief_collector.start() - - text_belief_extractor = TBeliefExtractor( - settings.agent_settings.text_belief_extractor_agent_name + '@' + settings.agent_settings.host, - settings.agent_settings.text_belief_extractor_agent_name, - ) - await text_belief_extractor.start() - - _temp_vad_agent = VADAgent("tcp://localhost:5558", False) - await _temp_vad_agent.start() + logger.info("Application startup complete.") yield - logger.info("%s shutting down.", app.title) + # --- APPLICATION SHUTDOWN --- + logger.info("%s is shutting down.", app.title) + + # Potential shutdown logic goes here + + logger.info("Application shutdown complete.") # if __name__ == "__main__":