enhance: cleanup env on close session

This commit is contained in:
a7m-1st 2026-01-16 17:00:21 +03:00
parent 89a38f815e
commit 47cf1be181
2 changed files with 70 additions and 0 deletions

View file

@ -270,6 +270,8 @@ class TaskLock:
last_accessed: datetime
background_tasks: set[asyncio.Task]
"""Track all background tasks for cleanup"""
registered_toolkits: list[Any]
"""Track toolkits for cleanup (e.g., TerminalToolkit venvs)"""
# Context management fields
conversation_history: List[Dict[str, Any]]
@ -290,6 +292,7 @@ class TaskLock:
self.created_at = datetime.now()
self.last_accessed = datetime.now()
self.background_tasks = set()
self.registered_toolkits = []
# Initialize context management fields
self.conversation_history = []
@ -339,8 +342,32 @@ class TaskLock:
except asyncio.CancelledError:
pass
self.background_tasks.clear()
# Clean up registered toolkits (e.g., remove TerminalToolkit venvs)
for toolkit in self.registered_toolkits:
try:
if hasattr(toolkit, 'cleanup'):
toolkit.cleanup()
logger.info("Toolkit cleanup completed", extra={"task_id": self.id, "toolkit": type(toolkit).__name__})
except Exception as e:
logger.warning(f"Failed to cleanup toolkit: {e}", extra={"task_id": self.id, "toolkit": type(toolkit).__name__})
self.registered_toolkits.clear()
logger.info("Task lock cleanup completed", extra={"task_id": self.id})
def register_toolkit(self, toolkit: Any) -> None:
"""Register a toolkit for cleanup when task ends.
This is used to track toolkits that create resources (like venvs) that
should be cleaned up when the task is complete.
"""
self.registered_toolkits.append(toolkit)
logger.debug("Toolkit registered for cleanup", extra={
"task_id": self.id,
"toolkit": type(toolkit).__name__,
"total_registered": len(self.registered_toolkits)
})
def add_conversation(self, role: str, content: str | dict):
"""Add a conversation entry to history"""
logger.debug("Adding conversation entry", extra={"task_id": self.id, "role": role, "content_length": len(str(content))})

View file

@ -73,6 +73,16 @@ class TerminalToolkit(BaseTerminalToolkit, AbstractToolkit):
"openpyxl",
],
)
# Auto-register with TaskLock for cleanup when task ends
from app.service.task import get_task_lock_if_exists
task_lock = get_task_lock_if_exists(api_task_id)
if task_lock:
task_lock.register_toolkit(self)
logger.info("TerminalToolkit registered for cleanup", extra={
"api_task_id": api_task_id,
"working_directory": working_directory
})
def _write_to_log(self, log_file: str, content: str) -> None:
r"""Write content to log file with optional ANSI stripping.
@ -175,6 +185,39 @@ class TerminalToolkit(BaseTerminalToolkit, AbstractToolkit):
return result
def cleanup(self, remove_venv: bool = True):
"""Clean up all active sessions and optionally remove the virtual environment.
Args:
remove_venv: If True, removes the .venv or .initial_env folder created
by this toolkit. Defaults to True to prevent disk bloat.
"""
# First call parent cleanup to kill all shell sessions
super().cleanup()
if remove_venv:
import shutil
# Remove cloned env (.venv) if it exists
if self.cloned_env_path and os.path.exists(self.cloned_env_path):
try:
shutil.rmtree(self.cloned_env_path)
logger.info(f"Removed cloned venv: {self.cloned_env_path}", extra={
"api_task_id": self.api_task_id
})
except Exception as e:
logger.warning(f"Failed to remove cloned venv {self.cloned_env_path}: {e}")
# Remove initial env (.initial_env) if it exists
if self.initial_env_path and os.path.exists(self.initial_env_path):
try:
shutil.rmtree(self.initial_env_path)
logger.info(f"Removed initial env: {self.initial_env_path}", extra={
"api_task_id": self.api_task_id
})
except Exception as e:
logger.warning(f"Failed to remove initial env {self.initial_env_path}: {e}")
@classmethod
def shutdown(cls):
if cls._thread_pool: