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:
443
docs/services/AGENTS_SERVICE_SPEC.md
Normal file
443
docs/services/AGENTS_SERVICE_SPEC.md
Normal file
@@ -0,0 +1,443 @@
|
||||
# AGENTS SERVICE SPEC (PORT 7002)
|
||||
# Version: 1.0.0
|
||||
|
||||
---
|
||||
|
||||
## 0. PURPOSE
|
||||
|
||||
`Agents Service` — це центральний сервіс текстових агентів DAGI:
|
||||
|
||||
- надає API для виклику Helion, Helix, Metamorph та інших текстових агентів;
|
||||
- інтегрується з DAGI Router / ProjectBus / Mesh Directory;
|
||||
- застосовує:
|
||||
- Agent Registry,
|
||||
- Context Router,
|
||||
- Silence Policy,
|
||||
- Throttling,
|
||||
- TeamDefinition/ProjectBus контекст.
|
||||
|
||||
Це логічний "Runtime осередок" для текстової частини DAGI.
|
||||
|
||||
Порт за замовчуванням (NODE1/NODE2): **7002**.
|
||||
|
||||
---
|
||||
|
||||
## 1. HIGH-LEVEL ARCHITECTURE
|
||||
|
||||
```text
|
||||
[ Gateway (Telegram/Web/Matrix/...) ]
|
||||
↓
|
||||
[ DAGI Router (gateway.daarion.city) ]
|
||||
↓
|
||||
[ Agents Service (7002) ]
|
||||
↓
|
||||
[ LLM Providers / Swapper / DAGI Mesh ]
|
||||
```
|
||||
|
||||
Agents Service отримує **RouterEvent-like** запити від DAGI Router (або внутрішніх сервісів) та:
|
||||
|
||||
1. Визначає, які агенти доступні (через AgentRegistry + Mesh Directory + TeamDefinition).
|
||||
2. Обирає найвідповіднішого/декількох (Context Router).
|
||||
3. Перевіряє Silence Policy.
|
||||
4. Застосовує throttling.
|
||||
5. Викликає відповідний LLM / backend агента.
|
||||
6. Повертає відповідь + metadata.
|
||||
|
||||
---
|
||||
|
||||
## 2. DEPENDENCIES
|
||||
|
||||
### 2.1. Внутрішні модулі
|
||||
|
||||
Agents Service використовує:
|
||||
|
||||
* `configs/AGENT_REGISTRY.yaml`
|
||||
* `configs/AGENT_REGISTRY_SCHEMA.yaml`
|
||||
* `services/agent_registry_loader.py`
|
||||
* `services/agent_context_router.py`
|
||||
* `services/agent_silence_policy.py`
|
||||
* `services/agent_throttle.py`
|
||||
* `services/agent_mesh_directory.py`
|
||||
* `configs/team_definition.yaml`
|
||||
* `configs/project_bus_config.yaml`
|
||||
|
||||
### 2.2. Зовнішні сервіси
|
||||
|
||||
* **LLM Provider / Swapper Service** (NODE1/NODE2)
|
||||
* **NATS** (або інший event-bus) для:
|
||||
|
||||
* ProjectBus,
|
||||
* Mesh Directory,
|
||||
* M2M-комунікації між агентами.
|
||||
* **PostgreSQL / Redis** (опційно) для:
|
||||
|
||||
* кешу відповідей,
|
||||
* logging / traces.
|
||||
|
||||
---
|
||||
|
||||
## 3. CONFIGURATION
|
||||
|
||||
ENV-змінні:
|
||||
|
||||
```env
|
||||
AGENTS_SERVICE_PORT=7002
|
||||
|
||||
AGENT_REGISTRY_PATH=configs/AGENT_REGISTRY.yaml
|
||||
AGENT_REGISTRY_SCHEMA_PATH=configs/AGENT_REGISTRY_SCHEMA.yaml
|
||||
|
||||
TEAM_DEFINITION_PATH=configs/team_definition.yaml
|
||||
PROJECT_BUS_CONFIG_PATH=configs/project_bus_config.yaml
|
||||
|
||||
MESH_DIRECTORY_MODE=inprocess # "inprocess" | "nats" | "http"
|
||||
MESH_DIRECTORY_NATS_SUBJECT_BASE=agent.directory
|
||||
|
||||
LLM_PROVIDER_BASE_URL=http://localhost:8890 # або інший super-service/swapper
|
||||
|
||||
AGENT_THROTTLE_LIMIT_PER_MINUTE=3
|
||||
AGENT_THROTTLE_WINDOW_SECONDS=60
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. PUBLIC API (HTTP)
|
||||
|
||||
### 4.1. `POST /agents/invoke`
|
||||
|
||||
Основний endpoint для DAGI Router та внутрішніх сервісів.
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"event": {
|
||||
"event_id": "tg:123",
|
||||
"source": "telegram",
|
||||
"chat": { "id": "123", "type": "group" },
|
||||
"user": { "id": "user1", "username": "alex" },
|
||||
"team_id": "team-daariandao-core",
|
||||
"project_id": "proj-daariandao",
|
||||
"text": "helix, перевір api",
|
||||
"attachments": {
|
||||
"images": [],
|
||||
"docs": [],
|
||||
"audio": [],
|
||||
"geo": [],
|
||||
"tables": []
|
||||
},
|
||||
"flags": {
|
||||
"command": null,
|
||||
"reply_to": null,
|
||||
"confidential_mode": "public"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"force_agent_id": null, // якщо заповнено, обійти context router
|
||||
"allow_panel_mode": true, // дозволити кільком агентам відповісти
|
||||
"max_agents": 2 // верхня межа для panel-режиму
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response (успішний сценарій):**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"replies": [
|
||||
{
|
||||
"agent_id": "ag_helix",
|
||||
"text": "Ось аналіз API ...",
|
||||
"meta": {
|
||||
"model": "HELIX_ENGINEER_MODEL",
|
||||
"tokens_in": 123,
|
||||
"tokens_out": 256,
|
||||
"latency_ms": 900
|
||||
}
|
||||
}
|
||||
],
|
||||
"context": {
|
||||
"project_id": "proj-daariandao",
|
||||
"team_id": "team-daariandao-core",
|
||||
"reply_mode": "panel"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response (ніхто не має відповідати):**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "silent",
|
||||
"reason": "no_agent_or_policy",
|
||||
"context": {
|
||||
"project_id": "proj-daariandao",
|
||||
"team_id": "team-daariandao-core"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response (throttling):**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "throttled",
|
||||
"reason": "rate_limit",
|
||||
"agent_id": "ag_helion"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.2. `GET /agents/registry`
|
||||
|
||||
Повертає список агентів (тільки для адміністраторів / системних агентів):
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": [
|
||||
{
|
||||
"agent_id": "ag_helion",
|
||||
"name": "Helion",
|
||||
"role": "assistant",
|
||||
"priority": 5,
|
||||
"model": "HELION_TEXT_MODEL",
|
||||
"skills": ["допоможи", "поясни"],
|
||||
"modalities": ["text"],
|
||||
"description": "Головний асистент DAARION."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.3. `GET /agents/instances`
|
||||
|
||||
Проксі до Mesh Directory (видно інстанси):
|
||||
|
||||
```json
|
||||
{
|
||||
"instances": [
|
||||
{
|
||||
"agent_id": "ag_helion",
|
||||
"instance_id": "ag_helion@noda1-01",
|
||||
"node_id": "NODA1",
|
||||
"status": "online",
|
||||
"project_ids": ["proj-daariandao"],
|
||||
"microdao_id": "microdao-root",
|
||||
"last_seen": 1732450200.123
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. INTERNAL LOGIC
|
||||
|
||||
### 5.1. Pipeline для `/agents/invoke`
|
||||
|
||||
Покроковий алгоритм:
|
||||
|
||||
1. **Parse event**
|
||||
|
||||
* прийняти `event` (RouterEvent-сумісний payload),
|
||||
* витягнути `project_id`, `team_id`, `chat.id`.
|
||||
|
||||
2. **Load TeamDefinition**
|
||||
|
||||
* знайти команду по `team_id` (або по `project_id` → команди, які працюють у цьому проекті),
|
||||
* зчитати `reply_mode`:
|
||||
|
||||
* `single` / `panel` / `silent`,
|
||||
* `max_agents_per_message`.
|
||||
|
||||
3. **Load AgentRegistry & MeshDirectory**
|
||||
|
||||
* завантажити список агентів із registry,
|
||||
* для кожного, хто в TeamDefinition:
|
||||
|
||||
* перевірити, чи є онлайн інстанси (Mesh Directory).
|
||||
|
||||
4. **Context Router**
|
||||
|
||||
* побудувати `AgentDescriptor` для кожного доступного агента (з skills, priority),
|
||||
* викликати `select_best_agent(event, descriptors)`:
|
||||
|
||||
* для `single`: обрати 1,
|
||||
* для `panel`: обрати до `max_agents_per_message`,
|
||||
* для `silent`: можна одразу повернути `status: silent`.
|
||||
|
||||
5. **Silence Policy** (per-agent)
|
||||
Для кожного кандидата:
|
||||
|
||||
* `should_agent_reply(agent_id, event)`:
|
||||
|
||||
* прямі згадки,
|
||||
* команди,
|
||||
* приватні чати,
|
||||
* контекстна релевантність.
|
||||
|
||||
Якщо жоден не проходить → `status: silent`.
|
||||
|
||||
6. **Throttling** (per-agent, per-chat)
|
||||
Для кожного, хто пройшов silence policy:
|
||||
|
||||
* `throttle.can_reply(agent_id, chat_id)`:
|
||||
|
||||
* якщо ні → позначити `throttled`,
|
||||
* якщо хоча б один агент може відповідати → продовжуємо.
|
||||
|
||||
7. **Invoke agents (LLM Provider)**
|
||||
Для кожного дозволеного агента:
|
||||
|
||||
* сформувати system prompt (на основі `AGENT_REGISTRY`, ролі, skills),
|
||||
* сформувати user/context prompt (із події),
|
||||
* відправити в LLM Provider / Swapper Service:
|
||||
|
||||
* `POST /llm/invoke` (або NATS subject `llm.invoke`).
|
||||
|
||||
8. **Aggregate response**
|
||||
|
||||
* зібрати `replies` (до N агентів),
|
||||
* зібрати `meta` (latency, tokens),
|
||||
* повернути у DAGI Router HTTP-відповідь.
|
||||
|
||||
---
|
||||
|
||||
## 6. INTEGRATION WITH DAGI ROUTER
|
||||
|
||||
### 6.1. З боку DAGI Router
|
||||
|
||||
При текстовій гілці (без мультимодальності):
|
||||
|
||||
```python
|
||||
# dagi_router.py (схематично)
|
||||
resp = http.post("http://agents-service:7002/agents/invoke", json={
|
||||
"event": router_event_dict,
|
||||
"options": {
|
||||
"force_agent_id": None,
|
||||
"allow_panel_mode": True,
|
||||
"max_agents": 2
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Router далі:
|
||||
|
||||
* бере `resp["replies"]`,
|
||||
* конвертує в повідомлення для Gateway (Telegram/Web/Matrix),
|
||||
* застосовує свої policy (наприклад, фільтрацію ненормативу, якщо треба).
|
||||
|
||||
---
|
||||
|
||||
## 7. NATS / PROJECT BUS INTEGRATION
|
||||
|
||||
Agents Service також:
|
||||
|
||||
1. Слухає ProjectBus:
|
||||
|
||||
* `project.<project_id>.chat.mixed` (через DAGI Router),
|
||||
* `project.<project_id>.tasks` (можна робити автоматичну обробку задач).
|
||||
|
||||
2. Може публікувати події:
|
||||
|
||||
* `project.<project_id>.agents` (наприклад, "Helix взяв task t123"),
|
||||
* `project.<project_id>.m2m.*` (M2M/R2D2 комунікація).
|
||||
|
||||
Це дозволяє:
|
||||
|
||||
* агентам працювати в командах,
|
||||
* не тільки як chatbot, а як учасники mesh-процесів.
|
||||
|
||||
---
|
||||
|
||||
## 8. HEALTHCHECK & METRICS
|
||||
|
||||
### 8.1. Healthcheck
|
||||
|
||||
`GET /healthz`:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"registry_loaded": true,
|
||||
"mesh_directory_mode": "inprocess",
|
||||
"uptime_seconds": 12345
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2. Prometheus метрики
|
||||
|
||||
* `agents_invocations_total{agent_id, project_id, status}`
|
||||
* `agents_throttled_total{agent_id}`
|
||||
* `agents_silent_decisions_total{reason}`
|
||||
* `agents_llm_latency_ms_bucket{agent_id, le=...}`
|
||||
|
||||
---
|
||||
|
||||
## 9. LOGGING
|
||||
|
||||
Кожен виклик `/agents/invoke` логувати:
|
||||
|
||||
* `event_id`, `source`, `chat.id`, `project_id`, `team_id`,
|
||||
* кандидатів агентів + scores (debug-level),
|
||||
* остаточно обраних агентів,
|
||||
* статус: `ok` / `silent` / `throttled` / `error`,
|
||||
* latency LLM.
|
||||
|
||||
Формат: JSON-лог для подальшого аналізу (ELK / Loki / Grafana).
|
||||
|
||||
---
|
||||
|
||||
## 10. TEST PLAN (SHORT)
|
||||
|
||||
Unit-тести (pytest):
|
||||
|
||||
1. `test_single_agent_selection()`
|
||||
|
||||
* один агент у команді, простий текст, немає throttling → відповідає.
|
||||
|
||||
2. `test_panel_mode_two_agents()`
|
||||
|
||||
* `reply_mode: panel`, `max_agents_per_message: 2`,
|
||||
* питання, релевантне Helix і Guardian → відповідають двоє.
|
||||
|
||||
3. `test_silence_policy_mentions()`
|
||||
|
||||
* повідомлення без згадок і без ключових слів → `status: silent`.
|
||||
|
||||
4. `test_throttling_per_agent()`
|
||||
|
||||
* 4 виклики поспіль у межах 60 сек,
|
||||
* `limit_per_minute=3`,
|
||||
* 4-й → `status: throttled`.
|
||||
|
||||
5. `test_team_definition_loading()`
|
||||
|
||||
* агрегація команд з `team_definition.yaml`,
|
||||
* мапінг на project_id.
|
||||
|
||||
---
|
||||
|
||||
## 11. SUMMARY
|
||||
|
||||
Agents Service (7002) — це:
|
||||
|
||||
* офіційний текстовий runtime DAGI,
|
||||
* точка входу для Helion/Helix/Metamorph та інших текстових агентів,
|
||||
* шар, який:
|
||||
|
||||
* "бачить" всю конфігурацію агентів (Registry),
|
||||
* "бачить" живі інстанси (Mesh Directory),
|
||||
* враховує TeamDefinition/ProjectBus,
|
||||
* контролює поведінку агентів у чатах (silence/panel/throttle).
|
||||
|
||||
Після реалізації цього сервісу DAGI Router зможе:
|
||||
|
||||
* делегувати всю текстову логіку в єдиний, стандартизований компонент,
|
||||
* який легко масштабувати між НОДА1/НОДА2 і далі.
|
||||
|
||||
Reference in New Issue
Block a user