From 164afd4a18d5a755815b111a5564f3d1e52af952 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Wed, 6 May 2026 16:01:16 -0700 Subject: [PATCH] fix(cleanup): drive session busy->ready after sweeper reaps stuck run _sweep_stuck_runs marks idle-timeout runs as error but never called refresh_session_status_from_runs, leaving the parent session permanently busy. Every other run-terminal path (cancel_run, daemon_append_event, /followup) calls the helper to flip busy -> ready; the sweeper was the only path that skipped it. After flipping each run to error, call refresh_session_status_from_runs inside the loop so a session whose only active run was reaped here transitions back to ready. Greptile P1 (review #PRR_kwDOKALCgc78u_NS, inline comment line 172). --- litellm/proxy/agent_session_endpoints/cleanup.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/litellm/proxy/agent_session_endpoints/cleanup.py b/litellm/proxy/agent_session_endpoints/cleanup.py index 851c83ab6d2..3322670625a 100644 --- a/litellm/proxy/agent_session_endpoints/cleanup.py +++ b/litellm/proxy/agent_session_endpoints/cleanup.py @@ -127,7 +127,16 @@ async def _sweep_stuck_runs(prisma_client) -> int: Sweeper-driven only — clients may legitimately have long-running runs so the threshold is generous (``RUN_IDLE_TIMEOUT_SECONDS``, 30 min by default). + + After flipping each run to ``error``, drive the parent session + ``busy`` -> ``ready`` via :func:`refresh_session_status_from_runs`. + Without this hook, sessions whose only active run was reaped here + would report ``busy`` indefinitely — Greptile P1. """ + from litellm.proxy.agent_session_endpoints.session_status import ( + refresh_session_status_from_runs, + ) + threshold = _now() - timedelta(seconds=RUN_IDLE_TIMEOUT_SECONDS) rows = await prisma_client.db.litellm_agentrun.find_many( where={ @@ -169,6 +178,10 @@ async def _sweep_stuck_runs(prisma_client) -> int: next_seq, exc, ) + # Run just transitioned ``running`` -> ``error`` (terminal). If + # the parent session has no other active runs, flip + # ``busy`` -> ``ready`` so SDK consumers see the right status. + await refresh_session_status_from_runs(prisma_client, run.session_id) return len(rows)