diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..7c07c7d --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,331 @@ +# 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 │ +│ │ │ +│ ├─ 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) + │ │ + └──────────────────────────────────────────────────────────────────┘ +``` diff --git a/README.md b/README.md index 72edd63..f109089 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,10 @@ The main objectives of this project are: --- +## Architecture + +See [ARCHITECTURE.md](./ARCHITECTURE.md) for a detailed system overview, component interaction, execution flow, and data flow diagrams. + ## Features - Automated onboarding workflow for new hires.