feat: оновлення інфраструктури з Node #2 та нові сервіси
This commit is contained in:
@@ -6,20 +6,36 @@
|
||||
|
||||
---
|
||||
|
||||
## 📍 Production Servers
|
||||
## 📍 Network Nodes
|
||||
|
||||
### GEX44 Server #2844465 (Hetzner)
|
||||
### Node #1: Production Server (Hetzner GEX44 #2844465)
|
||||
- **Node ID:** `node-1-hetzner-gex44`
|
||||
- **IP Address:** `144.76.224.179`
|
||||
- **SSH Access:** `ssh root@144.76.224.179`
|
||||
- **Location:** Hetzner Cloud
|
||||
- **Project Root:** `/opt/microdao-daarion` (or `/opt/dagi-router`)
|
||||
- **Location:** Hetzner Cloud (Germany)
|
||||
- **Project Root:** `/opt/microdao-daarion`
|
||||
- **Docker Network:** `dagi-network`
|
||||
- **Role:** Production Router + Gateway + All Services
|
||||
- **Uptime:** 24/7
|
||||
|
||||
**Domains:**
|
||||
- `gateway.daarion.city` → `144.76.224.179` (Gateway + Nginx)
|
||||
- `api.daarion.city` → TBD (API Gateway)
|
||||
- `daarion.city` → TBD (Main website)
|
||||
|
||||
### Node #2: Development Node (MacBook Pro M4 Max)
|
||||
- **Node ID:** `node-2-macbook-m4max`
|
||||
- **Local IP:** `192.168.1.244`
|
||||
- **SSH Access:** `ssh apple@192.168.1.244` (if enabled)
|
||||
- **Location:** Local Network (Ivan's Office)
|
||||
- **Project Root:** `/Users/apple/github-projects/microdao-daarion`
|
||||
- **Role:** Development + Testing + Backup Router
|
||||
- **Specs:** M4 Max (16 cores), 64GB RAM, 2TB SSD, 40-core GPU
|
||||
- **Uptime:** On-demand (battery-powered)
|
||||
|
||||
**See full specs:** [NODE-2-MACBOOK-SPECS.md](./NODE-2-MACBOOK-SPECS.md)
|
||||
**Current state:** [NODE-2-CURRENT-STATE.md](./NODE-2-CURRENT-STATE.md) — What's running now
|
||||
|
||||
---
|
||||
|
||||
## 🐙 GitHub Repositories
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
"source": [
|
||||
"# 🚀 Infrastructure Quick Reference — DAARION & MicroDAO\n",
|
||||
"\n",
|
||||
"**Версія:** 1.1.0 \n",
|
||||
"**Версія:** 1.2.0 \n",
|
||||
"**Останнє оновлення:** 2025-01-17 \n",
|
||||
"\n",
|
||||
"Цей notebook містить швидкий довідник по серверах, репозиторіях та endpoints для DAGI Stack.\n",
|
||||
"\n",
|
||||
"**NEW:** Vision Encoder + Qdrant vector database (OpenCLIP ViT-L/14)"
|
||||
"**NEW:** Vision Encoder + Qdrant + Node #2 (MacBook Pro M4 Max)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -48,6 +48,75 @@
|
||||
" print(f\"{name.upper():<20} {service['port']:<7} {service['container']:<30} {health}{gpu}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 🖥️ Network Nodes\n",
|
||||
"\n",
|
||||
"### Node #1: Production Server (Hetzner)\n",
|
||||
"- **Node ID:** node-1-hetzner-gex44\n",
|
||||
"- **IP:** 144.76.224.179\n",
|
||||
"- **Role:** Production Router + Gateway + All Services (24/7)\n",
|
||||
"- **Location:** Hetzner Cloud (Germany)\n",
|
||||
"\n",
|
||||
"### Node #2: Development Node (MacBook Pro M4 Max)\n",
|
||||
"- **Node ID:** node-2-macbook-m4max\n",
|
||||
"- **Local IP:** 192.168.1.244\n",
|
||||
"- **Role:** Development + Testing + Backup Router\n",
|
||||
"- **Specs:** M4 Max (16 cores), 64GB RAM, 2TB SSD, 40-core GPU\n",
|
||||
"- **Location:** Local Network (Ivan's Office)\n",
|
||||
"- **Docs:** [NODE-2-MACBOOK-SPECS.md](../NODE-2-MACBOOK-SPECS.md)\n",
|
||||
"\n",
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Network Nodes Configuration\n",
|
||||
"NODES = {\n",
|
||||
" \"node-1\": {\n",
|
||||
" \"name\": \"Hetzner GEX44\",\n",
|
||||
" \"ip\": \"144.76.224.179\",\n",
|
||||
" \"local_ip\": None,\n",
|
||||
" \"role\": \"production\",\n",
|
||||
" \"uptime\": \"24/7\",\n",
|
||||
" \"ssh\": \"root@144.76.224.179\",\n",
|
||||
" \"domain\": \"gateway.daarion.city\",\n",
|
||||
" \"services\": \"All (17 services)\",\n",
|
||||
" \"specs\": \"See SYSTEM-INVENTORY.md\"\n",
|
||||
" },\n",
|
||||
" \"node-2\": {\n",
|
||||
" \"name\": \"MacBook Pro M4 Max\",\n",
|
||||
" \"ip\": None,\n",
|
||||
" \"local_ip\": \"192.168.1.244\",\n",
|
||||
" \"role\": \"development\",\n",
|
||||
" \"uptime\": \"on-demand\",\n",
|
||||
" \"ssh\": \"apple@192.168.1.244\",\n",
|
||||
" \"domain\": None,\n",
|
||||
" \"services\": \"Core only (Router, DevTools, Memory, Ollama)\",\n",
|
||||
" \"specs\": \"M4 Max, 16 cores, 64GB RAM, 2TB SSD, 40-core GPU\"\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"print(\"DAGI Stack Network Nodes:\")\n",
|
||||
"print(\"=\"*80)\n",
|
||||
"for node_id, node in NODES.items():\n",
|
||||
" print(f\"\\n{node_id.upper()}: {node['name']}\")\n",
|
||||
" print(f\" Role: {node['role']}\")\n",
|
||||
" print(f\" IP: {node['ip'] or node['local_ip']}\")\n",
|
||||
" print(f\" SSH: {node['ssh']}\")\n",
|
||||
" print(f\" Uptime: {node['uptime']}\")\n",
|
||||
" print(f\" Services: {node['services']}\")\n",
|
||||
" if node['domain']:\n",
|
||||
" print(f\" Domain: https://{node['domain']}\")\n",
|
||||
" print(f\" Specs: {node['specs']}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@@ -157,7 +226,8 @@
|
||||
" \"Deployment\": \"../DEPLOY-NOW.md\",\n",
|
||||
" \"Helion Status\": \"../STATUS-HELION.md\",\n",
|
||||
" \"Architecture Index\": \"../docs/cursor/README.md\",\n",
|
||||
" \"API Reference\": \"../docs/api.md\"\n",
|
||||
" \"API Reference\": \"../docs/api.md\",\n",
|
||||
" \"Node #2 Specs\": \"../NODE-2-MACBOOK-SPECS.md\"\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"print(\"Documentation Quick Links:\")\n",
|
||||
@@ -180,11 +250,14 @@
|
||||
"- ✅ **768-dim embeddings** for multimodal RAG\n",
|
||||
"- ✅ Created VISION-ENCODER-STATUS.md with full implementation details\n",
|
||||
"- ✅ Added test-vision-encoder.sh smoke tests\n",
|
||||
"- ✅ **Added Node #2** (MacBook Pro M4 Max) as development node\n",
|
||||
"- ✅ Created NODE-2-MACBOOK-SPECS.md with complete specifications\n",
|
||||
"\n",
|
||||
"### Services Count: 17 (from 15)\n",
|
||||
"- Total Services: 17\n",
|
||||
"- GPU Services: 1 (Vision Encoder)\n",
|
||||
"- Vector Databases: 1 (Qdrant)\n",
|
||||
"### Network Architecture\n",
|
||||
"- **Nodes:** 2 (1 production + 1 development)\n",
|
||||
"- **Total Services:** 17\n",
|
||||
"- **GPU Services:** 1 (Vision Encoder) + Node #2 (40-core Apple GPU)\n",
|
||||
"- **Vector Databases:** 1 (Qdrant)\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
|
||||
33
http_api.py
33
http_api.py
@@ -5,7 +5,7 @@ Provides HTTP endpoints for routing requests
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
from typing import Optional, Dict, Any
|
||||
import logging
|
||||
|
||||
@@ -21,6 +21,8 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class IncomingRequest(BaseModel):
|
||||
"""HTTP request format"""
|
||||
model_config = ConfigDict(extra='allow') # Дозволити додаткові поля для сумісності
|
||||
|
||||
mode: Optional[str] = Field(None, description="Request mode (e.g., 'chat', 'crew')")
|
||||
agent: Optional[str] = Field(None, description="Agent ID (e.g., 'devtools')")
|
||||
message: Optional[str] = Field(None, description="User message")
|
||||
@@ -29,6 +31,7 @@ class IncomingRequest(BaseModel):
|
||||
session_id: Optional[str] = Field(None, description="Session identifier")
|
||||
user_id: Optional[str] = Field(None, description="User identifier")
|
||||
payload: Dict[str, Any] = Field(default_factory=dict, description="Additional payload data")
|
||||
context: Optional[Dict[str, Any]] = Field(None, description="Legacy: context on top level (will be migrated to payload.context)")
|
||||
|
||||
|
||||
class RouterAPIResponse(BaseModel):
|
||||
@@ -74,6 +77,32 @@ def build_router_http(app_core: RouterApp) -> APIRouter:
|
||||
- Other metadata
|
||||
"""
|
||||
logger.info(f"Incoming request: agent={req.agent}, mode={req.mode}")
|
||||
logger.info(f"Raw payload type: {type(req.payload)}, keys: {list(req.payload.keys()) if req.payload else []}")
|
||||
logger.info(f"Raw context: {req.context}")
|
||||
|
||||
# Нормалізувати payload: якщо є "context" на верхньому рівні (старий формат),
|
||||
# перемістити його в payload.context для уніфікованої обробки
|
||||
normalized_payload = req.payload.copy() if req.payload else {}
|
||||
|
||||
# Перевірити, чи є context на верхньому рівні (legacy формат від gateway-bot)
|
||||
# Це потрібно для сумісності з DAARWIZZ
|
||||
if req.context:
|
||||
# Якщо context на верхньому рівні, перемістити в payload.context
|
||||
if "context" not in normalized_payload:
|
||||
normalized_payload["context"] = {}
|
||||
# Мержити context з верхнього рівня в payload.context
|
||||
if isinstance(req.context, dict):
|
||||
normalized_payload["context"].update(req.context)
|
||||
logger.info(f"✅ Migrated top-level context to payload.context for agent={req.agent}, keys={list(req.context.keys())}")
|
||||
|
||||
logger.info(f"✅ Normalized payload keys: {list(normalized_payload.keys())}")
|
||||
if normalized_payload and "context" in normalized_payload:
|
||||
logger.info(f"✅ Context keys: {list(normalized_payload['context'].keys()) if isinstance(normalized_payload.get('context'), dict) else []}")
|
||||
if isinstance(normalized_payload.get('context'), dict) and "system_prompt" in normalized_payload['context']:
|
||||
sp = normalized_payload['context']['system_prompt']
|
||||
sp_len = len(sp) if sp else 0
|
||||
logger.info(f"✅ System prompt found in context: {sp_len} chars")
|
||||
logger.info(f"✅ System prompt preview: {sp[:100] if sp else 'None'}...")
|
||||
|
||||
# Convert to internal RouterRequest
|
||||
rreq = RouterRequest(
|
||||
@@ -84,7 +113,7 @@ def build_router_http(app_core: RouterApp) -> APIRouter:
|
||||
session_id=req.session_id,
|
||||
user_id=req.user_id,
|
||||
message=req.message,
|
||||
payload=req.payload,
|
||||
payload=normalized_payload,
|
||||
)
|
||||
|
||||
# Handle request
|
||||
|
||||
@@ -158,15 +158,34 @@ class LLMProvider(Provider):
|
||||
def _get_system_prompt(self, req: RouterRequest) -> Optional[str]:
|
||||
"""Get system prompt based on agent or context"""
|
||||
# 1. Check if context.system_prompt provided (e.g., from Gateway)
|
||||
logger.info(f"[DEBUG] _get_system_prompt called for agent={req.agent}")
|
||||
logger.info(f"[DEBUG] req.payload type: {type(req.payload)}, keys: {list(req.payload.keys()) if req.payload else []}")
|
||||
context = req.payload.get("context") or {}
|
||||
logger.info(f"[DEBUG] payload keys: {list(req.payload.keys())}")
|
||||
logger.info(f"[DEBUG] context keys: {list(context.keys())}")
|
||||
if "system_prompt" in context:
|
||||
logger.info(f"[DEBUG] context type: {type(context)}, keys: {list(context.keys()) if isinstance(context, dict) else 'not a dict'}")
|
||||
if isinstance(context, dict) and "system_prompt" in context:
|
||||
prompt = context["system_prompt"]
|
||||
logger.info(f"[DEBUG] Using context.system_prompt: {len(prompt)} chars, agent={req.agent}")
|
||||
logger.info(f"[DEBUG] ✅ Using context.system_prompt: {len(prompt)} chars, agent={req.agent}")
|
||||
logger.info(f"[DEBUG] System prompt type: {type(prompt)}")
|
||||
logger.info(f"[DEBUG] System prompt preview (first 200): {str(prompt)[:200]}...")
|
||||
logger.info(f"[DEBUG] System prompt full length check: {len(str(prompt))} chars")
|
||||
# Переконаємось, що це рядок
|
||||
if not isinstance(prompt, str):
|
||||
logger.warning(f"[DEBUG] ⚠️ System prompt is not a string! Type: {type(prompt)}, value: {prompt}")
|
||||
prompt = str(prompt) if prompt else None
|
||||
return prompt
|
||||
else:
|
||||
logger.info(f"[DEBUG] ⚠️ No system_prompt in context for agent={req.agent}")
|
||||
|
||||
# 2. Agent-specific system prompts (fallback, якщо не передано в context)
|
||||
if req.agent == "helion":
|
||||
return (
|
||||
"Ти - Helion, AI-агент платформи Energy Union екосистеми DAARION.city. "
|
||||
"Допомагай користувачам з технологіями EcoMiner/BioMiner, токеномікою та DAO governance. "
|
||||
"Твої основні функції: консультації з енергетичними технологіями, пояснення токеноміки Energy Union, "
|
||||
"допомога з onboarding в DAO, відповіді на питання про EcoMiner/BioMiner устаткування. "
|
||||
"Стиль спілкування: професійний, технічний, але зрозумілий, точний у цифрах та даних."
|
||||
)
|
||||
|
||||
# 2. Agent-specific system prompts
|
||||
if req.agent == "daarwizz":
|
||||
return (
|
||||
"Ти — DAARWIZZ, офіційний AI-агент екосистеми DAARION.city. "
|
||||
|
||||
@@ -89,6 +89,30 @@ agents:
|
||||
You are a multi-agent orchestrator for DAARION.city microDAO ecosystem.
|
||||
You coordinate complex workflows involving multiple specialized agents.
|
||||
|
||||
greenfood:
|
||||
description: "GREENFOOD Assistant - ERP orchestrator for craft food producers"
|
||||
default_llm: local_qwen3_8b
|
||||
system_prompt: |
|
||||
Ти — GREENFOOD Assistant, фронтовий оркестратор ERP-системи для крафтових виробників, хабів та покупців.
|
||||
Твоя місія: зрозуміти, хто з тобою говорить (комітент, менеджер складу, логіст, бухгалтер, маркетолог, покупець),
|
||||
виявити намір і делегувати завдання спеціалізованим агентам GREENFOOD.
|
||||
|
||||
У твоєму розпорядженні 12 спеціалізованих агентів:
|
||||
- Product & Catalog (каталог товарів)
|
||||
- Batch & Quality (партії та якість)
|
||||
- Vendor Success (успіх комітентів)
|
||||
- Warehouse (склад)
|
||||
- Logistics & Delivery (доставка)
|
||||
- Seller (продажі)
|
||||
- Customer Care (підтримка)
|
||||
- Finance & Pricing (фінанси)
|
||||
- SMM & Campaigns (маркетинг)
|
||||
- SEO & Web (SEO)
|
||||
- Analytics & BI (аналітика)
|
||||
- Compliance & Audit (аудит)
|
||||
|
||||
Відповідай українською, чітко та по-діло вому.
|
||||
|
||||
helion:
|
||||
description: "Helion - AI agent for Energy Union platform"
|
||||
default_llm: local_qwen3_8b
|
||||
|
||||
Reference in New Issue
Block a user