[Bugfix] Add Responses cache_write_tokens for API compat and CC parity (#57222)

Signed-off-by: Yifan Zong <yzong@redhat.com> Co-authored-by: Flora Feng <4florafeng@gmail.com>

yzong-rh committed Sep 16, 2026 at 17:52 UTC 5a6ccc589281b4302791cc301e258adcbcc5fead
5 files changed +17
tests/entrypoints/openai/responses/test_serving_responses.py
+7
@@ -18,6 +18,9 @@ from openai.types.responses import (
18 ResponseTextConfig,
19 ResponseTextDeltaEvent,
20 )
21 +from openai.types.responses import (
22 + ResponseUsage as OpenAIResponseUsage,
23 +)
24 from openai.types.responses.response_format_text_json_schema_config import (
25 ResponseFormatTextJSONSchemaConfig,
26 )
@@ -975,6 +978,7 @@ async def test_reasoning_tokens_counted_for_text_reasoning_model(monkeypatch):
978 outputs=[completion],
979 finished=True,
980 num_cached_tokens=0,
981 + num_cache_creation_tokens=3,
982 )
983 context.append_output(req_output)
984
@@ -995,6 +999,9 @@ async def test_reasoning_tokens_counted_for_text_reasoning_model(monkeypatch):
999 )
1000
1001 assert response.usage.output_tokens_details.reasoning_tokens == 1
1002 + assert response.usage.input_tokens_details.cache_write_tokens == 3
1003 +
1004 + OpenAIResponseUsage.model_validate(response.usage.model_dump(mode="json"))
1005
1006
1007 class TestExtractAllowedToolsFromMcpRequests:
tests/entrypoints/unit_tests/test_context.py
+5
@@ -682,6 +682,7 @@ def create_simple_context_output(
682 prompt="Test prompt",
683 prompt_token_ids=None,
684 num_cached_tokens=0,
685 + num_cache_creation_tokens=None,
686 logprobs=None,
687 finished=True,
688 ):
@@ -707,6 +708,7 @@ def create_simple_context_output(
708 ],
709 finished=finished,
710 num_cached_tokens=num_cached_tokens,
711 + num_cache_creation_tokens=num_cache_creation_tokens,
712 )
713
714
@@ -827,6 +829,7 @@ def test_simple_context_token_counting():
829 token_ids=[10, 11],
830 prompt_token_ids=[1, 2, 3, 4, 5],
831 num_cached_tokens=2,
832 + num_cache_creation_tokens=3,
833 )
834 )
835 context.append_output(
@@ -835,12 +838,14 @@ def test_simple_context_token_counting():
838 token_ids=[12],
839 prompt_token_ids=[1, 2, 3, 4, 5],
840 num_cached_tokens=2,
841 + num_cache_creation_tokens=3,
842 )
843 )
844
845 assert context.num_prompt_tokens == 5
846 assert context.num_output_tokens == 3 # 2 + 1
847 assert context.num_cached_tokens == 2
848 + assert context.num_cache_creation_tokens == 3
849
850
851 def test_simple_context_final_output():
vllm/entrypoints/openai/responses/context.py
+3
@@ -189,6 +189,7 @@ class SimpleContext(ConversationContext):
189 self.num_prompt_tokens = 0
190 self.num_output_tokens = 0
191 self.num_cached_tokens = 0
192 + self.num_cache_creation_tokens = 0
193 # todo num_reasoning_tokens is not implemented yet.
194 self.num_reasoning_tokens = 0
195 # not implemented yet for SimpleContext
@@ -204,6 +205,8 @@ class SimpleContext(ConversationContext):
205 raise ValueError("SimpleContext only supports RequestOutput.")
206 self.num_prompt_tokens = len(output.prompt_token_ids or [])
207 self.num_cached_tokens = output.num_cached_tokens or 0
208 + if output.num_cache_creation_tokens is not None:
209 + self.num_cache_creation_tokens = output.num_cache_creation_tokens
210 self.num_output_tokens += len(output.outputs[0].token_ids or [])
211 if output.kv_transfer_params is not None:
212 self.kv_transfer_params = output.kv_transfer_params
vllm/entrypoints/openai/responses/protocol.py
+1
@@ -80,6 +80,7 @@ _INT64_MAX = 2**63 - 1
80
81 class InputTokensDetails(OpenAIBaseModel):
82 cached_tokens: int
83 + cache_write_tokens: int
84 input_tokens_per_turn: list[int] = Field(default_factory=list)
85 cached_tokens_per_turn: list[int] = Field(default_factory=list)
86
vllm/entrypoints/openai/responses/serving.py
+1
@@ -837,6 +837,7 @@ class OpenAIServingResponses(GenerateBaseServing):
837 output_tokens=num_generated_tokens,
838 total_tokens=num_prompt_tokens + num_generated_tokens,
839 input_tokens_details=InputTokensDetails(
840 + cache_write_tokens=getattr(context, "num_cache_creation_tokens", 0),
841 cached_tokens=num_cached_tokens,
842 input_tokens_per_turn=[
843 turn.input_tokens for turn in context.all_turn_metrics