Skip to content

TASK: PHASE 3 — LLM PROXY + MEMORY ORCHESTRATOR + TOOLCORE

Goal: Зробити агентів DAARION по-справжньому розумними та інструментальними: - єдиний LLM Proxy з підтримкою кількох провайдерів і локальних моделей; - Memory Orchestrator, який дає єдиний API для памʼяті агентів; - Toolcore — реєстр інструментів і безпечне виконання tools для агентів.

PHASE 3 = інфраструктура мислення й дії для Agent Runtime.

Existing (assume from Phase 1–2): - messaging-service, matrix-gateway, Messenger UI. - agent-filter, DAGI Router (router.invoke.agent). - agent-runtime (використовує /internal/llm/proxy та /internal/agent-memory/*, але поки можуть бути stubs). - базова БД (users, microdaos, agents, channels, messages, etc.). - NATS JetStream, PostgreSQL, docker-compose.

Deliverables: 1. services/llm-proxy/ — LLM Router + Providers + Logging. 2. services/memory-orchestrator/ — єдиний API для памʼяті агентів. 3. services/toolcore/ — registry + execution engine для tools. 4. Інтеграція з agent-runtime. 5. Оновлення docker-compose та docs.


1) SERVICE: LLM PROXY (services/llm-proxy)

Create folder:

services/llm-proxy/
  main.py
  models.py
  router.py
  providers/
    __init__.py
    openai_provider.py
    deepseek_provider.py
    local_provider.py
  config.yaml
  middlewares.py
  logging_middleware.py
  Dockerfile
  requirements.txt
  README.md

1.1 API

Base URL (internal-only): - POST /internal/llm/proxy

Request (v1):

{
  "model": "gpt-4.1-mini",
  "messages": [
    { "role": "system", "content": "..." },
    { "role": "user", "content": "..." }
  ],
  "metadata": {
    "agent_id": "agent:sofia",
    "microdao_id": "microdao:7",
    "channel_id": "..."
  }
}

Response:

{
  "content": "текст відповіді",
  "usage": {
    "prompt_tokens": 123,
    "completion_tokens": 45,
    "total_tokens": 168
  },
  "provider": "openai",
  "model_resolved": "gpt-4.1-mini"
}

Optional (stub for later): - /internal/llm/batch - /internal/llm/stream (можна залишити TODO)

1.2 Model routing (router.py)

Створити модуль:

def route_model(logical_model: str) -> ProviderConfig:
    # Читає зі структури в config.yaml
    # Напр.:
    #  - gpt-4.1-mini → OpenAI (gpt-4.1-mini)
    #  - deepseek-r1 → DeepSeek API
    #  - dagi-local-8b → Local provider (Ollama / vllm)

config.yaml (приклад):

providers:
  openai:
    base_url: "https://api.openai.com/v1"
    api_key_env: "OPENAI_API_KEY"
  deepseek:
    base_url: "https://api.deepseek.com/v1"
    api_key_env: "DEEPSEEK_API_KEY"
  local:
    base_url: "http://local-llm:8000"

models:
  gpt-4.1-mini:
    provider: "openai"
    name: "gpt-4.1-mini"
  deepseek-r1:
    provider: "deepseek"
    name: "deepseek-r1"
  dagi-local-8b:
    provider: "local"
    name: "qwen2.5-8b-instruct"

1.3 Providers (providers/*.py)

Кожен провайдер:

class BaseProvider(Protocol):
    async def chat(self, messages: list[ChatMessage], model_name: str, **kwargs) -> LLMResponse: ...

Файли: - providers/openai_provider.py - providers/deepseek_provider.py - providers/local_provider.py

Вони: - отримують normalized messages, - викликають відповідний API/endpoint, - повертають LLMResponse (контент + usage).

Local provider: - для Phase 3 можна зробити простий HTTP-запит до існуючого локального сервісу (Ollama/vLLM), або stub.

1.4 Logging & limits (middlewares.py, logging_middleware.py)

Добавити: - простий rate limit per-agent (стабово, через in-memory або Redis stub). - логування викликів: - agent_id, microdao_id, model, latency, tokens. - TODO hooks для Billing/Usage Engine (на майбутнє).

1.5 README.md

Описати: - підтримувані моделі та мапінг, - як додати нового провайдера, - як викликати /internal/llm/proxy з інших сервісів (особливо agent-runtime).


2) SERVICE: MEMORY ORCHESTRATOR (services/memory-orchestrator)

Goal: Єдиний API для роботи з памʼяттю: - short-term (канальний контекст / event log), - mid-term (agent memory / RAG embedding store), - long-term (knowledge base, docs, roadmaps).

Create folder:

services/memory-orchestrator/
  main.py
  models.py
  router.py
  backends/
    __init__.py
    short_term_pg.py
    vector_store_pg.py
    kb_filesystem.py
  embedding_client.py
  config.yaml
  Dockerfile
  requirements.txt
  README.md

2.1 API

Base URL: - POST /internal/agent-memory/query - POST /internal/agent-memory/store - POST /internal/agent-memory/summarize (optional v1)

Request /query:

{
  "agent_id": "agent:sofia",
  "microdao_id": "microdao:7",
  "channel_id": "optional",
  "query": "коротко, які були останні зміни в цьому microDAO?",
  "limit": 5
}

Response:

{
  "items": [
    {
      "id": "mem-123",
      "kind": "conversation | kb | task | dao-event",
      "score": 0.87,
      "content": "Текст фрагменту памʼяті",
      "meta": {
        "source": "channel:...",
        "timestamp": "..."
      }
    }
  ]
}

Request /store:

{
  "agent_id": "agent:sofia",
  "microdao_id": "microdao:7",
  "channel_id": "optional",
  "kind": "conversation | kb | task | dao-event",
  "content": {
    "user_message": "...",
    "agent_reply": "..."
  }
}

Response:

{ "ok": true, "id": "mem-123" }

2.2 Backends

backends/short_term_pg.py: - зберігає сирі events (або посилання на messages) в PostgreSQL, якщо треба окремо від messenger.

backends/vector_store_pg.py: - використовує embeddings (через embedding_client.py) і зберігає в таблиці: sql agent_memories (id, agent_id, microdao_id, embedding vector, content, meta) - простий cosine similarity пошук.

backends/kb_filesystem.py: - stub для long-term знань (roadmaps, docs), можна залишити TODO.

2.3 Embedding client (embedding_client.py)

  • Простий клієнт до існуючої embedding-моделі (наприклад, BGE-M3 чи інша) через /internal/embedding/proxy або безпосередньо.
  • Якщо embedding-сервіс не описаний — зробити stub + TODO.

2.4 Integration points

agent-runtime: - замінити прямі виклики agent-memory на: - POST /internal/agent-memory/query - POST /internal/agent-memory/store

Надалі можна буде підʼєднати: - microDAO knowledge, - DAO events, - roadmaps.


3) SERVICE: TOOLCORE (services/toolcore)

Goal: Єдина точка для: - реєстрації tools (інструментів агентів), - перевірки дозволів, - виконання tools та повернення результату агенту.

Create folder:

services/toolcore/
  main.py
  models.py
  router.py
  registry.py
  executors/
    __init__.py
    http_executor.py
    python_executor.py (optional)
  config.yaml
  Dockerfile
  requirements.txt
  README.md

3.1 Data model

models.py:

class ToolDefinition(BaseModel):
    id: str                # "projects.list"
    name: str
    description: str
    input_schema: dict     # JSON Schema
    output_schema: dict    # JSON Schema
    executor: Literal["http", "python"]
    target: str            # HTTP URL or python path
    allowed_agents: list[str] | None

class ToolCallRequest(BaseModel):
    tool_id: str
    agent_id: str
    microdao_id: str
    args: dict
    context: dict | None = None

class ToolCallResult(BaseModel):
    ok: bool
    result: dict | None = None
    error: str | None = None

3.2 API

HTTP (internal):

  • GET /internal/tools → список доступних tools

  • POST /internal/tools/call Body: ToolCallRequest Behavior:

  • перевірити, чи agent_id має право на tool_id (allowed_agents).
  • знайти ToolDefinition.
  • виконати через відповідний executor.
  • повернути ToolCallResult.

3.3 Executors

executors/http_executor.py: - викликає target як HTTP endpoint (POST з args + context). - хендлінг помилок та таймаутів.

executors/python_executor.py (optional): - allows direct call of internal python functions (у v1 можна залишити TODO або мінімальний stub).

3.4 Registry (registry.py)

Початок — з config.yaml (static registry):

config.yaml:

tools:
  - id: "projects.list"
    name: "List projects"
    description: "Повертає список проєктів microDAO."
    input_schema:
      type: "object"
      properties:
        microdao_id: { type: "string" }
      required: ["microdao_id"]
    output_schema:
      type: "array"
      items: { type: "object" }
    executor: "http"
    target: "http://projects-service:8000/internal/tools/projects.list"
    allowed_agents: ["agent:sofia", "agent:pm", "agent:cto"]

Registry API: - load from config.yaml at startup - later можна зробити DB-backed registry.

3.5 NATS (optional для Phase 3)

Можна додати: - subject: tool.request - subject: tool.response

Але для Phase 3 достатньо HTTP-контракту, який викликає agent-runtime.


4) INTEGRATION: agent-runtime + LLM Proxy + Memory + Toolcore

Update agent-runtime:

4.1 Використовувати LLM Proxy

Замість прямого виклику будь-яких LLM: - завжди викликати: http POST /internal/llm/proxy { "model": "<logical model from agent blueprint>", "messages": [...], "metadata": { "agent_id": ..., "microdao_id": ..., "channel_id": ... } }

4.2 Використовувати Memory Orchestrator

При channel_message: - контекст: GET /internal/messaging/channels/{channelId}/messages?limit=50 - памʼять: POST /internal/agent-memory/query - запис: POST /internal/agent-memory/store після відповіді.

4.3 Виклик tools

Якщо в blueprint агента передбачені tools: - парсити вихід LLM (JSON/structured) або через simple convention (наприклад, спеціальний формат "TOOL: projects.list {...}"). - для кожного tool call: http POST /internal/tools/call { "tool_id": "...", "agent_id": "...", "microdao_id": "...", "args": {...} } - включати результати tools у наступний LLM виклик як контекст. - (На Phase 3 можна реалізувати один-два прості tools: projects.list, followups.create.)


5) DOCKER + DOCS

5.1 docker-compose

Додати new services: - llm-proxy - memory-orchestrator - toolcore

Переконатися, що: - вони в тій же мережі, що agent-runtime, messaging-service, NATS, DB; - є healthcheck-и (GET /health).

5.2 Документація

Додати/оновити: - docs/LLM_PROXY_SPEC.md - docs/MEMORY_ORCHESTRATOR_SPEC.md - docs/TOOLCORE_SPEC.md - оновити docs/INDEX.md (додати посилання на ці три сервіси). - в PHASE2_READY.md або окремому PHASE3_READY.md описати нову архітектуру agent pipeline.


6) ACCEPTANCE CRITERIA

1) LLM Proxy:

  • ✅ /internal/llm/proxy приймає запити, повертає відповіді.
  • ✅ Принаймні 2 логічні моделі працюють (наприклад, один remote, один local.stub).
  • ✅ Логуються виклики per-agent.

2) Memory Orchestrator:

  • ✅ /internal/agent-memory/query повертає релевантні фрагменти (можна з простим vector search або stub).
  • ✅ /internal/agent-memory/store зберігає нові entries.
  • ✅ agent-runtime успішно використовує його при відповіді.

3) Toolcore:

  • ✅ /internal/tools повертає список інструментів.
  • ✅ /internal/tools/call виконує хоча б один реальний tool (HTTP executor).
  • ✅ agent-runtime може викликати хоча б один tool впродовж свого pipeline.

4) End-to-end:

  • ✅ Агент у Messenger:
  • читає контекст (messages + memory),
  • викликає LLM через LLM Proxy,
  • за потреби викликає tool через Toolcore,
  • повертає відповідь у канал.
  • ✅ Для одного демо-агента (наприклад, Sofia-Prime) цей ланцюг стабільно працює.

END OF TASK

Estimated Time: 6-8 weeks
Priority: High
Dependencies: Phase 2 complete
Version: 1.0.0
Date: 2025-11-24