Extended thinking: por qué el historial de un agente no tolera ediciones retroactivas
Un harness de agentes suele tratar el historial de una conversación como una lista de mensajes a la que solo se agrega texto. Con extended thinking eso deja de ser cierto. El historial pasa a incluir bloques opacos (razonamiento, redacted_thinking, resultados de búsqueda cifrados) que el modelo generó y que el cliente no puede reconstruir. Y varias acciones que parecen inofensivas (cambiar de modelo a mitad de turno, editar un prompt anterior, reanudar una sesión tras un corte, compactar el contexto) en realidad reescriben la forma de ese historial. Cuando eso pasa, la API no se adapta con gracia: o descarta el razonamiento en silencio, o rechaza la request entera.
Los changelogs de Claude Code de esta semana muestran ese patrón de punta a punta, con suficientes casos como para sacar una regla general.
El historial se rompe de dos formas distintas
La primera es silenciosa. En Claude Code v2.1.282 se corrigió que el extended thinking se perdiera cuando se usaba /model, /rename, /artifacts u otro comando inmediato mientras Claude seguía trabajando, y que una conversación reanudada o continuada perdiera el razonamiento anterior al relanzarse con una lista de --tools que omite una herramienta nativa ofrecida antes. En ningún caso hay un error visible: el agente simplemente sigue, pero sin la cadena de razonamiento previa, respondiendo peor sin que nada lo indique.
La segunda es dura y se repite. La misma versión corrigió sesiones que fallaban en cada turno con un error de API “Invalid data in redacted_thinking block”, y conversaciones que fallaban con 400 cuando el historial contenía resultados de búsqueda web que la API no podía desencriptar (por ejemplo, de un turno respondido a través de un gateway de terceros). Claude Code v2.1.281, por su parte, arregló sesiones con un resultado de un advisor que la API ya no podía leer: fallaban una request en cada turno y perdían el razonamiento anterior repetidamente, hasta que el historial se reparaba una sola vez.
Reanudar y compactar son las rutas que más mutan el historial
v2.1.281 corrigió sesiones reanudadas o continuadas (--continue, --resume) que reenviaban turnos anteriores en una forma distinta (un turno de tool calls en paralelo, el input de una tool call de MCP, o un resultado de tool-search mientras su servidor seguía reconectando), lo que podía hacer que la API descartara el razonamiento previo de Claude. También arregló que una sesión reanudada después de un reinicio durante un permission prompt pendiente enviara un historial distinto al de antes, rompiendo el prompt cache desde ese punto en adelante. Y v2.1.282 corrigió que la compactación fallara por completo cuando la request de resumen era rechazada, en vez de reintentar en un modelo de respaldo.
El mismo tipo de fragilidad aparece un nivel más abajo, en el SDK. El Agent SDK de Python v0.2.160 corrigió turnos de seguimiento que fallaban con “Stream closed” cuando un subagente en background terminaba justo antes de que llegara el resultado del turno: se cerraba stdin demasiado pronto y el modelo terminaba reportando la tool como rechazada. El SDK de TypeScript v0.3.283 corrigió que getSessionMessages() y forkSession() devolvieran una rama del historial que ya había sido descartada por un rewind, cuando la rama más nueva terminaba en una fila de metadata o de un comando local. Son bugs distintos, pero la pregunta de fondo es la misma: ¿cuál es la forma verdadera y actual del historial, y qué pasa si algo la lee o la reenvía de otra forma?
La regla que se repite en cada fix
Ningún fix de esta lista intenta hacer que la API tolere un historial con forma distinta a la esperada. Todos hacen lo mismo: detectan la forma inválida específica y reparan el historial una vez, en lugar de reenviarlo sin cambios con la esperanza de que funcione, o reintentar indefinidamente contra el mismo payload roto. Eso es lo que hace, por ejemplo, la corrección del error de redacted_thinking: Claude Code ahora descarta los bloques de thinking de la conversación y reintenta una sola vez, en vez de fallar en cada turno subsiguiente.
Reglas para tu propio harness
Si tu harness reenvía extended thinking, resultados cifrados o cualquier bloque opaco generado por el proveedor:
- Trata esos bloques como unidades atómicas. Cualquier operación que reordene, trunque o resuma el historial debe conservarlos enteros o eliminarlos explícitamente, nunca dejarlos a mitad de camino.
- Prueba las rutas de resume, continue y compactación tanto como las sesiones nuevas. Son las que más cambian la forma del historial, y donde aparecen casi todos estos bugs.
- Considera un cambio de modelo o de lista de herramientas a mitad de turno como un cambio estructural del historial, no cosmético: puede invalidar bloques generados bajo la configuración anterior.
- Cuando la API rechace parte del historial, repáralo una vez y sigue. No reintentes el mismo payload inválido turno tras turno esperando un resultado distinto.
Fuentes: https://github.com/anthropics/claude-code/releases/tag/v2.1.281, https://github.com/anthropics/claude-code/releases/tag/v2.1.282, https://github.com/anthropics/claude-agent-sdk-python/releases/tag/v0.2.160, https://github.com/anthropics/claude-agent-sdk-typescript/releases/tag/v0.3.283
Seguir leyendo
Esto se demuestra en video, y se sigue a diario en la comunidad
Las demos completas van al canal. El seguimiento release por release, adentro.