fix(agent_endpoints): use status check (not terminated_at) for cascade filter

delete_agent's cascade filter previously used 'terminated_at is None'
to find non-terminal sessions. The fix is safe in practice because
_terminate_session_internal has its own SESSION_TERMINAL_STATUSES guard,
but it's inconsistent with the rest of the module which uses
'status in/notin SESSION_TERMINAL_STATUSES' everywhere else.

Switch to the status-based check to match.

Greptile P3 (review #PRR_kwDOKALCgc78u9En).
This commit is contained in:
Ishaan Jaffer 2026-05-06 15:51:52 -07:00
parent b7e971032b
commit a0015e8564
No known key found for this signature in database

View file

@ -20,6 +20,7 @@ from fastapi.responses import ORJSONResponse
from litellm._logging import verbose_proxy_logger
from litellm.proxy._types import UserAPIKeyAuth
from litellm.proxy.agent_session_endpoints.constants import SESSION_TERMINAL_STATUSES
from litellm.proxy.agent_session_endpoints.ids import new_agent_id
from litellm.proxy.agent_session_endpoints.ownership import (
assert_caller_can_mutate,
@ -196,12 +197,16 @@ async def delete_agent(
existing = await prisma_client.db.litellm_agent.find_unique(where={"id": agent_id})
assert_caller_owns_agent(user_api_key_dict, existing)
# Cascade: terminate every active session under this agent first. We
# gather them in parallel because each call hits the VM provider.
# Cascade: terminate every non-terminal session under this agent
# first. We gather them in parallel because each call hits the VM
# provider. ``status not in SESSION_TERMINAL_STATUSES`` matches the
# rest of the module — ``terminated_at is None`` was a near-equivalent
# but broke if a session had its status flipped without
# ``terminated_at`` being set (Greptile P3).
sessions = await prisma_client.db.litellm_agentsession.find_many(
where={"agent_id": agent_id}
)
active = [s for s in sessions if s.terminated_at is None]
active = [s for s in sessions if s.status not in SESSION_TERMINAL_STATUSES]
if active:
await asyncio.gather(
*[