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(),