surfaces/adapter/telegram/handlers/start.py
Mikhail Putilovskij 8901e60f6a fix(tg): reviewer fixes — error handling, timeouts, db index
- commands.py: try/except TelegramBadRequest around all Bot API calls (#2);
  /new handles "topics limit" with user-friendly message (#4)
- start.py: isolate _check_and_prune_stale_topics with try/except Exception (#3)
- message.py: asyncio.timeout(30) around stream_message; handle TimeoutError (#6)
- db.py: add idx_chats_user_id index in init_db() (#7)
- settings.py: remove dead active_chat_id variable (#8)
- tests: add test_message.py (stream error/success); add 2 tests in test_commands.py
  (topics limit, /archive in General topic)
2026-04-02 13:44:59 +03:00

78 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
import structlog
from aiogram import Router
from aiogram.exceptions import TelegramBadRequest
from aiogram.filters import CommandStart
from aiogram.types import Message
from adapter.telegram import db
logger = structlog.get_logger(__name__)
router = Router(name="start")
@router.message(CommandStart())
async def cmd_start(message: Message) -> None:
"""
Bootstrap the user's forum.
First visit: create Чат #1, hide General topic.
Returning visit: health-check all active topics, archive stale ones.
"""
user_id = message.from_user.id
chat_id = message.chat.id
try:
await _check_and_prune_stale_topics(message, user_id, chat_id)
except Exception:
logger.exception("prune_stale_topics_error", user_id=user_id)
active = db.get_active_chats(user_id)
if not active:
try:
topic = await message.bot.create_forum_topic(chat_id=chat_id, name="Чат #1")
thread_id = topic.message_thread_id
db.create_chat(user_id=user_id, thread_id=thread_id, chat_name="Чат #1")
logger.info("start_created_first_topic", user_id=user_id, thread_id=thread_id)
except TelegramBadRequest as e:
logger.warning("start_create_topic_failed", error=str(e))
await message.answer(
"Не удалось создать топик. Убедись, что в @BotFather включён "
"Threaded Mode для этого бота."
)
return
try:
await message.bot.hide_general_forum_topic(chat_id=chat_id)
except TelegramBadRequest:
pass # Not critical
await message.answer(
"Привет! Это твоё личное пространство с AI-агентом Lambda. "
"Каждый топик — отдельный контекст. Напиши что-нибудь."
)
else:
await message.answer(
f"Снова привет! У тебя {len(active)} активных чатов. "
"Напиши /new чтобы создать новый."
)
async def _check_and_prune_stale_topics(
message: Message, user_id: int, chat_id: int
) -> None:
"""Send typing action to each active topic; archive any that no longer exist."""
for chat in db.get_active_chats(user_id):
thread_id = chat["thread_id"]
try:
await message.bot.send_chat_action(
chat_id=chat_id,
action="typing",
message_thread_id=thread_id,
)
except TelegramBadRequest:
db.archive_chat(user_id=user_id, thread_id=thread_id)
logger.info("pruned_stale_topic", user_id=user_id, thread_id=thread_id)