Commit 8a96b7b
fix(models): gate Gemini cache creation on cacheable prefix tokens
Merge google#6137
### Link to Issue or Description of Change
- Closes: google#5847
**Problem:**
`GeminiContextCacheManager._create_new_cache_with_contents` decides whether a
request is large enough to cache by comparing
`llm_request.cacheable_contents_token_count` against Gemini's
`_GEMINI_MIN_CACHE_TOKENS` (4096). But `cacheable_contents_token_count` is set
(in `context_cache_processor.py`) to the **previous response's
`prompt_token_count`** — i.e. the token count of the *entire* previous prompt
(system instruction + tools + every content, including the trailing user turn).
The cache, however, only stores the **prefix** `contents[:cache_contents_count]`
(plus system instruction and tools — see `_create_gemini_cache`), where
`cache_contents_count` excludes the last continuous batch of user contents.
On a long conversation the full-prompt count can clear the 4096 gate while the
actual cached prefix is far below it, so `caches.create()` is invoked with a
sub-minimum payload and Gemini returns **`400 INVALID_ARGUMENT`**. The reporter
confirmed this in production, and a maintainer confirmed the root cause in the
issue thread.
**Solution:**
Gate cache creation on the size of the prefix that is *actually* cached rather
than on the full previous prompt.
Since the only accurate token count we have is for the whole prompt, the new
`_estimate_cacheable_prefix_tokens` scales that accurate count by the prefix's
estimated share of the request (`_estimate_request_tokens` is reused — now
accepting an optional `cache_contents_count` — to estimate both the full request
and the prefix). When the prefix already spans the whole request the scale
factor is `1.0` and the accurate count is used unchanged, so existing behavior
is preserved; when the prefix is a strict subset the estimate shrinks
accordingly and a too-small prefix is correctly skipped before any API call.
Scope note: this fixes the `400 INVALID_ARGUMENT` (the reported bug). The
separate latency concern discussed later in the thread (synchronous
`caches.create()` / cleanup on the request path, tracked in google#5889) is
intentionally out of scope. The user-configured `min_tokens` gate is left on the
full-prompt count, since the 4096 prefix gate is what prevents the invalid API
call; happy to extend `min_tokens` to the prefix too if maintainers prefer.
### Testing Plan
**Unit Tests:**
- [x] I have added or updated unit tests for my change.
- [x] All unit tests pass locally.
Added `test_create_cache_gates_on_prefix_not_full_prompt`: a tiny cacheable
prefix followed by a huge trailing user turn with
`cacheable_contents_token_count = 75000`. It asserts no cache is created and
`caches.create` is never called. This test is **red on `main`** (`caches.create`
is called once — the 400-inducing path) and **green with this change**.
Updated `test_fingerprint_only_metadata_transitions_to_active_cache` to use a
realistically large cacheable prefix, since its previous setup relied on the
buggy assumption that a tiny prefix would still be cached because the injected
full-prompt count cleared the gate.
```
$ pytest tests/unittests/agents/test_gemini_context_cache_manager.py \
tests/unittests/agents/test_context_cache_config.py \
tests/unittests/flows/llm_flows/test_context_cache_processor.py -q
59 passed
```
**Manual End-to-End (E2E) Tests:**
The fix is exercised entirely through the unit test above (it mocks
`genai_client.aio.caches.create` and asserts it is not called for a
below-minimum prefix), which mirrors the production failure mode reported in
google#5847 (`400 INVALID_ARGUMENT` from `caches.create` on a long conversation).
### Checklist
- [x] I have read the CONTRIBUTING.md document.
- [x] I have performed a self-review of my own code.
- [x] I have commented my code, particularly in hard-to-understand areas.
- [x] I have added tests that prove my fix is effective.
- [x] New and existing unit tests pass locally with my changes.
Co-authored-by: George Weale <gweale@google.com>
COPYBARA_INTEGRATE_REVIEW=google#6137 from nyxst4ck:fix/gemini-cache-prefix-token-gate ade7a1e
PiperOrigin-RevId: 9386597231 parent 58f4067 commit 8a96b7b
2 files changed
Lines changed: 109 additions & 10 deletions
File tree
- src/google/adk/models
- tests/unittests/agents
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
326 | 326 | | |
327 | 327 | | |
328 | 328 | | |
329 | | - | |
330 | | - | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
331 | 341 | | |
332 | | - | |
333 | | - | |
| 342 | + | |
| 343 | + | |
334 | 344 | | |
335 | 345 | | |
336 | 346 | | |
| |||
342 | 352 | | |
343 | 353 | | |
344 | 354 | | |
345 | | - | |
346 | | - | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
347 | 361 | | |
348 | 362 | | |
349 | 363 | | |
350 | 364 | | |
351 | 365 | | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
352 | 369 | | |
353 | 370 | | |
354 | 371 | | |
| |||
366 | 383 | | |
367 | 384 | | |
368 | 385 | | |
369 | | - | |
370 | | - | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
371 | 391 | | |
372 | 392 | | |
373 | 393 | | |
374 | 394 | | |
375 | 395 | | |
376 | 396 | | |
377 | 397 | | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
378 | 434 | | |
379 | 435 | | |
380 | 436 | | |
| |||
Lines changed: 45 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
202 | 202 | | |
203 | 203 | | |
204 | 204 | | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
205 | 242 | | |
206 | 243 | | |
207 | 244 | | |
| |||
916 | 953 | | |
917 | 954 | | |
918 | 955 | | |
919 | | - | |
| 956 | + | |
| 957 | + | |
| 958 | + | |
| 959 | + | |
920 | 960 | | |
921 | 961 | | |
922 | 962 | | |
| |||
997 | 1037 | | |
998 | 1038 | | |
999 | 1039 | | |
1000 | | - | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
1001 | 1044 | | |
1002 | 1045 | | |
1003 | 1046 | | |
| |||
0 commit comments