Skip to content

Commit 9a01a73

Browse files
committed
add ttl for tool and system
1 parent fdf8166 commit 9a01a73

File tree

2 files changed

+37
-11
lines changed

2 files changed

+37
-11
lines changed

pydantic_ai_slim/pydantic_ai/models/anthropic.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,28 @@ class AnthropicModelSettings(ModelSettings, total=False):
158158
See https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching for more information.
159159
"""
160160

161+
anthropic_cache_tool_definitions_ttl: Literal['5m', '1h']
162+
"""The TTL for tool definitions cache control.
163+
164+
When enabled, the last tool in the `tools` array will have `cache_control` set,
165+
allowing Anthropic to cache tool definitions and reduce costs.
166+
See https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching for more information.
167+
"""
168+
161169
anthropic_cache_instructions: bool
162170
"""Whether to add `cache_control` to the last system prompt block.
163171
164172
When enabled, the last system prompt will have `cache_control` set,
165173
allowing Anthropic to cache system instructions and reduce costs.
166-
See https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching for more information.
174+
See https://docs.claude.com/en/docs/build-with-claude/prompt-caching#1-hour-cache-duration for more information.
175+
"""
176+
177+
anthropic_cache_instructions_ttl: Literal['5m', '1h']
178+
"""The TTL for system instructions cache control.
179+
180+
When enabled, the last system prompt will have `cache_control` set,
181+
allowing Anthropic to cache system instructions and reduce costs.
182+
See https://docs.claude.com/en/docs/build-with-claude/prompt-caching#1-hour-cache-duration for more information.
167183
"""
168184

169185

@@ -439,7 +455,9 @@ def _get_tools(
439455
# Add cache_control to the last tool if enabled
440456
if tools and model_settings.get('anthropic_cache_tool_definitions'):
441457
last_tool = tools[-1]
442-
last_tool['cache_control'] = BetaCacheControlEphemeralParam(type='ephemeral')
458+
last_tool['cache_control'] = BetaCacheControlEphemeralParam(
459+
type='ephemeral', ttl=model_settings.get('anthropic_cache_tool_definitions_ttl', '5m')
460+
)
443461

444462
return tools
445463

@@ -677,7 +695,11 @@ async def _map_message( # noqa: C901
677695
if system_prompt and model_settings.get('anthropic_cache_instructions'):
678696
system_prompt_blocks = [
679697
BetaTextBlockParam(
680-
type='text', text=system_prompt, cache_control=BetaCacheControlEphemeralParam(type='ephemeral')
698+
type='text',
699+
text=system_prompt,
700+
cache_control=BetaCacheControlEphemeralParam(
701+
type='ephemeral', ttl=model_settings.get('anthropic_cache_instructions_ttl', '5m')
702+
),
681703
)
682704
]
683705
return system_prompt_blocks, anthropic_messages

tests/models/test_anthropic.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,11 @@ async def test_cache_point_adds_cache_control(allow_model_requests: None):
314314
{
315315
'role': 'user',
316316
'content': [
317-
{'text': 'Some context to cache', 'type': 'text', 'cache_control': {'type': 'ephemeral'}},
317+
{
318+
'text': 'Some context to cache',
319+
'type': 'text',
320+
'cache_control': {'type': 'ephemeral', 'ttl': '5m'},
321+
},
318322
{'text': 'Now the question', 'type': 'text'},
319323
],
320324
}
@@ -339,8 +343,8 @@ async def test_cache_point_multiple_markers(allow_model_requests: None):
339343

340344
assert content == snapshot(
341345
[
342-
{'text': 'First chunk', 'type': 'text', 'cache_control': {'type': 'ephemeral'}},
343-
{'text': 'Second chunk', 'type': 'text', 'cache_control': {'type': 'ephemeral'}},
346+
{'text': 'First chunk', 'type': 'text', 'cache_control': {'type': 'ephemeral', 'ttl': '5m'}},
347+
{'text': 'Second chunk', 'type': 'text', 'cache_control': {'type': 'ephemeral', 'ttl': '5m'}},
344348
{'text': 'Question', 'type': 'text'},
345349
]
346350
)
@@ -389,7 +393,7 @@ async def test_cache_point_with_image_content(allow_model_requests: None):
389393
{
390394
'source': {'type': 'url', 'url': 'https://example.com/image.jpg'},
391395
'type': 'image',
392-
'cache_control': {'type': 'ephemeral'},
396+
'cache_control': {'type': 'ephemeral', 'ttl': '5m'},
393397
},
394398
{'text': 'What is in this image?', 'type': 'text'},
395399
]
@@ -466,7 +470,7 @@ def tool_two() -> str: # pragma: no cover
466470
'name': 'tool_two',
467471
'description': '',
468472
'input_schema': {'additionalProperties': False, 'properties': {}, 'type': 'object'},
469-
'cache_control': {'type': 'ephemeral'},
473+
'cache_control': {'type': 'ephemeral', 'ttl': '5m'},
470474
},
471475
]
472476
)
@@ -496,7 +500,7 @@ async def test_anthropic_cache_instructions(allow_model_requests: None):
496500
{
497501
'type': 'text',
498502
'text': 'This is a test system prompt with instructions.',
499-
'cache_control': {'type': 'ephemeral'},
503+
'cache_control': {'type': 'ephemeral', 'ttl': '5m'},
500504
}
501505
]
502506
)
@@ -540,12 +544,12 @@ def my_tool(value: str) -> str: # pragma: no cover
540544
'required': ['value'],
541545
'type': 'object',
542546
},
543-
'cache_control': {'type': 'ephemeral'},
547+
'cache_control': {'type': 'ephemeral', 'ttl': '5m'},
544548
}
545549
]
546550
)
547551
assert system == snapshot(
548-
[{'type': 'text', 'text': 'System instructions to cache.', 'cache_control': {'type': 'ephemeral'}}]
552+
[{'type': 'text', 'text': 'System instructions to cache.', 'cache_control': {'type': 'ephemeral', 'ttl': '5m'}}]
549553
)
550554

551555

0 commit comments

Comments
 (0)