# 🔧 Завдання для Cursor: Виправити telegram-gateway (DAARWIZZ і Helion не відповідають) ## 🎯 Мета Зробити так, щоб обидва боти (DAARWIZZ і Helion) автоматично ініціалізувались при старті та відповідали на повідомлення через polling. --- ## 📋 Проблеми зараз 1. ❌ Боти не ініціалізуються автоматично при старті 2. ❌ `bots.yaml` не монтується в контейнер 3. ❌ Polling не запускається для ботів з конфігурації 4. ❌ Логування недостатнє для діагностики --- ## ✅ Що потрібно зробити ### 1. Виправити `docker-compose.yml` **Файл:** `/Users/apple/github-projects/microdao-daarion/telegram-infrastructure/docker-compose.yml` **Додати volume для bots.yaml:** ```yaml telegram-gateway: build: ./telegram-gateway container_name: telegram-gateway restart: unless-stopped env_file: - .env environment: - TELEGRAM_API_BASE=http://telegram-bot-api:8081 - NATS_URL=nats://nats:4222 - ROUTER_BASE_URL=http://router:9102 - DEBUG=true depends_on: - telegram-bot-api - nats ports: - "127.0.0.1:8000:8000" volumes: - ./telegram-gateway/bots.yaml:/app/bots.yaml:ro # ← ДОДАТИ ЦЕЙ РЯДОК networks: - telegram-net - dagi-network ``` **Чому:** Контейнер має читати `bots.yaml` при старті, але файл не копіюється в образ і не монтується як volume. --- ### 2. Виправити `app/main.py` — автоматична ініціалізація ботів **Файл:** `/Users/apple/github-projects/microdao-daarion/telegram-infrastructure/telegram-gateway/app/main.py` **Поточний код `on_startup()`:** ```python @app.on_event("startup") async def on_startup(): # Підключаємося до NATS await nats_client.connect() logger.info("Connected to NATS at %s", settings.NATS_URL) # На цьому етапі список ботів пустий; їх додаватимуть через /bots/register. # За потреби сюди можна додати завантаження конфігів з БД. ``` **Новий код `on_startup()` (ЗАМІНИТИ):** ```python @app.on_event("startup") async def on_startup(): # 1. Підключаємося до NATS await nats_client.connect() logger.info("✅ Connected to NATS at %s", settings.NATS_URL) # 2. Завантажити конфігурацію ботів з bots.yaml або env from .config import load_bots_config try: bot_configs = load_bots_config() logger.info("📋 Loaded %d bot(s) from config", len(bot_configs)) except Exception as e: logger.warning("⚠️ Failed to load bots config: %s", e) bot_configs = [] # 3. Зареєструвати всі боти в реєстрі if bot_configs: bots_registry.register_from_config(bot_configs) logger.info("📝 Registered %d bot(s) in registry", len(bot_configs)) # 4. Запустити polling для кожного бота for bot_config in bot_configs: agent_id = bot_config.agent_id bot_token = bot_config.bot_token # Запускаємо polling в фоновій задачі asyncio.create_task(telegram_listener.add_bot(bot_token)) logger.info("🚀 Started polling for agent=%s (token=%s...)", agent_id, bot_token[:16]) if not bot_configs: logger.warning("⚠️ No bots configured. Use /bots/register to add bots manually.") ``` **Чому:** Зараз боти не запускаються автоматично — треба викликати `/bots/register` вручну. Цей код автоматично завантажує конфіг і запускає polling при старті. --- ### 3. Перевірити `app/config.py` — функція `load_bots_config()` **Файл:** `/Users/apple/github-projects/microdao-daarion/telegram-infrastructure/telegram-gateway/app/config.py` **Переконайся, що функція існує і виглядає приблизно так:** ```python from pathlib import Path from typing import List import yaml import os from pydantic import BaseModel class BotConfig(BaseModel): agent_id: str bot_token: str def load_bots_config() -> List[BotConfig]: """ Завантажити конфігурацію ботів з bots.yaml або env variables. Пріоритет: 1. bots.yaml (якщо існує) 2. Environment variables: BOT__TOKEN """ bots = [] # Спробувати завантажити з bots.yaml config_path = Path("/app/bots.yaml") # Шлях в контейнері if config_path.exists(): try: with open(config_path, "r") as f: data = yaml.safe_load(f) if data and "bots" in data: for bot_data in data["bots"]: bots.append(BotConfig(**bot_data)) except Exception as e: # Fallback до env variables pass # Fallback: завантажити з env variables if not bots: for key, value in os.environ.items(): if key.startswith("BOT_") and key.endswith("_TOKEN"): agent_id = key[4:-6].lower() # BOT_DAARWIZZ_TOKEN -> daarwizz bots.append(BotConfig(agent_id=agent_id, bot_token=value)) return bots ``` **Якщо функція відсутня або неповна — додай/виправ її.** --- ### 4. Перевірити `app/bots_registry.py` — метод `register_from_config()` **Файл:** `/Users/apple/github-projects/microdao-daarion/telegram-infrastructure/telegram-gateway/app/bots_registry.py` **Переконайся, що метод існує:** ```python from typing import List from .config import BotConfig class BotsRegistry: # ... інші методи ... def register_from_config(self, configs: List[BotConfig]) -> None: """Масова реєстрація ботів з конфігурації""" for config in configs: self.register(config) # або напряму: # self._agent_to_token[config.agent_id] = config.bot_token # self._token_to_agent[config.bot_token] = config.agent_id ``` **Якщо метод відсутній — додай його.** --- ### 5. Додати детальне логування в `app/telegram_listener.py` **Файл:** `/Users/apple/github-projects/microdao-daarion/telegram-infrastructure/telegram-gateway/app/telegram_listener.py` **Оновити метод `add_bot()` для кращого логування:** ```python async def add_bot(self, bot_token: str) -> None: if bot_token in self._bots: logger.info("🔄 Bot already registered: %s...", bot_token[:16]) return logger.info("🤖 Creating bot: %s...", bot_token[:16]) bot = await self._create_bot(bot_token) dp = Dispatcher() @dp.message(F.text) async def on_message(message: Message) -> None: agent_id = bots_registry.get_agent_by_token(bot_token) if not agent_id: logger.warning("⚠️ No agent_id for bot_token=%s...", bot_token[:16]) return logger.info("📨 Received message: agent=%s, chat=%s, user=%s, len=%d", agent_id, message.chat.id, message.from_user.id if message.from_user else 0, len(message.text or "")) event = TelegramUpdateEvent( agent_id=agent_id, bot_id=f"bot:{bot_token[:8]}", chat_id=message.chat.id, user_id=message.from_user.id if message.from_user else 0, text=message.text, raw_update=message.model_dump() ) logger.info("📤 Publishing to NATS: subject=agent.telegram.update, agent=%s", agent_id) await nats_client.publish_json( subject="agent.telegram.update", data=event.model_dump() ) # Запускаємо polling у фоні async def _polling(): try: logger.info("🔁 Start polling for bot %s...", bot_token[:16]) await dp.start_polling(bot) except asyncio.CancelledError: logger.info("🛑 Polling cancelled for bot %s...", bot_token[:16]) except Exception as e: logger.exception("💥 Polling error for bot %s...: %s", bot_token[:16], e) raise task = asyncio.create_task(_polling()) self._bots[bot_token] = bot self._dispatchers[bot_token] = dp self._tasks[bot_token] = task logger.info("✅ Bot registered and polling started: %s...", bot_token[:16]) ``` **Чому:** Детальніше логування допоможе побачити, що відбувається при отриманні повідомлень. --- ### 6. Створити `bots.yaml` локально (якщо ще не створений) **Файл:** `/Users/apple/github-projects/microdao-daarion/telegram-infrastructure/telegram-gateway/bots.yaml` **Вміст:** ```yaml bots: - agent_id: daarwizz bot_token: 8323412397:AAFxaru-hHRl08A3T6TC02uHLvO5wAB0m3M - agent_id: helion bot_token: 8112062582:AAGI7tPFo4gvZ6bfbkFu9miq5GdAH2_LvcM ``` --- ## 🧪 Як перевірити після змін ### 1. Деплой на сервер (виконати з Mac) ```bash cd /Users/apple/github-projects/microdao-daarion/telegram-infrastructure # Синхронізація коду rsync -avz --exclude='.git' --exclude='__pycache__' --exclude='*.pyc' --exclude='data/' ./ root@144.76.224.179:/opt/telegram-infrastructure/ # Перезапуск на сервері ssh root@144.76.224.179 "cd /opt/telegram-infrastructure && docker compose down telegram-gateway && docker compose up -d --build telegram-gateway" ``` ### 2. Перевірка логів (на сервері) ```bash ssh root@144.76.224.179 docker logs -f telegram-gateway ``` **Очікувані рядки в логах:** ``` ✅ Connected to NATS at nats://nats:4222 📋 Loaded 2 bot(s) from config 📝 Registered 2 bot(s) in registry 🚀 Started polling for agent=daarwizz (token=8323412397:AAFxa...) 🚀 Started polling for agent=helion (token=8112062582:AAGI7...) 🔁 Start polling for bot 8323412397:AAFxa... 🔁 Start polling for bot 8112062582:AAGI7... ``` ### 3. Перевірка списку ботів ```bash curl -s http://127.0.0.1:8000/bots/list | jq . ``` **Очікувана відповідь:** ```json { "bots": ["daarwizz", "helion"], "count": 2 } ``` ### 4. Перевірка polling tasks ```bash curl -s http://127.0.0.1:8000/debug/bots | jq . ``` **Очікувана відповідь:** ```json { "registered_bots": 2, "bot_tokens": ["8323412397:AAFxa...", "8112062582:AAGI7..."], "registry_mappings": 2, "active_tasks": 2 } ``` ```bash curl -s http://127.0.0.1:8000/debug/bots/tasks | jq . ``` **Очікувана відповідь:** ```json { "8323412397:AAFxa...": { "done": false, "cancelled": false }, "8112062582:AAGI7...": { "done": false, "cancelled": false } } ``` ### 5. Надіслати тестове повідомлення **В Telegram:** 1. Надішліть "Привіт" в DAARWIZZ бот 2. Надішліть "Привіт" в Helion бот **В логах має з'явитись:** ``` 📨 Received message: agent=daarwizz, chat=123456, user=789, len=6 📤 Publishing to NATS: subject=agent.telegram.update, agent=daarwizz 📨 Received message: agent=helion, chat=123456, user=789, len=6 📤 Publishing to NATS: subject=agent.telegram.update, agent=helion ``` --- ## ⚠️ Troubleshooting ### Якщо боти не ініціалізуються: ```bash # Перевірити, чи bots.yaml є в контейнері docker exec telegram-gateway cat /app/bots.yaml # Має показати вміст файлу. Якщо "No such file" — volume не працює ``` ### Якщо polling не запускається: ```bash # Перевірити логи aiogram docker logs telegram-gateway 2>&1 | grep -i "polling\|error\|exception" ``` ### Якщо повідомлення не приходять: ```bash # Перевірити, чи webhooks видалені curl -s "https://api.telegram.org/bot8323412397:AAFxaru-hHRl08A3T6TC02uHLvO5wAB0m3M/getWebhookInfo" | jq .result.url curl -s "https://api.telegram.org/bot8112062582:AAGI7tPFo4gvZ6bfbkFu9miq5GdAH2_LvcM/getWebhookInfo" | jq .result.url # Обидва мають повертати: "" (порожній рядок = webhook видалений) ``` --- ## 📝 Checklist для Cursor - [ ] Додати `volumes:` в `docker-compose.yml` для `telegram-gateway` - [ ] Оновити `on_startup()` в `app/main.py` з автоматичною ініціалізацією - [ ] Перевірити/додати `load_bots_config()` в `app/config.py` - [ ] Перевірити/додати `register_from_config()` в `app/bots_registry.py` - [ ] Додати детальне логування в `app/telegram_listener.py` - [ ] Створити `telegram-gateway/bots.yaml` з реальними токенами --- ## 🎯 Очікуваний результат Після виконання всіх кроків: - ✅ Обидва боти (DAARWIZZ і Helion) автоматично стартують при запуску контейнера - ✅ Polling працює для обох ботів - ✅ Повідомлення отримуються і публікуються в NATS - ✅ Детальні логи для діагностики - ✅ `/bots/list` показує обидва боти **Після цього агенти мають відповідати на повідомлення!** 🎉