diff options
Diffstat (limited to 'agent/orchestrator/matrix_bot.py')
| -rw-r--r-- | agent/orchestrator/matrix_bot.py | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/agent/orchestrator/matrix_bot.py b/agent/orchestrator/matrix_bot.py new file mode 100644 index 0000000..30c23f1 --- /dev/null +++ b/agent/orchestrator/matrix_bot.py @@ -0,0 +1,76 @@ +"""Matrix bot adapter for Sénia. + +Runs as a long-lived asyncio task alongside the API server. Watches one room, +forwards messages to `handle_turn`, posts the reply back. +""" + +import asyncio +import logging +import os +from collections import deque + +from nio import AsyncClient, MatrixRoom, RoomMessageText + +from .loop import handle_turn +from .models import Message + + +log = logging.getLogger(__name__) + +HOMESERVER = os.environ.get("MATRIX_HOMESERVER", "https://beep.volfaria.xyz") +USER_ID = os.environ.get("MATRIX_USER_ID", "@senia:beep.volfaria.xyz") +TOKEN = os.environ["MATRIX_TOKEN"] +ROOM = os.environ.get("MATRIX_ROOM", "#senia:beep.volfaria.xyz") +SENIA_NAME = "Sénia" +HISTORY_LEN = 30 + + +class MatrixBot: + def __init__(self): + self.client = AsyncClient(HOMESERVER, USER_ID) + self.history: deque[Message] = deque(maxlen=HISTORY_LEN) + self._room_id: str | None = None + + async def start(self): + whoami = await self.client.whoami() + self.client.restore_login( + user_id=USER_ID, device_id=whoami.device_id, access_token=TOKEN + ) + + self._room_id = await self._resolve_room(ROOM) + await self.client.join(self._room_id) + + self.client.add_event_callback(self._on_message, RoomMessageText) + log.info("Sénia matrix bot connected, watching %s", self._room_id) + await self.client.sync_forever(timeout=30000, full_state=True) + + async def _resolve_room(self, room: str) -> str: + if room.startswith("!"): + return room + resp = await self.client.room_resolve_alias(room) + return resp.room_id + + async def _on_message(self, room: MatrixRoom, event: RoomMessageText): + if event.sender == self.client.user_id or room.room_id != self._room_id: + return + + sender_name = room.user_name(event.sender) or event.sender + self.history.append(Message(role="user", content=event.body, name=sender_name)) + + try: + reply = await asyncio.to_thread(handle_turn, list(self.history), sender_name) + except Exception: + log.exception("handle_turn failed") + return + + self.history.append(Message(role="assistant", content=reply, name=SENIA_NAME)) + await self.client.room_send( + room_id=self._room_id, + message_type="m.room.message", + content={"msgtype": "m.text", "body": reply}, + ) + + +async def run(): + bot = MatrixBot() + await bot.start() |
