| 43 | |
| 44 | # Global state for tracking running sessions |
| 45 | class SessionManager: |
| 46 | def __init__(self): |
| 47 | self.running_session = None |
| 48 | self.cancelled_sessions = set() # Track cancelled session IDs |
| 49 | self.lock = asyncio.Lock() |
| 50 | |
| 51 | async def start_session(self, session_id: str) -> bool: |
| 52 | """Try to start a new session. Returns False if another session is already running""" |
| 53 | async with self.lock: |
| 54 | if self.running_session is not None: |
| 55 | return False |
| 56 | self.running_session = session_id |
| 57 | # Remove from cancelled set when starting (for regeneration cases) |
| 58 | self.cancelled_sessions.discard(session_id) |
| 59 | return True |
| 60 | |
| 61 | async def end_session(self, session_id: str): |
| 62 | """End a session""" |
| 63 | async with self.lock: |
| 64 | if self.running_session == session_id: |
| 65 | self.running_session = None |
| 66 | # Keep cancelled flag for a bit, clean up later if needed |
| 67 | |
| 68 | async def cancel_session(self, session_id: str) -> bool: |
| 69 | """Cancel a running session. Returns True if session was running""" |
| 70 | async with self.lock: |
| 71 | if self.running_session == session_id: |
| 72 | self.cancelled_sessions.add(session_id) |
| 73 | logger.info(f"Session {session_id[:8]} marked for cancellation") |
| 74 | return True |
| 75 | return False |
| 76 | |
| 77 | def is_cancelled(self, session_id: str) -> bool: |
| 78 | """Check if a session has been cancelled""" |
| 79 | return session_id in self.cancelled_sessions |
| 80 | |
| 81 | def get_running_session(self) -> Optional[str]: |
| 82 | """Get the currently running session ID""" |
| 83 | return self.running_session |
| 84 | |
| 85 | session_manager = SessionManager() |
| 86 | |