- AGENTS.md: Sofiia Chief AI Architect role definition - SOFIIA_IN_OPENCODE.md, SOFIIA_NODA2_SETUP.md: NODA2 setup documentation - agromatrix_stepan_noda1_APPLY.md, agromatrix_stepan_noda1_prod.patch: AgroMatrix production patch - docker-compose.memory-node2.yml: memory service for NODA2 - docker-compose.node2-sofiia-supervisor.yml: sofiia supervisor for NODA2 - gateway-bot/gateway_boot.py, monitor_prompt.txt, vision_guard.py: gateway extras - models/Modelfile.qwen3.5-35b-a3b: Qwen model definition for NODA3 - opencode.json: OpenCode providers and agents config - scripts/init-sofiia-memory.py, scripts/node2/*, start-memory-node2.sh: NODA2 init scripts - setup_sofiia_node2.sh: NODA2 full setup script Made-with: Cursor
17 KiB
Застосування production-patch AgroMatrix/Stepan на НОДА1
Патч: agromatrix_stepan_noda1_prod.patch — тільки зміни для стабілізації Степана/AgroMatrix. Без vision/router/інших агентів.
Передумови
- Доступ по SSH на НОДА1 (144.76.224.179).
- Репозиторій на сервері:
/opt/microdao-daarion(або вашDEPLOY_ROOT). - На сервері є каталоги:
gateway-bot/,crews/,packages/agromatrix-tools/.
Крок 1 — Завантаження patch на НОДА1
Варіант A (з локальної машини):
scp /шлях/до/agromatrix_stepan_noda1_prod.patch USER@144.76.224.179:/opt/microdao-daarion/
Варіант B (якщо patch уже в репо):
ssh USER@144.76.224.179 "cd /opt/microdao-daarion && git pull && git show HEAD:agromatrix_stepan_noda1_prod.patch > agromatrix_stepan_noda1_prod.patch"
# або просто скопіювати вміст файла в репо на сервер
Варіант C (вміст патчу вставлений вручну):
На сервері створити файл /opt/microdao-daarion/agromatrix_stepan_noda1_prod.patch з повним вмістом unified diff.
Крок 2 — Застосування patch (git apply)
На НОДА1:
cd /opt/microdao-daarion
# Переконатися, що немає незакомічених змін у задіяних файлах (або зробити backup)
git status
# Сухий прогон (перевірка, що патч застосується без конфліктів)
git apply --check agromatrix_stepan_noda1_prod.patch
# Застосувати
git apply agromatrix_stepan_noda1_prod.patch
Якщо git apply --check повертає помилку (наприклад, через відмінний базовий коміт), можна спробувати:
git apply --reject --whitespace=fix agromatrix_stepan_noda1_prod.patch
# і вручну розв’язати файли *.rej, якщо з’являться.
Крок 3 — Rebuild і запуск gateway
cd /opt/microdao-daarion
# Зібрати образ gateway і запустити контейнер
docker compose -f docker-compose.node1.yml up -d --build gateway
Сервіс у compose називається gateway, контейнер — dagi-gateway-node1. Якщо використовуєте інший compose-файл або ім’я сервісу, підставте їх.
Крок 4 — Перевірка health
# Локально на сервері
curl -s http://localhost:9300/health
curl -s http://localhost:9300/
# Ззовні (якщо порт 9300 відкритий)
curl -s http://144.76.224.179:9300/health
Очікується: HTTP 200 і JSON зі статусом сервісу.
Крок 5 — Перевірка логів (NameError / ImportError)
docker logs dagi-gateway-node1 2>&1 | tail -100
docker logs dagi-gateway-node1 2>&1 | grep -E "NameError|ImportError|Stepan mode|Stepan inproc|Stepan disabled"
- Має з’явитися рядок типу
Stepan mode=inproc (AGX_STEPAN_MODE)після першого звернення до AgroMatrix або при старті (залежно від реалізації логу). - Не повинно бути
NameError: has_recent_interactionабоImportErrorчерез crews/agromatrix_tools після коректного монтування та env.
Якщо бачите Stepan disabled — перевірте AGX_REPO_ROOT, наявність томів crews і packages/agromatrix-tools у compose та що в контейнері є відповідні каталоги.
Крок 6 — Smoketests
-
Doc follow-up (раніше 500)
У Telegram-чаті агента AgroMatrix: надіслати документ, потім текстове питання по ньому.
Очікується: відповідь без HTTP 500 (відповідь з RAG або повідомлення про відсутність відповіді в документі). -
Оператор: /whoami
Від користувача зuser_idуAGX_OPERATOR_IDS(або в чаті зAGX_OPERATOR_CHAT_ID): надіслати/whoami.
Очікується: відповідь від Степана (whoami), не звичайний pipeline. -
Оператор: звичайний текст без slash
Від того ж оператора: надіслати текст без слеша (наприклад «привіт»).
Очікується: обробка через Степана (handle_stepan_message), не fallback у звичайний Router pipeline. -
Не-оператор: звичайний текст
Від користувача, який не входить до операторів: звичайне повідомлення.
Очікується: обробка стандартним Router pipeline, не через Степана.
Перед тестами 2–4 переконайтеся, що в env задані AGX_OPERATOR_IDS (та за потреби AGX_OPERATOR_CHAT_ID).
Rollback
Якщо потрібно повернути стан до патчу:
cd /opt/microdao-daarion
# Скасувати зміни в робочій копії (повернути файли до останнього коміту)
git checkout HEAD -- gateway-bot/http_api.py gateway-bot/services/doc_service.py gateway-bot/app.py gateway-bot/gateway_boot.py crews/agromatrix_crew/operator_commands.py docker-compose.node1.yml
rm -f gateway-bot/gateway_boot.py
# Перезібрати і перезапустити gateway
docker compose -f docker-compose.node1.yml up -d --build gateway
Або ж повернути весь репо до попереднього коміту і перезібрати образ:
git reset --hard HEAD
docker compose -f docker-compose.node1.yml up -d --build gateway
Env на НОДА1 (без секретів)
Переконайтеся, що в середовищі gateway (compose або .env) задані:
AGX_STEPAN_MODE=inproc(за замовчуванням)AGX_REPO_ROOT=/app(в контейнері; на хості відповідає вашомуDEPLOY_ROOTу путях томів)AGX_OPERATOR_IDS=***— список Telegram user_id операторів (через кому)AGX_OPERATOR_CHAT_ID=***— опційно, обмеження чату для операторівOPENAI_API_KEY=***— потрібен для inproc Степана
Секрети не виводьте в логи; у документації позначайте як KEY=***.
A. Імпорт gateway_boot (fail-closed)
У контейнері CMD: WORKDIR /app/gateway-bot і python -m uvicorn app:app. Тому поточний каталог для імпортів — /app/gateway-bot. У app.py використовується import gateway_boot (модуль у тій самій директорії, що й app.py), тож Python резолвить /app/gateway-bot/gateway_boot.py. Це коректно при volume ${DEPLOY_ROOT}/gateway-bot:/app/gateway-bot:ro.
Швидкий тест у контейнері (CWD /app/gateway-bot, як у uvicorn):
ssh root@144.76.224.179 'docker exec dagi-gateway-node1 sh -c "cd /app/gateway-bot && python3 -c \"import gateway_boot; print(\\\"gateway_boot OK\\\")\""'
Очікується: gateway_boot OK. Якщо тут ImportError — STEPAN_IMPORTS_OK ніколи не стане True і Степан залишиться тихо вимкненим.
B. Volume-монтування crews і packages/agromatrix-tools
У docker-compose.node1.yml томи змонтовані в контейнері так:
${DEPLOY_ROOT:-.}/crews→/app/crews${DEPLOY_ROOT:-.}/packages/agromatrix-tools→/app/packages/agromatrix-tools
На хості це може бути /opt/microdao-daarion/crews, але в контейнері завжди /app/crews та /app/packages/agromatrix-tools.
Перевірка наявності в контейнері:
ssh root@144.76.224.179 "docker exec dagi-gateway-node1 ls -la /app/crews | head"
ssh root@144.76.224.179 "docker exec dagi-gateway-node1 ls -la /app/packages/agromatrix-tools | head"
Очікується: список файлів/каталогів (наприклад agromatrix_crew у crews, пакет у agromatrix-tools). Якщо No such file or directory — томи не змонтовані або compose не оновлено після патчу.
PYTHONPATH у контейнері (crews і agromatrix_tools)
Щоб працювало from crews.agromatrix_crew.run import ..., у sys.path має бути /app (батько каталога crews), а не /app/crews.
Щоб працювало import agromatrix_tools, у sys.path має бути /app/packages/agromatrix-tools (батьківська директорія пакета).
У патчі задано: PYTHONPATH=/app:/app/packages/agromatrix-tools. При потребі можна додати /app/gateway-bot, але uvicorn і так додає робочу директорію при python -m uvicorn app:app.
Практичний контроль після деплою:
ssh root@144.76.224.179 "docker exec dagi-gateway-node1 sh -c 'env | grep -E \"^PYTHONPATH=\" || true'"
ssh root@144.76.224.179 "docker exec dagi-gateway-node1 sh -c 'cd /app/gateway-bot && python3 -c \"import sys; print(\\\"\\n\\\".join(sys.path))\"' | head -20"
Читання STEPAN_IMPORTS_OK (без “заморожування”)
Щоб прапорець оновлювався після startup, усі місця мають робити import gateway_boot і читати gateway_boot.STEPAN_IMPORTS_OK (або getattr(gateway_boot, "STEPAN_IMPORTS_OK", False)).
Не використовувати from gateway_boot import STEPAN_IMPORTS_OK — значення “заморозиться” на момент імпорту і не відобразиться після встановлення в app.py.
Grep-контроль на сервері:
ssh root@144.76.224.179 "cd /opt/microdao-daarion && grep -Rn 'from gateway_boot import' gateway-bot || true"
ssh root@144.76.224.179 "cd /opt/microdao-daarion && grep -Rn 'import gateway_boot' gateway-bot"
Очікується: немає збігів для from gateway_boot import; є лише import gateway_boot (у app.py та http_api.py).
Compose env: лапки для AGX_OPERATOR_*
Якщо значення задані прямо в YAML (а не тільки через ${...}), краще завжди брати їх у лапки, щоб уникнути проблем парсингу (зокрема від’ємні chat_id):
AGX_OPERATOR_CHAT_ID: "-1001234567890"AGX_OPERATOR_IDS: "123,456"
При використанні змінних середовища (AGX_OPERATOR_IDS=${AGX_OPERATOR_IDS:-}) лапки ставлять у .env або в значенні змінної при експорті.
Мінімальний фінальний чек-лист (після git apply і --build)
-
Патч застосовано чисто
Перед першим застосуванням:git apply --check agromatrix_stepan_noda1_prod.patch(код виходу 0 = можна застосовувати).
Після застосування можна перевірити наявність змін, наприклад:ssh root@144.76.224.179 "cd /opt/microdao-daarion && test -f gateway-bot/gateway_boot.py && grep -q 'import gateway_boot' gateway-bot/app.py && echo OK" -
Rebuild gateway
ssh root@144.76.224.179 "cd /opt/microdao-daarion && docker compose -f docker-compose.node1.yml up -d --build gateway" -
Stepan реально увімкнувся (логи)
ssh root@144.76.224.179 "docker logs dagi-gateway-node1 --since 10m 2>&1 | grep -E 'Stepan mode|STEPAN_IMPORTS_OK|Stepan disabled|Stepan inproc|ImportError|ModuleNotFoundError' | tail -30"Очікується: згадка
Stepan mode=inproc(після першого звернення до AgroMatrix) і відсутність "Stepan disabled". У логах після старту має з’явитися рядокSTEPAN_IMPORTS_OK=True(додано в app.py після встановлення прапорця), тоді fail-closed коректно пройшов. -
Оператори задані (обов’язково для "людського" режиму)
ssh root@144.76.224.179 "docker exec dagi-gateway-node1 env | grep -E '^AGX_OPERATOR_IDS=|^AGX_OPERATOR_CHAT_ID=' | sed 's/=.*/=***/'"Очікується: хоча б
AGX_OPERATOR_IDS=***(значення приховуються). Якщо змінних немає — операторські повідомлення не підуть у Степана. -
Опційно: резолв gateway_boot і томи (див. блоки A і B вище).
Нюанс: AGX_STEPAN_MODE=http
Режим AGX_STEPAN_MODE=http зараз повертає 501 stub (Степан "офіційно" недоступний). Щоб у проді не випадково вимкнути Степана:
- У docker-compose.node1.yml у секції gateway залишити явно
AGX_STEPAN_MODE=inproc(або не задавати — тоді default з патчу inproc). - Режим
httpвикористовувати лише в тестових середовищах, коли з’явиться реалізація клієнта crewai-service.
Фрагмент патчу для перевірки імпортів (app.py + gateway_boot)
Нижче — заголовки diff і контекст імпортів у app.py, щоб переконатися, що gateway_boot імпортується як модуль з тієї самої директорії, де лежить app.py, і резолвиться в контейнері.
gateway-bot/app.py (фрагмент після патчу):
import logging
import os
import sys
from pathlib import Path
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from http_api import router as gateway_router
from http_api_doc import router as doc_router
import gateway_boot # <-- той самий каталог: /app/gateway-bot/gateway_boot.py
gateway-bot/gateway_boot.py (новий файл):
"""
Boot-time state for Gateway. Set by app startup; read by http_api.
"""
STEPAN_IMPORTS_OK = False
У контейнері: WORKDIR /app/gateway-bot, volume монтує gateway-bot у /app/gateway-bot, тому app.py і gateway_boot.py лежать поруч — import gateway_boot коректно знаходить модуль. Після startup у startup_stepan_check() при успішному імпорті виконується gateway_boot.STEPAN_IMPORTS_OK = True і лог STEPAN_IMPORTS_OK=True; інакше прапорець залишається False (fail-closed). У http_api використовується лише import gateway_boot і getattr(gateway_boot, "STEPAN_IMPORTS_OK", False) — не from gateway_boot import ..., щоб значення читалося в runtime після оновлення в app.py.
Підсумок перевірок “готово до прод”
Мінімально достатньо три пункти:
-
Логи після старту (Stepan увімкнено, без ImportError):
ssh root@144.76.224.179 "docker logs dagi-gateway-node1 --since 10m 2>&1 | grep -E 'Stepan mode|STEPAN_IMPORTS_OK|Stepan disabled|ImportError|ModuleNotFoundError' | tail -120" -
Volumes на місці (
/app/crews,/app/packages/agromatrix-tools):ssh root@144.76.224.179 "docker exec dagi-gateway-node1 ls -la /app/crews | head" ssh root@144.76.224.179 "docker exec dagi-gateway-node1 ls -la /app/packages/agromatrix-tools | head" -
Env операторів і режиму (масковано):
ssh root@144.76.224.179 "docker exec dagi-gateway-node1 env | grep -E '^AGX_OPERATOR_IDS=|^AGX_OPERATOR_CHAT_ID=|^AGX_STEPAN_MODE=' | sed 's/=.*/=***/'"
Якщо ці три пункти зелені — патч відповідає fail-closed моделі і не повинен давати “тихих” падінь gateway при відсутніх crews/agromatrix-tools.