# Балда / Валера — эксплуатация & MCP debug ## Расположение - **Валера** = `balda-agent-valera-1`, конфиг: `~/Docker/balda-agent/.config/balda/config.yaml` - **Клавдий** = `claudio-agent-claudio-1`, конфиг: `~/Docker/claudio-agent/.config/balda/config.yaml` - **Общий образ**: собирается из `~/Docker/claudio-agent/Dockerfile.claudio`, контекст `/Users/admin/Developer` - **Norma-local** (форк с MCP tools): `~/Developer/norma-local/` - `go.mod` replace: `github.com/normahq/norma => ./norma-local` (в `~/Developer/balda/go.mod`) - Модифицирован `pkg/runtime/hostedagent/openai.go` + `pkg/runtime/agentfactory/agentfactory.go` - **Dockerfile**: `~/Docker/claudio-agent/Dockerfile.claudio` - Копирует `norma-local/` в `/src/norma-local/` - `go mod edit -replace github.com/normahq/norma=./norma-local` перед `go mod download` ## Архитектура - **Валера** = DeepSeek (`provider: deepseek`, модель `deepseek-chat`) - **Клавдий** = Claude через прокси (`provider: claude`, `claude-sonnet-4-6`) - Валера использует **Balda runtime** — OpenAIModel из openai.go вызывается (hostedagent провайдер). - `agentfactory.go` используется обоими — там лог версии на старте. ## Версионный лог (norma-tools) При старте Валеры в логах: ``` norma-tools version=v0.0.10 build=whale-YYYYMMDD-N ``` Где: - `version` — номер версии нормы (из `openAIVersion`) - `build` — тег сборки (из `buildTag`) **Перед каждым билдом апать `buildTag`** в `openai.go`: ```go const openAIVersion = "v0.0.10" const buildTag = "whale-YYYYMMDD-N" // ← менять! ``` Файлы где апать: - `~/Developer/norma-local/pkg/runtime/hostedagent/openai.go` — `buildTag` константа ## Статус: DeepSeek MCP tools — РАБОТАЕТ ### Что сделано (openai.go) Добавлена полная поддержка OpenAI tool_calls: - `openAIToolDefinition`, `openAIFunction`, `openAIToolCall` — структуры - `Tools []openAIToolDefinition` в `openAIChatRequest` - `openAIToolsFromConfig()` — конвертация genai.Tool[] → OpenAI definitions - `parseChatResponse()` — парсинг tool_calls из ответа DeepSeek (ID сохраняется) - `contentToOpenAI()` — конвертация FunctionCall/FunctionResponse в историю - `generate()` — TurnComplete=false при tool_calls (ADK делает второй раунд) ### Исправленные проблемы #### 1. DeepSeek возвращает аргументы с двойной сериализацией ✓ 22.06.2026 **Симптом:** `read_note`/`write_note` падали — Obsidian MCP возвращал `"Cannot read properties of undefined (reading 'replace')"`. **Корень:** DeepSeek возвращает `function.arguments` как JSON-строку (экранированную), а не как JSON-объект. **Фикс в `parseChatResponse`:** сперва пробуем распарсить Arguments как строку (`json.Unmarshal(&argsStr)`), потом эту строку как объект (`json.Unmarshal([]byte(argsStr), &args)`). #### 2. Obsidian MCP: get_vault_stats работает, read/write/delete нет ✓ 22.06.2026 **Корень:** двойная сериализация аргументов (см. проблему 1). После её фикса всё работает. #### 3. Key `output` не проверялся в contentToOpenAI ✓ 22.06.2026 Obsidian MCP возвращает response как `{"output":"..."}` — добавлена проверка на ключ `output`. ### Текущий билд - buildTag: `whale-20260622-7` - Все фиксы закоммичены в `master` (норма-локаль) - OPENAI-DEBUG стэш дропнут — логи в рабочей копии (не коммитятся) - Replace на норму работает через `go.mod` + Dockerfile - `norma-tools` лог подтверждён: `time=2026-06-22T13:00:37.170Z level=INFO msg=norma-tools version=v0.0.10 build=whale-20260622-7` ## Промежуточные статусы — ПОЧИНЕНО (23.06.2026) **Статус:** работает. - `RunSessionTurnPayload` (zulip_handler.go) — публикует промежуточный текст и ⚙️ function call статусы для `!ev.TurnComplete` ивентов через `sendPlain`. - `balda.go` (Telegram) — те же промежуточные публикации. - `handleAutoClaimMention` / `handleMessage` / `enqueueTurn` — передают `messageID` для точного Zulip threading. - Коммит: `05159d1` (main), запушен. ## Стэши debug-логов (23.06.2026) Дебаг логи не коммитятся, хранятся в стэшах. **balda** (`~/Developer/balda`): - `stash@{0}`: `debug: whale-20260623 — TASK-ACTOR logging in swarm_task_actor, event count & response_len debug in zulip_handler` - `internal/apps/balda/actors/swarm_task_actor.go` — TASK-ACTOR: dispatching/dispatch OK/FAILED - `internal/apps/balda/handlers/zulip_handler.go` — eventCount, response_len, running session turn log - `stash@{1}`: WIP on feat/zulip-events-polling **Восстановление balda стэша:** ```bash cd ~/Developer/balda && git stash pop stash@{0} ``` **norma-local** (`~/Developer/norma-local`): - OPENAI-DEBUG стэш дропнут — 9x fmt.Fprintf(os.Stderr, "OPENAI-DEBUG:...") в рабочей копии openai.go ## Бранчи (23.06.2026) **norma-local:** - `feat/hostedagent-mcp-tools` — коммит `56a6e1e` (DeepSeek tool_calls фикс), чистая бранча от `origin/master` - `master` — коммит `56a6e1e` (тот же, DeepSeek фиксы) **balda:** - `main` — `05159d1` (intermediate status фикс запушен) - `backup/our-main-before-upstream` — старый main - `feat/zulip-transport-intermediate` — от коммита `bc5fd03` ## Сборка ### Полный цикл сборки ```bash # 1. Инкремент buildTag в openai.go (строка buildTag) # ~/Developer/norma-local/pkg/runtime/hostedagent/openai.go # buildTag = "whale-YYYYMMDD-N" # 2. Применить OPENAI-DEBUG стэш (если нужно дебажить) cd ~/Developer/norma-local && git stash pop stash@{0} # 3. Сборка docker build --no-cache \ -f ~/Docker/claudio-agent/Dockerfile.claudio \ -t balda-agent-valera:latest \ /Users/admin/Developer # 4. Деплой cd ~/Docker/balda-agent && docker-compose up -d --force-recreate # 5. Проверка версии в логах docker logs balda-agent-valera-1 2>&1 | grep "norma-tools" ``` ### Особенности сборки - Dockerfile копирует `norma-local/` в `/src/norma-local/` - `go.mod` replace: `github.com/normahq/norma => ./norma-local` - `go mod edit -replace` применяется **до** `go mod download` - `--no-cache` обязателен при изменении norma-local - Образ надо таргетировать под нужное имя: `balda-agent-valera` для Валеры, `claudio-agent` для Клавдия - После сборки `docker-compose up -d --force-recreate` чтобы подхватить новый образ ## Диагностика молчания / проблем ### NORMA-TOOLS не появляется в логах Причина: агент использует не hostedagent провайдер. openai.go задействован только при provider=deepseek через ADK. ### MCP ошибка: `failed to list MCP tools: failed to connect: Not Found` Фикс: в config.yaml url должен заканчиваться на `/sse`: `url: http://obsidian-mcp:3101/sse` ### В логах `command running → command handled` за секунду, без `received provider event` Причина: стухший embedded NATS. Фикс: `docker-compose restart` или `up -d`. ### Удалён / пустой state.db Фикс: `rm state.db` и `up -d` (balda создаст заново). ### Нет owner Фикс: прописать `allowed_owners` в config.yaml. ### stream_only_with_session Фикс: написать `@Валера <текст>` чтобы создать сессию. ## Известные грабли ### OPENAI_BASE_URL — обязательная env var Norma не читает `base_url` из config.yaml для `provider: deepseek`. Читает env. ### DOCKER_OPTS — пустая строка убивает старт Должен быть валидный JSON: `DOCKER_OPTS={"max_tokens": 2048}` ### docker compose up -d не работает На этом хосте `docker compose` (без дефиса) не принимает `-d`. Использовать `docker-compose up -d`. ### Docker кеш COPY norma-local/ Слой копирования кешируется. `--no-cache` обязателен при изменении norma-local. ### go.mod replace `replace github.com/normahq/norma => ./norma-local` — путь относительно `/src` в контейнере, куда копируется `norma-local/`. ### zulip-router owner-форвард падал с 400 (23.06.2026) **Симптом:** Валера не отвечал на сообщения в закреплённых тредах без @mention. Router лог: `forward failed (owner) error="post ... status 400 body=bad request"`. Валера лог: `invalid zulip webhook payload error="unsupported message.type \"\""`. **Корень:** В `zulip-router/config.go` структура `Message` не имела поля `Type`. Zulip Events API присылает `message.type` ("stream"/"private"), но роутер его не парсил — в вебхук приходил пустой `""`. Balda-agent валидирует message.type. **Фикс:** Добавлен `Type string \`json:"type,omitempty"\`` в `Message struct`. Коммит `803ae68` (локальный, без remote). docker-compose up -d --build. Фикс: messageID int в сигнатуру handleAutoClaimMention, передаётся payload.Message.ID из processMessage. Файл: `~/Developer/balda/internal/apps/balda/handlers/zulip_handler.go` (в коммите `05159d1`)