Un turno que se corta no tira lo que ya hizo - #17
Merged
Conversation
Visto en una sala real: un agente fallo tres veces seguidas con "la respuesta del modelo se corto a media escritura". Cada intento releyo el proyecto entero desde cero, y escribir "@agentE continua" no servia: para el, ese turno nunca existio. La causa esta en runAgent: hace una COPIA del historial que recibe, asi que todo el turno crece en un array local. El camino de exito y el de interrupcion lo devuelven; el de error hacia throw y el array se iba con el stack, inalcanzable desde el catch del server. Ahora un callback (onProgreso) espeja el array hacia fuera antes de cada throw y en cada salida normal, asi que quien lo recibe siempre tiene la ultima version sin importar como termino el turno. Y al fallar, el server guarda ese historial y COMMITEA lo que el agente alcanzo a escribir, como un punto mas de la linea de tiempo marcado como cortado. Antes esos archivos quedaban en disco pero sin commitear: el trabajo estaba ahi, invisible para el scrubber y para el historial, y se perdia si alguien regresaba a un punto anterior. Dos cosas que hacen esto seguro: El historial rescatado YA es valido. El throw del loop ocurre ANTES del push del mensaje del assistant, asi que lo que sobrevive son vueltas completas con cada tool_use emparejado con su tool_result. No hay que sanear nada, y un guardado parcial mal hecho rompería el turno SIGUIENTE al mandarlo al proveedor. El turno sigue marcado como fallido. state y commit son campos independientes en Turn, asi que puede quedar failed y llevar su hash: state dice como termino, commit dice donde quedo el trabajo. Por eso failTurnConCommit en vez de reusar commitTurn, que fijaria "committed" y mentiria. De paso, el .gitignore del workspace ignora los *.tmp-* de la escritura atomica: si el proceso muere entre el writeFile y el rename queda uno tirado, y con este cambio entraria al commit. demo:turno-cortado (12/12) lo cubre con un proveedor falso con guion. Sin red ni API key.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Visto en una sala real: un agente fallo tres veces seguidas con "la respuesta del modelo se corto a media escritura". Cada intento releyo el proyecto entero desde cero, y escribir "@agentE continua" no servia: para el, ese turno nunca existio.
La causa esta en runAgent: hace una COPIA del historial que recibe, asi que todo el turno crece en un array local. El camino de exito y el de interrupcion lo devuelven; el de error hacia throw y el array se iba con el stack, inalcanzable desde el catch del server.
Ahora un callback (onProgreso) espeja el array hacia fuera antes de cada throw y en cada salida normal, asi que quien lo recibe siempre tiene la ultima version sin importar como termino el turno.
Y al fallar, el server guarda ese historial y COMMITEA lo que el agente alcanzo a escribir, como un punto mas de la linea de tiempo marcado como cortado. Antes esos archivos quedaban en disco pero sin commitear: el trabajo estaba ahi, invisible para el scrubber y para el historial, y se perdia si alguien regresaba a un punto anterior.
Dos cosas que hacen esto seguro:
El historial rescatado YA es valido. El throw del loop ocurre ANTES del push del mensaje del assistant, asi que lo que sobrevive son vueltas completas con cada tool_use emparejado con su tool_result. No hay que sanear nada, y un guardado parcial mal hecho rompería el turno SIGUIENTE al mandarlo al proveedor.
El turno sigue marcado como fallido. state y commit son campos independientes en Turn, asi que puede quedar failed y llevar su hash: state dice como termino, commit dice donde quedo el trabajo. Por eso failTurnConCommit en vez de reusar commitTurn, que fijaria "committed" y mentiria.
De paso, el .gitignore del workspace ignora los .tmp- de la escritura atomica: si el proceso muere entre el writeFile y el rename queda uno tirado, y con este cambio entraria al commit.
demo:turno-cortado (12/12) lo cubre con un proveedor falso con guion. Sin red ni API key.