Skip to content

# 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

    [ 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-змінні:

    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:

    {
      "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 (успішний сценарій):

    {
      "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 (ніхто не має відповідати):

    {
      "status": "silent",
      "reason": "no_agent_or_policy",
      "context": {
        "project_id": "proj-daariandao",
        "team_id": "team-daariandao-core"
      }
    }

Response (throttling):

    {
      "status": "throttled",
      "reason": "rate_limit",
      "agent_id": "ag_helion"
    }

### 4.2. `GET /agents/registry`

Повертає список агентів (тільки для адміністраторів / системних агентів):

Response:

    {
      "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 (видно інстанси):

    {
      "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

2. прийняти `event` (RouterEvent-сумісний payload),

3. витягнути `project_id`, `team_id`, `chat.id`.

4. Load TeamDefinition

5. знайти команду по `team_id` (або по `project_id` → команди, які працюють у цьому проекті),

6. зчитати `reply_mode`:

   - `single` / `panel` / `silent`,
   - `max_agents_per_message`.

7. Load AgentRegistry & MeshDirectory

8. завантажити список агентів із registry,

9. для кожного, хто в TeamDefinition:

   - перевірити, чи є онлайн інстанси (Mesh Directory).

10. Context Router

11. побудувати `AgentDescriptor` для кожного доступного агента (з skills, priority),

12. викликати `select_best_agent(event, descriptors)`:

    - для `single`: обрати 1,
    - для `panel`: обрати до `max_agents_per_message`,
    - для `silent`: можна одразу повернути `status: silent`.

13. Silence Policy (per-agent) Для кожного кандидата:

14. `should_agent_reply(agent_id, event)`:

    - прямі згадки,
    - команди,
    - приватні чати,
    - контекстна релевантність.

Якщо жоден не проходить → `status: silent`.

1. Throttling (per-agent, per-chat) Для кожного, хто пройшов silence policy:

2. `throttle.can_reply(agent_id, chat_id)`:

   - якщо ні → позначити `throttled`,
   - якщо хоча б один агент може відповідати → продовжуємо.

3. Invoke agents (LLM Provider) Для кожного дозволеного агента:

4. сформувати system prompt (на основі `AGENT_REGISTRY`, ролі, skills),

5. сформувати user/context prompt (із події),

6. відправити в LLM Provider / Swapper Service:

   - `POST /llm/invoke` (або NATS subject `llm.invoke`).

7. Aggregate response

8. зібрати `replies` (до N агентів),

9. зібрати `meta` (latency, tokens),
10. повернути у DAGI Router HTTP-відповідь.

## 6. INTEGRATION WITH DAGI ROUTER

### 6.1. З боку DAGI Router

При текстовій гілці (без мультимодальності):

    # 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:

2. `project.<project_id>.chat.mixed` (через DAGI Router),

3. `project.<project_id>.tasks` (можна робити автоматичну обробку задач).

4. Може публікувати події:

5. `project.<project_id>.agents` (наприклад, "Helix взяв task t123"),

6. `project.<project_id>.m2m.*` (M2M/R2D2 комунікація).

Це дозволяє:

- агентам працювати в командах,
- не тільки як chatbot, а як учасники mesh-процесів.

## 8. HEALTHCHECK & METRICS

### 8.1. Healthcheck

`GET /healthz`:

    {
      "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()`

2. один агент у команді, простий текст, немає throttling → відповідає.

3. `test_panel_mode_two_agents()`

4. `reply_mode: panel`, `max_agents_per_message: 2`,

5. питання, релевантне Helix і Guardian → відповідають двоє.

6. `test_silence_policy_mentions()`

7. повідомлення без згадок і без ключових слів → `status: silent`.

8. `test_throttling_per_agent()`

9. 4 виклики поспіль у межах 60 сек,

10. `limit_per_minute=3`,

11. 4-й → `status: throttled`.

12. `test_team_definition_loading()`

13. агрегація команд з `team_definition.yaml`,

14. мапінг на project_id.

## 11. SUMMARY

Agents Service (7002) — це:

- офіційний текстовий runtime DAGI,
- точка входу для Helion/Helix/Metamorph та інших текстових агентів,

- шар, який:

- "бачить" всю конфігурацію агентів (Registry),

- "бачить" живі інстанси (Mesh Directory),
- враховує TeamDefinition/ProjectBus,
- контролює поведінку агентів у чатах (silence/panel/throttle).

Після реалізації цього сервісу DAGI Router зможе:

- делегувати всю текстову логіку в єдиний, стандартизований компонент,
- який легко масштабувати між НОДА1/НОДА2 і далі.