feat: оновлення інфраструктури з Node #2 та нові сервіси

This commit is contained in:
Apple
2025-11-21 00:35:03 -08:00
parent 36c35cab57
commit 31f3602047
5 changed files with 179 additions and 18 deletions

View File

@@ -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` - **IP Address:** `144.76.224.179`
- **SSH Access:** `ssh root@144.76.224.179` - **SSH Access:** `ssh root@144.76.224.179`
- **Location:** Hetzner Cloud - **Location:** Hetzner Cloud (Germany)
- **Project Root:** `/opt/microdao-daarion` (or `/opt/dagi-router`) - **Project Root:** `/opt/microdao-daarion`
- **Docker Network:** `dagi-network` - **Docker Network:** `dagi-network`
- **Role:** Production Router + Gateway + All Services
- **Uptime:** 24/7
**Domains:** **Domains:**
- `gateway.daarion.city``144.76.224.179` (Gateway + Nginx) - `gateway.daarion.city``144.76.224.179` (Gateway + Nginx)
- `api.daarion.city` → TBD (API Gateway) - `api.daarion.city` → TBD (API Gateway)
- `daarion.city` → TBD (Main website) - `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 ## 🐙 GitHub Repositories

View File

@@ -6,12 +6,12 @@
"source": [ "source": [
"# 🚀 Infrastructure Quick Reference — DAARION & MicroDAO\n", "# 🚀 Infrastructure Quick Reference — DAARION & MicroDAO\n",
"\n", "\n",
"**Версія:** 1.1.0 \n", "**Версія:** 1.2.0 \n",
"**Останнє оновлення:** 2025-01-17 \n", "**Останнє оновлення:** 2025-01-17 \n",
"\n", "\n",
"Цей notebook містить швидкий довідник по серверах, репозиторіях та endpoints для DAGI Stack.\n", "Цей notebook містить швидкий довідник по серверах, репозиторіях та endpoints для DAGI Stack.\n",
"\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}\")" " 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", "cell_type": "markdown",
"metadata": {}, "metadata": {},
@@ -157,7 +226,8 @@
" \"Deployment\": \"../DEPLOY-NOW.md\",\n", " \"Deployment\": \"../DEPLOY-NOW.md\",\n",
" \"Helion Status\": \"../STATUS-HELION.md\",\n", " \"Helion Status\": \"../STATUS-HELION.md\",\n",
" \"Architecture Index\": \"../docs/cursor/README.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",
"\n", "\n",
"print(\"Documentation Quick Links:\")\n", "print(\"Documentation Quick Links:\")\n",
@@ -180,11 +250,14 @@
"- ✅ **768-dim embeddings** for multimodal RAG\n", "- ✅ **768-dim embeddings** for multimodal RAG\n",
"- ✅ Created VISION-ENCODER-STATUS.md with full implementation details\n", "- ✅ Created VISION-ENCODER-STATUS.md with full implementation details\n",
"- ✅ Added test-vision-encoder.sh smoke tests\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", "\n",
"### Services Count: 17 (from 15)\n", "### Network Architecture\n",
"- Total Services: 17\n", "- **Nodes:** 2 (1 production + 1 development)\n",
"- GPU Services: 1 (Vision Encoder)\n", "- **Total Services:** 17\n",
"- Vector Databases: 1 (Qdrant)\n", "- **GPU Services:** 1 (Vision Encoder) + Node #2 (40-core Apple GPU)\n",
"- **Vector Databases:** 1 (Qdrant)\n",
"\n", "\n",
"---\n", "---\n",
"\n", "\n",

View File

@@ -5,7 +5,7 @@ Provides HTTP endpoints for routing requests
""" """
from fastapi import APIRouter, HTTPException, status from fastapi import APIRouter, HTTPException, status
from pydantic import BaseModel, Field from pydantic import BaseModel, Field, ConfigDict
from typing import Optional, Dict, Any from typing import Optional, Dict, Any
import logging import logging
@@ -21,6 +21,8 @@ logger = logging.getLogger(__name__)
class IncomingRequest(BaseModel): class IncomingRequest(BaseModel):
"""HTTP request format""" """HTTP request format"""
model_config = ConfigDict(extra='allow') # Дозволити додаткові поля для сумісності
mode: Optional[str] = Field(None, description="Request mode (e.g., 'chat', 'crew')") mode: Optional[str] = Field(None, description="Request mode (e.g., 'chat', 'crew')")
agent: Optional[str] = Field(None, description="Agent ID (e.g., 'devtools')") agent: Optional[str] = Field(None, description="Agent ID (e.g., 'devtools')")
message: Optional[str] = Field(None, description="User message") message: Optional[str] = Field(None, description="User message")
@@ -29,6 +31,7 @@ class IncomingRequest(BaseModel):
session_id: Optional[str] = Field(None, description="Session identifier") session_id: Optional[str] = Field(None, description="Session identifier")
user_id: Optional[str] = Field(None, description="User identifier") user_id: Optional[str] = Field(None, description="User identifier")
payload: Dict[str, Any] = Field(default_factory=dict, description="Additional payload data") 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): class RouterAPIResponse(BaseModel):
@@ -74,6 +77,32 @@ def build_router_http(app_core: RouterApp) -> APIRouter:
- Other metadata - Other metadata
""" """
logger.info(f"Incoming request: agent={req.agent}, mode={req.mode}") 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 # Convert to internal RouterRequest
rreq = RouterRequest( rreq = RouterRequest(
@@ -84,7 +113,7 @@ def build_router_http(app_core: RouterApp) -> APIRouter:
session_id=req.session_id, session_id=req.session_id,
user_id=req.user_id, user_id=req.user_id,
message=req.message, message=req.message,
payload=req.payload, payload=normalized_payload,
) )
# Handle request # Handle request

View File

@@ -158,15 +158,34 @@ class LLMProvider(Provider):
def _get_system_prompt(self, req: RouterRequest) -> Optional[str]: def _get_system_prompt(self, req: RouterRequest) -> Optional[str]:
"""Get system prompt based on agent or context""" """Get system prompt based on agent or context"""
# 1. Check if context.system_prompt provided (e.g., from Gateway) # 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 {} context = req.payload.get("context") or {}
logger.info(f"[DEBUG] payload keys: {list(req.payload.keys())}") logger.info(f"[DEBUG] context type: {type(context)}, keys: {list(context.keys()) if isinstance(context, dict) else 'not a dict'}")
logger.info(f"[DEBUG] context keys: {list(context.keys())}") if isinstance(context, dict) and "system_prompt" in context:
if "system_prompt" in context:
prompt = context["system_prompt"] 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 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": if req.agent == "daarwizz":
return ( return (
"Ти — DAARWIZZ, офіційний AI-агент екосистеми DAARION.city. " "Ти — DAARWIZZ, офіційний AI-агент екосистеми DAARION.city. "

View File

@@ -89,6 +89,30 @@ agents:
You are a multi-agent orchestrator for DAARION.city microDAO ecosystem. You are a multi-agent orchestrator for DAARION.city microDAO ecosystem.
You coordinate complex workflows involving multiple specialized agents. 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: helion:
description: "Helion - AI agent for Energy Union platform" description: "Helion - AI agent for Energy Union platform"
default_llm: local_qwen3_8b default_llm: local_qwen3_8b