From 882d578960e1198aa62010cd0b33c4bcd08243de Mon Sep 17 00:00:00 2001 From: Jordan Date: Sat, 20 Jun 2026 16:44:36 +0100 Subject: [PATCH] =?UTF-8?q?Reconexi=C3=B3n:=20persistir=20'executing'=20+?= =?UTF-8?q?=20objetivo=20al=20inicio=20del=20turno?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Para que un reattach (tras recargar el frontend a mitad de turno) detecte que hay un turno en curso, se persiste status=EXECUTING + current_objective ANTES de la ejecución larga (el estado final lo sigue guardando el finally). Además get_session expone el objetivo desde metadata mientras status==executing, ya que current_task aún no está persistido durante el turno. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/api/routes.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/api/routes.py b/src/api/routes.py index 064777e..cae342d 100644 --- a/src/api/routes.py +++ b/src/api/routes.py @@ -414,6 +414,16 @@ async def _execute_and_persist(orchestrator, storage, session, message, attachme "status": "busy", } + # Persistir 'executing' + el objetivo ANTES de la ejecución larga, para que + # un reattach (tras recargar el frontend a mitad de turno) detecte que hay + # un turno en curso. El estado final lo guarda el `finally`. + try: + session.status = SessionStatus.EXECUTING + session.metadata["current_objective"] = message + await storage.update_session(session) + except Exception as e: + logger.warning("No se pudo persistir 'executing' al arrancar: %s", e) + try: result = await orchestrator.process_message(session, message, attachments) return result @@ -578,11 +588,20 @@ async def get_session(session_id: str) -> SessionResponse: "status": plan.get("status", "active"), } + # Durante el turno el current_task aún no está persistido (begin_task corre en + # process_message; solo se guarda en el finally). Para que un reattach sepa el + # objetivo, lo exponemos desde metadata mientras status==executing. + ct = session.current_task.model_dump() if session.current_task else None + if ct is None and session.status == SessionStatus.EXECUTING: + _obj = session.metadata.get("current_objective") + if _obj: + ct = {"objective": _obj} + return SessionResponse( session_id=session.session_id, status=session.status.value, turn_count=session.turn_count, - current_task=session.current_task.model_dump() if session.current_task else None, + current_task=ct, completed_tasks=session.completed_tasks, created_at=session.created_at.isoformat(), updated_at=session.updated_at.isoformat(),