From 8270e5821eca74f1ab2f14919c5e55e48a23f409 Mon Sep 17 00:00:00 2001 From: Mikhail Putilovskij Date: Sun, 19 Apr 2026 17:31:21 +0300 Subject: [PATCH] Assign matrix platform chat ids on creation --- adapter/matrix/handlers/auth.py | 103 +++++++++++++++------- adapter/matrix/handlers/chat.py | 1 + tests/adapter/matrix/test_chat_space.py | 5 +- tests/adapter/matrix/test_invite_space.py | 2 + 4 files changed, 76 insertions(+), 35 deletions(-) diff --git a/adapter/matrix/handlers/auth.py b/adapter/matrix/handlers/auth.py index 6882404..3fd6db5 100644 --- a/adapter/matrix/handlers/auth.py +++ b/adapter/matrix/handlers/auth.py @@ -16,16 +16,20 @@ from adapter.matrix.store import ( logger = structlog.get_logger(__name__) -async def handle_invite(client: Any, room: Any, event: Any, platform, store, auth_mgr, chat_mgr) -> None: - matrix_user_id = getattr(event, "sender", "") - display_name = getattr(room, "display_name", None) or matrix_user_id +def _default_room_name(chat_id: str) -> str: + suffix = chat_id[1:] if chat_id.startswith("C") else chat_id + return f"Чат {suffix}" - await client.join(room.room_id) - - existing = await get_user_meta(store, matrix_user_id) - if existing and existing.get("space_id"): - return +async def provision_workspace_chat( + client: Any, + matrix_user_id: str, + display_name: str, + platform, + store, + auth_mgr, + chat_mgr, +) -> dict: user = await platform.get_or_create_user( external_id=matrix_user_id, platform="matrix", @@ -34,24 +38,31 @@ async def handle_invite(client: Any, room: Any, event: Any, platform, store, aut await auth_mgr.confirm(matrix_user_id) homeserver = matrix_user_id.split(":")[-1] + user_meta = await get_user_meta(store, matrix_user_id) or {} + space_id = user_meta.get("space_id") - space_resp = await client.room_create( - name=f"Lambda — {display_name}", - space=True, - visibility=RoomVisibility.private, - invite=[matrix_user_id], - ) - if isinstance(space_resp, RoomCreateError): - logger.error( - "space creation failed", - user=matrix_user_id, - error=getattr(space_resp, "status_code", None), + if not space_id: + space_resp = await client.room_create( + name=f"Lambda — {display_name}", + space=True, + visibility=RoomVisibility.private, + invite=[matrix_user_id], ) - return - space_id = space_resp.room_id + if isinstance(space_resp, RoomCreateError): + logger.error( + "space creation failed", + user=matrix_user_id, + error=getattr(space_resp, "status_code", None), + ) + raise RuntimeError("Не удалось создать Space.") + space_id = space_resp.room_id + user_meta["space_id"] = space_id + await set_user_meta(store, matrix_user_id, user_meta) + chat_id = await next_chat_id(store, matrix_user_id) + room_name = _default_room_name(chat_id) chat_resp = await client.room_create( - name="Чат 1", + name=room_name, visibility=RoomVisibility.private, is_direct=False, invite=[matrix_user_id], @@ -62,7 +73,7 @@ async def handle_invite(client: Any, room: Any, event: Any, platform, store, aut user=matrix_user_id, error=getattr(chat_resp, "status_code", None), ) - return + raise RuntimeError("Не удалось создать рабочий чат.") chat_room_id = chat_resp.room_id await client.room_put_state( @@ -72,21 +83,16 @@ async def handle_invite(client: Any, room: Any, event: Any, platform, store, aut state_key=chat_room_id, ) - chat_id = await next_chat_id(store, matrix_user_id) - - user_meta = await get_user_meta(store, matrix_user_id) or {} - user_meta["space_id"] = space_id - await set_user_meta(store, matrix_user_id, user_meta) - await set_room_meta( store, chat_room_id, { "room_type": "chat", "chat_id": chat_id, - "display_name": "Чат 1", + "display_name": room_name, "matrix_user_id": matrix_user_id, "space_id": space_id, + "platform_chat_id": f"matrix:{chat_room_id}", }, ) await chat_mgr.get_or_create( @@ -94,15 +100,44 @@ async def handle_invite(client: Any, room: Any, event: Any, platform, store, aut chat_id=chat_id, platform="matrix", surface_ref=chat_room_id, - name="Чат 1", + name=room_name, + ) + + return { + "user": user, + "space_id": space_id, + "chat_room_id": chat_room_id, + "chat_id": chat_id, + "room_name": room_name, + } + + +async def handle_invite(client: Any, room: Any, event: Any, platform, store, auth_mgr, chat_mgr) -> None: + matrix_user_id = getattr(event, "sender", "") + display_name = getattr(room, "display_name", None) or matrix_user_id + + await client.join(room.room_id) + + existing = await get_user_meta(store, matrix_user_id) + if existing and existing.get("space_id"): + return + + created = await provision_workspace_chat( + client, + matrix_user_id, + display_name, + platform, + store, + auth_mgr, + chat_mgr, ) welcome = ( - f"Привет, {user.display_name or matrix_user_id}! Пиши — я здесь.\n\n" - "Команды: !new · !chats · !rename · !archive · !skills · !soul · !safety · !settings" + f"Привет, {created['user'].display_name or matrix_user_id}! Пиши — я здесь.\n\n" + "Команды: !new · !chats · !rename · !archive · !context · !save · !load · !help" ) await client.room_send( - chat_room_id, + created["chat_room_id"], "m.room.message", {"msgtype": "m.text", "body": welcome}, ) diff --git a/adapter/matrix/handlers/chat.py b/adapter/matrix/handlers/chat.py index c5096ff..a63a966 100644 --- a/adapter/matrix/handlers/chat.py +++ b/adapter/matrix/handlers/chat.py @@ -106,6 +106,7 @@ def make_handle_new_chat( "display_name": room_name, "matrix_user_id": event.user_id, "space_id": space_id, + "platform_chat_id": f"matrix:{room_id}", }, ) ctx = await chat_mgr.get_or_create( diff --git a/tests/adapter/matrix/test_chat_space.py b/tests/adapter/matrix/test_chat_space.py index 91ee27a..bda29bf 100644 --- a/tests/adapter/matrix/test_chat_space.py +++ b/tests/adapter/matrix/test_chat_space.py @@ -7,7 +7,7 @@ from nio.api import RoomVisibility from nio.responses import RoomCreateError from adapter.matrix.handlers.chat import make_handle_archive, make_handle_new_chat, make_handle_rename -from adapter.matrix.store import set_user_meta +from adapter.matrix.store import get_room_meta, set_user_meta from core.auth import AuthManager from core.chat import ChatManager from core.protocol import IncomingCommand, OutgoingMessage @@ -57,6 +57,9 @@ async def test_mat04_new_chat_calls_room_put_state_with_space_id(): assert kwargs.get("room_id") == "!space:ex" assert kwargs.get("event_type") == "m.space.child" assert kwargs.get("state_key") == "!newroom:ex" + room_meta = await get_room_meta(store, "!newroom:ex") + assert room_meta is not None + assert room_meta["platform_chat_id"] == "matrix:!newroom:ex" assert any(isinstance(item, OutgoingMessage) and "Test" in item.text for item in result) diff --git a/tests/adapter/matrix/test_invite_space.py b/tests/adapter/matrix/test_invite_space.py index a14ef0a..c43b31b 100644 --- a/tests/adapter/matrix/test_invite_space.py +++ b/tests/adapter/matrix/test_invite_space.py @@ -64,6 +64,7 @@ async def test_mat01_invite_creates_space_and_chat1(): assert room_meta is not None assert room_meta["chat_id"] == "C4" assert room_meta["space_id"] == "!space:example.org" + assert room_meta["platform_chat_id"] == "matrix:!chat1:example.org" assert user_meta["next_chat_index"] == 5 chats = await runtime.chat_mgr.list_active("@alice:example.org") @@ -119,6 +120,7 @@ async def test_mat03_no_hardcoded_c1(): room_meta = await get_room_meta(runtime.store, "!chat1:example.org") assert room_meta is not None assert room_meta["chat_id"] == "C7" + assert room_meta["platform_chat_id"] == "matrix:!chat1:example.org" user_meta = await get_user_meta(runtime.store, "@alice:example.org") assert user_meta is not None