Transition through STOPPING → STOPPED, killing the subprocess.
(self, session_id: str)
| 138 | info.last_active_at = time.time() |
| 139 | |
| 140 | async def stop_session(self, session_id: str) -> None: |
| 141 | """Transition through STOPPING → STOPPED, killing the subprocess.""" |
| 142 | info = self._sessions.get(session_id) |
| 143 | if info is None: |
| 144 | return |
| 145 | info.status = SessionState.STOPPING |
| 146 | proc = info.process |
| 147 | if proc is not None and proc.returncode is None: |
| 148 | try: |
| 149 | proc.terminate() |
| 150 | # Give the agent a chance to flush; SIGKILL after 5s. |
| 151 | try: |
| 152 | await asyncio.wait_for(proc.wait(), timeout=5.0) |
| 153 | except asyncio.TimeoutError: |
| 154 | proc.kill() |
| 155 | await proc.wait() |
| 156 | except (ProcessLookupError, OSError): |
| 157 | pass |
| 158 | info.status = SessionState.STOPPED |
| 159 | info.process = None |
| 160 | remove_entry(session_id, path=self.index_path) |
| 161 | self._sessions.pop(session_id, None) |
| 162 | |
| 163 | # ─── Read-side helpers ──────────────────────────────────────────── |
| 164 |