From 78019efd57b1e82a389914ed5dd6393b97caaeaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:36 -0300 Subject: [PATCH 01/14] docs: update .github/workflows/ci.yml --- .github/workflows/ci.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e82a7e9..af1cefc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: - name: Install linting tools run: | python -m pip install --upgrade pip - pip install ruff black isort + pip install ruff black - name: Lint with Ruff run: ruff check src/ tests/ --output-format=github @@ -37,8 +37,13 @@ jobs: - name: Check formatting with Black run: black --check --diff src/ tests/ - - name: Check import sorting with isort - run: isort --check-only --diff src/ tests/ --profile black -p medex + # Note: import sorting is handled by ruff's "I" rule (I001). + # A standalone isort step was removed because ruff and isort + # disagree on aliased imports (e.g., `from x import Y as Z`), + # creating an unresolvable conflict where neither tool accepts + # the other's output. Ruff's isort implementation is the + # industry-standard replacement. See: + # https://docs.astral.sh/ruff/faq/#how-does-ruffs-import-sorting-compare-to-isort # ========================================================================= # REQUIRED: Stable tests — files with 100% pass rate From 502362fa9e9f86ec476d0e452e749f311b017f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:37 -0300 Subject: [PATCH 02/14] docs: update CONTRIBUTING.md --- CONTRIBUTING.md | 91 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 16c1e04..4ca93f9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,10 +7,18 @@ Thank you for your interest in contributing to MedeX! This document provides gui - [Code of Conduct](#code-of-conduct) - [Getting Started](#getting-started) - [Development Setup](#development-setup) +- [Docker Setup](#docker-setup) +- [Environment Variables](#environment-variables) +- [Running the UI (Reflex)](#running-the-ui-reflex) - [Making Changes](#making-changes) - [Pull Request Process](#pull-request-process) - [Coding Standards](#coding-standards) - [Testing](#testing) +- [Troubleshooting](#troubleshooting) + +> **Full reference:** See [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) for the +> complete development environment guide with API reference, project structure, +> and advanced configuration. ## 📜 Code of Conduct @@ -28,12 +36,12 @@ This project adheres to a Code of Conduct. By participating, you are expected to 1. **Fork the repository** on GitHub 2. **Clone your fork** locally: ```bash - git clone https://github.com/YOUR_USERNAME/Med-X-KimiK2-RAG.git - cd Med-X-KimiK2-RAG + git clone https://github.com/YOUR_USERNAME/MedX.git + cd MedX ``` 3. **Add the upstream remote**: ```bash - git remote add upstream https://github.com/DeepRatAI/Med-X-KimiK2-RAG.git + git remote add upstream https://github.com/DeepRatAI/MedX.git ``` ## 💻 Development Setup @@ -42,7 +50,8 @@ This project adheres to a Code of Conduct. By participating, you are expected to - Python 3.10+ - Git -- A Moonshot/Kimi API key (for testing) +- Docker & Docker Compose (optional, for full-stack development) +- A Moonshot/Kimi API key (optional, only needed for LLM features) ### Environment Setup @@ -73,6 +82,51 @@ pytest tests/ --cov=src/medex --cov-report=html pytest tests/test_detection.py -v ``` +## 🐳 Docker Setup + +```bash +# Full stack (API + UI + infrastructure) +docker compose up --build -d + +# API only +docker compose up api -d + +# Rebuild after code changes +docker compose up --build -d + +# View logs +docker compose logs -f api +``` + +## 🔑 Environment Variables + +Create a `.env` file in the project root: + +```env +# Required for LLM features +KIMI_API_KEY=your_kimi_api_key_here + +# Optional +HF_TOKEN=your_huggingface_token # For embedding models +DATABASE_URL=postgresql+asyncpg://... # Defaults to SQLite +REDIS_URL=redis://localhost:6379/0 # For caching +QDRANT_URL=http://localhost:6333 # For vector store +MEDEX_ENV=development # development | test | production +MEDEX_LOG_LEVEL=DEBUG # DEBUG | INFO | WARNING | ERROR +``` + +> **Note:** Medical tools (drug interactions, dosage calculator, lab interpreter, +> triage) work without any API keys — they use local databases. + +## 🖥️ Running the UI (Reflex) + +```bash +cd ui +reflex init # First time only +reflex run --env dev +# UI available at http://localhost:3000 +``` + ## ✏️ Making Changes ### Branch Naming @@ -265,6 +319,35 @@ When adding medical content: 4. **Add appropriate disclaimers** 5. **Review with medical professionals** when possible +## 🔧 Troubleshooting + +**Import errors after install:** +```bash +pip install -e . --no-deps +pip install -r requirements.txt +``` + +**Port already in use:** +```bash +lsof -i :8000 # API +lsof -i :3000 # UI +kill -9 +``` + +**Pre-commit hook failures:** +```bash +black src/ tests/ && ruff check --fix src/ tests/ +git add -u && git commit +``` + +**Database connection errors:** +```bash +# Use SQLite (no setup needed): +unset DATABASE_URL +# Or check if Postgres is running: +docker compose ps postgres +``` + ## ❓ Questions? - Open an issue for bugs or feature requests From 456c3af65fc4e68696ae058e6bccc447791a011f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:38 -0300 Subject: [PATCH 03/14] docs: update pyproject.toml --- pyproject.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index a6e2ee0..1901363 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -141,3 +141,11 @@ exclude_lines = [ "raise NotImplementedError", "if TYPE_CHECKING:", ] + +# Bandit security linter configuration +# B104: binding to 0.0.0.0 is intentional — the API server runs inside +# Docker containers where binding to all interfaces is required for +# container networking. Access control is handled by the container +# orchestrator / reverse proxy, not by bind address restriction. +[tool.bandit] +skips = ["B104"] From de0b199cc92017d5a17ec0a2f3cc3f987de0c317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:39 -0300 Subject: [PATCH 04/14] docs: update src/medex/api/__init__.py --- src/medex/api/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/medex/api/__init__.py b/src/medex/api/__init__.py index d5ae3ed..834b48a 100644 --- a/src/medex/api/__init__.py +++ b/src/medex/api/__init__.py @@ -86,7 +86,9 @@ create_connection_manager, create_websocket_handler, ) -from .websocket import WSMessage as WebSocketMessage +from .websocket import ( + WSMessage as WebSocketMessage, +) __all__ = [ # App From 33164eda87d2cef1da09ca6114b36c8095f48153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:40 -0300 Subject: [PATCH 05/14] docs: update docs/DEVELOPMENT.md --- docs/DEVELOPMENT.md | 276 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 docs/DEVELOPMENT.md diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md new file mode 100644 index 0000000..6ae1715 --- /dev/null +++ b/docs/DEVELOPMENT.md @@ -0,0 +1,276 @@ +# Development Environment Setup + +Complete guide to set up MedeX for local development. + +## Prerequisites + +| Tool | Version | Purpose | +|------|---------|---------| +| Python | ≥ 3.10 | Runtime | +| pip | Latest | Package management | +| Git | ≥ 2.30 | Version control | +| Docker | ≥ 24.0 | Container runtime (optional) | +| Docker Compose | ≥ 2.20 | Service orchestration (optional) | + +## Quick Start (Minimal) + +```bash +# 1. Clone the repository +git clone https://github.com/DeepRatAI/MedX.git +cd MedX + +# 2. Create virtual environment +python3.10 -m venv .venv +source .venv/bin/activate # Linux/macOS +# .venv\Scripts\activate # Windows + +# 3. Install dependencies +pip install --upgrade pip +pip install -e ".[dev]" +# Or from requirements.txt: +pip install -r requirements.txt +pip install pytest pytest-asyncio pytest-cov pytest-mock black ruff mypy pre-commit + +# 4. Install pre-commit hooks +pre-commit install + +# 5. Verify installation +python -c "import medex; print('MedeX imported successfully')" +pytest tests/test_detection.py -v # Quick sanity check +``` + +## Environment Variables + +Create a `.env` file in the project root: + +```env +# Required for LLM features +KIMI_API_KEY=your_kimi_api_key_here + +# Optional: HuggingFace (for embedding models) +HF_TOKEN=your_huggingface_token_here + +# Optional: Database (defaults to SQLite if not set) +DATABASE_URL=postgresql+asyncpg://medex:medex@localhost:5432/medex +REDIS_URL=redis://localhost:6379/0 +QDRANT_URL=http://localhost:6333 + +# Optional: Environment +MEDEX_ENV=development +MEDEX_LOG_LEVEL=DEBUG +MEDEX_UI_PORT=3000 +``` + +> **Note**: The application runs without any API keys for local medical tools +> (drug interactions, dosage calculator, lab interpreter, triage). LLM features +> require at least `KIMI_API_KEY`. + +## Full Stack (Docker Compose) + +For the complete development stack with all services: + +```bash +# Build and start all services +docker compose up --build -d + +# Services will be available at: +# - API: http://localhost:8000 +# - UI: http://localhost:3000 +# - Docs: http://localhost:8000/docs (OpenAPI/Swagger) + +# View logs +docker compose logs -f api +docker compose logs -f ui + +# Stop all services +docker compose down +``` + +### Individual Services + +```bash +# API only (FastAPI + Uvicorn) +docker compose up api -d + +# UI only (Reflex) +docker compose up ui -d + +# Infrastructure only (Postgres + Redis + Qdrant) +docker compose up postgres redis qdrant -d +``` + +## Running Without Docker + +### API Server + +```bash +# Development mode with auto-reload +uvicorn medex.api.app:create_app --factory --reload --host 0.0.0.0 --port 8000 + +# Or use the standalone server +python run_api.py +``` + +### UI (Reflex) + +```bash +cd ui +reflex init # First time only +reflex run --env dev +# UI available at http://localhost:3000 +``` + +## Development Workflow + +### 1. Code Quality + +```bash +# Format code +black src/ tests/ + +# Lint +ruff check src/ tests/ +ruff check --fix src/ tests/ # Auto-fix safe issues + +# Type checking +mypy src/medex --ignore-missing-imports + +# All checks at once (via pre-commit) +pre-commit run --all-files +``` + +### 2. Testing + +```bash +# Run stable tests +pytest tests/test_api_v2.py tests/test_detection.py tests/test_differential_diagnosis.py -v + +# Run with coverage +pytest tests/ -v --cov=src/medex --cov-report=html +open htmlcov/index.html + +# Run specific test +pytest tests/test_detection.py::TestEmergencyDetection::test_chest_pain_detected -v + +# Skip slow/integration tests +pytest tests/ -v -m "not slow and not integration" +``` + +### 3. Branch Naming + +``` +fix/short-description # Bug fixes +feat/short-description # New features +docs/short-description # Documentation +ci/short-description # CI/CD changes +refactor/short-description # Code restructuring +test/short-description # Test additions/fixes +``` + +### 4. Commit Messages (Conventional Commits) + +``` +fix: correct dosage calculation for pediatric patients +feat: add ICD-10 code lookup API endpoint +docs: update development setup guide +ci: enforce ruff check in CI pipeline +test: add unit tests for triage engine +refactor: extract medical ontology into separate module +``` + +## Project Structure + +``` +MedX/ +├── src/medex/ # Main package +│ ├── agent/ # Agentic controller, planner, intent analysis +│ ├── api/ # FastAPI app, routes, middleware, models +│ ├── core/ # Config, constants, base classes +│ ├── db/ # SQLAlchemy models, repositories, migrations +│ ├── detection/ # Emergency detection engine +│ ├── knowledge/ # Medical knowledge base (1000+ conditions) +│ ├── llm/ # LLM router, parser, streaming +│ ├── medical/ # Clinical models, triage, reasoner, formatter +│ ├── memory/ # Conversation memory, context windows +│ ├── observability/ # Logging, tracing, metrics +│ ├── providers/ # LLM provider adapters (Kimi, HuggingFace) +│ ├── rag/ # RAG pipeline (chunker, embedder, reranker) +│ ├── security/ # Audit logging, input validation +│ ├── tools/ # Medical tools (drugs, dosage, labs, triage) +│ └── vision/ # Medical image analysis +├── ui/medex_ui/ # Reflex UI application +│ ├── app.py # UI components (3800+ lines) +│ └── state.py # Reactive state management (2900+ lines) +├── tests/ # Test suite (18 test files + 2 E2E) +├── docs/ # Documentation +│ ├── adr/ # Architecture Decision Records +│ ├── ARCHITECTURE.md # System architecture overview +│ └── *.md # Various technical docs +├── .github/workflows/ # CI/CD +├── pyproject.toml # Project config (black, ruff, mypy, pytest) +├── requirements.txt # Python dependencies +├── Dockerfile # Multi-stage Docker build +└── docker-compose.yml # Service orchestration +``` + +## API Reference + +The API is auto-documented via OpenAPI/Swagger: + +```bash +# Start the API server +python run_api.py +# or +uvicorn medex.api.app:create_app --factory --port 8000 + +# Access documentation +open http://localhost:8000/docs # Swagger UI +open http://localhost:8000/redoc # ReDoc +``` + +### Key Endpoints + +| Method | Path | Description | +|--------|------|-------------| +| `POST` | `/api/v1/query` | Main query endpoint (LLM-powered) | +| `POST` | `/api/v1/tools/drug-interactions` | Check drug interactions | +| `POST` | `/api/v1/tools/dosage-calculator` | Calculate dosage | +| `POST` | `/api/v1/tools/lab-interpreter` | Interpret lab values | +| `POST` | `/api/v1/triage/assess` | Emergency triage assessment | +| `GET` | `/api/v1/tools/` | List available tools | +| `GET` | `/health` | Health check | +| `WS` | `/ws` | WebSocket for streaming | + +## Troubleshooting + +### Common Issues + +**Import errors after install:** +```bash +pip install -e . --no-deps +# If still failing, install deps explicitly: +pip install -r requirements.txt +``` + +**Port already in use:** +```bash +# Find and kill the process +lsof -i :8000 # API +lsof -i :3000 # UI +kill -9 +``` + +**Database connection errors:** +```bash +# Check if Postgres is running +docker compose ps postgres +# Or use SQLite (no setup needed): +unset DATABASE_URL +``` + +**Pre-commit hook failures:** +```bash +# Auto-fix formatting +black src/ tests/ && ruff check --fix src/ tests/ +git add -u && git commit +``` From 541c98468e0cef71199a963d9048e24f43f78582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:41 -0300 Subject: [PATCH 06/14] docs: update docs/adr/0001-reflex-migration.md --- docs/adr/0001-reflex-migration.md | 92 +++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 docs/adr/0001-reflex-migration.md diff --git a/docs/adr/0001-reflex-migration.md b/docs/adr/0001-reflex-migration.md new file mode 100644 index 0000000..2ae89b6 --- /dev/null +++ b/docs/adr/0001-reflex-migration.md @@ -0,0 +1,92 @@ +# ADR-0001: Migración de Streamlit a Reflex + +**Fecha:** 2026-01-15 +**Estado:** Aceptado +**Autor:** Gonzalo + +## Contexto + +MedeX originalmente utilizaba Streamlit como framework de UI. A medida que el proyecto +evolucionó hacia una plataforma médica profesional con múltiples módulos interactivos +(chat en tiempo real, herramientas médicas, triage, investigación profunda), las +limitaciones de Streamlit se hicieron evidentes. + +### Limitaciones de Streamlit + +1. **Modelo de re-ejecución completa**: Cada interacción del usuario re-ejecuta el + script completo, lo que es ineficiente para aplicaciones con estado complejo. + +2. **Sin WebSocket nativo**: Streamlit usa polling HTTP para actualizaciones, lo que + impide streaming en tiempo real del LLM con baja latencia. + +3. **Control limitado del layout**: La API de componentes no permite layouts + responsivos complejos como el panel lateral con múltiples secciones desplegables + que MedeX requiere. + +4. **Estado global frágil**: `st.session_state` no escala bien cuando hay 50+ + variables de estado interrelacionadas (como en MedeXState). + +5. **Sin soporte multi-página nativo**: Las soluciones de routing son workarounds, + no primera clase. + +## Decisión + +**Adoptar Reflex (reflex.dev) como framework de UI.** + +### Justificación + +| Criterio | Streamlit | Reflex | +|----------|-----------|--------| +| Estado reactivo | Re-ejecución completa | Granular, por componente | +| WebSocket | No nativo | Nativo, bidireccional | +| Layout | Limitado | Full CSS/Flexbox/Grid | +| Backend | Implícito | FastAPI integrado | +| Despliegue | Streamlit Cloud | Cualquier infraestructura | +| Python puro | Sí | Sí | +| Componentes custom | Limitado | React wrapping completo | + +### Factores Decisivos + +1. **Streaming LLM**: Reflex permite `rx.State` con `yield` para streaming token + por token via WebSocket, esencial para la experiencia de chat médico. + +2. **Estado complejo**: `MedeXState` (~2900 líneas) gestiona >50 variables de estado + con lógica condicional compleja. El modelo reactivo de Reflex lo maneja nativamente. + +3. **Layout profesional**: El sidebar con navegación por módulos, paneles colapsables, + y grid de herramientas requiere control CSS completo. + +4. **Backend unificado**: Reflex compila a FastAPI internamente, eliminando la + necesidad de mantener dos servidores separados para UI y API. + +## Consecuencias + +### Positivas + +- Streaming en tiempo real para respuestas del LLM +- Estado reactivo granular sin re-renders innecesarios +- Control total del layout para la interfaz médica profesional +- Un solo proceso Python para UI + API +- Deploy containerizado estándar + +### Negativas + +- Curva de aprendizaje para contribuyentes acostumbrados a Streamlit +- Reflex es un framework más joven con ecosistema más pequeño +- El código UI es más verboso (componentes explícitos vs. API implícita de Streamlit) +- Debugging del frontend compilado (React) requiere herramientas adicionales + +### Riesgos Mitigados + +- **Madurez de Reflex**: El framework tiene releases regulares y soporte activo. + MedeX usa solo APIs estables. +- **Complejidad de UI**: Se documentan patterns y convenciones en DEVELOPMENT.md + para onboarding de nuevos contribuyentes. + +## Implementación + +- Todos los archivos de UI residen en `ui/medex_ui/` +- `app.py` contiene los componentes de UI (~3800 líneas) +- `state.py` contiene el estado reactivo (~2900 líneas) +- Referencias residuales a Streamlit eliminadas en PR #17 +- El `Dockerfile` y `docker-compose.yml` usan `reflex run` como entrypoint From 8855e37fb71c12fff854b10882348a4d2777c483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:44 -0300 Subject: [PATCH 07/14] docs: update .github/workflows/ci.yml From 448ef73f8d86d96b672f0f3a2f696ddb6bb0072f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:45 -0300 Subject: [PATCH 08/14] docs: update CONTRIBUTING.md From a7bdc67173d12ff7b09e09e628b2d00259dc0b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:47 -0300 Subject: [PATCH 09/14] docs: update pyproject.toml From 56d776156dc08723fe083091196477a4d71b82d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:48 -0300 Subject: [PATCH 10/14] docs: update src/medex/api/__init__.py From 90de1d3a49207fd0ee934af6250b6989daf8739b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:49 -0300 Subject: [PATCH 11/14] docs: update docs/DEVELOPMENT.md From 47266b4f20ed3f93c664e457f16a5cabd0c09943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:50 -0300 Subject: [PATCH 12/14] docs: update docs/adr/0001-reflex-migration.md From 7c5537647a771ce52491f0e92d79d9eca7544050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:49:51 -0300 Subject: [PATCH 13/14] docs: update docs/adr/0002-agent-architecture.md --- docs/adr/0002-agent-architecture.md | 150 ++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 docs/adr/0002-agent-architecture.md diff --git a/docs/adr/0002-agent-architecture.md b/docs/adr/0002-agent-architecture.md new file mode 100644 index 0000000..fcc9ba3 --- /dev/null +++ b/docs/adr/0002-agent-architecture.md @@ -0,0 +1,150 @@ +# ADR-0002: Arquitectura Multi-Agente Médica + +**Fecha:** 2026-01-15 +**Estado:** Aceptado +**Autor:** Gonzalo + +## Contexto + +MedeX es un asistente médico que necesita manejar múltiples tipos de consultas: +consultas simples de chat, uso de herramientas especializadas (interacciones +medicamentosas, dosificación, interpretación de laboratorio), triage de emergencia, +investigación profunda con fuentes externas y análisis de imágenes médicas. + +Un enfoque monolítico con un solo prompt y un solo modelo LLM no escala para: +- Diferentes niveles de criticidad (emergencia vs. consulta informativa) +- Diferentes fuentes de conocimiento (base local vs. PubMed vs. web) +- Diferentes latencias aceptables (triage inmediato vs. investigación exhaustiva) +- Presupuestos de tokens variables por tipo de consulta + +## Decisión + +**Adoptar una arquitectura de controlador-agente con routing inteligente.** + +### Componentes + +``` +┌─────────────────────────────────────────────────┐ +│ Controller │ +│ (agent/controller.py) │ +│ - Intent analysis │ +│ - Route selection │ +│ - Context assembly │ +│ - Response orchestration │ +└──────────┬──────────────────────────────────────┘ + │ + ┌──────┴──────┐ + │ Planner │ (agent/planner.py) + │ + Intent │ (agent/intent_analysis.py) + └──────┬──────┘ + │ + ┌────────┼────────┬────────────┬──────────┐ + ▼ ▼ ▼ ▼ ▼ +┌─────┐ ┌─────┐ ┌────────┐ ┌────────┐ ┌────────┐ +│Chat │ │Tools│ │Triage │ │Deep │ │Vision │ +│ │ │ │ │ │ │Research│ │ │ +│ LLM │ │Local│ │Detect +│ │RAG + │ │Image │ +│ only│ │calc │ │LLM │ │Sources │ │Analysis│ +└─────┘ └─────┘ └────────┘ └────────┘ └────────┘ +``` + +### Routing + +El `IntentAnalyzer` clasifica cada consulta del usuario y el `Controller` la +enruta al subsistema apropiado: + +| Intent | Subsistema | Modelo | Latencia | +|--------|-----------|--------|----------| +| Consulta general | Chat (LLM) | Kimi K2 | ~2-5s | +| Interacción medicamentosa | Tools (local) | Ninguno | <100ms | +| Dosificación | Tools (local) | Ninguno | <100ms | +| Valores de laboratorio | Tools (local) | Ninguno | <100ms | +| Emergencia detectada | Triage | Detection + LLM | ~1-3s | +| Investigación profunda | Deep Research | RAG + LLM | ~30-120s | +| Imagen médica | Vision | LLM multimodal | ~5-15s | + +### Principios de Diseño + +1. **Herramientas locales sin LLM**: Las calculadoras de dosificación, interacciones + medicamentosas e interpretación de laboratorio operan con lógica determinista + (base de conocimiento local de 1061 condiciones). No requieren llamada a LLM, + lo que garantiza respuestas instantáneas y reproducibles. + +2. **Detección de emergencia como guardia**: Antes de cualquier routing, el + `EmergencyDetector` evalúa la consulta. Si detecta una emergencia, el triage + se activa inmediatamente, bypasseando el routing normal. + +3. **Memoria contextual por sesión**: El `MemoryService` mantiene una ventana de + contexto por sesión del usuario, permitiendo consultas de seguimiento sin + repetir información clínica. + +4. **Multi-modelo**: El `LLMRouter` puede dirigir consultas a diferentes modelos + según el tipo de tarea (razonamiento complejo vs. respuesta rápida). + +## Consecuencias + +### Positivas + +- Latencia optimizada por tipo de consulta +- Las herramientas locales funcionan offline (sin dependencia de API externa) +- La detección de emergencia es determinista y no depende de un LLM +- Los módulos son independientemente testables +- Nuevas herramientas se agregan sin modificar el controller + +### Negativas + +- Complejidad de routing: errores en clasificación de intent llevan a respuestas + incorrectas +- El `IntentAnalyzer` mismo puede requerir un LLM, añadiendo latencia +- Mantener coherencia entre módulos (misma terminología, mismo nivel de detalle) + requiere disciplina + +### Trade-offs Aceptados + +- **Controller centralizado vs. orquestador distribuido**: Se eligió un controller + centralizado por simplicidad. Si la cantidad de agentes crece >10, se + reconsiderará un orquestador basado en grafos (LangGraph, AutoGen). + +- **Herramientas deterministas vs. LLM-powered**: Las herramientas médicas usan + lógica determinista para garantizar reproducibilidad y auditabilidad. El trade-off + es que no pueden manejar casos ambiguos o fuera de su base de conocimiento. + +## Implementación + +### Estructura de Archivos + +``` +src/medex/ +├── agent/ +│ ├── controller.py # Controlador principal, orquesta el flujo +│ ├── planner.py # Planificación de acciones +│ └── intent_analysis.py # Clasificación de intents del usuario +├── detection/ +│ └── emergency.py # Detección de emergencia (determinista) +├── tools/ +│ ├── drug_interactions.py # Interacciones medicamentosas +│ ├── dosage_calculator.py # Calculadora de dosificación +│ ├── lab_interpreter.py # Interpretación de laboratorio +│ └── triage.py # Motor de triage +├── llm/ +│ ├── router.py # Routing multi-modelo +│ ├── parser.py # Parsing de respuestas LLM +│ └── streaming.py # Streaming de tokens +├── rag/ +│ ├── chunker.py # Chunking de documentos +│ ├── embedder.py # Generación de embeddings +│ └── reranker.py # Re-ranking de resultados +└── memory/ + └── memory_service.py # Gestión de contexto conversacional +``` + +### Extensibilidad + +Para agregar una nueva herramienta: + +1. Crear módulo en `src/medex/tools/` +2. Registrar en `IntentAnalyzer` el nuevo intent +3. Agregar routing en `Controller` +4. Agregar panel de UI en `app.py` +5. Agregar estado en `state.py` +6. Escribir tests en `tests/` From 129c837ba2aacb14371a8aeed8989b684544a2c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 13:53:52 -0300 Subject: [PATCH 14/14] fix: replace libgl1-mesa-glx with libgl1 for Debian Trixie --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 2d9d263..d93d633 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,8 +56,9 @@ ENV PYTHONDONTWRITEBYTECODE=1 \ MEDEX_UI_PORT=3000 # Install runtime dependencies only +# Note: libgl1-mesa-glx was renamed to libgl1 in Debian Trixie (python:3.12-slim) RUN apt-get update && apt-get install -y --no-install-recommends \ - libgl1-mesa-glx \ + libgl1 \ libglib2.0-0 \ libsm6 \ libxext6 \