feat(node2): Full DAGI integration - 50 agents synced

- Created sync-node2-dagi-agents.py script to sync agents from agents_city_mapping.yaml
- Synced 50 DAGI agents across 10 districts:
  - Leadership Hall (4): Solarius, Sofia, PrimeSynth, Nexor
  - System Control (6): Monitor, Strategic Sentinels, Vindex, Helix, Aurora, Arbitron
  - Engineering Lab (5): ByteForge, Vector, ChainWeaver, Cypher, Canvas
  - Marketing Hub (6): Roxy, Mira, Tempo, Harmony, Faye, Storytelling
  - Finance Office (4): Financial Analyst, Accountant, Budget Planner, Tax Advisor
  - Web3 District (5): Smart Contract Dev, DeFi Analyst, Tokenomics Expert, NFT Specialist, DAO Governance
  - Security Bunker (7): Shadelock, Exor, Penetration Tester, Security Monitor, Incident Responder, Shadelock Forensics, Exor Forensics
  - Vision Studio (4): Iris, Lumen, Spectra, Video Analyzer
  - R&D Lab (6): ProtoMind, LabForge, TestPilot, ModelScout, BreakPoint, GrowCell
  - Memory Vault (3): Somnia, Memory Manager, Knowledge Indexer
- Fixed Swapper config to use swapper_config_node2.yaml with 8 models
- Created TASK_PHASE_NODE2_FULL_DAGI_INTEGRATION_v1.md

NODE2 now shows:
- 50 agents in DAGI Router Card
- 8 models in Swapper Service (gpt-oss, phi3, starcoder2, mistral-nemo, gemma2, deepseek-coder, qwen2.5-coder, deepseek-r1)
- Full isolation from NODE1
This commit is contained in:
Apple
2025-12-01 08:31:25 -08:00
parent a818f2ac2f
commit 2f8e471e03
4 changed files with 778 additions and 52 deletions

View File

@@ -0,0 +1,370 @@
# TASK_PHASE_NODE2_FULL_DAGI_INTEGRATION_v1
Проєкт: DAARION.city
Нода: NODE2 (MacBook M4 Max)
Мета: зробити так, щоб DAARION MVP бачив **реальний DAGI-стек NODE2**:
- Swapper з локальними моделями (Ollama, HF);
- DAGI Router та Gateway;
- усі ~50 DAGI-агентів у районах міста;
- коректні метрики в Node Cabinet.
---
## 0. Джерела істини (OBLIGATORY READ)
Спочатку **прочитати, не редагувати**:
- `docs/users/nodes/NODE_STATE_node-2-macbook-m4max.md`
- `docs/users/nodes/NODE_STATE_node-1-hetzner-gex44.md` (для порівняння)
- `docs/users/nodes/walkthrough.md` (якщо існує)
- `docs/users/nodes/NODE_GUARDIAN_AND_STEWARD.md`
- `docs/tasks/TASK_PHASE_SWAPPER_NODE_METRICS_AND_UI_v1.md`
- `docs/tasks/TASK_PHASE_NODE2_ROUTER_SWAPPER_ISOLATION_AND_AGENT_DISCOVERY_v1.md`
Конфігурація DAGI на NODE2 (знайти й використати, не вигадувати заново):
- `swapper_config_node2.yaml`
- `router_config_node2.yaml` (або подібний)
- `agents_city_mapping.yaml` / `agents/`
- логи в `logs/node2_*`
Мета цього таска — **під'єднати існуючий стек**, а не створювати новий.
---
## 1. Поточний стан (узагальнення)
Зафіксувати в коментарях до MR (або в кінці файлу), але орієнтовно:
- NODE2:
- Swapper: працює на `http://localhost:8890`, статус healthy, 8 моделей;
- DAGI Router: працює на `http://localhost:9102`;
- LLM Proxy: `http://localhost:7007`;
- Gateway з 5 агентами (daarwizz, helion, greenfood, nutra, druid);
- ~50 DAGI-агентів, розкладених по районах (Leadership Hall, System Control, Engineering Lab, Marketing Hub, Finance Office, Web3 District, Security Bunker, Vision Studio, R&D Lab, Memory Vault);
- node-guardian вже шле heartbeat, але МВП не бачить агентів/моделей повністю.
- NODE1:
- Swapper + Router вже інтегровані в MVP й працюють як еталон.
---
## 2. Scope
### Включено
1. **Swapper NODE2 → city-service**
- коректні метрики per-node (healthy, models_loaded/total, swapper_state).
2. **DAGI Router NODE2 → city-service**
- статус роутера (up/down);
- кількість агентів, список агентів з Router API.
3. **Agent Registry NODE2**
- записати 50 DAGI-агентів у БД (таблиця `agents` / `node_agents` / аналогічна);
- прив'язка до NODE2 та відповідних MicroDAO.
4. **API для Node Cabinet**
- `/internal/node/{node_id}/models`
- `/internal/node/{node_id}/router`
- `/internal/node/{node_id}/agents`
(або адаптація існуючих, якщо вони вже є).
5. **UI Node Cabinet**
- NODE2 має показувати свої:
- Swapper моделі;
- Router статус;
- список агентів (хоча б з іменем, типом і MicroDAO).
### Виключено
- CrewAI-кімнати, групові чати, кнопки створення кімнат — це **окремий таск**.
- Авто-самолікування роутера / свопера.
- Веб-інтерфейс кар'єру/налаштувань для кожного агента.
---
## 3. Swapper інтеграція NODE2
### 3.1. Перевірити конфіг
- підтвердити точний Swapper URL для NODE2:
- `http://localhost:8890/health`
- `http://localhost:8890/models` (або фактичний endpoint; див. `swapper_config_node2.yaml` та `logs/node2_swapper_models.json`).
### 3.2. Оновити node-guardian-loop (NODE2)
У `scripts/node-guardian-loop.py`:
- переконатися, що при запуску з NODE2:
- використовується **локальний** Swapper URL (`localhost`, а не `swapper-service`);
- логуються `node_id` і `swapper_url` (для дебагу в майбутньому).
- функція збору Swapper-метрик повинна:
- витягнути **реальний список моделей**;
- порахувати `models_total`, `models_loaded`;
- скласти `swapper_state` (JSON) з полями:
- `name`
- `backend` (ollama / hf / інше)
- `type` (llm / code / vision / reasoning)
- `loaded`
- `vram_gb` (якщо відомо).
Передавати ці значення в `POST /internal/node/{node_id}/metrics/update`.
### 3.3. Перевірити fn_node_heartbeat та `node_cache`
- переконатися, що `fn_node_heartbeat` оновлює **тільки один запис** по `node_id` і не перетирає дані іншої ноди;
- стовпці:
- `swapper_healthy`
- `swapper_models_loaded`
- `swapper_models_total`
- `swapper_state`
Перевірити руками:
```sql
select node_id, swapper_healthy, swapper_models_loaded, swapper_models_total
from node_cache
order by node_id;
```
---
## 4. DAGI Router інтеграція NODE2
### 4.1. Виявити Router API
З логів і конфігів (NODE2):
* підтвердити базовий URL:
* `http://localhost:9102` (наприклад, `/health`, `/status`, `/agents`).
Зробити невеликий helper (окрема функція) у `node-guardian-loop.py`:
```python
def collect_router_metrics(router_base_url: str) -> dict:
# router_healthy (bool)
# router_agents_total (int)
# router_agents_active (int / optional)
# router_state (json: список агентів з базовою інформацією)
```
Передавати ці дані в `metrics/update`.
### 4.2. Розширити схему БД (якщо потрібно)
Міграція, наприклад `migrations/041_node_cache_router_metrics.sql`:
* `router_healthy boolean`
* `router_agents_total integer`
* `router_state jsonb`
Оновити `repo_city.py` / `models_city.py` / `routes_city.py`, щоб ці поля поверталися для:
* `GET /internal/node/{node_id}/metrics/current`
* `GET /internal/node/{node_id}` (якщо є short summary).
---
## 5. Node2 Agent Registry (50 DAGI-агентів)
### 5.1. Зчитати конфіги
Знайти та використати (тільки читання):
* `agents_city_mapping.yaml`
* директорію `agents/` (конфіги окремих агентів)
* звіт discovery (walkthrough / NODE_STATE)
Не створювати агентів "із голови": брати **тільки те, що описано в цих файлах**.
### 5.2. Оновити таблиці БД
Залежно від існуючої схеми, але логіка така:
* таблиця `agents` / `node_agents` повинна мати:
* `id` / `slug`
* `node_id` (node-1 / node-2)
* `name`
* `role` / `district` / `team`
* `microdao_slug` (якщо прив'язано)
* `is_core` / `is_system` / `is_microdao` (флаги)
* `model_name` / `model_backend` (ollama / hf / інше)
Потрібно:
1. Створити окремий **sync-скрипт** для NODE2, напр.:
`scripts/sync-node2-dagi-agents.py`
Він повинен:
* прочитати `agents_city_mapping.yaml` та `agents/`;
* для кожного агента:
* вставити/оновити запис у БД з `node_id = 'node-2-macbook-m4max'`;
* не чіпати агентів NODE1.
2. Перед запуском — зробити dry-run (print summary), потім запустити реально.
---
## 6. API для Node Cabinet (тільки те, що потрібно зараз)
### 6.1. Agents
Endpoint:
* `GET /internal/node/{node_id}/agents`
Повертає:
```json
{
"node_id": "node-2-macbook-m4max",
"total": 50,
"agents": [
{
"id": "helix",
"name": "Helix",
"role": "CTO",
"district": "System Control",
"microdao": "daarion-dao",
"model_name": "qwen2.5-coder:32b",
"kind": "core"
},
...
]
}
```
Node Cabinet на фронтенді вже має секцію "Агенти цієї ноди" — під'єднати її до цього endpoint (без змін дизайну).
### 6.2. Models (опційно, але бажано)
`GET /internal/node/{node_id}/models`
Повертає агреговані дані з `swapper_state`:
* скільки моделей,
* які backend'и,
* який тип.
Це потрібно, щоб у Node Cabinet список моделей точно відповідав тому, що Swapper бачить на NODE2.
---
## 7. UI Node Cabinet — очікуваний результат для NODE2
Після завершення таска:
1. **Swapper Service (NODE2)**:
* статус: `Healthy`;
* `Models Loaded: X / 8` (від Swapper, а не від NODE1);
* у списку моделей показуються саме локальні:
* `deepseek-r1:70b`, `qwen2.5-coder:32b`, `gemma2:27b`, `mistral-nemo`, `phi3`, `starcoder2`, `gpt-oss`, `deepseek-coder:33b`.
2. **DAGI Router (NODE2)**:
* статус: `Up` (якщо сервіс запущений);
* `Agents: 50` (або актуальна кількість);
* кнопка "Агенти цієї ноди" відкриває список з усіма 50 агентами.
3. **Ізоляція по node_id**:
* NODE1 показує свої 9 агентів і 7 моделей;
* NODE2 показує свої 50 агентів і 8 моделей, але **через свій Swapper/Router**;
* дані не змішуються.
---
## 8. Acceptance Criteria
1. `scripts/discover_node_state.py` (якщо є) показує різні Router/Swapper-дані для NODE1 та NODE2 (і вони збігаються з Node Cabinet).
2. `GET /internal/node/node-2-macbook-m4max/metrics/current` показує:
* `swapper_healthy = true`,
* `swapper_models_total = 8`,
* `router_healthy = true`,
* `router_agents_total >= 40`.
3. `GET /internal/node/node-2-macbook-m4max/agents` повертає список із ~50 агентів.
4. На UI:
* Node Cabinet для NODE2 показує коректні Swapper-метрики й Router-агентів;
* при перезапуску node-guardian дані оновлюються без ручних SQL.
5. Жоден endpoint / UI-блок для NODE1 не зламаний.
---
## 9. Район-агент маппінг (50 агентів NODE2)
### Leadership Hall (4)
- Solarius (CEO)
- Sofia
- PrimeSynth
- Nexor
### System Control (6)
- monitor-node2
- vindex
- helix
- aurora
- та інші...
### Engineering Lab (5)
- byteforge
- vector
- chainweaver
- cypher
- canvas
### Marketing Hub (6)
- roxy
- mira
- tempo
- harmony
- faye
- та інші...
### Finance Office (4)
- financial-analyst
- accountant
- budget-planner
- та інші...
### Web3 District (5)
- smart-contract-dev
- defi-analyst
- tokenomics-expert
- та інші...
### Security Bunker (7)
- shadelock
- exor
- penetration-tester
- та інші...
### Vision Studio (4)
- iris
- lumen
- spectra
- video-analyzer
### R&D Lab (6)
- protomind
- labforge
- testpilot
- modelscout
- та інші...
### Memory Vault (3)
- somnia
- memory-manager
- knowledge-indexer
---
Як тільки цей крок буде виконаний і задеплоєний, далі можемо рухатись:
- крок 2: кімнати/чати MicroDAO + публічний головний чат;
- крок 3: кнопки створення/видалення агента й групи (CrewAI-команди).

View File

@@ -0,0 +1,266 @@
#!/usr/bin/env python3
"""
Sync NODE2 DAGI Agents from agents_city_mapping.yaml to database.
This script reads the agent configuration from agents_city_mapping.yaml
and syncs all 50 agents to the database with node_id = 'node-2-macbook-m4max'.
Usage:
python scripts/sync-node2-dagi-agents.py --dry-run # Preview changes
python scripts/sync-node2-dagi-agents.py # Apply changes
"""
import argparse
import asyncio
import os
import sys
from pathlib import Path
import yaml
# Add project root to path
PROJECT_ROOT = Path(__file__).parent.parent
sys.path.insert(0, str(PROJECT_ROOT))
# Database connection
DATABASE_URL = os.getenv(
"DATABASE_URL",
"postgresql://postgres:postgres@144.76.224.179:5432/daarion"
)
NODE2_ID = "node-2-macbook-m4max"
CONFIG_PATH = PROJECT_ROOT / "config" / "agents_city_mapping.yaml"
def load_agents_config() -> dict:
"""Load agents configuration from YAML file."""
if not CONFIG_PATH.exists():
print(f"❌ Config file not found: {CONFIG_PATH}")
sys.exit(1)
with open(CONFIG_PATH, 'r', encoding='utf-8') as f:
config = yaml.safe_load(f)
return config
def parse_agent(agent_data: dict, districts: list) -> dict:
"""Parse agent data from YAML to database format."""
# Find district info
district_id = agent_data.get('district', '')
district_info = next((d for d in districts if d['id'] == district_id), None)
return {
'id': agent_data['agent_id'],
'slug': agent_data['agent_id'],
'display_name': agent_data['display_name'],
'kind': agent_data.get('kind', 'assistant'),
'role': agent_data.get('role', ''),
'model': agent_data.get('model', ''),
'node_id': agent_data.get('node_id', NODE2_ID),
'district': district_id,
'primary_room_slug': agent_data.get('primary_room_slug', ''),
'avatar_url': agent_data.get('avatar_url', ''),
'color_hint': agent_data.get('color_hint', ''),
'priority': agent_data.get('priority', 'medium'),
'is_active': True,
'status': 'offline',
'is_public': True,
'public_slug': agent_data['agent_id'],
'public_title': agent_data['display_name'],
'public_tagline': agent_data.get('role', ''),
'public_district': district_info['name'] if district_info else '',
'public_primary_room_slug': agent_data.get('primary_room_slug', ''),
'is_listed_in_directory': True,
'visibility_scope': 'global',
'is_orchestrator': agent_data.get('kind') == 'orchestrator',
'home_node_id': agent_data.get('node_id', NODE2_ID),
}
async def sync_agents(dry_run: bool = True):
"""Sync agents to database."""
import asyncpg
print(f"📂 Loading config from: {CONFIG_PATH}")
config = load_agents_config()
districts = config.get('districts', [])
agents_data = config.get('agents', [])
print(f"📊 Found {len(agents_data)} agents in config")
print(f"📊 Found {len(districts)} districts")
# Parse agents
agents = [parse_agent(a, districts) for a in agents_data]
# Group by district for summary
by_district = {}
for agent in agents:
d = agent['district']
if d not in by_district:
by_district[d] = []
by_district[d].append(agent['display_name'])
print("\n📋 Agents by district:")
for district_id, agent_names in sorted(by_district.items()):
district_info = next((d for d in districts if d['id'] == district_id), None)
district_name = district_info['name'] if district_info else district_id
print(f" {district_name}: {len(agent_names)} agents")
for name in agent_names:
print(f" - {name}")
if dry_run:
print("\n🔍 DRY RUN - No changes will be made")
print(f"Would sync {len(agents)} agents to NODE2")
return
# Connect to database
print(f"\n🔗 Connecting to database...")
conn = await asyncpg.connect(DATABASE_URL)
try:
# Start transaction
async with conn.transaction():
inserted = 0
updated = 0
for agent in agents:
# Check if agent exists
existing = await conn.fetchrow(
"SELECT id FROM agents WHERE id = $1",
agent['id']
)
if existing:
# Update existing agent
await conn.execute("""
UPDATE agents SET
display_name = $2,
kind = $3,
role = $4,
model = $5,
node_id = $6,
district = $7,
primary_room_slug = $8,
avatar_url = $9,
color_hint = $10,
priority = $11,
is_active = $12,
is_public = $13,
public_slug = $14,
public_title = $15,
public_tagline = $16,
public_district = $17,
public_primary_room_slug = $18,
is_listed_in_directory = $19,
visibility_scope = $20,
is_orchestrator = $21,
home_node_id = $22,
slug = $23,
updated_at = NOW()
WHERE id = $1
""",
agent['id'],
agent['display_name'],
agent['kind'],
agent['role'],
agent['model'],
agent['node_id'],
agent['district'],
agent['primary_room_slug'],
agent['avatar_url'],
agent['color_hint'],
agent['priority'],
agent['is_active'],
agent['is_public'],
agent['public_slug'],
agent['public_title'],
agent['public_tagline'],
agent['public_district'],
agent['public_primary_room_slug'],
agent['is_listed_in_directory'],
agent['visibility_scope'],
agent['is_orchestrator'],
agent['home_node_id'],
agent['slug'],
)
updated += 1
else:
# Insert new agent
await conn.execute("""
INSERT INTO agents (
id, display_name, kind, role, model, node_id, district,
primary_room_slug, avatar_url, color_hint, priority,
is_active, status, is_public, public_slug, public_title,
public_tagline, public_district, public_primary_room_slug,
is_listed_in_directory, visibility_scope, is_orchestrator,
home_node_id, slug
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13,
$14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24
)
""",
agent['id'],
agent['display_name'],
agent['kind'],
agent['role'],
agent['model'],
agent['node_id'],
agent['district'],
agent['primary_room_slug'],
agent['avatar_url'],
agent['color_hint'],
agent['priority'],
agent['is_active'],
agent['status'],
agent['is_public'],
agent['public_slug'],
agent['public_title'],
agent['public_tagline'],
agent['public_district'],
agent['public_primary_room_slug'],
agent['is_listed_in_directory'],
agent['visibility_scope'],
agent['is_orchestrator'],
agent['home_node_id'],
agent['slug'],
)
inserted += 1
print(f"\n✅ Sync complete!")
print(f" Inserted: {inserted} agents")
print(f" Updated: {updated} agents")
# Verify count
count = await conn.fetchval(
"SELECT COUNT(*) FROM agents WHERE node_id = $1 AND deleted_at IS NULL",
NODE2_ID
)
print(f" Total NODE2 agents: {count}")
finally:
await conn.close()
def main():
parser = argparse.ArgumentParser(
description="Sync NODE2 DAGI agents from config to database"
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Preview changes without applying them"
)
args = parser.parse_args()
print("=" * 60)
print("🤖 NODE2 DAGI Agent Sync")
print("=" * 60)
asyncio.run(sync_agents(dry_run=args.dry_run))
if __name__ == "__main__":
main()

View File

@@ -1,75 +1,83 @@
# Swapper Configuration for Node #1 (Production Server) # Swapper Configuration for Node #2 (Development Node)
# Single-active LLM scheduler # Single-active LLM scheduler
# Hetzner GEX44 - NVIDIA RTX 4000 SFF Ada (20GB VRAM) # MacBook Pro M4 Max - Apple Silicon (40-core GPU, 64GB RAM)
# Auto-generated configuration with all available Ollama models # Auto-generated configuration with available Ollama models
swapper: swapper:
mode: single-active mode: single-active
max_concurrent_models: 1 max_concurrent_models: 1
model_swap_timeout: 300 model_swap_timeout: 300
gpu_enabled: true gpu_enabled: true
metal_acceleration: false # NVIDIA GPU, not Apple Silicon metal_acceleration: true # Apple Silicon GPU acceleration
# Модель для автоматичного завантаження при старті (опціонально) # Модель для автоматичного завантаження при старті (опціонально)
# Якщо не вказано - моделі завантажуються тільки за запитом # Якщо не вказано - моделі завантажуються тільки за запитом
# Рекомендовано: qwen3-8b (основна модель) або qwen2.5-3b-instruct (легка модель) # Рекомендовано: gpt-oss:latest (швидка модель) або phi3:latest (легка модель)
default_model: qwen3-8b # Модель активується автоматично при старті default_model: gpt-oss:latest # Модель активується автоматично при старті
models: models:
# Primary LLM - Qwen3 8B (High Priority) - Main model from INFRASTRUCTURE.md # Fast LLM - GPT-OSS 20B (High Priority) - Main model for general tasks
qwen3-8b: gpt-oss-latest:
path: ollama:qwen3:8b path: ollama:gpt-oss:latest
type: llm type: llm
size_gb: 4.87 size_gb: 13.0
priority: high priority: high
description: "Primary LLM for general tasks and conversations" description: "Fast LLM for general tasks and conversations (20.9B params)"
# Vision Model - Qwen3-VL 8B (High Priority) - For image processing # Lightweight LLM - Phi3 3.8B (High Priority) - Fast responses
qwen3-vl-8b: phi3-latest:
path: ollama:qwen3-vl:8b path: ollama:phi3:latest
type: vision
size_gb: 5.72
priority: high
description: "Vision model for image understanding and processing"
# Qwen2.5 7B Instruct (High Priority)
qwen2.5-7b-instruct:
path: ollama:qwen2.5:7b-instruct-q4_K_M
type: llm type: llm
size_gb: 4.36 size_gb: 2.2
priority: high priority: high
description: "Qwen2.5 7B Instruct model" description: "Lightweight LLM for fast responses (3.8B params)"
# Lightweight LLM - Qwen2.5 3B Instruct (Medium Priority) # Code Specialist - StarCoder2 3B (Medium Priority) - Code engineering
qwen2.5-3b-instruct: starcoder2-3b:
path: ollama:qwen2.5:3b-instruct-q4_K_M path: ollama:starcoder2:3b
type: llm type: code
size_gb: 1.80 size_gb: 1.7
priority: medium priority: medium
description: "Lightweight LLM for faster responses" description: "Code specialist model for code engineering (3B params)"
# Math Specialist - Qwen2 Math 7B (High Priority) # Reasoning Model - Mistral Nemo 12.2B (High Priority) - Advanced reasoning
qwen2-math-7b: mistral-nemo-12b:
path: ollama:qwen2-math:7b path: ollama:mistral-nemo:12b
type: math
size_gb: 4.13
priority: high
description: "Specialized model for mathematical tasks"
# Lightweight conversational LLM - Mistral Nemo 2.3B (Medium Priority)
mistral-nemo-2_3b:
path: ollama:mistral-nemo:2.3b-instruct
type: llm type: llm
size_gb: 1.60 size_gb: 7.1
priority: high
description: "Advanced reasoning model for complex tasks (12.2B params)"
# Reasoning Model - Gemma2 27B (Medium Priority) - Strategic reasoning
gemma2-27b:
path: ollama:gemma2:27b
type: llm
size_gb: 15.0
priority: medium priority: medium
description: "Fast low-cost replies for monitor/service agents" description: "Reasoning model for strategic tasks (27.2B params)"
# Compact Math Specialist - Qwen2.5 Math 1.5B (Medium Priority) # Code Specialist - DeepSeek Coder 33B (High Priority) - Advanced code tasks
qwen2_5-math-1_5b: deepseek-coder-33b:
path: ollama:qwen2.5-math:1.5b path: ollama:deepseek-coder:33b
type: math type: code
size_gb: 1.20 size_gb: 18.0
priority: medium priority: high
description: "Lightweight math model for DRUID/Nutra micro-calculations" description: "Advanced code specialist model (33B params)"
# Code Specialist - Qwen2.5 Coder 32B (High Priority) - Advanced code tasks
qwen2.5-coder-32b:
path: ollama:qwen2.5-coder:32b
type: code
size_gb: 19.0
priority: high
description: "Advanced code specialist model (32.8B params)"
# Reasoning Model - DeepSeek R1 70B (High Priority) - Strategic reasoning (large model)
deepseek-r1-70b:
path: ollama:deepseek-r1:70b
type: llm
size_gb: 42.0
priority: high
description: "Strategic reasoning model (70.6B params, quantized)"
storage: storage:
models_dir: /app/models models_dir: /app/models
@@ -77,5 +85,6 @@ storage:
swap_dir: /app/swap swap_dir: /app/swap
ollama: ollama:
url: http://ollama:11434 # From Docker container to Ollama service url: http://localhost:11434 # Native Ollama on MacBook (via Pieces OS or brew)
timeout: 300 timeout: 300

View File

@@ -0,0 +1,81 @@
# Swapper Configuration for Node #1 (Production Server)
# Single-active LLM scheduler
# Hetzner GEX44 - NVIDIA RTX 4000 SFF Ada (20GB VRAM)
# Auto-generated configuration with all available Ollama models
swapper:
mode: single-active
max_concurrent_models: 1
model_swap_timeout: 300
gpu_enabled: true
metal_acceleration: false # NVIDIA GPU, not Apple Silicon
# Модель для автоматичного завантаження при старті (опціонально)
# Якщо не вказано - моделі завантажуються тільки за запитом
# Рекомендовано: qwen3-8b (основна модель) або qwen2.5-3b-instruct (легка модель)
default_model: qwen3-8b # Модель активується автоматично при старті
models:
# Primary LLM - Qwen3 8B (High Priority) - Main model from INFRASTRUCTURE.md
qwen3-8b:
path: ollama:qwen3:8b
type: llm
size_gb: 4.87
priority: high
description: "Primary LLM for general tasks and conversations"
# Vision Model - Qwen3-VL 8B (High Priority) - For image processing
qwen3-vl-8b:
path: ollama:qwen3-vl:8b
type: vision
size_gb: 5.72
priority: high
description: "Vision model for image understanding and processing"
# Qwen2.5 7B Instruct (High Priority)
qwen2.5-7b-instruct:
path: ollama:qwen2.5:7b-instruct-q4_K_M
type: llm
size_gb: 4.36
priority: high
description: "Qwen2.5 7B Instruct model"
# Lightweight LLM - Qwen2.5 3B Instruct (Medium Priority)
qwen2.5-3b-instruct:
path: ollama:qwen2.5:3b-instruct-q4_K_M
type: llm
size_gb: 1.80
priority: medium
description: "Lightweight LLM for faster responses"
# Math Specialist - Qwen2 Math 7B (High Priority)
qwen2-math-7b:
path: ollama:qwen2-math:7b
type: math
size_gb: 4.13
priority: high
description: "Specialized model for mathematical tasks"
# Lightweight conversational LLM - Mistral Nemo 2.3B (Medium Priority)
mistral-nemo-2_3b:
path: ollama:mistral-nemo:2.3b-instruct
type: llm
size_gb: 1.60
priority: medium
description: "Fast low-cost replies for monitor/service agents"
# Compact Math Specialist - Qwen2.5 Math 1.5B (Medium Priority)
qwen2_5-math-1_5b:
path: ollama:qwen2.5-math:1.5b
type: math
size_gb: 1.20
priority: medium
description: "Lightweight math model for DRUID/Nutra micro-calculations"
storage:
models_dir: /app/models
cache_dir: /app/cache
swap_dir: /app/swap
ollama:
url: http://ollama:11434 # From Docker container to Ollama service
timeout: 300