From f3101be1a10af0aaa0b57c4b7ecce839d95fb412 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Wed, 6 May 2026 15:51:24 -0700 Subject: [PATCH] fix(internal_endpoints): drive session busy<->ready oscillation from daemon callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two call sites added: * After _claim_next_queued_run flips a queued run to running, call refresh_session_status_from_runs so a session that was 'ready' transitions to 'busy'. Idempotent for already-busy sessions. * After daemon_append_event finalizes a terminal event (run_finished / run_cancelled / run_error), call refresh_session_status_from_runs so a session with no remaining active runs transitions back to 'ready'. Without these hooks, session.status stayed permanently 'busy' after the first run started — clients polling GET /v2/sessions/{id} always saw 'busy' regardless of run state. Greptile P1 (review #PRR_kwDOKALCgc78u9En). --- .../agent_session_endpoints/internal_endpoints.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/litellm/proxy/agent_session_endpoints/internal_endpoints.py b/litellm/proxy/agent_session_endpoints/internal_endpoints.py index 55e7fbed20a..69585295bf8 100644 --- a/litellm/proxy/agent_session_endpoints/internal_endpoints.py +++ b/litellm/proxy/agent_session_endpoints/internal_endpoints.py @@ -33,6 +33,9 @@ from litellm.proxy.agent_session_endpoints.constants import ( SESSION_STATUS_PROVISIONING, SESSION_STATUS_READY, ) +from litellm.proxy.agent_session_endpoints.session_status import ( + refresh_session_status_from_runs, +) from litellm.proxy.agent_session_endpoints.schemas import ( DaemonHeartbeatRequest, DaemonRegisterRequest, @@ -185,6 +188,11 @@ async def daemon_next_run( while True: claimed = await _claim_next_queued_run(prisma_client, session_id) if claimed is not None: + # Run just transitioned queued -> running; if the session is + # still ``ready``, flip it to ``busy``. Idempotent — if the + # session is already ``busy`` (e.g. concurrent runs), this + # is a no-op via ``derive_session_status_from_runs``. + await refresh_session_status_from_runs(prisma_client, session_id) return NextRunResponse( run_id=claimed.id, prompt=claimed.prompt or {}, @@ -282,6 +290,10 @@ async def daemon_append_event( ), }, ) + # Drive the session ``busy`` -> ``ready`` flip. Without this, + # the parent session stays permanently ``busy`` after the first + # run terminates — Greptile P1. + await refresh_session_status_from_runs(prisma_client, session_id) return { "run_id": run_id,