[2026-06-16] balda: sync setup.md with current state; fix claudio owner note; correct zulip-router plan for balda bots
This commit is contained in:
@@ -1,34 +1,40 @@
|
||||
---
|
||||
tags: [project, hermes, zulip, go, infra]
|
||||
status: deployed
|
||||
created: 2026-06-16
|
||||
---
|
||||
|
||||
# Zulip Router
|
||||
|
||||
_Последнее обновление: 2026-06-16_
|
||||
|
||||
## Цель
|
||||
|
||||
Event-роутер между Zulip и несколькими Hermes-инстансами.
|
||||
Решает проблему конкурентного получения событий (Валера, Клавдий и другие боты видели все сообщения одновременно, `reset` срабатывал у всех).
|
||||
Event-роутер между Zulip и balda-ботами (Валера, Клавдий).
|
||||
Решает проблему конкурентного получения событий — сейчас оба бота через Events API видят все сообщения одновременно.
|
||||
|
||||
## Проблема (root cause)
|
||||
|
||||
- Каждый Hermes-инстанс в polling-режиме регистрирует собственную event queue в Zulip
|
||||
- `reset` — системная команда Hermes, обрабатывается до хука `whale-thread-guard`
|
||||
- Нет механизма ownership топика между инстансами
|
||||
- Каждый balda-бот регистрирует собственную event queue в Zulip Events API
|
||||
- Без роутера оба получают все сообщения, и каждый может ответить на @mention другого
|
||||
- `extractOtherMention()` патч в коде — костыль, не решает проблему полностью
|
||||
|
||||
## Архитектура
|
||||
## Как сейчас (до роутера)
|
||||
|
||||
```
|
||||
Zulip
|
||||
├── Events API ← Валера (valera-bot, poll на :8091)
|
||||
└── Events API ← Клавдий (claudio-bot, poll на :8092)
|
||||
└── Webhook → оба (outgoing webhook bot_type=3 через @mention)
|
||||
```
|
||||
|
||||
## Архитектура (с роутером)
|
||||
|
||||
```
|
||||
Zulip Event Queue
|
||||
↓ poll (valera-bot credentials)
|
||||
[zulip-router]
|
||||
├── @Валера → http://hermes-valera:8765/zulip-webhook
|
||||
└── @Клавдий → http://hermes-klavdiy:8765/zulip-webhook
|
||||
↓ poll (отдельный бот-роутер или reuse одного из существующих)
|
||||
[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)
|
||||
```
|
||||
|
||||
Hermes/Орёл — не трогаем, остаётся в polling-режиме.
|
||||
**Важно:** таргеты — не Hermes инстансы, а balda-боты (Go бинарники). У каждого уже есть webhook endpoint `/zulip/webhook`.
|
||||
|
||||
## Правила маршрутизации
|
||||
|
||||
@@ -36,11 +42,24 @@ Hermes/Орёл — не трогаем, остаётся в polling-режим
|
||||
2. `@Клавдий` или `@Klavdiy` в тексте → Клавдий (+ ownership обновляется)
|
||||
3. Топик уже у кого-то → туда же (TTL refreshed)
|
||||
4. Новый топик без @mention → Валера (default)
|
||||
5. `reset` без @mention → уходит только к владельцу топика ✓
|
||||
5. `reset` без @mention → только владельцу топика
|
||||
|
||||
## Что меняется в balda
|
||||
|
||||
После деплоя роутера у обоих ботов нужно **отключить Events API polling** в config.yaml:
|
||||
|
||||
```yaml
|
||||
zulip:
|
||||
events_polling:
|
||||
enabled: false # ← было true
|
||||
```
|
||||
|
||||
После этого сообщения приходят **только через webhook** (от роутера).
|
||||
Перезапуск: `docker-compose up -d` (в каждом compose).
|
||||
|
||||
## Код
|
||||
|
||||
`~/docker/zulip-router/` — Go, ~260 LOC
|
||||
`~/Docker/zulip-router/` — Go, ~260 LOC (план)
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|------------|
|
||||
@@ -48,47 +67,32 @@ Hermes/Орёл — не трогаем, остаётся в polling-режим
|
||||
| `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 к Hermes webhook endpoints |
|
||||
| `forwarder.go` | HTTP POST к balda webhook endpoints |
|
||||
|
||||
## Deployment
|
||||
|
||||
**Compose:** `~/docker/hermes/docker-compose.yml` — сервис `zulip-router`
|
||||
**Compose:** `~/Docker/zulip-router/docker-compose.yaml`
|
||||
|
||||
**Env vars** (`~/docker/hermes/.env`):
|
||||
```
|
||||
ZULIP_ROUTER_API_KEY=<valera-bot api key из ~/.hermes/profiles/valera/config.yaml>
|
||||
ZULIP_WEBHOOK_TOKEN=zr-secret-2026
|
||||
**Env vars:**
|
||||
```env
|
||||
ZULIP_ROUTER_API_KEY=<api-key бота-роутера>
|
||||
```
|
||||
|
||||
**Запуск после заполнения .env:**
|
||||
**Запуск:**
|
||||
```bash
|
||||
cd ~/docker/hermes
|
||||
docker compose up -d --force-recreate
|
||||
cd ~/Docker/zulip-router
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
**Перезапуск после изменений в профилях:**
|
||||
```bash
|
||||
docker compose restart hermes-valera hermes-klavdiy
|
||||
```
|
||||
|
||||
## Hermes профили
|
||||
|
||||
Валера и Клавдий переведены в webhook-режим:
|
||||
```yaml
|
||||
platforms:
|
||||
zulip:
|
||||
webhook_port: 8765
|
||||
webhook_path: /zulip-webhook
|
||||
webhook_token: 'zr-secret-2026'
|
||||
```
|
||||
|
||||
Токен должен совпадать с `ZULIP_WEBHOOK_TOKEN` в `.env`.
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] Заполнить ZULIP_ROUTER_API_KEY в ~/docker/hermes/.env
|
||||
- [ ] `docker compose up -d --force-recreate`
|
||||
- [ ] Проверить логи: `docker compose logs -f zulip-router`
|
||||
- [ ] Протестировать: написать @Клавдий и @Валера в отдельных топиках
|
||||
- [ ] Проверить ownership: обратиться в топик без @mention — должен отвечать последний бот
|
||||
- [ ] При необходимости: добавить Hermes/Орёл в роутер (отдельная задача)
|
||||
- [ ] Написать код роутера (~260 LOC)
|
||||
- [ ] Создать compose `~/Docker/zulip-router/docker-compose.yaml`
|
||||
- [ ] Создать бота-роутера в Zulip (или реюзнуть valera-bot/claudio-bot), получить API key
|
||||
- [ ] `docker-compose up -d`
|
||||
- [ ] Проверить логи: `docker logs zulip-router --tail 50`
|
||||
- [ ] Отключить `events_polling.enabled` у Валеры → `docker-compose up -d`
|
||||
- [ ] Отключить `events_polling.enabled` у Клавдия → `docker-compose up -d`
|
||||
- [ ] Протестировать: @Клавдий и @Валера в разных топиках
|
||||
- [ ] Проверить ownership: сообщение в топик без @mention → последний бот
|
||||
- [ ] Удалить `extractOtherMention()` патч из кода (больше не нужен)
|
||||
|
||||
Reference in New Issue
Block a user