Architecture for 150+ nodes: - global_capabilities_client.py: NATS scatter-gather discovery using wildcard subject node.*.capabilities.get — zero static node lists. New nodes auto-register by deploying NCS and subscribing to NATS. Dead nodes expire from cache after 3x TTL automatically. Multi-node model_select.py: - ModelSelection now includes node, local, via_nats fields - select_best_model prefers local candidates, then remote - Prefer list resolution: local first, remote second - All logged per request: node, runtime, model, local/remote NODA1 compose: - Added node-capabilities service (NCS) to docker-compose.node1.yml - NATS subscription: node.noda1.capabilities.get - Router env: NODE_CAPABILITIES_URL + ENABLE_GLOBAL_CAPS_NATS=true NODA2 compose: - Router env: ENABLE_GLOBAL_CAPS_NATS=true Router main.py: - Startup: initializes global_capabilities_client (NATS connect + first discovery). Falls back to local-only capabilities_client if unavailable. - /infer: uses get_global_capabilities() for cross-node model pool - Offload support: send_offload_request(node_id, type, payload) via NATS Verified on NODA2: - Global caps: 1 node, 14 models (NODA1 not yet deployed) - Sofiia: cloud_grok → grok-4-1-fast-reasoning (OK) - Helion: NCS → qwen3:14b local (OK) - When NODA1 deploys NCS, its models appear automatically via NATS discovery Made-with: Cursor
DAGI Router Service
Routes events to appropriate agents and services
Purpose
DAGI Router is the central orchestrator that routes various events (filter decisions, direct invocations, scheduled jobs) to agent-runtime for execution.
Features
- Filter Decision Routing: Processes
agent.filter.decisionevents - Agent Invocation: Creates and publishes
router.invoke.agentmessages - Configurable: YAML-based routing configuration
- Test Mode: HTTP endpoint for testing routing logic
Architecture
agent.filter.decision (NATS)
↓
router: Create AgentInvocation
↓
router.invoke.agent (NATS)
↓
agent-runtime (subscribes)
Routing Rules
Messaging Inbound (Phase 2)
Input: agent.filter.decision (from agent-filter)
Output: router.invoke.agent (to agent-runtime)
Logic:
- Only process
decision == "allow" - Ensure
target_agent_idis present - Create
AgentInvocationwith channel context - Publish to NATS
Future Rules (Phase 3+)
- Direct agent invocations (API calls)
- Scheduled/cron invocations
- Webhook-triggered invocations
- Agent-to-agent communication
API
Health Check
GET /health
Response:
{
"status": "ok",
"service": "router",
"version": "1.0.0",
"nats_connected": true,
"messaging_inbound_enabled": true
}
Test Routing (Manual)
POST /internal/router/test-messaging
Content-Type: application/json
{
"channel_id": "test-channel",
"matrix_event_id": "$event123",
"microdao_id": "microdao:daarion",
"decision": "allow",
"target_agent_id": "agent:sofia"
}
Response:
{
"agent_id": "agent:sofia",
"entrypoint": "channel_message",
"payload": {
"channel_id": "test-channel",
"matrix_event_id": "$event123",
"microdao_id": "microdao:daarion",
"rewrite_prompt": null
}
}
Configuration
File: router_config.yaml
messaging_inbound:
enabled: true
source_subject: "agent.filter.decision"
target_subject: "router.invoke.agent"
Environment Variables
NATS_URL: NATS server URL (default:nats://nats:4222)
Running Locally
Install Dependencies
pip install -r requirements.txt
Run Service
uvicorn main:app --reload --port 8000
Test
# Health check
curl http://localhost:8000/health
# Test routing
curl -X POST http://localhost:8000/internal/router/test-messaging \
-H "Content-Type: application/json" \
-d '{
"channel_id": "test-123",
"matrix_event_id": "$test",
"microdao_id": "microdao:daarion",
"decision": "allow",
"target_agent_id": "agent:sofia"
}'
Docker
Build
docker build -t daarion/router:latest .
Run
docker run -p 8000:8000 \
-e NATS_URL=nats://nats:4222 \
daarion/router:latest
NATS Events
Subscribes To
- Subject:
agent.filter.decision - Payload:
FilterDecision
Publishes To
- Subject:
router.invoke.agent - Payload:
AgentInvocation
Monitoring
Logs
docker logs -f router
# Look for:
# ✅ Connected to NATS
# ✅ Subscribed to agent.filter.decision
# 🔀 Processing filter decision
# ✅ Decision: allow
# 🚀 Created invocation for agent:sofia
# ✅ Published invocation
Troubleshooting
Not Routing Messages
Check:
- Is router subscribed to NATS?
- Is agent-filter publishing decisions?
- Are decisions "allow"?
- Is target_agent_id present?
# Check NATS subscription
docker exec -it router cat /app/router_config.yaml
# Test routing logic
curl -X POST http://localhost:8000/internal/router/test-messaging \
-d @test_decision.json
Future Enhancements
- Multiple routing strategies
- Agent load balancing
- Priority queues
- Rate limiting per agent
- Retry logic
- Dead letter queue
- Routing analytics
Version
Current: 1.0.0
Status: Production Ready (Phase 2)
Last Updated: 2025-11-24