fix(subagent): cascade exec session termination on /stop

cancel_by_session() only cancelled asyncio tasks, leaving child
processes from exec sessions orphaned. Since each SubagentManager
now owns a dedicated ExecSessionManager, terminate those sessions
by owner_session_key after cancelling tasks.

Add ExecSessionManager.terminate_by_owner() to kill all sessions
for a given owner, and call it from cancel_by_session().
This commit is contained in:
yorkhellen
2026-07-22 15:28:34 +08:00
committed by chengyongru
parent 254497c02e
commit 7b1d81a868
2 changed files with 14 additions and 0 deletions
+1
View File
@@ -457,6 +457,7 @@ class SubagentManager:
t.cancel()
if tasks:
await asyncio.gather(*tasks, return_exceptions=True)
await self._exec_session_manager.terminate_by_owner(session_key)
return len(tasks)
async def close(self) -> None:
+13
View File
@@ -334,6 +334,19 @@ class ExecSessionManager:
)
return len(sessions)
async def terminate_by_owner(self, owner_session_key: str) -> int:
"""Terminate all sessions owned by owner_session_key. Returns count."""
async with self._lock:
victims = []
for sid, s in list(self._sessions.items()):
if s.owner_session_key == owner_session_key:
victims.append(self._sessions.pop(sid))
await asyncio.gather(
*(s.kill() for s in victims),
return_exceptions=True,
)
return len(victims)
async def _cleanup_locked(self) -> None:
now = time.monotonic()
stale = [