8.2 KiB
Балда / Валера — эксплуатация
Расположение
- 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)
Запуск / рестарт
cd ~/Docker/balda-agent
docker-compose restart
# Rebuild после изменений в коде:
cd ~/Docker/claudio-agent && docker-compose build && docker-compose up -d
cd ~/Docker/balda-agent && docker-compose up -d
Валера и Клавдий — один образ (
balda-agent-valera), собирается из одного Dockerfile (Dockerfile.claudio). Разница только в конфиге (config.yaml) и.env, которые монтируются volumes.Сборка образа:
cd ~/Docker/claudio-agent && docker-compose build && docker-compose up -dПерезапуск Валеры:cd ~/Docker/balda-agent && docker-compose up -dСборка идёт из
~/Docker/claudio-agent/— там есть build секция с Dockerfile.
Архитектура получения сообщений
Валера — 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 обрабатываются
После перезапуска: нужно один раз написать @Валера <текст> чтобы создать сессию в теме.
Диагностика молчания
- Проверить логи:
docker logs balda-agent-valera-1 --tail 50 - Проверить что бот запущен и webhook слушает: в логах
zulip webhook server starting addr=0.0.0.0:8091 - Стухший NATS-таск (симптом: логов нет после @mention)
Фикс:docker-compose restart(NATS embedded, состояние в памяти) - Проверить webhook со стороны: отправить POST с curl:
curl -X POST http://localhost:8091/zulip/webhook \ -H "Content-Type: application/json" \ -d '{"type":"test"}'
Патчи в коде (общие с Клавдием)
В zulip_handler.go добавлены:
botName— извлекается из bot_email (часть до @). Используется чтобы отличить свой @mention от чужого.extractOtherMention()— проверяет текст на @Name, где Name не равен botName и не @all/@everyone. Если найден чужой @mention — сообщение игнорируется.- Детальное логирование в
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.
Контекст (история сообщений)
Не работает для OpenAI-совместимых провайдеров (DeepSeek, ChatGPT и т.д.).
Причина: ADK Runner (google.golang.org/adk) inject'ит историю в мульти-тур только для Gemini API. Для OpenAI-compatible провайдеров (через base_url переопределение) ADK не inject'ит предыдущие сообщения в вызов модели — каждый turn получает только одно сообщение.
balda.sessions.persistent: true — влияет на хранение balda-сессии между рестартами, но не на inject истории в API вызов.
Возможные решения
- Inject'ить историю в RunSessionTurnPayload — перед вызовом
r.Run()загрузить предыдущие сообщения из ADK session store и передать как мульти-контент. Патч вzulip_handler.goиbalda.go. - Передать историю через global_instruction — обогащать промпт предыдущими сообщениями из balda session хранилища.
- Использовать Gemini API (нативный ADK inject истории).
Owner token
При старте генерируется owner token. Выводится в лог:
balda owner authentication required auth_command="/start owner=<TOKEN>"
Для авторизации через Telegram (или Zulip с /start):
/start owner=<TOKEN>
При старте с пустым state.db (после rm) — owner не зарегистрирован. Бот принимает сообщения но не отвечает до /start.
state.db путь: контейнер /workspace/.config/balda/state.db, на хосте ~/Docker/balda-agent/.config/balda/state.db.
Диагностика: Валера не отвечает в Zulip
Симптом: в логах command running → command handled за секунду, без received provider event
Причины (проверять по порядку):
-
Стухший embedded NATS — swarm внутри процесса не может доставить команду до session/task actor'ов. Фикс:
docker-compose restart(если не помогло →up -d) -
Удалён / пустой state.db — после удаления balda не может зарегистрировать swarm акторы. Фикс:
rm state.dbиup -d(balda создаст заново). Owner токен сбросится — нужен/start owner=.... -
Нет owner —
handleMessageвыходит приgetOwnerID() == 0. Фикс:/start owner=<TOKEN>в Telegram или Zulip. -
stream_only_with_session — сообщение в теме без сессии молча дропается. Фикс: написать
@Валера <текст>чтобы создать сессию. -
DeepSeek не отвечает (context loss) — см. раздел «Контекст».
Конфигурация провайдера
В config.yaml обязательно:
balda:
provider: deepseek
sessions:
persistent: true
persistence: sqlite
zulip:
events_polling:
enabled: false
stream_only_with_session: true
runtime:
providers:
deepseek:
openai:
base_url: https://api.deepseek.com/v1