Sintoma: "el agente se para cuando hace acciones". MCPClient._read_loop lee las
respuestas JSON-RPC con stdout.readline(), cuyo StreamReader tenia buffer de 1MB.
Una respuesta llega en UNA linea; playwright__browser_take_screenshot({fullPage:
true}) devuelve la imagen en base64 en esa linea y supera el limite →
asyncio.LimitOverrunError → el except Exception mataba el read loop y dejaba la
sesion MCP inservible (los turnos siguientes ejecutaban 0 tools).
Fix en dos capas:
- MCP_STREAM_LIMIT=64MB en create_subprocess_exec(limit=...) — cubre cualquier
screenshot real.
- Read loop tolerante: captura (ValueError, LimitOverrunError), descarta solo esa
respuesta re-sincronizando el stream hasta el \n (_drain_until_newline) y sigue
vivo, en vez de matar toda la sesion MCP.
Validado: navegar + screenshot fullPage + glob ejecuta las 4 tools sin "read loop
error" y sin colapsar el contexto.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dos bugs encadenados impedían que el agente ejecutara tools (emitía los tool
calls como texto sin ejecutarlos, y degradaba el contexto):
1. Conector: el OpenAIAdapter pasaba los mensajes en formato Anthropic (bloques
tool_use/tool_result) que la API OpenAI de DeepSeek rechaza, y defaulteaba el
modelo a "gpt-4o". Añade `_to_openai_messages()` (assistant.tool_use →
tool_calls; user.tool_result → role:tool con tool_call_id) y `_blocks_text()`,
y usa `settings.default_model_id`. Con esto DeepSeek devuelve tool_calls
nativos vía https://api.deepseek.com (endpoint OpenAI), sin parsear texto y
sin la degradación que sufría el endpoint Anthropic-compat.
2. followup_mode: `_classify_followup_mode` marcaba como "transform" cualquier
PRIMER mensaje que contuviera un marker ("resumen", "estructura", "busca",
"adapta"…), y `_get_allowed_tools` devuelve [] en modo transform → el agente
se quedaba SIN tools. Un follow-up no tiene sentido sin turno anterior, así
que ahora solo se clasifica si hay task_history/recent_messages.
claude_adapter: parser DSML/DeepSeek para tool calls como texto (fallback del
endpoint Anthropic-compat, ya no es la vía principal).
Validado: el prompt de análisis de estilos ("Guarda un resumen…") ahora explora
los módulos y escribe docs/project-styles.md vía save_project_styles.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Las sesiones MCP no se limpiaban (registry._sessions crecía sin límite); cada
una arranca 3 subprocesos stdio (acai-code, playwright+chromium, fetch) con sus
read-loops. Con varias vivas a la vez, las sesiones nuevas recibían cada vez
menos contexto/tools al modelo, hasta que el modelo dejaba de recibir tools y
emitía los tool calls como texto sin ejecutarlos (~300 input_tokens). Esto
degradaba el chat a lo largo del día hasta reiniciar el container.
Fix: MAX_ACTIVE_MCP_SESSIONS=2 con evicción LRU (touch last_used en
create/get_for_session, _evict_lru destruye las menos usadas). Seguro porque
send_message reconecta el MCP de una sesión evictada si vuelve a usarse.
Validado: 1 sesión viva era estable, 6 colapsaban; con cap=2, 7 sesiones
secuenciales se mantienen estables (40-115K tokens, tools OK).
Mitigación, no cura de fondo: el motivo por el que N managers vivos degradan
(probable: chromium de playwright) queda pendiente para subir el umbral.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Antes, al parar el agente y mandar un mensaje nuevo, la ejecución previa
seguía viva reteniendo el session_lock: el mensaje nuevo recibía "busy" y el
stream mostraba la ejecución anterior. La tarea detached (create_task) no se
guardaba en ningún sitio y era imposible cancelarla.
- _running_executions: registro de la tarea asyncio por session_id.
- _cancel_running_execution(): cancela y espera a que libere el lock.
- send_message: preempt — un mensaje nuevo cancela la ejecución previa.
- _execute_and_persist: maneja CancelledError dejando la sesión en ACTIVE.
- POST /sessions/{id}/abort: cancela, cierra el stream SSE y limpia el lock.
- RedisStorage.clear_session_lock(): libera locks huérfanos.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
El MCP server creaba archivos con UID 1000 que el server Python
(UID 1001) no podía modificar ni borrar. Ahora ambos containers
usan UID 1001, eliminando conflictos de permisos en volúmenes compartidos.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Nueva variable AGENTIC_OPENAI_BASE_URL para proveedores compatibles
con OpenAI API (MiniMax, DeepInfra, Together, etc.).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
El modelo repetía tareas anteriores porque el historial se
reconstruía como mensajes user/assistant que parecían peticiones
nuevas. Ahora el historial va como un bloque de contexto marcado
explícitamente con [HISTORIAL — NO ejecutar de nuevo].
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- role=tool → role=user con tool_result blocks
- assistant con tool_calls → assistant con tool_use blocks
- Merge mensajes consecutivos del mismo role (Claude requiere alternancia)
- Capturar input_tokens del evento message_start
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
El endpoint /context-debug ahora devuelve full_context con el
system_prompt y messages exactos enviados al modelo.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extraída lógica de carga a _load_knowledge_from_dir() reutilizable.
Se llama automáticamente en el lifespan después de set_dependencies().
Si falla, solo loguea warning — no bloquea el arranque.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
El sistema multi-agente (planner → coder → reviewer) añadía
complejidad y causaba problemas (sobreplanificaci��n, repetición
de tareas, pérdida de contexto entre steps).
Ahora: mensaje → coder → respuesta. Como Claude Code.
- El coder decide si responder directamente o usar tools
- Sin plan intermedio, sin reviewer, sin steps
- Un solo execute() con conversación real completa
- Historial compactado con key_data al finalizar
- System prompt actualizado: asistente de desarrollo, no agente
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GPT-5.4 ignora las convenciones del knowledge base (42K tokens).
Las reglas más críticas se duplican en el system prompt del coder:
- script.js y style.css son ESTÁTICOS (sin Twig)
- Valores dinámicos via data-* attributes
- CmsApi.hook() en vez de fetch
- querySelectorAll con clase raíz en vez de getElementById
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
El planner generaba 3+ steps para tareas simples causando que el
coder repitiera acciones en cada step (creaba el módulo varias veces).
Ahora el engine fusiona los steps en 1 coder con descripción combinada.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>