feat(01-03): remove Matrix reaction confirmation flow

- drop reaction event handling from Matrix bot
- render OutgoingUI as text with !yes/!no instructions
- persist pending confirmations when UI buttons are sent
This commit is contained in:
Mikhail Putilovskij 2026-04-02 22:55:24 +03:00
parent 4636b359e2
commit 8a6a33a2ce

View file

@ -11,16 +11,16 @@ from nio import (
AsyncClientConfig, AsyncClientConfig,
InviteMemberEvent, InviteMemberEvent,
MatrixRoom, MatrixRoom,
ReactionEvent,
RoomMemberEvent, RoomMemberEvent,
RoomMessageText, RoomMessageText,
) )
from dotenv import load_dotenv from dotenv import load_dotenv
from adapter.matrix.converter import from_reaction, from_room_event from adapter.matrix.converter import from_room_event
from adapter.matrix.handlers import register_matrix_handlers from adapter.matrix.handlers import register_matrix_handlers
from adapter.matrix.handlers.auth import handle_invite from adapter.matrix.handlers.auth import handle_invite
from adapter.matrix.room_router import resolve_chat_id from adapter.matrix.room_router import resolve_chat_id
from adapter.matrix.store import set_pending_confirm
from core.auth import AuthManager from core.auth import AuthManager
from core.chat import ChatManager from core.chat import ChatManager
from core.handler import EventDispatcher from core.handler import EventDispatcher
@ -103,16 +103,6 @@ class MatrixBot:
outgoing = await self.runtime.dispatcher.dispatch(incoming) outgoing = await self.runtime.dispatcher.dispatch(incoming)
await self._send_all(room.room_id, outgoing) await self._send_all(room.room_id, outgoing)
async def on_reaction(self, room: MatrixRoom, event: ReactionEvent) -> None:
if getattr(event, "sender", None) == self.client.user_id:
return
chat_id = await resolve_chat_id(self.runtime.store, room.room_id, event.sender)
incoming = from_reaction(event, sender=event.sender, chat_id=chat_id)
if incoming is None:
return
outgoing = await self.runtime.dispatcher.dispatch(incoming)
await self._send_all(room.room_id, outgoing)
async def on_member(self, room: MatrixRoom, event: RoomMemberEvent) -> None: async def on_member(self, room: MatrixRoom, event: RoomMemberEvent) -> None:
if getattr(event, "sender", None) == self.client.user_id: if getattr(event, "sender", None) == self.client.user_id:
return return
@ -129,18 +119,14 @@ class MatrixBot:
async def _send_all(self, room_id: str, outgoing: list[OutgoingEvent]) -> None: async def _send_all(self, room_id: str, outgoing: list[OutgoingEvent]) -> None:
for event in outgoing: for event in outgoing:
await send_outgoing(self.client, room_id, event) await send_outgoing(self.client, room_id, event, store=self.runtime.store)
async def send_outgoing(
def _button_action_to_reaction(action: str) -> str | None: client: AsyncClient,
if action in {"confirm", "ok", "accept"}: room_id: str,
return "👍" event: OutgoingEvent,
if action in {"cancel", "reject", "deny"}: store: StateStore | None = None,
return "" ) -> None:
return None
async def send_outgoing(client: AsyncClient, room_id: str, event: OutgoingEvent) -> None:
if isinstance(event, OutgoingTyping): if isinstance(event, OutgoingTyping):
await client.room_typing(room_id, event.is_typing, timeout=25000) await client.room_typing(room_id, event.is_typing, timeout=25000)
return return
@ -152,31 +138,27 @@ async def send_outgoing(client: AsyncClient, room_id: str, event: OutgoingEvent)
await client.room_send(room_id, "m.room.message", {"msgtype": "m.text", "body": event.text}) await client.room_send(room_id, "m.room.message", {"msgtype": "m.text", "body": event.text})
return return
if isinstance(event, OutgoingUI): if isinstance(event, OutgoingUI):
body = event.text lines = [event.text]
buttons = [] if event.buttons:
for button in event.buttons: lines.append("")
buttons.append(f"{button.label}")
if buttons:
body = "\n".join([body, "", *buttons])
resp = await client.room_send(
room_id, "m.room.message", {"msgtype": "m.text", "body": body}
)
event_id = getattr(resp, "event_id", None)
if event_id:
for button in event.buttons: for button in event.buttons:
reaction = _button_action_to_reaction(button.action) lines.append(f" {button.label}")
if reaction: lines.append("")
await client.room_send( lines.append("Ответьте !yes для подтверждения или !no для отмены.")
room_id, body = "\n".join(lines)
"m.reaction", await client.room_send(room_id, "m.room.message", {"msgtype": "m.text", "body": body})
{ if event.buttons and store is not None:
"m.relates_to": { action_id = event.buttons[0].action
"rel_type": "m.annotation", payload = event.buttons[0].payload
"event_id": event_id, await set_pending_confirm(
"key": reaction, store,
} room_id,
}, {
) "action_id": action_id,
"description": event.text,
"payload": payload,
},
)
return return
@ -213,7 +195,6 @@ async def main() -> None:
bot = MatrixBot(client, runtime) bot = MatrixBot(client, runtime)
client.add_event_callback(bot.on_room_message, RoomMessageText) client.add_event_callback(bot.on_room_message, RoomMessageText)
client.add_event_callback(bot.on_reaction, ReactionEvent)
client.add_event_callback(bot.on_member, (InviteMemberEvent, RoomMemberEvent)) client.add_event_callback(bot.on_member, (InviteMemberEvent, RoomMemberEvent))
logger.info( logger.info(