Que las conversaciones largas no se rompan ni gasten de más:
Ventana de contexto por modelo (antes: budget estático 120k/200k para todos):
- cost.resolve_context_window: lee context_length del catálogo OpenRouter/DeepSeek
en Redis, con fallback a litellm. config.budget_for_window deriva el budget de
la ventana real (window - max_output - reserve). build_context lo aplica por
turno (param model_id) en vez del fijo de settings.
- Self-heal del catálogo OpenRouter: el admin panel lo cachea con TTL 1h y solo lo
repuebla al abrir su ventana de IA → en runtime caducaba y se perdían ventana y
precio. Ahora cost._get_catalog lo refresca solo (fetch público, mismo shape,
cooldown 5min, TTL 24h). Arregla también el coste (caía al fijo).
Recuperación ante overflow:
- adapters.base.ContextOverflowError; openai_adapter traduce el error de
context-length del proveedor (init e iteración del stream).
- base.py: retry proactivo que recompacta hasta caber en la ventana ANTES de
llamar al LLM; si ni así cabe → error accionable (no rompe la sesión).
- engine.py: mensaje user-facing claro (modelo + ventana).
Tests: ventana/budget, self-heal (mockeado), overflow, y sesión REAL de Redis. 106 verdes.
evals/: harness para evaluar al agente acai-code (driver + README + resultados).
Comparativa kimi vs deepseek vs glm (deepseek-v4-pro high = mejor calidad/precio).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Las sesiones largas con DeepSeek quedaban bloqueadas permanentemente con
400 "Messages with role 'tool' must be a response to a preceding message
with 'tool_calls'": el paso de ultimo recurso del compactor colapsaba
assistants con tool_use a un string placeholder dejando huerfanos los
tool_result del user siguiente.
- compactor: paso de ultimo recurso pair-aware + _enforce_tool_pairing
como invariante final (matching por IDs, ambas direcciones, repara
tambien historiales ya corruptos persistidos).
- openai_adapter: _repair_tool_sequence como guard defensivo del contrato
del proveedor (tool huerfano -> user; tool_call sin respuesta -> fuera),
con warning para detectar regresiones.
- recent_messages: trim por presupuesto de tokens al persistir
(AGENTIC_RECENT_MESSAGES_MAX_TOKENS, default 60k) sin cortar pares;
cierra el crecimiento sin limite que empujaba al paso destructivo.
- tests/test_tool_pairing_real.py: 23 tests que importan el codigo REAL
(a diferencia de los tests standalone existentes). Suite completa: 92 ok.
Verificado offline contra los recent_messages reales de la sesion
bloqueada en prod: 0 violaciones con presupuesto normal y agresivo.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>