diff --git a/ddtrace/llmobs/_integrations/openai.py b/ddtrace/llmobs/_integrations/openai.py index c3abcd7c446..d122a5936cf 100644 --- a/ddtrace/llmobs/_integrations/openai.py +++ b/ddtrace/llmobs/_integrations/openai.py @@ -4,6 +4,7 @@ from ddtrace.internal.constants import COMPONENT from ddtrace.internal.logger import get_logger from ddtrace.llmobs._constants import CACHE_READ_INPUT_TOKENS_METRIC_KEY +from ddtrace.llmobs._constants import CACHE_WRITE_INPUT_TOKENS_METRIC_KEY from ddtrace.llmobs._constants import INPUT_TOKENS_METRIC_KEY from ddtrace.llmobs._constants import OUTPUT_TOKENS_METRIC_KEY from ddtrace.llmobs._constants import PROXY_REQUEST @@ -230,6 +231,9 @@ def _extract_llmobs_metrics_tags( cached_tokens = _get_attr(prompt_tokens_details, "cached_tokens", None) if cached_tokens is not None: metrics[CACHE_READ_INPUT_TOKENS_METRIC_KEY] = cached_tokens + cache_write_tokens = _get_attr(prompt_tokens_details, "cache_write_tokens", None) + if cache_write_tokens is not None: + metrics[CACHE_WRITE_INPUT_TOKENS_METRIC_KEY] = cache_write_tokens # Chat completion returns `completion_tokens_details` while responses api returns `output_tokens_details` reasoning_output_tokens_details = _get_attr(token_usage, "completion_tokens_details", {}) or _get_attr( token_usage, "output_tokens_details", {} diff --git a/releasenotes/notes/openai-cache-write-tokens-1a880b4309652378.yaml b/releasenotes/notes/openai-cache-write-tokens-1a880b4309652378.yaml new file mode 100644 index 00000000000..78f7e528b93 --- /dev/null +++ b/releasenotes/notes/openai-cache-write-tokens-1a880b4309652378.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + LLM Observability: This fixes an issue where cache write input tokens were not captured by the OpenAI integration when using newer models that include cache write token charges. diff --git a/tests/contrib/openai/cassettes/v1/chat_completion_prompt_caching_5_6_cache_write.yaml b/tests/contrib/openai/cassettes/v1/chat_completion_prompt_caching_5_6_cache_write.yaml new file mode 100644 index 00000000000..984787a1b7f --- /dev/null +++ b/tests/contrib/openai/cassettes/v1/chat_completion_prompt_caching_5_6_cache_write.yaml @@ -0,0 +1,200 @@ +interactions: +- request: + body: '{"messages":[{"role":"system","content":"You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer "},{"role":"user","content":"What are the + best practices for API design?"}],"model":"gpt-5.6-sol","max_completion_tokens":100}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate, zstd + Connection: + - keep-alive + Content-Length: + - '7367' + Content-Type: + - application/json + Host: + - api.openai.com + User-Agent: + - OpenAI/Python 2.32.0 + X-Stainless-Arch: + - arm64 + X-Stainless-Async: + - 'false' + X-Stainless-Lang: + - python + X-Stainless-OS: + - MacOS + X-Stainless-Package-Version: + - 2.32.0 + X-Stainless-Runtime: + - CPython + X-Stainless-Runtime-Version: + - 3.13.7 + x-stainless-read-timeout: + - '600' + x-stainless-retry-count: + - '0' + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAA/3VSy27DIBC8+ysszknkPJ321kNuVXurVFWRRWBj02KwYJ20ivLvBRLbRE0vSOzs + LLPDnJI0JYKTx5SwiiKrGzneZE/w2mbZYrPUanew62c0b4f8uH55VzMy8gy9+wSGHWvCtOMBCq0u + MDNAEfzUab6e59nDarEOQK05SE8rGxwvJ6ux1fJKqbRgYB324a5pegqnF6c4fLtyNuoqNVhLS3C1 + rskVjZa+Qqi1wiJVSEYDyLRCUEFvXDawby31elQrZQRQpTRSv08QtL0i517CXihhq8Ktad3ObqwE + VWJFAn525zYs1d7oJI1xPmGB+gvC4Olsdt2KDA5GcNah6NTICJj3vJuRBQekQtrIGcIoq4AP3MHG + gBRHIxBiSdO876AtFzqiJpEJfxXfe/1ikFDlna3uPDAAjEHjElQ0Brhgt74MbQZ8DP9r6z8jSCYW + zMFFrEABxn8Zhz1t5SUnxP5YhLpw/1qCaYwIYfGpSM7JL8Z6UzckAwAA + headers: + Access-Control-Expose-Headers: + - CF-Ray + CF-Cache-Status: + - DYNAMIC + CF-Ray: + - a191c6768b40425d-EWR + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Fri, 10 Jul 2026 18:54:12 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + - CF-Ray + alt-svc: + - h3=":443"; ma=86400 + openai-organization: + - datadog-4 + openai-processing-ms: + - '4355' + openai-project: + - proj_6cMiry5CHgK3zKotG0LtMb9H + openai-version: + - '2020-10-01' + set-cookie: + - __cf_bm=tZJcDUefN9G7GCUT4gj9nLfCgTACPkVFoTzE12Icf2s-1783709648.4058647-1.0.1.1-ewWSiLx9Yfb5R9zJCF_BKSi8upd5ydk3Sn.lHDNs1FBd0eSli2ycKMJhqqOhQbjHuggo6r.FSzVC_Hz33Rgt7XVmP2XDYGZHVQttl3ZyuzjJ1rT9IGfBb4WLbPqZGeqt; + HttpOnly; SameSite=None; Secure; Path=/; Domain=api.openai.com; Expires=Fri, + 10 Jul 2026 19:24:12 GMT + x-openai-proxy-wasm: + - v0.1 + x-ratelimit-limit-requests: + - '15000' + x-ratelimit-limit-tokens: + - '40000000' + x-ratelimit-remaining-requests: + - '14999' + x-ratelimit-remaining-tokens: + - '39998186' + x-ratelimit-reset-requests: + - 4ms + x-ratelimit-reset-tokens: + - 2ms + x-request-id: + - req_ed1692f28b27414ebc298d2b377f052d + status: + code: 200 + message: OK +version: 1 diff --git a/tests/contrib/openai/cassettes/v1/responses_prompt_caching_5_6_cache_write.yaml b/tests/contrib/openai/cassettes/v1/responses_prompt_caching_5_6_cache_write.yaml new file mode 100644 index 00000000000..ef407f96eb4 --- /dev/null +++ b/tests/contrib/openai/cassettes/v1/responses_prompt_caching_5_6_cache_write.yaml @@ -0,0 +1,195 @@ +interactions: +- request: + body: '{"input":"What are the best practices for API design?","instructions":"You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer You are + an expert software engineer You are an expert software engineer You are an expert + software engineer You are an expert software engineer You are an expert software + engineer You are an expert software engineer You are an expert software engineer + You are an expert software engineer You are an expert software engineer You + are an expert software engineer You are an expert software engineer ","max_output_tokens":100,"model":"gpt-5.6-sol"}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate, zstd + Connection: + - keep-alive + Content-Length: + - '7319' + Content-Type: + - application/json + Cookie: + - __cf_bm=tZJcDUefN9G7GCUT4gj9nLfCgTACPkVFoTzE12Icf2s-1783709648.4058647-1.0.1.1-ewWSiLx9Yfb5R9zJCF_BKSi8upd5ydk3Sn.lHDNs1FBd0eSli2ycKMJhqqOhQbjHuggo6r.FSzVC_Hz33Rgt7XVmP2XDYGZHVQttl3ZyuzjJ1rT9IGfBb4WLbPqZGeqt + Host: + - api.openai.com + User-Agent: + - OpenAI/Python 2.32.0 + X-Stainless-Arch: + - arm64 + X-Stainless-Async: + - 'false' + X-Stainless-Lang: + - python + X-Stainless-OS: + - MacOS + X-Stainless-Package-Version: + - 2.32.0 + X-Stainless-Runtime: + - CPython + X-Stainless-Runtime-Version: + - 3.13.7 + x-stainless-read-timeout: + - '600' + x-stainless-retry-count: + - '0' + method: POST + uri: https://api.openai.com/v1/responses + response: + body: + string: !!binary | + H4sIAAAAAAAA/+yQQW6DMBBF9z2FxbqqbAgEepOu0AQG5MYZU3vcJop699qEih6hCy/n/zd/vn1/ + EqLQY/EqCod+6SUeqqmsDrIsO1WpSaoGalVNY1u1sm1VV7YSpVQ1HEqomxOUxXOKsKd3HPg3xpLH + hz44BMaxh+SpY1sdZdfUzep5Bg4+7Wga7GUxyNvWCYbz7GygVGwC4/Eha2M0zVG7xzEKC9zQpYAR + P9HYJQ7R+H5c3hK32xSMWXV0zrq/wuTwIyANt35BAsO3aMoXuXp7sX5EBm38fjy+zFtK1y9w7W3g + JXDP9ozk9xaaPLswsI5fktA3GwQ4FEACr7EvC28n/koS0qwJ0YnMZCYzmclMZjKTmcxkJjP/lvkB + AAD//+1aO2/bMBDe8ysEZTOcQHJtx+5WoECRrXtTCJR4solIpEBSdj34v/dISpTkR9oCHZkpuvt4 + 76OHjwETMAETMAETMAETMAETMAETMAETMAETMP+EcfznNaH4OUqTxOu0EFVWkMrSkZ7IrAWFypCM + u0Y/rZ7XT0pUsddIYkjIMd55QMkPS2g6WnOgg9UHZDBslokhg0mxLNerfLVK0oS8bDfWnTWiTw04 + OtiwpIa19apCcA3cOv7phaqtayJPVmhl5/mtqGq1ux/WtnjZFiasfLHBkNZlkSZ0vaWL67BqUIrs + YFDcJaMvQ+5EQ2QTu33X4Jf2py2AcC406XngIXGrrMSukSK/obGG0O43IWj05ftrREGxHY9q8g7K + TJKRzWaNBMoKTfIK5hEGq5gy8c4jBUUrUQYHUR2cmnAaYVNOkRaRocyJhtns+Y2/8cfHKH2OvjoP + xPLv1lhb42S2CqKCKFAG+RS9UrTPyhMCcH6PQr6XlTiqKIfSCCiUzHQdJ5s2gnFtOXH3d+7+G5rf + 7NGwSRMPkSojXB1BDtWXorJaokxeBPvw0NuxNuKGSFwGqKaLoWXr3g1gdRTwAm4Q/Kg6MNGqrH+2 + kNk58zuCbakbjSaLPWTvcLqrk2AK7jYsXiz3bvGG6ffPBuwouaZinJluJU6ESzWGEoun3XxS1ta9 + 3OyvkZrkKZG0lw9LY4Lyjw4UKUGfMBPbIgaT5w4K5IFhLTTrn06UpK3ctKIDbN7kzYWG2s5Ia+Vp + V7Yugy4lDLomw/doHSxuvM7xAWQuFLNN6LP0gbv27QXGZ+vTahEPitZurPfKavzMdsDHjhmfXJrJ + /Jbi6i3HyN710S7dkaZTnL3xy7s6ua357341XinVJaCv9BHyTAGRxX5cIN7WmX3wovToyKQDwzWE + n002upwSL2zsDm03TiBbXvQ/LzFlylw0bkjjy6ZN+5MuFl2+f2pQ7NbsKJmG8fn0ZT5B0HvluPN7 + +hc9GrZ4OL1aToxfNCL9tEh8SfHinCxgjQ4o0cR4OD+cfwMbOAnfgiUAAA== + headers: + Access-Control-Expose-Headers: + - CF-Ray + CF-Cache-Status: + - DYNAMIC + CF-Ray: + - a191c6a62c402e7a-EWR + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Fri, 10 Jul 2026 18:54:18 GMT + Server: + - cloudflare + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + - CF-Ray + alt-svc: + - h3=":443"; ma=86400 + openai-organization: + - datadog-4 + openai-processing-ms: + - '2449' + openai-project: + - proj_6cMiry5CHgK3zKotG0LtMb9H + openai-version: + - '2020-10-01' + x-request-id: + - req_52ba3534e6e0406abd04d9bb92a1ab54 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/contrib/openai/test_openai_llmobs.py b/tests/contrib/openai/test_openai_llmobs.py index df0a5e446c3..6cf19cc987b 100644 --- a/tests/contrib/openai/test_openai_llmobs.py +++ b/tests/contrib/openai/test_openai_llmobs.py @@ -1555,6 +1555,42 @@ def test_chat_completion_prompt_caching(self, openai, openai_llmobs, test_spans) tags={"ml_app": "", "service": "tests.contrib.openai", "integration": "openai"}, ) + def test_chat_completion_prompt_caching_cache_write(self, openai, openai_llmobs, test_spans): + """Test that cache write token metrics are captured for models that report them. + + Newer OpenAI models (GPT-5.6+) report ``cache_write_tokens`` on + ``usage.prompt_tokens_details`` for the chat completions API. + """ + model = "gpt-5.6-sol" + client = openai.OpenAI() + base_messages = [{"role": "system", "content": "You are an expert software engineer " * 200}] + with get_openai_vcr(subdirectory_name="v1").use_cassette("chat_completion_prompt_caching_5_6_cache_write.yaml"): + resp = client.chat.completions.create( + model=model, + messages=base_messages + [{"role": "user", "content": "What are the best practices for API design?"}], + ) + spans = [s for trace in test_spans.pop_traces() for s in trace] + assert len(spans) == 1 + + assert_llmobs_span_data( + _get_llmobs_data_metastruct(spans[0]), + span_kind="llm", + name="OpenAI.createChatCompletion", + model_name=resp.model, + model_provider="openai", + input_messages=base_messages + [{"role": "user", "content": "What are the best practices for API design?"}], + output_messages=[{"role": "assistant", "content": mock.ANY}], + metrics={ + "input_tokens": 1220, + "output_tokens": 100, + "total_tokens": 1320, + "cache_read_input_tokens": 0, + "cache_write_input_tokens": 1217, + "reasoning_output_tokens": 100, + }, + tags={"ml_app": "", "service": "tests.contrib.openai", "integration": "openai"}, + ) + def test_embedding_string(self, openai, openai_llmobs, test_spans): with get_openai_vcr(subdirectory_name="v1").use_cassette("embedding.yaml"): client = openai.OpenAI() @@ -2299,6 +2335,45 @@ def test_responses_prompt_caching(self, openai, openai_llmobs, test_spans): tags={"ml_app": "", "service": "tests.contrib.openai", "integration": "openai"}, ) + @pytest.mark.skipif( + parse_version(openai_module.version.VERSION) < (1, 66), reason="Response options only available openai >= 1.66" + ) + def test_responses_prompt_caching_cache_write(self, openai, openai_llmobs, test_spans): + """Test that cache write token metrics are captured for the responses API. + + Newer OpenAI models (GPT-5.6+) report ``cache_write_tokens`` on + ``usage.input_tokens_details`` for the responses API. + """ + client = openai.OpenAI() + model = "gpt-5.6-sol" + base_instructions = "You are an expert software engineer " * 200 + with get_openai_vcr(subdirectory_name="v1").use_cassette("responses_prompt_caching_5_6_cache_write.yaml"): + resp = client.responses.create( + model=model, + instructions=base_instructions, + input="What are the best practices for API design?", + max_output_tokens=100, + ) + spans = [s for trace in test_spans.pop_traces() for s in trace] + assert len(spans) == 1 + + assert_llmobs_span_data( + _get_llmobs_data_metastruct(spans[0]), + span_kind="llm", + name="OpenAI.createResponse", + model_name=resp.model, + model_provider="openai", + metrics={ + "input_tokens": 1220, + "output_tokens": 100, + "total_tokens": 1320, + "cache_read_input_tokens": 0, + "cache_write_input_tokens": 1217, + "reasoning_output_tokens": 54, + }, + tags={"ml_app": "", "service": "tests.contrib.openai", "integration": "openai"}, + ) + @pytest.mark.skipif( parse_version(openai_module.version.VERSION) < (1, 66), reason="Response options only available openai >= 1.66" ) @@ -3128,11 +3203,14 @@ def test_shadow_tags_chat_completion_with_cache_tokens(tracer): response.usage.completion_tokens = 10 response.usage.total_tokens = 60 response.usage.prompt_tokens_details.cached_tokens = 12 + response.usage.prompt_tokens_details.cache_write_tokens = 34 # responses-API style fallback: input_tokens_details.cached_tokens response.usage.input_tokens_details.cached_tokens = 12 + response.usage.input_tokens_details.cache_write_tokens = 34 with tracer.trace("openai.request") as span: span._set_attribute("openai.response.model", "gpt-4o-mini") integration._set_apm_shadow_tags(span, [], {}, response=response, operation="chat") assert span.get_metric("_dd.llmobs.cache_read_input_tokens") == 12 + assert span.get_metric("_dd.llmobs.cache_write_input_tokens") == 34