-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
🔴 Required Information
Describe the Bug:
When using EventsCompactionConfig with LlmEventSummarizer, the compaction triggers correctly after the configured compaction_interval but fails during the async LLM summarization call with RuntimeError: Event loop is closed. The error occurs during HTTP connection cleanup after the summarization LLM request. The compaction attempts to run but never completes, resulting in no CompactedEvent being created and the full conversation history being retained.
Steps to Reproduce:
- Configure an ADK App with EventsCompactionConfig:
from google.adk.apps.app import App, EventsCompactionConfig
from google.adk.apps.llm_event_summarizer import LlmEventSummarizer
from google.adk.models import Gemini
compaction_summarizer = LlmEventSummarizer(
llm=Gemini(model="gemini-2.5-flash")
)
adk_app = App(
name="my_agent",
root_agent=my_agent,
events_compaction_config=EventsCompactionConfig(
summarizer=compaction_summarizer,
compaction_interval=5,
overlap_size=1,
),
)- Deploy to Vertex AI Agent Engine using
vertexai.agent_engines.create() - Send 5+ messages in a conversation
- Observe error in logs after the 5th message
Expected Behavior:
After compaction_interval events, the LlmEventSummarizer should successfully call the LLM to summarize older events and create a CompactedEvent, reducing the conversation context size.
Observed Behavior:
The compaction triggers (stack trace shows _run_compaction_for_sliding_window is called) but fails during HTTP connection cleanup with:
RuntimeError: Event loop is closed
The conversation history remains intact with all messages, and no summarization occurs.
Environment Details:
- ADK Library Version: >=1.23.0
- Desktop OS: Deployed on Google Cloud (Vertex AI Agent Engine)
- Python Version: 3.10
Model Information:
- Are you using LiteLLM: No
- Which model is being used: gemini-2.5-flash (for summarization), gemini-2.0-flash (for agent)
🟡 Optional Information
Regression:
N/A - First time using EventsCompactionConfig
Logs:
Traceback (most recent call last):
File "/usr/local/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
self.run()
File "/usr/local/lib/python3.10/threading.py", line 953, in run
self._target(*self._args, **self._kwargs)
File ".../google/adk/runners.py", line 436, in _asyncio_thread_main
asyncio.run(_invoke_run_async())
File "/usr/local/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/local/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
return future.result()
File ".../google/adk/runners.py", line 429, in _invoke_run_async
async for event in agen:
File ".../google/adk/runners.py", line 562, in run_async
async for event in agen:
File ".../google/adk/runners.py", line 557, in _run_with_trace
await _run_compaction_for_sliding_window(
File ".../google/adk/apps/compaction.py", line 194, in _run_compaction_for_sliding_window
await app.events_compaction_config.summarizer.maybe_summarize_events(
File ".../google/adk/apps/llm_event_summarizer.py", line 107, in maybe_summarize_events
async for llm_response in self._llm.generate_content_async(
File ".../google/adk/models/google_llm.py", line 241, in generate_content_async
response = await self.api_client.aio.models.generate_content(
File ".../google/genai/models.py", line 7042, in generate_content
response = await self._generate_content(
File ".../google/genai/models.py", line 5848, in _generate_content
response = await self._api_client.async_request(
File ".../google/genai/_api_client.py", line 1432, in async_request
result = await self._async_request(
File ".../google/genai/_api_client.py", line 1365, in _async_request
return await self._async_retry(
File ".../tenacity/asyncio/__init__.py", line 111, in __call__
do = await self.iter(retry_state=retry_state)
File ".../tenacity/asyncio/__init__.py", line 153, in iter
result = await action(retry_state)
File ".../tenacity/_utils.py", line 99, in inner
return call(*args, **kwargs)
File ".../tenacity/__init__.py", line 420, in exc_check
raise retry_exc.reraise()
File ".../tenacity/__init__.py", line 187, in reraise
raise self.last_attempt.result()
File "/usr/local/lib/python3.10/concurrent/futures/_base.py", line 451, in result
return self.__get_result()
File "/usr/local/lib/python3.10/concurrent/futures/_base.py", line 403, in __get_result
raise self._exception
File ".../tenacity/asyncio/__init__.py", line 114, in __call__
result = await fn(*args, **kwargs)
File ".../google/genai/_api_client.py", line 1338, in _async_request_once
client_response = await self._async_httpx_client.request(
File ".../httpx/_client.py", line 1540, in request
return await self.send(request, auth=auth, follow_redirects=follow_redirects)
File ".../httpx/_client.py", line 1629, in send
response = await self._send_handling_auth(
File ".../httpx/_client.py", line 1657, in _send_handling_auth
response = await self._send_handling_redirects(
File ".../httpx/_client.py", line 1694, in _send_handling_redirects
response = await self._send_single_request(request)
File ".../httpx/_client.py", line 1730, in _send_single_request
response = await transport.handle_async_request(request)
File ".../httpx/_transports/default.py", line 394, in handle_async_request
resp = await self._pool.handle_async_request(req)
File ".../httpcore/_async/connection_pool.py", line 256, in handle_async_request
raise exc from None
File ".../httpcore/_async/connection_pool.py", line 229, in handle_async_request
await self._close_connections(closing)
File ".../httpcore/_async/connection_pool.py", line 345, in _close_connections
await connection.aclose()
File ".../httpcore/_async/connection.py", line 173, in aclose
await self._connection.aclose()
File ".../httpcore/_async/http11.py", line 258, in aclose
await self._network_stream.aclose()
File ".../httpcore/_backends/anyio.py", line 53, in aclose
await self._stream.aclose()
File ".../anyio/streams/tls.py", line 241, in aclose
await self.transport_stream.aclose()
File ".../anyio/_backends/_asyncio.py", line 1329, in aclose
self._transport.close()
File "/usr/local/lib/python3.10/asyncio/selector_events.py", line 706, in close
self._loop.call_soon(self._call_connection_lost, None)
File "/usr/local/lib/python3.10/asyncio/base_events.py", line 753, in call_soon
self._check_closed()
File "/usr/local/lib/python3.10/asyncio/base_events.py", line 515, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Additional Context:
- This occurs when deployed to Vertex AI Agent Engine (ReasoningEngine)
- The compaction runs in a separate thread (
_asyncio_thread_maininrunners.py) - The LLM request appears to complete, but the error occurs during HTTP connection cleanup
- The event loop seems to be closed before the httpx/httpcore connection pool can properly close its connections
Minimal Reproduction Code:
from google.adk.apps.app import App, EventsCompactionConfig
from google.adk.apps.llm_event_summarizer import LlmEventSummarizer
from google.adk.models import Gemini
from google.adk.agents import Agent
from vertexai import agent_engines
from vertexai.preview import reasoning_engines
# Create a simple agent
agent = Agent(
name="test_agent",
model="gemini-2.0-flash",
instruction="You are a helpful assistant.",
)
# Configure compaction
summarizer = LlmEventSummarizer(llm=Gemini(model="gemini-2.5-flash"))
app = App(
name="test_app",
root_agent=agent,
events_compaction_config=EventsCompactionConfig(
summarizer=summarizer,
compaction_interval=5,
overlap_size=1,
),
)
# Deploy to Agent Engine
adk_app = reasoning_engines.AdkApp(app=app, enable_tracing=False)
deployed = agent_engines.create(
agent_engine=adk_app,
requirements=["google-adk>=1.23.0"],
display_name="test-compaction",
)
# Send 5+ messages to trigger compaction -> Error occursHow often has this issue occurred?:
- Always (100%) - Occurs every time compaction_interval is reached