aboutsummaryrefslogtreecommitdiff
path: root/agent/orchestrator/matrix_bot.py
diff options
context:
space:
mode:
Diffstat (limited to 'agent/orchestrator/matrix_bot.py')
-rw-r--r--agent/orchestrator/matrix_bot.py76
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()