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).
This commit is contained in:
Ishaan Jaffer 2026-05-06 16:01:16 -07:00
parent 7a23f04849
commit 164afd4a18
No known key found for this signature in database

View file

@ -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)