feat(05-02): ship room-local clear semantics

- register clear as the room-context reset entrypoint when supported
- keep save and context bound to room platform chat ids and clear old upstream state
This commit is contained in:
Mikhail Putilovskij 2026-04-28 01:15:39 +03:00
parent df6d8bf628
commit 85e2fda6bc
2 changed files with 39 additions and 22 deletions

View file

@ -47,13 +47,12 @@ def register_matrix_handlers(
dispatcher.register(IncomingCommand, "archive", make_handle_archive(client, store))
dispatcher.register(IncomingCommand, "help", handle_help)
dispatcher.register(IncomingCommand, "settings", handle_settings)
dispatcher.register(
IncomingCommand,
"reset",
make_handle_reset(store, prototype_state)
if prototype_state is not None
else handle_settings,
)
if prototype_state is not None:
clear_handler = make_handle_reset(store, prototype_state)
dispatcher.register(IncomingCommand, "clear", clear_handler)
dispatcher.register(IncomingCommand, "reset", clear_handler)
else:
dispatcher.register(IncomingCommand, "reset", handle_settings)
dispatcher.register(IncomingCommand, "settings_skills", handle_settings_skills)
dispatcher.register(IncomingCommand, "settings_connectors", handle_settings_connectors)
dispatcher.register(IncomingCommand, "settings_soul", handle_settings_soul)

View file

@ -59,6 +59,17 @@ async def _resolve_context_scope(
return room_id, platform_chat_id
async def _require_platform_context(
event: IncomingCommand,
store: StateStore,
chat_mgr,
) -> tuple[str, str]:
room_id, platform_chat_id = await _resolve_context_scope(event, store, chat_mgr)
if not platform_chat_id:
raise RuntimeError(f"matrix room context is incomplete: {room_id}")
return room_id, platform_chat_id
def make_handle_save(agent_api, store: StateStore, prototype_state: PrototypeStateStore):
async def handle_save(
event: IncomingCommand, auth_mgr, platform, chat_mgr, settings_mgr
@ -85,11 +96,16 @@ def make_handle_save(agent_api, store: StateStore, prototype_state: PrototypeSta
logger.warning("save_agent_call_failed", error=str(exc))
return [OutgoingMessage(chat_id=event.chat_id, text=f"Ошибка при сохранении: {exc}")]
_, platform_chat_id = await _resolve_context_scope(event, store, chat_mgr)
try:
_, platform_chat_id = await _require_platform_context(event, store, chat_mgr)
except RuntimeError as exc:
logger.warning("save_context_incomplete", error=str(exc))
return [OutgoingMessage(chat_id=event.chat_id, text="Контекст комнаты не готов. Попробуй позже.")]
await prototype_state.add_saved_session(
event.user_id,
name,
source_context_id=platform_chat_id or event.chat_id,
source_context_id=platform_chat_id,
)
return [
OutgoingMessage(
@ -132,9 +148,11 @@ def make_handle_reset(store: StateStore, prototype_state: PrototypeStateStore):
async def handle_reset(
event: IncomingCommand, auth_mgr, platform, chat_mgr, settings_mgr
) -> list[OutgoingEvent]:
room_id = await _resolve_room_id(event, chat_mgr)
room_meta = await get_room_meta(store, room_id)
old_chat_id = (room_meta or {}).get("platform_chat_id") or room_id
try:
room_id, old_chat_id = await _require_platform_context(event, store, chat_mgr)
except RuntimeError as exc:
logger.warning("clear_context_incomplete", error=str(exc))
return [OutgoingMessage(chat_id=event.chat_id, text="Контекст комнаты не готов. Попробуй позже.")]
new_chat_id = await next_platform_chat_id(store)
await set_platform_chat_id(store, room_id, new_chat_id)
@ -143,6 +161,7 @@ def make_handle_reset(store: StateStore, prototype_state: PrototypeStateStore):
if callable(disconnect):
await disconnect(old_chat_id)
await prototype_state.clear_current_session(old_chat_id)
await prototype_state.clear_current_session(new_chat_id)
return [
@ -182,20 +201,19 @@ def make_handle_context(store: StateStore, prototype_state: PrototypeStateStore)
async def handle_context(
event: IncomingCommand, auth_mgr, platform, chat_mgr, settings_mgr
) -> list[OutgoingEvent]:
_, platform_chat_id = await _resolve_context_scope(event, store, chat_mgr)
context_key = platform_chat_id or event.chat_id
current_session = await prototype_state.get_current_session(context_key)
tokens_used = await prototype_state.get_last_tokens_used(context_key)
if platform_chat_id is not None and event.chat_id != platform_chat_id:
if current_session is None:
current_session = await prototype_state.get_current_session(event.chat_id)
if tokens_used == 0:
tokens_used = await prototype_state.get_last_tokens_used(event.chat_id)
try:
_, platform_chat_id = await _require_platform_context(event, store, chat_mgr)
except RuntimeError as exc:
logger.warning("context_scope_incomplete", error=str(exc))
return [OutgoingMessage(chat_id=event.chat_id, text="Контекст комнаты не готов. Попробуй позже.")]
current_session = await prototype_state.get_current_session(platform_chat_id)
tokens_used = await prototype_state.get_last_tokens_used(platform_chat_id)
sessions = await prototype_state.list_saved_sessions(event.user_id)
lines = [
"Контекст:",
f" Контекст чата: {platform_chat_id or event.chat_id}",
f" Контекст чата: {platform_chat_id}",
f" Сессия: {current_session or 'не загружена'}",
f" Токены (последний ответ): {tokens_used}",
f" Сохранения ({len(sessions)}):",