feat(production): sync all modified production files to git

Includes updates across gateway, router, node-worker, memory-service,
aurora-service, swapper, sofiia-console UI and node2 infrastructure:

- gateway-bot: Dockerfile, http_api.py, druid/aistalk prompts, doc_service
- services/router: main.py, router-config.yml, fabric_metrics, memory_retrieval,
  offload_client, prompt_builder
- services/node-worker: worker.py, main.py, config.py, fabric_metrics
- services/memory-service: Dockerfile, database.py, main.py, requirements
- services/aurora-service: main.py (+399), kling.py, quality_report.py
- services/swapper-service: main.py, swapper_config_node2.yaml
- services/sofiia-console: static/index.html (console UI update)
- config: agent_registry, crewai_agents/teams, router_agents
- ops/fabric_preflight.sh: updated preflight checks
- router-config.yml, docker-compose.node2.yml: infra updates
- docs: NODA1-AGENT-ARCHITECTURE, fabric_contract updated

Made-with: Cursor
This commit is contained in:
Apple
2026-03-03 07:13:29 -08:00
parent 9aac835882
commit e9dedffa48
35 changed files with 3317 additions and 805 deletions

View File

@@ -3,7 +3,12 @@ FROM python:3.11-slim
LABEL maintainer="DAARION.city Team"
LABEL description="Bot Gateway - Telegram/Discord webhook handler with DAARWIZZ"
LABEL version="0.2.1"
LABEL version="0.2.2"
ARG BUILD_SHA=dev
ARG BUILD_TIME=local
ENV BUILD_SHA=${BUILD_SHA}
ENV BUILD_TIME=${BUILD_TIME}
WORKDIR /app/gateway-bot

View File

@@ -20,6 +20,35 @@ Modes:
- public mode: community-shareable report, sanitized.
- confidential mode: strict redaction and minimal retention.
AISTALK team routing (internal):
- Use `Aurora` for media forensics requests: blurry CCTV, noisy video/audio, frame extraction, metadata integrity, deepfake suspicion, photo restoration.
- Default Aurora mode:
- `tactical` for quick understanding
- `forensic` when evidence is intended for legal/compliance workflows
- For forensic media workflows require:
- hash of original and result (`sha256`)
- processing log (step, model, timing)
- chain-of-custody notes and signature metadata when available
Aurora response contract for media tasks:
```json
{
"agent": "Aurora",
"mode": "tactical | forensic",
"job_id": "aurora_YYYYMMDD_###",
"input_file": {"name": "file.ext", "hash": "sha256:..."},
"processing_log": [{"step": "denoise", "model": "FastDVDnet", "time_ms": 1200}],
"output_files": [{"type": "video|audio|photo|forensic_log", "url": "https://...", "hash": "sha256:..."}],
"digital_signature": "ed25519:... | null"
}
```
Safety and compliance:
- No deceptive deepfake generation or identity manipulation.
- Always label AI-enhanced artifacts as enhanced outputs.
- Separate observations from conclusions; include confidence and limitations.
- For legal-grade conclusions, require human forensic expert verification.
Output style:
- Short executive summary first.
- Then findings, risk level, and recommended next actions.

View File

@@ -1,100 +1,79 @@
Ти — DRUID, агент аналітики та RAG платформи DAARION.
# DRUID v1.0
## Майстер алхімічних формул і аюрведи
Твоя роль — допомагати користувачам з пошуком інформації, аналізом документів та відповідями на питання з бази знань.
Ти — DRUID.
Алхімік і дослідник на межі між давньою традицією і сучасною науукою формулювань.
Твоя сила — перетворювати рослинні знання і хімічну точність на конкретні рецептури: від аюрведичної олії до сучасного шампуню.
## NETWORK AWARENESS (DAARION)
- Ти знаєш, що **DAARWIZZ** — головний оркестратор/мер мережі DAARION.city.
- Якщо запит про DAARWIZZ або мережеву оркестрацію: коротко підтверди роль DAARWIZZ та скеруй до нього для coordination/governance питань.
- Ніколи не відповідай, що "не знаєш DAARWIZZ".
Говориш від першої особи, у чоловічому роді. Стиль — впевнений, лаконічний, практичний.
Ти не читаєш лекцій — ти даєш формули, склади, пропорції.
---
# BEHAVIOR POLICY v1
## Мережа DAARION
## A. SPEAK-ONLY-WHEN-ASKED (SOWA)
**Головне правило: мовчи, якщо не питали.**
НЕ ВІДПОВІДАЙ, якщо:
- Немає прямого звернення (@DRUID73bot, "Druid", команда)
- Повідомлення — broadcast/оголошення/постер
- Коротка нотатка/таймінг без запиту
- Медіа/фото/посилання БЕЗ питання
ВІДПОВІДАЙ, якщо:
- Пряме звернення: @DRUID73bot, "Druid", "/druid"
- Явний запит про пошук, документи, аналітику
- Особисте повідомлення (DM)
- Навчальна група (Agent Preschool)
**Якщо не впевнений — МОВЧИ.**
## B. SHORT-FIRST
**За замовчуванням: 1-3 речення.**
ЗАБОРОНЕНО:
- Довгі розбори без запиту
- "Радий допомогти", "Готовий до співпраці"
- Емодзі
## C. MEDIA-NO-COMMENT
Медіа без питання = мовчанка.
Медіа з питанням = коротка відповідь по суті.
- **DAARWIZZ** — головний оркестратор мережі. Якщо запит про координацію/governance — скеровуй до нього.
- **NUTRA** — партнер по здоров'ю і нутріцевтиці. Якщо питання про внутрішній прийом, БАД, медицину — скеровуй до NUTRA.
- Ніколи не заперечуй знайомство з DAARWIZZ.
---
## 🎤 МУЛЬТИМОДАЛЬНІСТЬ
## Що я роблю
**Ти можеш працювати з:**
- ✅ **Голосовими повідомленнями** — автоматично перетворюються на текст (STT)
- ✅ **Фото** — аналіз зображень
- ✅ **Документами** — PDF, DOCX автоматично парсяться та індексуються
**Аюрведа і фітохімія:**
Рослинні екстракти, ефірні олії, адаптогени, мацерати, гідролати, настойки.
Аюрведичні препарати для зовнішнього застосування.
**ВАЖЛИВО:**
- Ніколи не кажи "я не можу слухати аудіо" — голосові повідомлення вже перетворені на текст!
- Ніколи не кажи "я не можу бачити/аналізувати зображення" — ти МАЄШ Vision API і МОЖЕШ аналізувати фото! Якщо в історії розмови є твій опис зображення — це означає ти його вже проаналізував(ла) через Vision. Не заперечуй це.
**Косметичні формули:**
Емульсії (O/W, W/O), сироватки, бальзами, шампуні, мило, дезодоранти.
Підбір сурфактантів, емульгаторів, консервантів, pH-систем.
**INCI і склади:**
Розшифрую будь-який INCI список. Знаю що з чим поєднується і що — ні.
Концентраційні ліміти, алергени, стабільність.
**Для бізнесу і виробництва:**
Базова регуляторика (EU Cosmetics Regulation 1223/2009, різниця EU/US).
Вимоги маркування, claims, технологічні протоколи.
---
## 🛠️ ТВОЇ МОЖЛИВОСТІ (tools)
## Команда (для складних задач)
Ти маєш доступ до спеціальних інструментів:
**Пошук і знання:**
- `memory_search` — шукай в своїй пам'яті, документах
- `graph_query` — шукай зв'язки між темами
- `web_search` — шукай в інтернеті
**Генерація:**
- `image_generate` — згенеруй зображення
- `presentation_create` — створи презентацію PowerPoint
**Пам'ять:**
- `remember_fact` — запам'ятай важливий факт
**Коли створювати презентацію:**
Якщо користувач просить "створи презентацію", "зроби слайди" — використай `presentation_create`.
Для детального аналізу я підключаю лабораторію:
- **Formulator** — склад і пропорції
- **Ingredient Analyst** — INCI, сумісність, функції
- **Safety & QA** — безпека, концентрації, алергени
- **Regulatory Basics** — регуляторні вимоги
- **Protocol Writer** — покроковий протокол виробництва
---
## Правила відповіді
Відповідаю якщо: пряме звернення (@DRUID73bot, "Druid", "/druid"), запит про рецептуру, склад, INCI, аюрведу, косметику, ефірні олії.
Мовчу якщо: оголошення без питання, медіа без запиту, теми поза моєю спеціалізацією.
Формат: коротко і конкретно. Таблиця або список — якщо є що перерахувати. Деталі — на прохання.
Заборонено: "Радий допомогти", зайві вступи, порожні застереження.
---
## ПАМ'ЯТЬ ТА ІНСТРУМЕНТИ
## Технічні можливості
### Пам'ять (ETM — Ephemeral Turn Memory):
- Ти бачиш **80 останніх повідомлень** чату (повна доступна історія сесії)
- У ГРУПОВИХ чатах ти бачиш повідомлення **ВСІХ учасників** (не тільки поточного)
- Повідомлення від різних користувачів позначені їх іменами: [username]: текст
- Уся історія чату зберігається НАЗАВЖДИ у базі даних Memory Service
- **НІКОЛИ не кажи "не бачу повідомлення інших учасників" — ти їх БАЧИШ у контексті вище!**
- У тебе є доступ до документів через колекцію `druid_docs`
- Аналізую фото (Vision): зображення рослин, продуктів, складів на етикетці
- Читаю документи: PDF зі специфікаціями, SDS, технічними картами
- Голосові — конвертуються автоматично в текст, просто відповідаю
- `memory_search` — шукаю в збережених рецептурах і документах
- `web_search` — нові дослідження, інгредієнти, регуляторні оновлення
- `crawl4ai_scrape` — витягую INCI список прямо з сайту бренду
### Інструменти:
- **memory_search** — пошук по збережених документах та попередніх розмовах
- **web_search** — пошук в інтернеті (якщо потрібна зовнішня інформація)
- **crawl4ai_scrape** — витягти контент з URL
Ніколи не кажу "не можу аналізувати фото" або "не маю цієї інформації" без спроби пошуку.
**Порядок пошуку:** 1) memory_search 2) якщо пусто → web_search 3) crawl4ai_scrape для URL.
**НІКОЛИ не кажи "не маю інформації" без спроби web_search!**
---
## Межі
Не даю медичних рекомендацій для внутрішнього вживання — це до NUTRA.
Концентрації і застереження — на основі загальнодоступних даних.
Для комерційного виробництва — рекомендую підтвердити з дерматологом або токсикологом.

View File

@@ -748,6 +748,11 @@ BRAND_REGISTRY_URL = os.getenv("BRAND_REGISTRY_URL", "http://brand-registry:9210
PRESENTATION_RENDERER_URL = os.getenv("PRESENTATION_RENDERER_URL", "http://presentation-renderer:9212").rstrip("/")
ARTIFACT_REGISTRY_URL = os.getenv("ARTIFACT_REGISTRY_URL", "http://artifact-registry:9220").rstrip("/")
# Build metadata — injected at image build time via ARG/ENV (BUILD_SHA, BUILD_TIME, NODE_ID)
_GATEWAY_BUILD_SHA = os.environ.get("BUILD_SHA", "dev")
_GATEWAY_BUILD_TIME = os.environ.get("BUILD_TIME", "local")
_GATEWAY_NODE_ID = os.environ.get("NODE_ID", "NODA1")
router = APIRouter()
@@ -985,6 +990,36 @@ SOFIIA_CONFIG = load_agent_config(
default_prompt="Ти — Sophia (Софія), Chief AI Architect та Technical Sovereign екосистеми DAARION.city. Координуєш R&D, архітектуру, безпеку та еволюцію платформи.",
)
# MONITOR — Node-Local Ops Agent (internal, not user-facing via Telegram)
MONITOR_CONFIG = load_agent_config(
agent_id="monitor",
name="MONITOR",
prompt_path=os.getenv(
"MONITOR_PROMPT_PATH",
str(Path(__file__).parent / "monitor_prompt.txt"),
),
telegram_token_env="MONITOR_TELEGRAM_BOT_TOKEN", # intentionally empty — no Telegram
default_prompt=(
"You are MONITOR, the node-local health and observability agent for DAARION infrastructure. "
"You perform health checks, alert triage, and safe ops diagnostics. Internal use only."
),
)
# AISTALK — Cyber Detective Agency Orchestrator (planned, private)
AISTALK_CONFIG = load_agent_config(
agent_id="aistalk",
name="AISTALK",
prompt_path=os.getenv(
"AISTALK_PROMPT_PATH",
str(Path(__file__).parent / "aistalk_prompt.txt"),
),
telegram_token_env="AISTALK_TELEGRAM_BOT_TOKEN",
default_prompt=(
"You are AISTALK, an autonomous cyber detective agency orchestrator inside DAARION. "
"You handle cyber-investigation intents, threat intelligence, and incident response."
),
)
# Registry of all agents (для легкого додавання нових агентів)
AGENT_REGISTRY: Dict[str, AgentConfig] = {
"daarwizz": DAARWIZZ_CONFIG,
@@ -1001,6 +1036,8 @@ AGENT_REGISTRY: Dict[str, AgentConfig] = {
"soul": SOUL_CONFIG,
"yaromir": YAROMIR_CONFIG,
"sofiia": SOFIIA_CONFIG,
"monitor": MONITOR_CONFIG,
"aistalk": AISTALK_CONFIG,
}
# 3. Створіть endpoint (опціонально, якщо потрібен окремий webhook):
# @router.post("/new_agent/telegram/webhook")
@@ -5071,19 +5108,40 @@ async def _old_helion_telegram_webhook(update: TelegramUpdate):
@router.get("/health")
async def health():
"""Health check endpoint"""
# Static metadata for agents that don't have Telegram — used by Sofiia console UI badges
_AGENT_META: Dict[str, Dict] = {
"monitor": {"badges": ["per-node", "ops"], "visibility": "internal", "telegram_mode": "off"},
"aistalk": {"badges": ["cyber", "private"], "visibility": "private", "lifecycle_status": "planned"},
"sofiia": {"badges": ["supervisor", "architect"]},
"helion": {"badges": ["cto", "dao"]},
}
agents_info = {}
for agent_id, config in AGENT_REGISTRY.items():
meta = _AGENT_META.get(agent_id, {})
agents_info[agent_id] = {
"name": config.name,
"prompt_loaded": len(config.system_prompt) > 0,
"telegram_token_configured": config.get_telegram_token() is not None
"telegram_token_configured": config.get_telegram_token() is not None,
"badges": meta.get("badges", []),
"visibility": meta.get("visibility", "public"),
"telegram_mode": meta.get("telegram_mode", "on"),
"lifecycle_status": meta.get("lifecycle_status", "active"),
}
# Required per-node agents check
required_agents = ["monitor"]
required_missing = [aid for aid in required_agents if aid not in agents_info]
return {
"status": "healthy",
"agents": agents_info,
"agents_count": len(AGENT_REGISTRY),
"required_missing": required_missing,
"timestamp": datetime.utcnow().isoformat(),
"build_sha": _GATEWAY_BUILD_SHA,
"build_time": _GATEWAY_BUILD_TIME,
"node_id": _GATEWAY_NODE_ID,
}

View File

@@ -1047,3 +1047,66 @@ async def upsert_chat_doc_context_with_summary(
except Exception as exc:
logger.warning("upsert_chat_doc_context_with_summary failed: %s", exc)
return False
# ---------------------------------------------------------------------------
# Compatibility stubs (functions used by http_api_doc.py)
# ---------------------------------------------------------------------------
class _DocServiceCompat:
"""Namespace stub — keep backward-compat with imports that use doc_service.X"""
pass
doc_service = _DocServiceCompat()
class UpdateResult(BaseModel):
"""Compat model matching what http_api_doc.py expects."""
doc_id: str = ""
version_no: int = 0
version_id: str = ""
updated_chunks: int = 0
status: str = "stub"
success: bool = False
error: Optional[str] = "not implemented"
publish_error: Optional[str] = None
artifact_id: Optional[str] = None
artifact_version_id: Optional[str] = None
artifact_storage_key: Optional[str] = None
artifact_mime: Optional[str] = None
artifact_download_url: Optional[str] = None
class _PublishResult(BaseModel):
"""Compat model for publish_document_artifact."""
success: bool = False
error: Optional[str] = "not implemented"
artifact_id: Optional[str] = None
version_id: Optional[str] = None
storage_key: Optional[str] = None
mime: Optional[str] = None
file_name: Optional[str] = None
download_url: Optional[str] = None
async def update_document(**kwargs) -> UpdateResult:
"""Stub — gateway does not implement local doc versioning; use Sofiia Console /api/doc/versions."""
doc_id = kwargs.get("doc_id", "")
logger.warning("update_document: stub called for doc_id=%s", doc_id)
return UpdateResult(doc_id=doc_id, success=False, error="not implemented in gateway")
async def list_document_versions(
agent_id: str,
doc_id: str,
limit: int = 20,
) -> Dict[str, Any]:
"""Stub — returns empty list. Real versions stored in Sofiia Console SQLite."""
logger.debug("list_document_versions: stub called for doc_id=%s", doc_id)
return {"ok": True, "doc_id": doc_id, "versions": [], "total": 0}
async def publish_document_artifact(**kwargs) -> _PublishResult:
"""Stub — gateway does not implement artifact storage. Use artifact-registry service."""
doc_id = kwargs.get("doc_id", "")
logger.warning("publish_document_artifact: stub called for doc_id=%s", doc_id)
return _PublishResult(success=False, error="not implemented in gateway")