Compactación de contexto
La compactación reemplaza los mensajes antiguos por un checkpoint estructurado generado por el proveedor actual y conserva intactos los turnos recientes. Los mensajes reemplazados permanecen en la base de datos de sesiones marcados como compactados (para auditoría), pero ya no se envían al modelo.
Secciones del checkpoint
Al resumidor se le pide JSON validado con zod. El checkpoint tiene estas secciones:
| Sección | Campo | Contenido |
|---|---|---|
| Goal | goal | Lo que la sesión intenta lograr |
| User instructions/constraints | instructions | Instrucciones y restricciones indicadas por el usuario |
| Discoveries | discoveries | Hechos aprendidos en el camino |
| Accomplished | accomplished | Trabajo ya realizado |
| Current state | currentState | Situación actual |
| Next steps | nextSteps | Lo que queda pendiente |
| Relevant files | relevantFiles | Archivos relevantes |
Si el resumidor no devuelve JSON válido, su texto se usa tal cual (un checkpoint solo de texto).
Garantías
- Una llamada a herramienta nunca se separa de sus resultados, y los IDs de llamada nunca se alteran.
- Se conservan
keepTurnsturnos recientes; si hay menos, se conserva al menos el último. Dentro de un único turno largo, el corte se hace en el último límite seguro entre llamadas. - Una sesión con resultados de herramientas inciertos no se compacta hasta recuperarla.
- La persistencia es transaccional.
Manual y automática
- Manual:
/compact [focus]en la TUI, con instrucciones de foco opcionales. - Automática: antes de una llamada al modelo, cuando el contexto usado alcanza
thresholdde una ventana de contexto conocida (provider.contextWindow, elvalues.contextWindowdel perfil activo de/connect, oGET /models). Cuando la ventana es desconocida — o una ventana declarada es absurdamente grande (más de2_000_000tokens, para queventana × thresholdno oculte la presión real) — Alisio recurre alimits.maxContextChars: los tokens estimados (≈ caracteres / 4) que alcanzanmaxContextChars / 4también compactan. Independientemente de eso, el presupuesto de caracteres es también un disparador para todos los modelos: cuando la conversación (instrucciones + transcript) alcanzathreshold(85 %) delimits.maxContextChars, Alisio compacta, aunque una ventana grande (por ejemplo 1M de tokens) indique que sobra espacio. La regla de la ventana y la de caracteres son alternativas: cualquiera de las dos dispara la compactación. Los criterios de ventana y de reserva miden la petición completa (instrucciones, transcript y el catálogo fijo de herramientas), porque protegen lo que el modelo ve realmente.maxContextCharsademás sigue siendo el límite duro posterior a la compactación — pero allí cuenta solo el contenido reducible (instrucciones + transcript), nunca el catálogo de herramientas (ver más abajo). Si comprimir no logra dejar la conversación por debajo, la cola conservada se reduce (ver más abajo) y solo una sesión irreducible falla con un error accionable en vez de enviar una petición descomunal.auto: falsedesactiva la compactación automática por completo. - Último recurso: si la conversación sigue por encima de
maxContextCharstras el recorte descrito abajo, Alisio ejecuta una compactación automática (motivo"budget") y recorta de nuevo antes de fallar. Se intenta como máximo una vez por turno.
El respaldo por defecto es de 800000 caracteres (≈ 200000 tokens): una suposición para ventanas desconocidas, el mismo presupuesto de ~200k tokens que OpenCode asume para proveedores personalizados, para que los servidores locales que no informan su ventana (por ejemplo llama.cpp) obtengan un presupuesto de unos 200k tokens en lugar de uno de 40k. Una ventana conocida (hasta el límite de confianza de 2M de tokens) siempre la anula, y /settings → Presupuesto de caracteres de contexto permite bajar el respaldo en cualquier momento.
Configuración
{
"compaction": { "auto": true, "threshold": 0.85, "keepTurns": 2, "maxOutputTokens": 16000 }
}| Campo | Por defecto | Descripción |
|---|---|---|
auto | true | Compactación automática |
threshold | 0.85 | Fracción de una ventana de contexto conocida (0.1–0.99) |
keepTurns | 2 | Turnos recientes conservados sin cambios (0–20) |
maxOutputTokens | 16000 | Presupuesto de tokens de salida para la llamada del resumidor; independiente de limits.maxOutputTokens |
La ventana de contexto proviene de provider.contextWindow, del values.contextWindow del perfil activo de /connect, o de GET /models. El consumo de tokens de la compactación no se descuenta de limits.maxTokens, y las estimaciones antes/después son aproximadas (unos 4 caracteres por token).
Resúmenes truncados
El resumidor tiene su propio presupuesto de salida (compaction.maxOutputTokens, por defecto 16000 — mayor que el limits.maxOutputTokens del bucle del agente a propósito, porque un resumen debe caber en todo el historial). Si el presupuesto corta un resumen:
- Un resumen parcial aprovechable (JSON de checkpoint estructurado o texto plano) se conserva: la compactación termina y
compaction_completedincluye"partial": true. El aviso de la TUI marca el checkpoint como parcial y sugiere aumentarcompaction.maxOutputTokens. - Si el corte no produjo nada aprovechable, la compactación falla con un mensaje accionable que apunta a
compaction.maxOutputTokens.
Un checkpoint parcial conserva todo lo que el modelo produjo antes del corte, pero puede omitir contexto posterior; trátelo como un respaldo degradado, no como un resumen completo.
Reducción de una cola conservada descomunal
La compactación conserva keepTurns turnos recientes sin cambios. Si esos turnos contienen salidas enormes de herramientas (por ejemplo grep sobre un repositorio grande), ni siquiera un checkpoint perfecto logra dejar el contenido reducible de la sesión por debajo de limits.maxContextChars, y la sesión solía morir en cada prompt. En su lugar, tras una compactación el runner ahora comprueba el límite duro y, si sigue superado, reduce los mensajes conservados en su sitio antes de enviar nada:
- La reducción apunta a un presupuesto total de caracteres para el transcript:
objetivo = max(4 000, limits.maxContextChars − instrucciones), de modo que también cubre sesiones con muchos resultados MEDIOS de herramientas (por ejemplo salidas MCP de unos pocos miles de caracteres cada una) que individualmente quedan bajo los límites por mensaje pero juntos superan el límite. - El contenido se recorta de forma iterativa, primero el más grande, en rondas de límites descendentes: resultados de herramientas a 8 000 → 4 096 → 2 048 → 1 024 → 512 caracteres, textos de usuario/asistente a 16 000 → 8 192 → 4 096 → 2 048 → 1 024. Cada ronda corta primero los mensajes más caros (empates por posición), de modo que el menor número de cambios alcanza el objetivo; el recorrido se detiene en cuanto el transcript cabe, o al llegar a los límites mínimos.
- Cada corte lleva el marcador explícito
… [truncated by context budget]. Solo cambia el contenido de los mensajes: roles, IDs de llamada, orden y fronteras de mensajes quedan idénticos, de modo que el transcript sigue siendo válido y reproducible y una llamada a herramienta nunca se separa de sus resultados. El transcript reducido se persiste (los originales permanecen en la base marcados como compactados, igual que en la propia compactación). - El evento
context_reducedinforma cuántos mensajes se cortaron. - Solo una sesión patológica — las
instruccionespor sí solas (más el mínimo de 4 000 caracteres) que ya superan el límite, de modo que ni siquiera el suelo de la reducción cabe — falla con un error accionable que nombra el tamaño aproximado de la conversación y sugiere/compact, recortar salidas grandes de herramientas, iniciar una sesión nueva o desactivar con/pluginslos servidores MCP innecesarios. El mensaje dice qué hizo la compactación:Context budget exceeded (approximately N characters of conversation; limit L). Automatic compaction ran but could not reduce it enough.(owas skipped because there is no safe boundary to summarize,failed (<error>)ois disabled). Un único turno enorme sin frontera segura todavía puede fallar, ahora con ese mensaje exacto. La reducción igualmente se persiste, así que la sesión sigue funcionando para prompts posteriores.
Los checkpoints (summary: true) están acotados por diseño y este paso nunca los corta.
El catálogo de herramientas no se cuenta
El límite duro anterior mide deliberadamente solo el contenido reducible — instrucciones más el transcript. El catálogo serializado de herramientas (toolsText: nombre, esquema y descripción de cada herramienta registrada) es una realidad de despliegue fija: forma parte de cada petición sin importar la historia, de modo que un servidor con decenas de herramientas (por ejemplo un catálogo MCP grande) puede valer por sí solo 100k+ caracteres, y un transcript pequeño ya no cabe bajo el límite una vez que se cuenta el catálogo. Antes de esta distinción, esas sesiones fallaban con el error fatal «Context budget exceeded» incluso con un transcript casi vacío — la falla reportada en subagentes y exploraciones en repositorios con varios servidores MCP.
- El tamaño del catálogo es una decisión de
/plugins, no crecimiento de sesión: desactive allí los servidores MCP innecesarios (/mcpsmuestra el recuento de herramientas de cada servidor), en lugar de que el runner corrompa un transcript sano para «caber» un catálogo que no puede reducir. - La compactación automática sigue midiendo la petición completa (los umbrales de ventana protegen todo lo que el modelo ve, herramientas incluidas); solo el límite duro posterior a la compactación y la reducción del transcript excluyen el catálogo, de modo que el error fatal nunca se dispara por
toolsTextsolo.
Eventos
| Evento | Cuándo |
|---|---|
compaction_started | Comienza la compactación |
compaction_completed | Terminó; incluye estimaciones before/after, el tamaño del tramo resumido y del checkpoint, informes de plugins y partial: true cuando el resumen se cortó pero se conservó |
compaction_skipped | No hay historia suficiente para compactar |
context_reduced | Tras la compactación los mensajes conservados seguían superando maxContextChars y se recortaron hasta un objetivo total de caracteres (messages = cuántos) |
compaction_failed | Falló la llamada al resumidor (incluido un resumen cortado sin nada aprovechable) |
plugin_hook_failed | Un hook de plugin falló o agotó su tiempo; la compactación continúa sin él |
Con --json los eventos se emiten como JSONL versionado.
Modo Responses
En modo Responses, los items opacos de continuación (por ejemplo, el razonamiento cifrado) del tramo resumido se descartan junto con esos mensajes. Los mensajes conservados mantienen los suyos sin cambios.
Hooks de plugins
Los plugins pueden ampliar la compactación con compaction.register({ beforeCompact, afterCompact }):
beforeCompactañade instrucciones y campos JSON adicionales (outputFields) a la misma llamada al resumidor.afterCompactrecibe el checkpoint y los campos extraídos propios del plugin, y puede devolverinjectContext(texto añadido tras el checkpoint) y unreport(susummaryse muestra en la TUI).
Los hooks se ejecutan con el tiempo límite del host pluginHooks.timeoutMs. El plugin de memoria integrado usa estos hooks. Consulte Escribir plugins.
Resultados inciertos de herramientas
Si una caída deja una herramienta con un resultado incierto, Alisio no la repite automáticamente. Inspeccione sus efectos y después ejecute:
alisio sessions recover <session> --acknowledgeLa recuperación registra la incertidumbre como resultado; no asegura que un efecto externo se haya completado ni deshace cambios.
