diff --git a/README.md b/README.md index cc9355a..6a5510e 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ Client → API (FastAPI) → Orchestrator → Subagents (planner/coder/collector **Principios:** - **Context over chat history** — el modelo recibe estado estructurado, nunca raw tool outputs -- **Knowledge filtering** — solo los docs relevantes al task entran en contexto (keyword scoring) -- **Compaction** — extracción de facts, eliminación de redundancia, prioridades por sección +- **Semantic search** — embeddings (OpenAI text-embedding-3-small) para seleccionar los docs más relevantes por similitud semántica +- **Task history compaction** — al completar una tarea, se comprime a ~50 tokens; en sesiones largas el agente recuerda todo sin desbordar el contexto - **Artifact summarization** — outputs de tools resumidos antes de entrar al contexto - **Error recovery** — steps fallidos se saltan, timeout global, sesión nunca se queda en executing - **Concurrency lock** — Redis SETNX impide ejecución simultánea en la misma sesión @@ -62,12 +62,15 @@ python3 -m uvicorn src.main:app --reload --port 8001 ### Cargar Knowledge Base ```bash -# Cargar docs desde el directorio docs/ +# Cargar docs + generar embeddings para semantic search curl -X POST http://localhost:8001/api/v1/knowledge/load \ -H "Content-Type: application/json" \ -d '{"docs_path": "docs"}' +# → {"status": "loaded", "count": 13, "embeddings": true, ...} ``` +Los embeddings se generan en batch via OpenAI `text-embedding-3-small` (~$0.001 por los 13 docs) y se almacenan en Redis. Solo se recalculan al hacer `/knowledge/load` de nuevo. + ## Dashboard Interfaz web para testing integrada en el microservicio. Se accede en `/dashboard/`. @@ -176,7 +179,7 @@ curl http://localhost:8001/api/v1/knowledge curl -X DELETE http://localhost:8001/api/v1/knowledge/{doc_id} ``` -Los docs se cargan como `*.md` del directorio. Se sobreescriben si ya existen. No requiere reinicio — la siguiente conversación usa los docs actualizados. +Los docs se cargan como `*.md` del directorio. Se sobreescriben si ya existen. No requiere reinicio — la siguiente conversación usa los docs actualizados. Al cargar se generan embeddings automáticamente para semantic search. ### Debug @@ -199,17 +202,33 @@ El componente más crítico del sistema. Ensambla el prompt que recibe el modelo |---------|-----------|-----------| | `immutable_rules` | 100 | System prompt del agente + reglas de sesión. Nunca se recorta | | `project_profile` | 80 | Perfil del proyecto (nombre, tech stack) | -| `knowledge_base` | 60 | Docs relevantes filtrados por keywords del task | +| `knowledge_base` | 60 | Docs relevantes por semantic search + índice de títulos de todos | +| `task_history` | 55 | Resúmenes compactos de tareas anteriores (~50 tokens c/u) | | `task_state` | 70 | Objetivo, plan, step actual, facts, constraints | -| `artifact_memory` | 50 | Resúmenes de outputs de herramientas | +| `artifact_memory` | 50 | Resúmenes de outputs de herramientas (solo tarea actual) | | `working_context` | 30 | Items de trabajo recientes entre steps | -**Knowledge filtering:** no carga todos los docs. Extrae keywords del objetivo y step actual, puntúa cada doc (título ×10, tags ×5, contenido ×1), y selecciona los más relevantes dentro de un budget de 15k tokens. Los docs que no caben entran como summary de una línea. +**Semantic search:** genera embedding del objetivo/step del usuario y busca por cosine similarity contra los embeddings de todos los docs. Los más relevantes entran completos (budget 15k tokens), el resto aparece como título + summary para que el agente sepa que existen y pueda pedir rehidratación. + +**Task history compaction:** al completar cada tarea, sus artifacts, facts y resultados se comprimen en un bloque de ~50 tokens que se guarda en `task_history`. Los artifacts viejos se borran de Redis. En una sesión de 20 tareas, el historial ocupa ~1000 tokens vs los miles que ocuparían los artifacts completos. El agente nunca pierde contexto de lo que hizo antes. **Token counting:** usa `tiktoken` (encoding `cl100k_base`) para conteo real. Fallback a estimación si tiktoken no está instalado. **Compaction:** si el total excede el context window (120k tokens default), las secciones de menor prioridad se comprimen o eliminan. `immutable_rules` nunca se toca. +**Presupuesto típico tras 20 tareas:** +``` +immutable_rules: ~250 tokens (fijo) +project_profile: ~15 tokens (fijo) +knowledge_base: ~15,000 tokens (semantic search) +task_history: ~1,000 tokens (20 tareas × ~50 tokens) +task_state: ~400 tokens (tarea actual) +artifact_memory: ~500 tokens (solo tarea actual) +working_context: ~500 tokens (solo step actual) +───────────────────────────────────── +TOTAL: ~17,700 tokens / 120,000 disponibles +``` + ## Orchestrator Pipeline ``` @@ -239,7 +258,7 @@ Docker (microservicio — uno solo corriendo) POST /sessions { mcp_env: { ACAI_WEB_URL: "https://tienda.com", ... } } → Arranca subprocesos MCP con esas env vars → Session aislada con su propio MCPManager - → 33 tools descubiertas automáticamente + → 55 tools descubiertas (acai-code: 33, playwright: 21, fetch: 1) DELETE /sessions/{id} → Mata los subprocesos MCP de esa sesión @@ -258,6 +277,18 @@ DELETE /sessions/{id} "env": {}, "timeout": 30, "startup_timeout": 10 + }, + "playwright": { + "command": "npx", + "args": ["@playwright/mcp", "--headless"], + "timeout": 30, + "startup_timeout": 15 + }, + "fetch": { + "command": "uvx", + "args": ["mcp-server-fetch"], + "timeout": 30, + "startup_timeout": 15 } } } @@ -294,7 +325,7 @@ AGENTIC_MCP_SERVER_ARGS=["mcp-server/stdio.js"] ### Tool namespacing -En modo multi-server, los tools se namespean: `acai-code.compile_module`, `filesystem.read_file`. En modo single-server los tools mantienen su nombre original. +En modo multi-server, los tools se namespean con `__` (compatible con OpenAI que no acepta puntos): `acai_code__compile_module`, `playwright__browser_navigate`. En modo single-server los tools mantienen su nombre original. ### API de gestión MCP @@ -343,15 +374,16 @@ Variables de entorno con prefijo `AGENTIC_`: ## Redis Key Structure ``` -agentic:session:{id} → SessionState JSON (TTL 24h) -agentic:session:{id}:artifacts → Hash de ArtifactSummary -agentic:session:{id}:events → Lista de SSE events (cap 500) -agentic:session:{id}:lock → Execution lock (SETNX, TTL 5min) -agentic:sessions:index → Set de session IDs activos -agentic:memory:knowledge:{doc_id} → MemoryDocument JSON -agentic:memory:knowledge:_index → Set de doc IDs -agentic:memory:_tag:{tag} → Set de doc IDs por tag -agentic:memory:_type:{type} → Set de doc IDs por tipo +agentic:session:{id} → SessionState JSON (TTL 24h) +agentic:session:{id}:artifacts → Hash de ArtifactSummary +agentic:session:{id}:events → Lista de SSE events (cap 500) +agentic:session:{id}:lock → Execution lock (SETNX, TTL 5min) +agentic:sessions:index → Set de session IDs activos +agentic:memory:knowledge:{doc_id} → MemoryDocument JSON +agentic:memory:knowledge:_index → Set de doc IDs +agentic:embeddings:knowledge:{doc_id} → Embedding vector (1536 floats JSON) +agentic:memory:_tag:{tag} → Set de doc IDs por tag +agentic:memory:_type:{type} → Set de doc IDs por tipo ``` ## Project Structure @@ -371,7 +403,8 @@ agentic:memory:_type:{type} → Set de doc IDs por tipo │ │ ├── engine.py # Prompt assembly, knowledge filtering, debug │ │ └── compactor.py # Compaction, summarization, tiktoken │ ├── memory/ # Persistent memory -│ │ └── store.py # Redis-backed memory + embeddings +│ │ ├── store.py # Redis-backed memory + similarity search +│ │ └── embeddings.py # OpenAI embedding service │ ├── adapters/ # Model provider adapters │ │ ├── base.py # ModelAdapter interface │ │ ├── claude_adapter.py # Anthropic Claude (streaming)