Files
microdao-daarion/scripts/sync-node2-dagi-agents.py
Apple 2f8e471e03 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
2025-12-01 08:31:25 -08:00

267 lines
9.6 KiB
Python

#!/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()