mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-22 00:31:44 +00:00
fix(gemini): drop ttl values outside the protobuf Duration range and the explanatory docstrings
This commit is contained in:
parent
2303379c20
commit
3684e5cbcb
4 changed files with 10 additions and 29 deletions
|
|
@ -89,24 +89,18 @@ def extract_ttl_from_cached_messages(messages: list[AllMessageValues]) -> str |
|
|||
|
||||
_TTL_PATTERN: Final = re.compile(r"^([0-9]*\.?[0-9]+)([smh])$")
|
||||
_TTL_UNIT_SECONDS: Final = MappingProxyType({"s": 1, "m": 60, "h": 3600})
|
||||
_PROTOBUF_DURATION_MAX_SECONDS: Final = 315_576_000_000
|
||||
|
||||
|
||||
def _normalize_ttl_to_seconds(ttl: object) -> str | None:
|
||||
"""
|
||||
Gemini's cachedContents API only takes a TTL as "<seconds>s", while Anthropic clients
|
||||
(Claude Code among them) send the minute and hour units the Anthropic API defines, "5m"
|
||||
and "1h". Returns the Gemini form for any of the three units, or None for a missing,
|
||||
non-positive, or unparseable value so the cache falls back to Gemini's default TTL.
|
||||
"""
|
||||
if not isinstance(ttl, str):
|
||||
return None
|
||||
match: Final = _TTL_PATTERN.match(ttl)
|
||||
if match is None:
|
||||
return None
|
||||
value: Final = float(match.group(1))
|
||||
if value <= 0:
|
||||
seconds: Final = round(float(match.group(1)) * _TTL_UNIT_SECONDS[match.group(2)], 9)
|
||||
if not 0 < seconds <= _PROTOBUF_DURATION_MAX_SECONDS:
|
||||
return None
|
||||
seconds: Final = round(value * _TTL_UNIT_SECONDS[match.group(2)], 9)
|
||||
return f"{seconds:.9f}".rstrip("0").rstrip(".") + "s"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2102,11 +2102,7 @@ def test_should_add_cache_control_for_anthropic_model():
|
|||
|
||||
|
||||
def test_should_not_add_cache_control_for_non_anthropic_model():
|
||||
"""Should not add cache_control for providers that reject an explicit cache_control field.
|
||||
|
||||
OpenAI/Azure do prompt caching implicitly and 400 on an unexpected
|
||||
cache_control field, so it must not be forwarded to them.
|
||||
"""
|
||||
"""Should not add cache_control for non-Anthropic models."""
|
||||
adapter = LiteLLMAnthropicMessagesAdapter()
|
||||
cache_control = {"type": "ephemeral"}
|
||||
|
||||
|
|
@ -2122,13 +2118,6 @@ def test_should_not_add_cache_control_for_non_anthropic_model():
|
|||
|
||||
|
||||
def test_should_add_cache_control_for_gemini_model():
|
||||
"""Should add cache_control for Gemini / Vertex Gemini targets.
|
||||
|
||||
These consume anthropic-style cache_control blocks via the Gemini context
|
||||
caching path, so /v1/messages requests (e.g. Claude Code) routed to a
|
||||
Gemini model must keep it. Regression for the adapter dropping the field
|
||||
before it reaches the Gemini transformation.
|
||||
"""
|
||||
adapter = LiteLLMAnthropicMessagesAdapter()
|
||||
cache_control = {"type": "ephemeral", "ttl": "1h"}
|
||||
|
||||
|
|
@ -2146,7 +2135,6 @@ def test_should_add_cache_control_for_gemini_model():
|
|||
|
||||
|
||||
def test_cache_control_preserved_in_text_content_for_gemini():
|
||||
"""cache_control must survive message translation for a Gemini target."""
|
||||
anthropic_messages = [
|
||||
AnthropicMessagesUserMessageParam(
|
||||
role="user",
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ from litellm.llms.vertex_ai.context_caching.transformation import (
|
|||
|
||||
|
||||
class TestTTLNormalization:
|
||||
"""Gemini only takes "<seconds>s"; Anthropic clients send "5m" and "1h" too"""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"ttl, expected",
|
||||
[
|
||||
|
|
@ -23,6 +21,8 @@ class TestTTLNormalization:
|
|||
("1h", "3600s"),
|
||||
("0.5h", "1800s"),
|
||||
("48h", "172800s"),
|
||||
("315576000000s", "315576000000s"),
|
||||
("87660000h", "315576000000s"),
|
||||
],
|
||||
)
|
||||
def test_normalizes_supported_units_to_seconds(self, ttl, expected):
|
||||
|
|
@ -44,6 +44,10 @@ class TestTTLNormalization:
|
|||
"3600 s",
|
||||
"3600ss",
|
||||
"1 h",
|
||||
"0.0000000001s",
|
||||
"315576000001s",
|
||||
"87660001h",
|
||||
"9" * 400 + "h",
|
||||
None,
|
||||
123,
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1399,11 +1399,6 @@ class TestContextCachingEndpoints:
|
|||
def test_check_and_create_cache_skips_between_default_and_gemini_2_5_pro_minimum(
|
||||
self, local_model_cost_map
|
||||
):
|
||||
"""Gemini 2.5 Pro needs 2048 cached tokens, twice the provider-agnostic default.
|
||||
|
||||
Content between the two used to reach Google's cachedContents endpoint and 400
|
||||
with "Cached content is too small".
|
||||
"""
|
||||
model = "gemini-2.5-pro"
|
||||
self._token_check_patcher.stop()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue