- matrix-gateway: POST /internal/matrix/presence/online endpoint - usePresenceHeartbeat hook with activity tracking - Auto away after 5 min inactivity - Offline on page close/visibility change - Integrated in MatrixChatRoom component
320 lines
11 KiB
Markdown
320 lines
11 KiB
Markdown
# Node Communication Guide - Як агенти Node #1 контактують з Node #2
|
||
|
||
## 📋 Огляд
|
||
|
||
Агенти на різних нодах можуть спілкуватися через кілька механізмів. Цей документ описує всі доступні методи та їх використання.
|
||
|
||
---
|
||
|
||
## 🔗 Методи комунікації
|
||
|
||
### 1. DAGI Router (Основний метод)
|
||
|
||
**Призначення:** Маршрутизація запитів між нодами через централізовані роутери.
|
||
|
||
**Node #1 Router:**
|
||
- URL: `http://144.76.224.179:9102`
|
||
- Endpoint: `/v1/chat/completions`
|
||
- Порт: `9102`
|
||
|
||
**Node #2 Router:**
|
||
- URL: `http://localhost:9102`
|
||
- Endpoint: `/v1/chat/completions`
|
||
- Порт: `9102`
|
||
|
||
**Як працює:**
|
||
1. Агент на Node #1 відправляє запит до свого локального DAGI Router
|
||
2. Router перевіряє Node Registry для визначення розташування цільового агента
|
||
3. Якщо агент на іншій ноді, Router пересилає запит до Router цільової ноди
|
||
4. Цільовий Router доставляє повідомлення агенту
|
||
5. Відповідь проходить зворотним шляхом
|
||
|
||
**Приклад використання:**
|
||
```python
|
||
import httpx
|
||
|
||
async def contact_agent_on_other_node(agent_id: str, message: str, target_node: str):
|
||
router_url = "http://144.76.224.179:9102" if target_node == "node1" else "http://localhost:9102"
|
||
|
||
async with httpx.AsyncClient() as client:
|
||
response = await client.post(
|
||
f"{router_url}/v1/chat/completions",
|
||
json={
|
||
"model": "agent-model",
|
||
"messages": [
|
||
{"role": "user", "content": message}
|
||
],
|
||
"agent_id": agent_id,
|
||
"target_node": target_node
|
||
}
|
||
)
|
||
return response.json()
|
||
```
|
||
|
||
---
|
||
|
||
### 2. Node Registry (Service Discovery)
|
||
|
||
**Призначення:** Централізований реєстр всіх нод та агентів для service discovery.
|
||
|
||
**URL:** `http://144.76.224.179:9205`
|
||
|
||
**Endpoints:**
|
||
- `/health` - перевірка статусу
|
||
- `/api/v1/nodes` - список зареєстрованих нод
|
||
- `/api/v1/agents` - список агентів з їх розташуванням
|
||
- `/api/v1/agent/{agent_id}` - інформація про конкретного агента
|
||
|
||
**Як працює:**
|
||
1. Кожна нода реєструється в Node Registry при старті
|
||
2. Агенти реєструються з інформацією про свою ноду
|
||
3. При пошуку агента, система запитує Registry для визначення його розташування
|
||
4. Registry повертає інформацію про ноду та доступні endpoints
|
||
|
||
**Приклад використання:**
|
||
```python
|
||
async def find_agent_location(agent_id: str):
|
||
registry_url = "http://144.76.224.179:9205"
|
||
|
||
async with httpx.AsyncClient() as client:
|
||
response = await client.get(f"{registry_url}/api/v1/agent/{agent_id}")
|
||
agent_info = response.json()
|
||
return agent_info.get("node"), agent_info.get("endpoint")
|
||
```
|
||
|
||
---
|
||
|
||
### 3. NATS JetStream (Message Broker)
|
||
|
||
**Призначення:** Асинхронна комунікація через message broker для event-driven архітектури.
|
||
|
||
**URL:** `nats://144.76.224.179:4222`
|
||
|
||
**HTTP Monitoring:** `http://144.76.224.179:8222/varz`
|
||
|
||
**Як працює:**
|
||
1. Агент публікує повідомлення в NATS subject (наприклад, `agent.{agent_id}.inbox`)
|
||
2. Node Registry визначає, на якій ноді знаходиться цільовий агент
|
||
3. NATS маршрутизує повідомлення до відповідної ноди
|
||
4. Агент на цільовій ноді підписується на свій subject та отримує повідомлення
|
||
5. Відповідь публікується в subject відправника
|
||
|
||
**Приклад використання:**
|
||
```python
|
||
import nats
|
||
from nats.aio.client import Client as NATS
|
||
|
||
async def send_message_via_nats(agent_id: str, message: str):
|
||
nc = await nats.connect("nats://144.76.224.179:4222")
|
||
|
||
# Публікувати повідомлення
|
||
subject = f"agent.{agent_id}.inbox"
|
||
await nc.publish(subject, message.encode())
|
||
|
||
# Підписатися на відповідь
|
||
reply_subject = f"agent.{agent_id}.reply"
|
||
sub = await nc.subscribe(reply_subject)
|
||
|
||
# Очікувати відповідь
|
||
msg = await sub.next_msg()
|
||
return msg.data.decode()
|
||
```
|
||
|
||
---
|
||
|
||
### 4. HTTP/HTTPS API (Direct Calls)
|
||
|
||
**Призначення:** Прямі REST API виклики між нодами для синхронної комунікації.
|
||
|
||
**Node #1 API:**
|
||
- Base URL: `http://144.76.224.179:9102`
|
||
- Agent endpoint: `/api/agent/{agent_id}/chat`
|
||
|
||
**Node #2 API:**
|
||
- Base URL: `http://localhost:9102`
|
||
- Agent endpoint: `/api/agent/{agent_id}/chat`
|
||
|
||
**Як працює:**
|
||
1. Якщо відома адреса цільової ноди, можна зробити прямий HTTP запит
|
||
2. Запит йде безпосередньо до API цільової ноди
|
||
3. Відповідь повертається синхронно
|
||
|
||
**Приклад використання:**
|
||
```python
|
||
async def direct_agent_call(agent_id: str, message: str, target_node_url: str):
|
||
async with httpx.AsyncClient() as client:
|
||
response = await client.post(
|
||
f"{target_node_url}/api/agent/{agent_id}/chat",
|
||
json={"message": message}
|
||
)
|
||
return response.json()
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 Cross-Node Communication Flow
|
||
|
||
### Типовий сценарій: Agent на Node #1 → Agent на Node #2
|
||
|
||
```
|
||
┌─────────────────┐
|
||
│ Agent (Node #1) │
|
||
│ (Daarwizz) │
|
||
└────────┬────────┘
|
||
│ 1. Send request
|
||
▼
|
||
┌─────────────────┐
|
||
│ DAGI Router │
|
||
│ (Node #1) │
|
||
└────────┬────────┘
|
||
│ 2. Query Node Registry
|
||
▼
|
||
┌─────────────────┐
|
||
│ Node Registry │
|
||
│ (Centralized) │
|
||
└────────┬────────┘
|
||
│ 3. Return agent location (Node #2)
|
||
▼
|
||
┌─────────────────┐
|
||
│ DAGI Router │
|
||
│ (Node #1) │
|
||
└────────┬────────┘
|
||
│ 4. Forward to Node #2 Router
|
||
▼
|
||
┌─────────────────┐
|
||
│ DAGI Router │
|
||
│ (Node #2) │
|
||
└────────┬────────┘
|
||
│ 5. Deliver to agent
|
||
▼
|
||
┌─────────────────┐
|
||
│ Agent (Node #2) │
|
||
│ (Solarius) │
|
||
└────────┬────────┘
|
||
│ 6. Process & respond
|
||
▼
|
||
[Response follows reverse path]
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 Порівняння методів
|
||
|
||
| Метод | Тип | Latency | Надійність | Використання |
|
||
|-------|-----|---------|------------|--------------|
|
||
| **DAGI Router** | Синхронний | Низька | Висока | Основна комунікація між агентами |
|
||
| **Node Registry** | Service Discovery | N/A | Висока | Пошук агентів та нод |
|
||
| **NATS JetStream** | Асинхронний | Низька | Висока | Event-driven, pub/sub |
|
||
| **HTTP/HTTPS** | Синхронний | Середня | Висока | Прямі API виклики |
|
||
|
||
---
|
||
|
||
## 🛠️ Реалізація в коді
|
||
|
||
### Python приклад для агента
|
||
|
||
```python
|
||
class CrossNodeAgent:
|
||
def __init__(self, agent_id: str, node: str):
|
||
self.agent_id = agent_id
|
||
self.node = node
|
||
self.router_url = self._get_router_url()
|
||
self.registry_url = "http://144.76.224.179:9205"
|
||
|
||
def _get_router_url(self):
|
||
if self.node == "node1":
|
||
return "http://144.76.224.179:9102"
|
||
else:
|
||
return "http://localhost:9102"
|
||
|
||
async def contact_agent(self, target_agent_id: str, message: str):
|
||
# 1. Знайти розташування цільового агента
|
||
async with httpx.AsyncClient() as client:
|
||
registry_response = await client.get(
|
||
f"{self.registry_url}/api/v1/agent/{target_agent_id}"
|
||
)
|
||
target_info = registry_response.json()
|
||
target_node = target_info.get("node")
|
||
|
||
# 2. Визначити router URL для цільової ноди
|
||
if target_node == "node1":
|
||
target_router = "http://144.76.224.179:9102"
|
||
else:
|
||
target_router = "http://localhost:9102"
|
||
|
||
# 3. Відправити запит через router
|
||
response = await client.post(
|
||
f"{target_router}/v1/chat/completions",
|
||
json={
|
||
"model": target_info.get("model", "default"),
|
||
"messages": [
|
||
{"role": "user", "content": message}
|
||
],
|
||
"agent_id": target_agent_id,
|
||
"source_agent": self.agent_id,
|
||
"source_node": self.node
|
||
}
|
||
)
|
||
|
||
return response.json()
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ Перевірка зв'язку
|
||
|
||
### Тестування через API
|
||
|
||
```bash
|
||
# Перевірка зв'язку між нодами
|
||
curl http://localhost:8899/api/agents/connection-test
|
||
|
||
# Перевірка Node Registry
|
||
curl http://144.76.224.179:9205/health
|
||
|
||
# Перевірка NATS
|
||
curl http://144.76.224.179:8222/varz
|
||
|
||
# Перевірка DAGI Router (Node #1)
|
||
curl http://144.76.224.179:9102/health
|
||
|
||
# Перевірка DAGI Router (Node #2)
|
||
curl http://localhost:9102/health
|
||
```
|
||
|
||
---
|
||
|
||
## 📍 Де знаходиться інформація
|
||
|
||
### В кабінеті агента
|
||
|
||
Кожен агент має свій кабінет (`/agent/{agent_id}`), де відображається:
|
||
|
||
1. **Current Node** - на якій ноді знаходиться агент
|
||
2. **Communication Methods** - доступні методи комунікації
|
||
3. **How to Contact Agents on Other Nodes** - інструкції
|
||
4. **Cross-Node Communication Flow** - схема процесу
|
||
|
||
### На сторінці Agent Connections
|
||
|
||
Сторінка `/agents/connections` показує:
|
||
- Список агентів на кожній ноді
|
||
- Результати тестів зв'язку
|
||
- Статус кожного методу комунікації
|
||
|
||
---
|
||
|
||
## 🎯 Рекомендації
|
||
|
||
1. **Для синхронної комунікації:** Використовуйте DAGI Router
|
||
2. **Для event-driven:** Використовуйте NATS JetStream
|
||
3. **Для service discovery:** Використовуйте Node Registry
|
||
4. **Для прямих викликів:** Використовуйте HTTP/HTTPS API (якщо відома адреса)
|
||
|
||
---
|
||
|
||
**Status:** ✅ Complete
|
||
**Date:** 2025-11-22
|
||
**Version:** DAGI Monitor V5.1
|
||
|