@@ -124,7 +124,7 @@ async def test_handle_context_caching_no_existing_cache(self):
124124 assert result .invocations_used is None
125125 assert result .created_at is None
126126 assert result .fingerprint == "test_fp"
127- assert result .contents_count == 5 # Total contents count
127+ assert result .contents_count == 0
128128
129129 # No cache should be created
130130 self .manager .genai_client .aio .caches .create .assert_not_called ()
@@ -233,7 +233,7 @@ async def test_handle_context_caching_invalid_cache_fingerprint_mismatch(
233233 assert result .invocations_used is None
234234 assert result .created_at is None
235235 assert result .fingerprint == "new_fp"
236- assert result .contents_count == 5 # Total contents count
236+ assert result .contents_count == 0
237237 mock_cleanup .assert_called_once_with (existing_cache .cache_name )
238238 self .manager .genai_client .aio .caches .create .assert_not_called ()
239239
@@ -584,7 +584,7 @@ async def test_cache_creation_with_sufficient_token_count(self):
584584 assert result is not None
585585 assert result .cache_name is None # Fingerprint-only state
586586 assert result .fingerprint == "test_fp"
587- assert result .contents_count == 3
587+ assert result .contents_count == 0
588588 self .manager .genai_client .aio .caches .create .assert_not_called ()
589589
590590 async def test_cache_creation_with_insufficient_token_count (self ):
@@ -752,12 +752,10 @@ async def test_multi_turn_fingerprint_stable_when_below_token_threshold(
752752 contents_counts_seen .append (result .contents_count )
753753 metadata = result
754754
755- # First turn has no metadata, so uses total (1).
756- # Subsequent turns preserve contents_count=1 from the prefix.
757- # Fingerprint stays stable because contents[:1] is always the
758- # same user message.
755+ # All contents in this helper are user-role messages, so there is no
756+ # cacheable content prefix before the final user batch.
759757 assert len (set (fingerprints_seen )) == 1
760- assert contents_counts_seen == [1 , 1 , 1 ]
758+ assert contents_counts_seen == [0 , 0 , 0 ]
761759
762760 async def test_contents_count_should_remain_stable_after_cache_creation_failure (
763761 self ,
@@ -911,7 +909,7 @@ async def test_fingerprint_only_metadata_transitions_to_active_cache(
911909
912910 assert result_1 is not None
913911 assert result_1 .cache_name is None
914- assert result_1 .contents_count == 3
912+ assert result_1 .contents_count == 0
915913
916914 # --- Second LLM call: carry forward fingerprint-only metadata ---
917915 # Contents grew but we still have same prefix
@@ -948,6 +946,73 @@ async def test_fingerprint_only_metadata_transitions_to_active_cache(
948946 assert result_2 .cache_name == (
949947 "projects/test/locations/us-central1/cachedContents/new789"
950948 )
951- assert result_2 .contents_count == 3 # Preserved from prefix
949+ assert result_2 .contents_count == 0 # Preserved from prefix
950+ assert result_2 .invocations_used == 1
951+ self .manager .genai_client .aio .caches .create .assert_called_once ()
952+
953+ async def test_dynamic_instruction_does_not_break_initial_cache_fingerprint (
954+ self ,
955+ ):
956+ """Request-scoped dynamic instructions stay out of the cache prefix."""
957+ dynamic_instruction = types .Content (
958+ role = "user" , parts = [types .Part (text = "Turn context: locale=en-US" )]
959+ )
960+ user_msg = types .Content (
961+ role = "user" , parts = [types .Part (text = "what time is it?" )]
962+ )
963+ model_tool_call = types .Content (
964+ role = "model" ,
965+ parts = [
966+ types .Part (
967+ function_call = types .FunctionCall (name = "get_time" , args = {})
968+ )
969+ ],
970+ )
971+ tool_response = types .Content (
972+ role = "user" ,
973+ parts = [
974+ types .Part (
975+ function_response = types .FunctionResponse (
976+ name = "get_time" , response = {"time" : "12:00" }
977+ )
978+ )
979+ ],
980+ )
981+
982+ request_1 = self .create_llm_request (contents_count = 0 )
983+ request_1 .contents = [dynamic_instruction , user_msg ]
984+
985+ result_1 = await self .manager .handle_context_caching (request_1 )
986+
987+ assert result_1 is not None
988+ assert result_1 .cache_name is None
989+ assert result_1 .contents_count == 0
990+
991+ request_2 = self .create_llm_request (
992+ cache_metadata = result_1 , contents_count = 0
993+ )
994+ request_2 .contents = [
995+ user_msg ,
996+ model_tool_call ,
997+ dynamic_instruction ,
998+ tool_response ,
999+ ]
1000+ request_2 .cacheable_contents_token_count = 4096
1001+
1002+ mock_cached_content = AsyncMock ()
1003+ mock_cached_content .name = (
1004+ "projects/test/locations/us-central1/cachedContents/new789"
1005+ )
1006+ self .manager .genai_client .aio .caches .create = AsyncMock (
1007+ return_value = mock_cached_content
1008+ )
1009+
1010+ result_2 = await self .manager .handle_context_caching (request_2 )
1011+
1012+ assert result_2 is not None
1013+ assert result_2 .cache_name == (
1014+ "projects/test/locations/us-central1/cachedContents/new789"
1015+ )
1016+ assert result_2 .contents_count == 0
9521017 assert result_2 .invocations_used == 1
9531018 self .manager .genai_client .aio .caches .create .assert_called_once ()
0 commit comments