# Zulip Router _Последнее обновление: 2026-06-16_ ## Цель Event-роутер между Zulip и balda-ботами (Валера, Клавдий). Решает проблему конкурентного получения событий — сейчас оба бота видят все сообщения одновременно. ## Проблема (root cause) - Каждый balda-бот регистрирует собственную event queue в Zulip Events API - Без роутера оба получают все сообщения, и каждый может ответить на @mention другого - `extractOtherMention()` патч в коде — костыль, не решает проблему полностью ## Как сейчас (до роутера) ``` Zulip ├── Events API ← Валера (valera-bot, poll на :8091) — отключён ├── Events API ← Клавдий (claudio-bot, poll на :8092) — отключён └── Webhook → оба (outgoing webhook через @mention) ``` ## Архитектура (с роутером) ``` Zulip Event Queue ↓ poll (credentials Eagle из ~/.hermes/config.yaml) [zulip-router] (~/Docker/zulip-router/) ├── @Валера / @Valera → POST http://balda-agent-valera-1:8091/zulip/webhook ├── @Клавдий / @Klavdiy → POST http://claudio-agent-claudio-1:8092/zulip/webhook └── (default / unknown) → POST http://balda-agent-valera-1:8091/zulip/webhook ↕ ownership: stream+topic → bot (TTL 24h, persisted to /data/ownership.json) ``` **Ключевое:** credentials — Eagle/Орла (не новый бот). Роутер регистрирует свою event queue (отдельную от очереди Eagle). ## Правила маршрутизации 1. `@Валера` или `@Valera` в тексте → Валера (+ ownership обновляется) 2. `@Клавдий` или `@Klavdiy` в тексте → Клавдий (+ ownership обновляется) 3. Топик уже у кого-то → туда же (TTL refreshed) 4. Новый топик без @mention → Валера (default) 5. `reset` без @mention → только владельцу топика ## Что меняется в balda После деплоя роутера Events API polling уже отключён у обоих ботов (сделано 2026-06-16): ```yaml zulip: events_polling: enabled: false ``` Сообщения приходят **только через webhook** от роутера. ## Код **Репозиторий:** `~/Developer/zulip-router/` — Go, ~260 LOC (план) **Deploy:** `~/Docker/zulip-router/docker-compose.yaml` | Файл | Назначение | |------|------------| | `main.go` | Poll loop, routing, dispatch | | `config.go` | Config struct + YAML loading + env var expansion | | `zulip.go` | Zulip API client (register_queue, get_events, long-poll) | | `ownership.go` | Topic ownership store (RW mutex + JSON persistence) | | `forwarder.go` | HTTP POST к balda webhook endpoints | ## Deployment **Compose:** `~/Docker/zulip-router/docker-compose.yaml` ### Credentials: Eagle, не новый бот Роутер использует credentials Eagle/Орла из `~/.hermes/config.yaml` → `platforms.zulip`. Не создавать нового бота. Eagle уже имеет права на чтение всех публичных стримов. ### Env vars Создать `~/Docker/zulip-router/.env`: ```env # Credentials Eagle/Орла — из ~/.hermes/config.yaml ZULIP_BOT_EMAIL=eagle-bot@zulip.qentra.top ZULIP_API_KEY=<скопировать из конфига Eagle> # Куда форвардить (Docker DNS, сеть balda_default) VALERA_WEBHOOK=http://balda-agent-valera-1:8091/zulip/webhook CLAUDIO_WEBHOOK=http://claudio-agent-claudio-1:8092/zulip/webhook ``` ### Запуск ```bash cd ~/Docker/zulip-router docker-compose up -d docker logs zulip-router --tail 20 # проверить poll loop ``` ## TODO - [ ] Написать код роутера (~260 LOC) - [ ] Создать compose `~/Docker/zulip-router/docker-compose.yaml` - [ ] Набить `.env` с credentials Eagle (из `~/.hermes/config.yaml`) - [ ] `docker-compose up -d` - [ ] Проверить логи: `docker logs zulip-router --tail 50` - [ ] Протестировать: @Клавдий и @Валера в разных топиках - [ ] Проверить ownership: сообщение в топик без @mention → последний бот - [ ] Удалить `extractOtherMention()` патч из кода (больше не нужен)