Skip to content

Commit 9c5de58

Browse files
GWealecopybara-github
authored andcommitted
fix(cache): handle fingerprint-only metadata in performance analyzer
The analyzer crashed on `sum([None, ...])` whenever any event had fingerprint-only cache metadata (cache_name=None, invocations_used=None), which happens on every session's first turn. Also fixes `cache_refreshes` over-counting None as a unique cache instance. Co-authored-by: George Weale <gweale@google.com> PiperOrigin-RevId: 912722966
1 parent 91cb5c6 commit 9c5de58

2 files changed

Lines changed: 52 additions & 2 deletions

File tree

src/google/adk/utils/cache_performance_analyzer.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,11 @@ async def analyze_agent_cache_performance(
144144
total_cached_tokens / total_requests if total_requests > 0 else 0.0
145145
)
146146

147-
invocations_used = [c.invocations_used for c in cache_history]
147+
invocations_used = [
148+
c.invocations_used
149+
for c in cache_history
150+
if c.invocations_used is not None
151+
]
148152
total_invocations = sum(invocations_used)
149153

150154
return {
@@ -156,7 +160,9 @@ async def analyze_agent_cache_performance(
156160
else 0
157161
),
158162
"latest_cache": cache_history[-1].cache_name,
159-
"cache_refreshes": len(set(c.cache_name for c in cache_history)),
163+
"cache_refreshes": len(
164+
{c.cache_name for c in cache_history if c.cache_name is not None}
165+
),
160166
"total_invocations": total_invocations,
161167
"total_prompt_tokens": total_prompt_tokens,
162168
"total_cached_tokens": total_cached_tokens,

tests/unittests/utils/test_cache_performance_analyzer.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,50 @@ async def test_session_service_integration(self):
401401
assert result["status"] == "active"
402402
assert result["requests_with_cache"] == 1
403403

404+
async def test_analyze_agent_cache_performance_with_fingerprint_only(self):
405+
"""Fingerprint-only entries (cache_name=None, invocations_used=None) don't crash."""
406+
fp_only = CacheMetadata(fingerprint="fp", contents_count=3)
407+
active = self.create_cache_metadata(invocations_used=4, cache_name="active")
408+
fp_usage = self.create_mock_usage_metadata(
409+
prompt_tokens=1000, cached_tokens=0
410+
)
411+
active_usage = self.create_mock_usage_metadata(
412+
prompt_tokens=1000, cached_tokens=800
413+
)
414+
415+
events = [
416+
self.create_mock_event(
417+
author="test_agent",
418+
cache_metadata=fp_only,
419+
usage_metadata=fp_usage,
420+
),
421+
self.create_mock_event(
422+
author="test_agent",
423+
cache_metadata=active,
424+
usage_metadata=active_usage,
425+
),
426+
]
427+
mock_session = Session(
428+
id="test_session",
429+
app_name="test_app",
430+
user_id="test_user",
431+
events=events,
432+
)
433+
self.mock_session_service.get_session = AsyncMock(return_value=mock_session)
434+
435+
result = await self.analyzer.analyze_agent_cache_performance(
436+
"test_session", "test_user", "test_app", "test_agent"
437+
)
438+
439+
assert result["status"] == "active"
440+
assert result["total_requests"] == 2
441+
assert result["total_prompt_tokens"] == 2000
442+
assert result["total_cached_tokens"] == 800
443+
assert result["total_invocations"] == 4
444+
assert result["avg_invocations_used"] == 4.0
445+
assert result["cache_refreshes"] == 1
446+
assert result["requests_with_cache"] == 2
447+
404448
async def test_mixed_agents_filtering(self):
405449
"""Test that analysis correctly filters by agent name."""
406450
target_cache = self.create_cache_metadata(

0 commit comments

Comments
 (0)