mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-18 18:44:42 -05:00
The copilot executor runs each worker in its own thread with a dedicated event loop (`asyncio.new_event_loop()`). `aiohttp.ClientSession` is bound to the event loop where it was created — using it from a different loop causes `asyncio.timeout()` to fail with: ``` RuntimeError: Timeout context manager should be used inside a task ``` This was the root cause of transcript upload failures tracked in SECRT-2009 and [Sentry #7272473694](https://significant-gravitas.sentry.io/issues/7272473694/). ### Fix **One `GCSWorkspaceStorage` instance per event loop** instead of a single shared global. - `get_workspace_storage()` now returns a per-loop GCS instance (keyed by `id(asyncio.get_running_loop())`). Local storage remains shared since it has no async I/O. - `shutdown_workspace_storage()` closes the instance for the **current** loop only, so `session.close()` always runs on the loop that created the session. - `CoPilotProcessor.cleanup()` shuts down workspace storage on the worker's own loop, then stops the loop. - Manager cleanup submits `cleanup_worker` to each thread pool worker before shutting down the executor — replacing the old approach of creating a temporary event loop that couldn't close cross-loop sessions. ### Changes | File | Change | |------|--------| | `util/workspace_storage.py` | `GCSWorkspaceStorage` back to simple single-session class; `get_workspace_storage()` returns per-loop GCS instance; `shutdown_workspace_storage()` scoped to current loop | | `copilot/executor/processor.py` | Added `CoPilotProcessor.cleanup()` and `cleanup_worker()` | | `copilot/executor/manager.py` | Calls `cleanup_worker` on each thread pool worker during shutdown | Fixes SECRT-2009 --------- Co-authored-by: Reinier van der Leer <pwuts@agpt.co>