feat: Add presence heartbeat for Matrix online status
- 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
This commit is contained in:
319
NODE-COMMUNICATION-GUIDE.md
Normal file
319
NODE-COMMUNICATION-GUIDE.md
Normal file
@@ -0,0 +1,319 @@
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user