Skip to content

Commit 3f4bd67

Browse files
hangfeicopybara-github
authored andcommitted
fix: Make compactor optional in EventsCompactionConfig and add a default
If `EventsCompactionConfig` is provided without a `compactor`, a `SlidingWindowCompactor` is now automatically instantiated using the `root_agent`'s LLM. This simplifies configuration by providing a sensible default. PiperOrigin-RevId: 816038579
1 parent 238472d commit 3f4bd67

File tree

6 files changed

+36
-24
lines changed

6 files changed

+36
-24
lines changed

src/google/adk/apps/app.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
from ..agents.base_agent import BaseAgent
2323
from ..agents.context_cache_config import ContextCacheConfig
24-
from ..apps.base_events_compactor import BaseEventsCompactor
24+
from ..apps.base_events_summarizer import BaseEventsSummarizer
2525
from ..plugins.base_plugin import BasePlugin
2626
from ..utils.feature_decorator import experimental
2727

@@ -56,11 +56,13 @@ class EventsCompactionConfig(BaseModel):
5656
extra="forbid",
5757
)
5858

59-
compactor: BaseEventsCompactor
60-
"""The event compactor strategy for the application."""
59+
summarizer: Optional[BaseEventsSummarizer] = None
60+
"""The event summarizer to use for compaction."""
61+
6162
compaction_interval: int
6263
"""The number of *new* user-initiated invocations that, once
6364
fully represented in the session's events, will trigger a compaction."""
65+
6466
overlap_size: int
6567
"""The number of preceding invocations to include from the
6668
end of the last compacted range. This creates an overlap between consecutive

src/google/adk/apps/base_events_compactor.py renamed to src/google/adk/apps/base_events_summarizer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323

2424

2525
@experimental
26-
class BaseEventsCompactor(abc.ABC):
26+
class BaseEventsSummarizer(abc.ABC):
2727
"""Base interface for compacting events."""
2828

2929
@abc.abstractmethod
30-
async def maybe_compact_events(
30+
async def maybe_summarize_events(
3131
self, *, events: list[Event]
3232
) -> Optional[Event]:
3333
"""Compact a list of events into a single event.

src/google/adk/apps/compaction.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import logging
1818

1919
from google.adk.apps.app import App
20+
from google.adk.apps.llm_event_summarizer import LlmEventSummarizer
2021
from google.adk.sessions.base_session_service import BaseSessionService
2122
from google.adk.sessions.session import Session
2223

@@ -180,8 +181,13 @@ async def _run_compaction_for_sliding_window(
180181
if not events_to_compact:
181182
return None
182183

184+
if not app.events_compaction_config.summarizer:
185+
app.events_compaction_config.summarizer = LlmEventSummarizer(
186+
llm=app.root_agent.canonical_model
187+
)
188+
183189
compaction_event = (
184-
await app.events_compaction_config.compactor.maybe_compact_events(
190+
await app.events_compaction_config.summarizer.maybe_summarize_events(
185191
events=events_to_compact
186192
)
187193
)

src/google/adk/apps/llm_event_summarizer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919
from google.genai.types import Content
2020
from google.genai.types import Part
2121

22+
from ..apps.base_events_summarizer import BaseEventsSummarizer
2223
from ..events.event import Event
2324
from ..events.event_actions import EventActions
2425
from ..events.event_actions import EventCompaction
2526
from ..models.base_llm import BaseLlm
2627
from ..models.llm_request import LlmRequest
27-
from .base_events_compactor import BaseEventsCompactor
2828

2929

30-
class LlmEventSummarizer(BaseEventsCompactor):
30+
class LlmEventSummarizer(BaseEventsSummarizer):
3131
"""An LLM-based event summarizer for sliding window compaction.
3232
3333
This class is responsible for summarizing a provided list of events into a
@@ -81,7 +81,7 @@ def _format_events_for_prompt(self, events: list[Event]) -> str:
8181
formatted_history.append(f'{event.author}: {part.text}')
8282
return '\\n'.join(formatted_history)
8383

84-
async def maybe_compact_events(
84+
async def maybe_summarize_events(
8585
self, *, events: list[Event]
8686
) -> Optional[Event]:
8787
"""Compacts given events and returns the compacted content.

tests/unittests/apps/test_compaction.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ async def test_run_compaction_for_sliding_window_no_events(self):
7272
await _run_compaction_for_sliding_window(
7373
app, session, self.mock_session_service
7474
)
75-
self.mock_compactor.maybe_compact_events.assert_not_called()
75+
self.mock_compactor.maybe_summarize_events.assert_not_called()
7676
self.mock_session_service.append_event.assert_not_called()
7777

7878
async def test_run_compaction_for_sliding_window_not_enough_new_invocations(
@@ -82,7 +82,7 @@ async def test_run_compaction_for_sliding_window_not_enough_new_invocations(
8282
name='test',
8383
root_agent=Mock(spec=BaseAgent),
8484
events_compaction_config=EventsCompactionConfig(
85-
compactor=self.mock_compactor,
85+
summarizer=self.mock_compactor,
8686
compaction_interval=3,
8787
overlap_size=1,
8888
),
@@ -100,15 +100,15 @@ async def test_run_compaction_for_sliding_window_not_enough_new_invocations(
100100
await _run_compaction_for_sliding_window(
101101
app, session, self.mock_session_service
102102
)
103-
self.mock_compactor.maybe_compact_events.assert_not_called()
103+
self.mock_compactor.maybe_summarize_events.assert_not_called()
104104
self.mock_session_service.append_event.assert_not_called()
105105

106106
async def test_run_compaction_for_sliding_window_first_compaction(self):
107107
app = App(
108108
name='test',
109109
root_agent=Mock(spec=BaseAgent),
110110
events_compaction_config=EventsCompactionConfig(
111-
compactor=self.mock_compactor,
111+
summarizer=self.mock_compactor,
112112
compaction_interval=2,
113113
overlap_size=1,
114114
),
@@ -124,14 +124,16 @@ async def test_run_compaction_for_sliding_window_first_compaction(self):
124124
mock_compacted_event = self._create_compacted_event(
125125
1.0, 4.0, 'Summary inv1-inv4'
126126
)
127-
self.mock_compactor.maybe_compact_events.return_value = mock_compacted_event
127+
self.mock_compactor.maybe_summarize_events.return_value = (
128+
mock_compacted_event
129+
)
128130

129131
await _run_compaction_for_sliding_window(
130132
app, session, self.mock_session_service
131133
)
132134

133135
# Expected events to compact: inv1, inv2, inv3, inv4
134-
compacted_events_arg = self.mock_compactor.maybe_compact_events.call_args[
136+
compacted_events_arg = self.mock_compactor.maybe_summarize_events.call_args[
135137
1
136138
]['events']
137139
self.assertEqual(
@@ -147,7 +149,7 @@ async def test_run_compaction_for_sliding_window_with_overlap(self):
147149
name='test',
148150
root_agent=Mock(spec=BaseAgent),
149151
events_compaction_config=EventsCompactionConfig(
150-
compactor=self.mock_compactor,
152+
summarizer=self.mock_compactor,
151153
compaction_interval=2,
152154
overlap_size=1,
153155
),
@@ -174,7 +176,9 @@ async def test_run_compaction_for_sliding_window_with_overlap(self):
174176
mock_compacted_event = self._create_compacted_event(
175177
2.0, 5.0, 'Summary inv2-inv5'
176178
)
177-
self.mock_compactor.maybe_compact_events.return_value = mock_compacted_event
179+
self.mock_compactor.maybe_summarize_events.return_value = (
180+
mock_compacted_event
181+
)
178182

179183
await _run_compaction_for_sliding_window(
180184
app, session, self.mock_session_service
@@ -183,7 +187,7 @@ async def test_run_compaction_for_sliding_window_with_overlap(self):
183187
# New invocations are inv3, inv4, inv5 (3 new) > threshold (2).
184188
# Overlap size is 1, so start from 1 inv before inv3, which is inv2.
185189
# Compact range: inv2 to inv5.
186-
compacted_events_arg = self.mock_compactor.maybe_compact_events.call_args[
190+
compacted_events_arg = self.mock_compactor.maybe_summarize_events.call_args[
187191
1
188192
]['events']
189193
self.assertEqual(
@@ -201,19 +205,19 @@ async def test_run_compaction_for_sliding_window_no_compaction_event_returned(
201205
name='test',
202206
root_agent=Mock(spec=BaseAgent),
203207
events_compaction_config=EventsCompactionConfig(
204-
compactor=self.mock_compactor,
208+
summarizer=self.mock_compactor,
205209
compaction_interval=1,
206210
overlap_size=0,
207211
),
208212
)
209213
events = [self._create_event(1.0, 'inv1', 'e1')]
210214
session = Session(app_name='test', user_id='u1', id='s1', events=events)
211215

212-
self.mock_compactor.maybe_compact_events.return_value = None
216+
self.mock_compactor.maybe_summarize_events.return_value = None
213217

214218
await _run_compaction_for_sliding_window(
215219
app, session, self.mock_session_service
216220
)
217221

218-
self.mock_compactor.maybe_compact_events.assert_called_once()
222+
self.mock_compactor.maybe_summarize_events.assert_called_once()
219223
self.mock_session_service.append_event.assert_not_called()

tests/unittests/apps/test_llm_event_summarizer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ async def async_gen():
6464

6565
self.mock_llm.generate_content_async.return_value = async_gen()
6666

67-
compacted_event = await self.compactor.maybe_compact_events(events=events)
67+
compacted_event = await self.compactor.maybe_summarize_events(events=events)
6868

6969
self.assertIsNotNone(compacted_event)
7070
self.assertEqual(
@@ -101,11 +101,11 @@ async def async_gen():
101101

102102
self.mock_llm.generate_content_async.return_value = async_gen()
103103

104-
compacted_event = await self.compactor.maybe_compact_events(events=events)
104+
compacted_event = await self.compactor.maybe_summarize_events(events=events)
105105
self.assertIsNone(compacted_event)
106106

107107
async def test_maybe_compact_events_empty_input(self):
108-
compacted_event = await self.compactor.maybe_compact_events(events=[])
108+
compacted_event = await self.compactor.maybe_summarize_events(events=[])
109109
self.assertIsNone(compacted_event)
110110
self.mock_llm.generate_content_async.assert_not_called()
111111

0 commit comments

Comments
 (0)