feat: додано Node Registry, GreenFood, Monitoring та Utils
This commit is contained in:
412
telegram-infrastructure/CURSOR_FIX_BOTS.md
Normal file
412
telegram-infrastructure/CURSOR_FIX_BOTS.md
Normal file
@@ -0,0 +1,412 @@
|
||||
# 🔧 Завдання для 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_<AGENT_ID>_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` показує обидва боти
|
||||
|
||||
**Після цього агенти мають відповідати на повідомлення!** 🎉
|
||||
Reference in New Issue
Block a user