Skip to content

Commit ffc9677

Browse files
abhinavmaddinenixuanyang15
authored andcommitted
feat: add create_http_options to ContextCacheConfig for cache creation timeout
Merge #4702 Close #4703 Co-authored-by: Xuan Yang <xygoogle@google.com> PiperOrigin-RevId: 932753541
1 parent 4aaf494 commit ffc9677

5 files changed

Lines changed: 97 additions & 17 deletions

File tree

src/google/adk/agents/context_cache_config.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from __future__ import annotations
1616

17+
from google.genai import types
1718
from pydantic import BaseModel
1819
from pydantic import ConfigDict
1920
from pydantic import Field
@@ -72,6 +73,18 @@ class ContextCacheConfig(BaseModel):
7273
),
7374
)
7475

76+
create_http_options: types.HttpOptions | None = Field(
77+
default=None,
78+
description=(
79+
"Optional HTTP options to pass to the GenAI client. Set this to add a"
80+
" timeout on CachedContent.create() calls (e.g."
81+
" types.HttpOptions(timeout=10000) for a 10-second timeout in"
82+
" milliseconds). When the cache creation call exceeds the timeout,"
83+
" it fails and the request proceeds without caching. None uses the"
84+
" client's default HTTP options."
85+
),
86+
)
87+
7588
@property
7689
def ttl_string(self) -> str:
7790
"""Get TTL as string format for cache creation."""
@@ -81,5 +94,6 @@ def __str__(self) -> str:
8194
"""String representation for logging."""
8295
return (
8396
f"ContextCacheConfig(cache_intervals={self.cache_intervals}, "
84-
f"ttl={self.ttl_seconds}s, min_tokens={self.min_tokens})"
97+
f"ttl={self.ttl_seconds}s, min_tokens={self.min_tokens}, "
98+
f"create_http_options={self.create_http_options})"
8599
)

src/google/adk/models/gemini_context_cache_manager.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,13 @@ async def _create_gemini_cache(
411411
if llm_request.config and llm_request.config.tool_config:
412412
cache_config.tool_config = llm_request.config.tool_config
413413

414+
# Pass through HTTP options (e.g. timeout) from cache config
415+
if (
416+
llm_request.cache_config
417+
and llm_request.cache_config.create_http_options
418+
):
419+
cache_config.http_options = llm_request.cache_config.create_http_options
420+
414421
span.set_attribute("cache_contents_count", cache_contents_count)
415422
span.set_attribute("model", llm_request.model)
416423
span.set_attribute("ttl_seconds", llm_request.cache_config.ttl_seconds)

tests/unittests/agents/test_context_cache_config.py

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,19 @@ def test_str_representation(self):
106106
)
107107

108108
expected = (
109-
"ContextCacheConfig(cache_intervals=15, ttl=3600s, min_tokens=1024)"
109+
"ContextCacheConfig(cache_intervals=15, ttl=3600s, min_tokens=1024, "
110+
"create_http_options=None)"
110111
)
111112
assert str(config) == expected
112113

113114
def test_str_representation_defaults(self):
114115
"""Test string representation with default values."""
115116
config = ContextCacheConfig()
116117

117-
expected = "ContextCacheConfig(cache_intervals=10, ttl=1800s, min_tokens=0)"
118+
expected = (
119+
"ContextCacheConfig(cache_intervals=10, ttl=1800s, min_tokens=0, "
120+
"create_http_options=None)"
121+
)
118122
assert str(config) == expected
119123

120124
def test_pydantic_model_validation(self):
@@ -126,25 +130,19 @@ def test_pydantic_model_validation(self):
126130

127131
def test_field_descriptions(self):
128132
"""Test that fields have proper descriptions."""
129-
config = ContextCacheConfig()
130-
schema = config.model_json_schema()
133+
fields = ContextCacheConfig.model_fields
131134

132-
assert "cache_intervals" in schema["properties"]
135+
assert "cache_intervals" in fields
133136
assert (
134-
"Maximum number of invocations"
135-
in schema["properties"]["cache_intervals"]["description"]
137+
"Maximum number of invocations" in fields["cache_intervals"].description
136138
)
137139

138-
assert "ttl_seconds" in schema["properties"]
139-
assert (
140-
"Time-to-live for cache"
141-
in schema["properties"]["ttl_seconds"]["description"]
142-
)
140+
assert "ttl_seconds" in fields
141+
assert "Time-to-live for cache" in fields["ttl_seconds"].description
143142

144-
assert "min_tokens" in schema["properties"]
143+
assert "min_tokens" in fields
145144
assert (
146-
"Minimum estimated request tokens"
147-
in schema["properties"]["min_tokens"]["description"]
145+
"Minimum estimated request tokens" in fields["min_tokens"].description
148146
)
149147

150148
def test_immutability_config(self):

tests/unittests/agents/test_gemini_context_cache_manager.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,3 +951,63 @@ async def test_fingerprint_only_metadata_transitions_to_active_cache(
951951
assert result_2.contents_count == 3 # Preserved from prefix
952952
assert result_2.invocations_used == 1
953953
self.manager.genai_client.aio.caches.create.assert_called_once()
954+
955+
async def test_create_http_options_passthrough(self):
956+
"""Test that create_http_options is passed through to cache creation config."""
957+
mock_cached_content = AsyncMock()
958+
mock_cached_content.name = (
959+
"projects/test/locations/us-central1/cachedContents/test123"
960+
)
961+
self.manager.genai_client.aio.caches.create = AsyncMock(
962+
return_value=mock_cached_content
963+
)
964+
965+
# Create config with http_options (e.g. 10s timeout)
966+
http_options = types.HttpOptions(timeout=10000)
967+
cache_config_with_timeout = ContextCacheConfig(
968+
cache_intervals=10,
969+
ttl_seconds=1800,
970+
min_tokens=0,
971+
create_http_options=http_options,
972+
)
973+
974+
llm_request = self.create_llm_request()
975+
llm_request.cache_config = cache_config_with_timeout
976+
977+
cache_contents_count = max(0, len(llm_request.contents) - 1)
978+
979+
with patch.object(
980+
self.manager, "_generate_cache_fingerprint", return_value="test_fp"
981+
):
982+
await self.manager._create_gemini_cache(llm_request, cache_contents_count)
983+
984+
# Verify cache creation call includes http_options
985+
create_call = self.manager.genai_client.aio.caches.create.call_args
986+
assert create_call is not None
987+
cache_config = create_call[1]["config"]
988+
assert cache_config.http_options is not None
989+
assert cache_config.http_options.timeout == 10000
990+
991+
async def test_create_without_http_options(self):
992+
"""Test that cache creation works without create_http_options."""
993+
mock_cached_content = AsyncMock()
994+
mock_cached_content.name = (
995+
"projects/test/locations/us-central1/cachedContents/test123"
996+
)
997+
self.manager.genai_client.aio.caches.create = AsyncMock(
998+
return_value=mock_cached_content
999+
)
1000+
1001+
llm_request = self.create_llm_request()
1002+
cache_contents_count = max(0, len(llm_request.contents) - 1)
1003+
1004+
with patch.object(
1005+
self.manager, "_generate_cache_fingerprint", return_value="test_fp"
1006+
):
1007+
await self.manager._create_gemini_cache(llm_request, cache_contents_count)
1008+
1009+
# Verify cache creation call does not include http_options
1010+
create_call = self.manager.genai_client.aio.caches.create.call_args
1011+
assert create_call is not None
1012+
cache_config = create_call[1]["config"]
1013+
assert cache_config.http_options is None

tests/unittests/test_runners.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1304,7 +1304,8 @@ def test_runner_realistic_cache_config_scenario(self):
13041304

13051305
# Verify string representation
13061306
expected_str = (
1307-
"ContextCacheConfig(cache_intervals=30, ttl=14400s, min_tokens=4096)"
1307+
"ContextCacheConfig(cache_intervals=30, ttl=14400s, min_tokens=4096, "
1308+
"create_http_options=None)"
13081309
)
13091310
assert str(runner.context_cache_config) == expected_str
13101311

0 commit comments

Comments
 (0)