Files
obsidian-vault/personal/projects/balda/balda-valera.md
T

8.2 KiB
Raw Blame History

Балда / Валера — эксплуатация

Расположение

  • 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 обрабатываются

После перезапуска: нужно один раз написать @Валера <текст> чтобы создать сессию в теме.

Диагностика молчания

  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:
    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.

Контекст (история сообщений)

Не работает для 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 вызов.

Возможные решения

  1. Inject'ить историю в RunSessionTurnPayload — перед вызовом r.Run() загрузить предыдущие сообщения из ADK session store и передать как мульти-контент. Патч в zulip_handler.go и balda.go.
  2. Передать историю через global_instruction — обогащать промпт предыдущими сообщениями из balda session хранилища.
  3. Использовать 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 runningcommand handled за секунду, без received provider event

Причины (проверять по порядку):

  1. Стухший embedded NATS — swarm внутри процесса не может доставить команду до session/task actor'ов. Фикс: docker-compose restart (если не помогло → up -d)

  2. Удалён / пустой state.db — после удаления balda не может зарегистрировать swarm акторы. Фикс: rm state.db и up -d (balda создаст заново). Owner токен сбросится — нужен /start owner=....

  3. Нет ownerhandleMessage выходит при getOwnerID() == 0. Фикс: /start owner=<TOKEN> в Telegram или Zulip.

  4. stream_only_with_session — сообщение в теме без сессии молча дропается. Фикс: написать @Валера <текст> чтобы создать сессию.

  5. 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