AdkApp.async_stream_query(session_events=...) creates a managed session per call and never deletes it
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 74/100
Línea de trabajo
Empieza en vertexai/agent_engines/templates/adk.py, en async_stream_query, y compara después su rama session_events con la ruta hermana _StreamRunRequest alrededor de adk.py:1364. Reprodúcelo con session_events=[] contra un engine desplegado y enumera las sesiones después. Se considera terminado cuando la sesión desechable no persiste como sesión administrada y se elimina después del streaming.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
Every async_stream_query(session_events=...) call against a deployed Agent Engine creates a persisted Vertex session, appends the caller's supplied transcript to it, and abandons it. The session id is never returned to the caller, so it cannot be deleted, and it persists until TTL — 365 days by default.
This is independent of #7118. That issue is about session_events raising an AttributeError; this is about the session created before the raise. The fix suggested in #7118 does not address it, so applying that fix alone changes the behaviour from "leaks a session and fails" to "leaks a session and succeeds".
Environment
google-cloud-aiplatform1.163.0 and 2.0.1 (read from 1.162.0 in the wheel cache; #7118 confirms the same code atadk.py:1182in 1.163.0 andadk.py:1229in 2.0.1)google-adk2.6.3- Deployed Agent Engine,
europe-west1
Cause
In vertexai/agent_engines/templates/adk.py, async_stream_query:
if not session_id:
session = await self.async_create_session(user_id=user_id) # persisted session
session_id = session["id"]
if session_events is not None:
session_service = self._tmpl_attrs.get("session_service") # VertexAiSessionService when deployed
for event in session_events:
await session_service.append_event(session=session, event=event)
The generator's finally calls only _force_flush_otel. There is no delete_session.
Three things make it unrecoverable for the caller:
- The id is never surfaced. It is bound to a local and not yielded.
google/adk/events/event.pydefines nosession_idfield, so nothing in the response stream carries it either. - It accumulates per turn, not per conversation.
session_eventsexists for callers that hold their own history and replay it, so an N-turn conversation leaves N sessions, each holding a longer prefix of the same transcript. - No retention control reaches it.
ttlandexpire_timecannot be passed throughasync_stream_query, so every one of them gets the 365-day default.
Reproduction
Against a deployed engine:
async for event in remote_app.async_stream_query(
message="hello", user_id="u", session_events=[]
):
print(event)
session_events=[] is deliberate: the loop body never runs, so there is no exception and none of #7118 is involved. Then list sessions on the engine — one new session per call, none of them reachable from the code that made them.
Impact
The main use for session_events is a caller that owns the transcript and does not want a server-side copy of user-supplied conversation content. As implemented, a server-side copy is created anyway, in a resource the caller cannot address, delete, or set a retention policy on. For anything handling personal data, that turns an opt-out into an undeletable copy with the longest available lifetime.
Suggested fix
The sibling _StreamRunRequest path already does the right thing: when no session_id is supplied it uses in_memory_session_service and deletes the session in a finally (around adk.py:1364). Routing the session_events branch the same way fits — the session is throwaway by construction, so it does not need to be managed. It also removes the per-event round trips noted in #7118's second follow-up point, since in-memory appends are local.
Related observation
The async_create_session call sits above the session_events check, so any async_stream_query call without a session_id creates a managed session that is never deleted and whose id is never returned. That broader case may be intended — the docstring says a new session will be created — but the id not being returned makes it unusable as a resumable session either way. Filing this scoped to session_events, where there is a clear expectation of no server-side copy.
- Lenguaje dominante
- Python
- Estrellas
- 907
- Forks
- 467
- Merge medio
- 1 d 8 h
- PR fusionados (30 d)
- 40
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de googleapis/python-aiplatform
-
Protobuf 7.35.1+ support Abiertoapi: vertex-ai
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
googleapis/python-aiplatform#7132 ·
-
api: vertex-ai
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
googleapis/python-aiplatform#7097 ·
-
CustomContainerTrainingJob.run drops max_wait_duration=0 instead of requesting indefinite DWS wait Abiertoapi: vertex-ai
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
googleapis/python-aiplatform#7067 · 1 comentario ·
-
api: vertex-ai
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
googleapis/python-aiplatform#6877 ·
-
api: vertex-ai
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
googleapis/python-aiplatform#6865 · 1 comentario ·
Todos los issues de googleapis/python-aiplatform
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
stephrobert/dsoxlab#238 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
sublimehq/package_control#1780 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
nwg-piotr/nwg-displays#145 ·