From cb0efba1b99d5918118e4f8ce7b86a2a7fa38f36 Mon Sep 17 00:00:00 2001 From: jayy-77 <1427jay@gmail.com> Date: Fri, 6 Feb 2026 19:25:51 +0530 Subject: [PATCH] context_compaction added --- src/google/adk/apps/app.py | 6 ++++++ src/google/adk/apps/compaction.py | 3 ++- src/google/adk/apps/llm_event_summarizer.py | 15 ++++++++++++++- tests/integration/test_multi_turn.py | 9 +++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/google/adk/apps/app.py b/src/google/adk/apps/app.py index 71ea5ce5aa..57526a6b33 100644 --- a/src/google/adk/apps/app.py +++ b/src/google/adk/apps/app.py @@ -80,6 +80,12 @@ class EventsCompactionConfig(BaseModel): end of the last compacted range. This creates an overlap between consecutive compacted summaries, maintaining context.""" + token_threshold: Optional[int] = None + """Token count that triggers compaction when exceeded.""" + + retain_recent_events: Optional[int] = None + """Number of the most recent events to retain during compaction.""" + class App(BaseModel): """Represents an LLM-backed agentic application. diff --git a/src/google/adk/apps/compaction.py b/src/google/adk/apps/compaction.py index 5f3edd92e7..ca0870097d 100644 --- a/src/google/adk/apps/compaction.py +++ b/src/google/adk/apps/compaction.py @@ -192,7 +192,8 @@ async def _run_compaction_for_sliding_window( compaction_event = ( await app.events_compaction_config.summarizer.maybe_summarize_events( - events=events_to_compact + events=events_to_compact, + config=app.events_compaction_config ) ) if compaction_event: diff --git a/src/google/adk/apps/llm_event_summarizer.py b/src/google/adk/apps/llm_event_summarizer.py index 81ac7c6814..9708000fc8 100644 --- a/src/google/adk/apps/llm_event_summarizer.py +++ b/src/google/adk/apps/llm_event_summarizer.py @@ -81,12 +81,13 @@ def _format_events_for_prompt(self, events: list[Event]) -> str: return '\\n'.join(formatted_history) async def maybe_summarize_events( - self, *, events: list[Event] + self, *, events: list[Event], config: EventsCompactionConfig ) -> Optional[Event]: """Compacts given events and returns the compacted content. Args: events: A list of events to compact. + config: The configuration for event compaction. Returns: The new compacted event, or None if no compaction is needed. @@ -94,6 +95,18 @@ async def maybe_summarize_events( if not events: return None + # Placeholder for token counting logic + def count_tokens(events: list[Event]) -> int: + return sum(len(event.content.parts) for event in events if event.content) + + token_count = count_tokens(events) + + if config.token_threshold and token_count <= config.token_threshold: + return None + + if config.retain_recent_events: + events = events[-config.retain_recent_events:] + conversation_history = self._format_events_for_prompt(events) prompt = self._prompt_template.format( conversation_history=conversation_history diff --git a/tests/integration/test_multi_turn.py b/tests/integration/test_multi_turn.py index a2f3af15cb..1c37ce009f 100644 --- a/tests/integration/test_multi_turn.py +++ b/tests/integration/test_multi_turn.py @@ -36,6 +36,15 @@ async def test_dependent_tool_calls(): ) +@pytest.mark.asyncio +async def test_context_compaction_with_thresholds(): + """Test context compaction using token threshold and retaining recent events.""" + await AgentEvaluator.evaluate( + agent_module="tests.integration.fixture.compaction_evaluation_agent", + eval_dataset_file_path_or_dir="tests/integration/fixture/compaction_evaluation_agent/test_files/compaction_with_thresholds.test.json", + num_runs=4, + ) + @pytest.mark.asyncio async def test_memorizing_past_events(): """Test memorizing past events."""