feat(01-03): switch Matrix confirmations to text commands

- replace reaction-based helper text with !yes/!no and !skill commands
- resolve confirm and cancel through pending confirmation state
- render !settings as a read-only status dashboard
This commit is contained in:
Mikhail Putilovskij 2026-04-02 22:56:16 +03:00
parent 8a6a33a2ce
commit 01610ef768
4 changed files with 86 additions and 70 deletions

View file

@ -6,7 +6,7 @@ from adapter.matrix.handlers.chat import (
make_handle_new_chat,
make_handle_rename,
)
from adapter.matrix.handlers.confirm import handle_cancel, handle_confirm
from adapter.matrix.handlers.confirm import make_handle_cancel, make_handle_confirm
from adapter.matrix.handlers.settings import (
handle_settings,
handle_settings_connectors,
@ -36,6 +36,6 @@ def register_matrix_handlers(dispatcher: EventDispatcher, client=None, store=Non
dispatcher.register(IncomingCommand, "settings_status", handle_settings_status)
dispatcher.register(IncomingCommand, "settings_whoami", handle_settings_whoami)
dispatcher.register(IncomingCallback, "confirm", handle_confirm)
dispatcher.register(IncomingCallback, "cancel", handle_cancel)
dispatcher.register(IncomingCallback, "confirm", make_handle_confirm(store))
dispatcher.register(IncomingCallback, "cancel", make_handle_cancel(store))
dispatcher.register(IncomingCallback, "toggle_skill", handle_toggle_skill)

View file

@ -1,19 +1,40 @@
from __future__ import annotations
from adapter.matrix.store import clear_pending_confirm, get_pending_confirm
from core.protocol import IncomingCallback, OutgoingMessage
async def handle_confirm(
event: IncomingCallback, auth_mgr, platform, chat_mgr, settings_mgr
) -> list:
action_id = event.payload.get("action_id", "unknown")
return [
OutgoingMessage(chat_id=event.chat_id, text=f"Действие подтверждено (id: {action_id}).")
]
def make_handle_confirm(store=None):
async def handle_confirm(
event: IncomingCallback, auth_mgr, platform, chat_mgr, settings_mgr
) -> list:
if store is None:
return [OutgoingMessage(chat_id=event.chat_id, text="Нет ожидающих подтверждений.")]
pending = await get_pending_confirm(store, event.chat_id)
if not pending:
return [OutgoingMessage(chat_id=event.chat_id, text="Нет ожидающих подтверждений.")]
description = pending.get("description", "действие")
await clear_pending_confirm(store, event.chat_id)
return [OutgoingMessage(chat_id=event.chat_id, text=f"Подтверждено: {description}")]
return handle_confirm
async def handle_cancel(
event: IncomingCallback, auth_mgr, platform, chat_mgr, settings_mgr
) -> list:
action_id = event.payload.get("action_id", "unknown")
return [OutgoingMessage(chat_id=event.chat_id, text=f"Действие отменено (id: {action_id}).")]
def make_handle_cancel(store=None):
async def handle_cancel(
event: IncomingCallback, auth_mgr, platform, chat_mgr, settings_mgr
) -> list:
if store is None:
return [OutgoingMessage(chat_id=event.chat_id, text="Нет ожидающих подтверждений.")]
pending = await get_pending_confirm(store, event.chat_id)
if not pending:
return [OutgoingMessage(chat_id=event.chat_id, text="Нет ожидающих подтверждений.")]
await clear_pending_confirm(store, event.chat_id)
return [OutgoingMessage(chat_id=event.chat_id, text="Действие отменено.")]
return handle_cancel

View file

@ -22,21 +22,50 @@ def _parse_bool(value: str) -> bool:
async def handle_settings(
event: IncomingCommand, auth_mgr, platform, chat_mgr, settings_mgr
) -> list:
return [
OutgoingMessage(
chat_id=event.chat_id,
text=(
"⚙️ Настройки Matrix\n"
"!skills\n"
"!connectors\n"
"!soul [field value]\n"
"!safety [trigger on|off]\n"
"!plan\n"
"!status\n"
"!whoami"
),
)
]
settings = await settings_mgr.get(event.user_id)
chats = await chat_mgr.list_active(event.user_id)
skills_lines = []
for name, enabled in settings.skills.items():
state = "on" if enabled else "off"
skills_lines.append(f" {state} {name}")
skills_text = "\n".join(skills_lines) if skills_lines else " нет навыков"
soul_lines = []
for key, value in (settings.soul or {}).items():
soul_lines.append(f" {key}: {value}")
soul_text = "\n".join(soul_lines) if soul_lines else " по умолчанию"
safety_lines = []
for key, value in (settings.safety or {}).items():
state = "on" if value else "off"
safety_lines.append(f" {state} {key}")
safety_text = "\n".join(safety_lines) if safety_lines else " по умолчанию"
chat_lines = [f" {chat.display_name} ({chat.chat_id})" for chat in chats]
chats_text = "\n".join(chat_lines) if chat_lines else " нет активных чатов"
dashboard = "\n".join(
[
"Настройки",
"",
"Скиллы:",
skills_text,
"",
"Личность:",
soul_text,
"",
"Безопасность:",
safety_text,
"",
f"Активные чаты ({len(chats)}):",
chats_text,
"",
"Изменить: !skills, !soul, !safety",
]
)
return [OutgoingMessage(chat_id=event.chat_id, text=dashboard)]
async def handle_settings_skills(