Dynavera/ARCHITECTURE.md
2025-12-17 13:50:18 +00:00

24 KiB

Agent System Architecture Diagram

System Overview (current stack)

Docker Compose (dev) services on one network:

  • web (Vite dev) :5173
  • api (Django + Channels) :8000
  • celery worker shares Django code
  • fyp-redis broker/channel :6379
  • mcp-agent-server MCP runtime :8001 (HTTP)

MCP wiring:

  • MCP_AGENT_URL=http://mcp-agent-server:8001 (required)
  • MCP server runs in HTTP mode, exposes /execute and /health endpoints
  • All agent execution delegates to the remote MCP server (no local LLM fallback)

Flow: Frontend → API (HTTP), Frontend ↔ AgentConsumer (WS), API queues Celery, Celery calls MCP server over HTTP, events return via Redis → Channels → WS.

┌──────────────────────────────────────────────────────────────────────────┐
│                        FRONTEND (Vue 3 + TypeScript)                     │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────┐  ┌──────────────────────┐  ┌─────────────────────┐  │
│  │  Agents.vue     │  │  AgentDetail.vue     │  │  agentStore.ts      │  │
│  ├─────────────────┤  ├──────────────────────┤  ├─────────────────────┤  │
│  │ • List agents   │  │ • Run execution      │  │ • WebSocket connect │  │
│  │ • Fetch from API│  │ • JSON input         │  │ • Event handling    │  │
│  │ • Show status   │  │ • Live log display   │  │ • State management  │  │
│  └────────┬────────┘  │ • Stop button        │  │ • Auto-reconnect    │  │
│           │           │ • Status indicator   │  │ • Type-safe API     │  │
│           │           └────────┬─────────────┘  └─────────────────────┘  │
│           │                    │                                         │
└───────────┼────────────────────┼─────────────────────────────────────────┘
            │                    │
            │                    │ WebSocket
            │ HTTP/REST          │
            ▼                    ▼
┌──────────────────────────────────────────────────────────────────────────┐
│                    BACKEND (Django + Channels)                           │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────┐  ┌──────────────────────────┐  ┌─────────────────┐  │
│  │  AgentViewSet   │  │  AgentConsumer           │  │  Middleware     │  │
│  ├─────────────────┤  ├──────────────────────────┤  ├─────────────────┤  │
│  │ REST API:       │  │ WebSocket Handler:       │  │ • Auth check    │  │
│  │ • GET /agent/   │  │ • connect()              │  │ • User validate │  │
│  │ • POST /agent/  │  │ • receive()              │  │ • Group mgmt    │  │
│  │ • GET /agent/id │  │ • handle_start_agent()   │  └─────────────────┘  │
│  │                 │  │ • handle_stop_agent()    │                       │
│  │ Returns: Agent  │  │ • agent_event()          │  ┌─────────────────┐  │
│  │ metadata        │  │ • agent_completed()      │  │  Serializers    │  │
│  └────────┬────────┘  │ • agent_error()          │  ├─────────────────┤  │
│           │           └────────┬─────────────────┘  │ • AgentSerializer  │
│           │                    │                    │ • ExecutionSer. │  │
│           │                    │                    │ • EventSerializer  │
│           │                    │                    └────────┬────────┘  │
│           │                    │                             │           │
│           ▼                    ▼                             ▼           │
│  ┌─────────────────────────────────────────────────────────────────┐     │
│  │        Django Database (SQLite/PostgreSQL)                      │     │
│  ├─────────────────────────────────────────────────────────────────┤     │
│  │ • Agent (uuid, name, description, status, user)                 │     │
│  │ • AgentExecution (uuid, input_data, output_data, status)        │     │
│  │ • AgentEvent (uuid, event_type, content, timestamp)             │     │
│  └─────────────────────────────────────────────────────────────────┘     │
│                                                                          │
└──────────────────────┬───────────────────────────────────────────────────┘
                       │
                       │ Celery Task Queue
                       ▼
┌──────────────────────────────────────────────────────────────────────────┐
│                      CELERY WORKER PROCESS                               │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌──────────────────────────────────────────────────────────────────┐    │
│  │  start_agent_task_mcp() [MCP-only execution]                     │    │
│  ├──────────────────────────────────────────────────────────────────┤    │
│  │  ┌──────────────────────────────────────────────────────────┐    │    │
│  │  │  1. Initialize & Output "started" event                  │    │    │
│  │  │                                                          │    │    │
│  │  │  2. Call MCPAgentClient.execute_agent()                  │    │    │
│  │  │     └─ POST to {MCP_AGENT_URL}/execute                   │    │    │
│  │  │        with: agent_id, query, input_data                 │    │    │
│  │  │                                                          │    │    │
│  │  │  3. Await response from MCP server                       │    │    │
│  │  │     (handles all RAG, LLM, context retrieval)            │    │    │
│  │  │                                                          │    │    │
│  │  │  4. Forward any events from MCP to WebSocket             │    │    │
│  │  │     └─ Progress, message, step events displayed live     │    │    │
│  │  │                                                          │    │    │
│  │  │  5. Save result & Output "completed" event               │    │    │
│  │  │     └─ Send via Channel Layer to WebSocket Group         │    │    │
│  │  │                                                          │    │    │
│  │  └──────────────────────────────────────────────────────────┘    │    │
│  └──────────────────────────────────────────────────────────────────┘    │
│                                                                          │
└──────────────────────┬───────────────────────────────────────────────────┘
                       │
                       │ Channel Layer Broadcast
                       ▼
┌──────────────────────────────────────────────────────────────────────────┐
│                   REDIS (Message Broker & Cache)                         │
├──────────────────────────────────────────────────────────────────────────┤
│ • Celery task queue                                                      │
│ • Channel layer for WebSocket group communication                        │
│ • Session cache (optional)                                               │
└──────────────────────────────────────────────────────────────────────────┘

MCP Runtime (HTTP mode)

  • Service: mcp-agent-server (container dynavera-mcp-agent)
  • Listens on 0.0.0.0:8001 with /execute and /health HTTP endpoints
  • Handles all agent execution: RAG retrieval, LLM inference, context management
  • Shares code and build/rag_db read-only from host
  • Completely separate from Django/Celery; communicates only via HTTP

Execution Flow Sequence

Frontend                    Backend                    LLM System
  │                            │                            │
  ├─ User Input ──────────────>│                            │
  │  (JSON via WebSocket)      │                            │
  │                            │                            │
  │                            ├─ Create Execution          │
  │                            │  Record                    │
  │                            │                            │
  │                            ├─ Queue Celery Task         │
  │                            │                            │
  │<── execution_started ──────┤                            │
  │  (WebSocket message)       │                            │
  │                            │                            │
  │                            ├─ Output "initializing"     │
  │<── agent_event ────────────┤                            │
  │  (WebSocket)               │                            │
  │                            │                            │
  │                            ├─ Load GPT4All Model        │
  │                            │                            │
  │                            │─────────────────────────>│ Load Model
  │                            │  (~10-30 seconds)          │
  │                            │<───────────────────────── Model Ready
  │                            │                            │
  │                            ├─ Output "retrieving"       │
  │<── agent_event ────────────┤                            │
  │  (WebSocket)               │                            │
  │                            │                            │
  │                            ├─ Query RAG DB (if exists)  │
  │                            │  (ChromaDB)                │
  │                            │                            │
  │                            ├─ Output "generating"       │
  │<── agent_event ────────────┤                            │
  │  (WebSocket)               │                            │
  │                            │                            │
  │                            │───────────────────────────>│ Generate
  │                            │  generate(prompt,          │ Response
  │                            │   max_tokens=200)          │
  │                            │<───────────────────────── Response
  │                            │  (5-30 seconds)            │
  │                            │                            │
  │<── execution_completed ────┤                            │
  │  (WebSocket with output)   │                            │
  │                            │                            │
  └ Display Log & Result       │                            │

Data Flow: Input to Output

User Enters JSON
    ↓
{"query": "What is fNIRS?"}
    ↓
Frontend sends via WebSocket
    ↓
    ┌─────────────────────────────────────┐
    │  AgentConsumer.receive(text_data)   │
    └──────────────┬──────────────────────┘
                   │
                   ├─ Parse JSON
                   ├─ Validate action
                   └─ Route to handler
                   ↓
    ┌─────────────────────────────────────┐
    │ handle_start_agent()                │
    ├─────────────────────────────────────┤
    │ • Get agent from DB                 │
    │ • Create AgentExecution             │
    │ • Queue Celery task                 │
    └──────────────┬──────────────────────┘
                   │
                   ├─ Send execution_started event
                   │  (back to WebSocket)
                   │
                   ├─ Queue in Celery/Redis
                   │
    ┌──────────────┴──────────────────────┐
    │                                     │
    ▼                                     ▼
Celery Worker                       Database Updated
    │                                     │
    ├─ Fetch execution                    │
    ├─ Initialize models                  │
    ├─ Send progress events               │
    │                                     │
    ├─ Query RAG (if available)           │
    │  ├─ Load embedder                   │
    │  ├─ Connect to ChromaDB             │
    │  └─ Query for context               │
    │                                     │
    ├─ Initialize LLM                     │
    │  ├─ Load GPT4All model              │
    │  └─ Prepare prompt                  │
    │                                     │
    ├─ Generate response                  │
    │  └─ model.generate()                │
    │                                     │
    ├─ Create result dict                 │
    │                                     │
    ├─ Save to AgentExecution             │
    │  ├─ output_data                     │
    │  ├─ status = 'completed'            │
    │  └─ completed_at                    │
    │                                     │
    └─ Send via Channel Layer
       to WebSocket Group
                   │
                   ├─ event_type: agent_event
                   ├─ event_type: agent_completed
                   │
                   ▼
           Frontend receives
                   │
                   ├─ Update agentStore
                   ├─ Push to eventLog
                   ├─ Display in UI
                   │
                   ▼
           User sees result

Component Interaction

┌─────────────────────────────────────────────────────────┐
│              FRONTEND STATE MANAGEMENT                  │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  agentStore (Pinia)                                     │
│  ├─ socket: WebSocket connection                        │
│  ├─ isConnected: boolean                                │
│  ├─ agentId: UUID                                       │
│  ├─ currentExecutionId: UUID                            │
│  ├─ executionStatus: 'idle'|'running'|'completed'       │
│  ├─ events: Array<AgentEvent>                           │
│  │                                                      │
│  ├─ connect(agentId)                                    │
│  ├─ startAgent(inputData)                               │
│  ├─ stopAgent()                                         │
│  ├─ disconnect()                                        │
│  └─ handleMessage(data)                                 │
│                                                         │
│  AgentDetail.vue (Uses Store)                           │
│  ├─ Subscribes to:                                      │
│  │  ├─ agentStore.isConnected                           │
│  │  ├─ agentStore.executionStatus                       │
│  │  └─ agentStore.eventLog                              │
│  │                                                      │
│  └─ Calls:                                              │
│     ├─ agentStore.connect() on mount                    │
│     ├─ agentStore.startAgent() on button click          │
│     ├─ agentStore.disconnect() on unmount               │
│     └─ agentStore.stopAgent() on stop button            │
│                                                         │
└─────────────────────────────────────────────────────────┘

Message Type Mapping

WebSocket Message Type → Handler Function → Event Display

"execution_started"      → handleMessage   → "Started" tag + message
"agent_event"           → handleMessage   → Event type specific
  ├─ "progress"         → Display stage   → [PROGRESS] stage: message
  ├─ "message"          → Display text    → [MESSAGE] content
  └─ "step"             → Display step    → [STEP] content

"execution_completed"   → handleMessage   → "Completed" tag + output
"execution_error"       → handleMessage   → "Error" tag + message
"execution_stopped"     → handleMessage   → "Stopped" tag + message
"error"                 → handleMessage   → "Error" tag + message
"connection"            → handleMessage   → Console log

Database Schema Relationships

User (from auth)
  │
  ├─────── (1:N) ─────────> Agent
  │                          ├─ uuid (PK)
  │                          ├─ name
  │                          ├─ description
  │                          ├─ status
  │                          ├─ created_at
  │                          └─ updated_at
  │                                │
  │                                ├─────── (1:N) ──────────> AgentExecution
  │                                                           ├─ uuid (PK)
  │                                                           ├─ status
  │                                                           ├─ input_data (JSON)
  │                                                           ├─ output_data (JSON)
  │                                                           ├─ error_message
  │                                                           ├─ created_at
  │                                                           ├─ started_at
  │                                                           ├─ completed_at
  │                                                           │     │
  │                                                           │     ├─ (1:N) ──> AgentEvent
  │                                                           │                ├─ uuid (PK)
  │                                                           │                ├─ event_type
  │                                                           │                ├─ content (JSON)
  │                                                           │                └─ timestamp
  │                                                           │
  │                                                           └─ user_id (FK)
  │                                                                  │
  └──────────────────────────────────────────────────────────────────┘