# Балда / Валера — эксплуатация ## Расположение - Repo: `~/Developer/balda/` - **Рабочий compose**: `~/Docker/balda-agent/docker-compose.yaml` → контейнер `balda-agent-valera-1` - Config (persistent): `~/Docker/balda-agent/.config/balda/config.yaml` - Env: `~/Docker/balda-agent/.env` - Дублирующий compose `~/Developer/balda/compose.valera.yaml` — НЕ использовать (сеть `balda_default` без DNS) ## Запуск / рестарт ```bash cd ~/Docker/balda-agent docker-compose restart # Rebuild после изменений в коде: docker-compose build && docker-compose up -d ``` ## Архитектура получения сообщений Валера — **outgoing webhook bot** (bot_type=3). Zulip отправляет webhook только для @mention и DM. Для получения всех сообщений в теме — **Events API polling** (отключён, после деплоя zulip-router будет удалён из кода): - `events_polling.enabled: false` в config.yaml (текущее состояние) - Сообщения приходят только через **outgoing webhook** (webhook_token в .env) - После @mention создаётся сессия; последующие сообщения без @mention обрабатываются **После перезапуска**: нужно один раз написать `@Валера <текст>` чтобы создать сессию в теме. ## Диагностика молчания 1. Проверить логи: `docker logs balda-agent-valera-1 --tail 50` 2. Проверить что бот запущен и webhook слушает: в логах `zulip webhook server starting addr=0.0.0.0:8091` 3. Стухший NATS-таск (симптом: логов нет после @mention) Фикс: `docker-compose restart` (NATS embedded, состояние в памяти) 4. Проверить webhook со стороны: отправить POST с curl: ```bash curl -X POST http://localhost:8091/zulip/webhook \ -H "Content-Type: application/json" \ -d '{"type":"test"}' ``` ## Патчи в коде (общие с Клавдием) В `zulip_handler.go` добавлены: 1. `botName` — извлекается из bot_email (часть до @). Используется чтобы отличить свой @mention от чужого. 2. `extractOtherMention()` — проверяет текст на @**Name**, где Name не равен botName и не @**all**/@**everyone**. Если найден чужой @mention — сообщение игнорируется. 3. Детальное логирование в `handleAutoClaimMention` — видны все шаги от входа до ошибки. ## Ключевые грабли ### 1. OPENAI_BASE_URL — обязательная env var Norma не читает `base_url` из config.yaml для `provider: deepseek`. Она читает env `OPENAI_BASE_URL`. Без неё запросы уходят на `api.openai.com` (401). **В `.env` обязательно:** ``` OPENAI_BASE_URL=https://api.deepseek.com/v1 ``` **ВАЖНО:** `docker-compose restart` не перечитывает `.env`. Нужно `docker-compose up -d` (пересоздание контейнера). ### 2. DOCKER_OPTS — пустая строка убивает старт Если `DOCKER_OPTS=""` (или пустая строка в `.env`), norma падает на парсинге float: ``` strconv.ParseFloat: parsing "" ``` **Должен быть валидный JSON:** ``` DOCKER_OPTS={"max_tokens": 2048, "temperature": 0.7} ``` ### 3. composerestart vs compose up -d - `docker-compose restart` — не перечитывает `.env`, не пересоздаёт контейнер - `docker-compose up -d` — пересоздаёт контейнер с обновлённым `.env` При изменении `.env` всегда использовать `up -d`. ## Конфигурация провайдера В `config.yaml` обязательно: ```yaml balda: provider: deepseek zulip: events_polling: enabled: false # true → если events polling нужен (сейчас отключён) stream_only_with_session: true runtime: providers: deepseek: openai: base_url: https://api.deepseek.com/v1 ```