@tanstack/openai-base: Responses usage drops input_tokens_details.cache_write_tokens
Maintainer thường phản hồi trong vòng 1 ngày
@tombeckenham đang làm issue này rồi.
Từ ngày 13/10/2026.
Đánh giá
Issue này chưa được đánh giá.
Mô tả
Package / version: @tanstack/openai-base 0.13.1 via @tanstack/ai-openai 0.29.1, @tanstack/ai 0.68.0, openai 7.32.0, Node 24.20.0. The same code is on main.
Summary
buildResponsesUsage in packages/openai-base/src/usage.ts reads input_tokens_details.cached_tokens and ignores input_tokens_details.cache_write_tokens. A Responses API call that writes the prompt cache reports the written count, and OpenAI prices cache writes separately from uncached input on current models, but the number never reaches TokenUsage.promptTokensDetails.cacheWriteTokens. Anything that meters spend from usage under-counts every call that primes a cache.
buildChatCompletionsUsage in the same file already maps the field (prompt_tokens_details.cache_write_tokens → cacheWriteTokens), so the two paths disagree. The openai SDK types cache_write_tokens as a required member of ResponseUsage.input_tokens_details.
Reproduction
import { chat } from '@tanstack/ai'
import { createOpenaiChat } from '@tanstack/ai-openai'
import OpenAI from 'openai'
const MODEL = 'gpt-6-luna'
// A system prompt past the 1024-token caching floor. A fresh nonce makes each prompt a first
// sighting, so the call writes the cache instead of reading it.
const filler = 'The quarterly report covers revenue, margin, churn, headcount, and regional growth across every business unit. '
const fresh = () => `You answer in one word. Session ${crypto.randomUUID()}.\n\n${filler.repeat(90)}`
const question = 'What colour is the sky on a clear day?'
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
const raw = await client.responses.create({ model: MODEL, instructions: fresh(), input: question })
console.log('raw Responses usage, fresh prompt =', JSON.stringify(raw.usage))
const adapter = createOpenaiChat(MODEL, process.env.OPENAI_API_KEY)
for await (const c of chat({ adapter, systemPrompts: [fresh()], messages: [{ role: 'user', content: question }] })) {
if (c.type === 'RUN_FINISHED') console.log('RUN_FINISHED usage, fresh prompt =', JSON.stringify(c.usage))
}
Observed
raw Responses usage, fresh prompt = {"input_tokens":1941,"input_tokens_details":{"cache_write_tokens":1938,"cached_tokens":0},"output_tokens":5,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":1946}
RUN_FINISHED usage, fresh prompt = {"promptTokens":1944,"completionTokens":18,"totalTokens":1962,"completionTokensDetails":{"reasoningTokens":11}}
OpenAI reports 1938 tokens written to the cache. The RUN_FINISHED usage has no promptTokensDetails at all.
A second call with the same prompt comes back with cached_tokens: 1914 and the adapter does surface that one as promptTokensDetails.cachedTokens, so only the write side is missing.
Expected
usage.promptTokensDetails.cacheWriteTokens equal to input_tokens_details.cache_write_tokens, as the Chat Completions path does.
Cause and fix
buildResponsesUsage only copies cached_tokens (packages/openai-base/src/usage.ts, around line 111 on main). I'm carrying this as a local patch to the built file, the same shape as the cachedTokens block above it, in case it saves whoever picks this up a minute:
const cacheWriteTokens = usage.input_tokens_details?.cache_write_tokens
if (cacheWriteTokens && cacheWriteTokens > 0) {
result.promptTokensDetails = {
...result.promptTokensDetails,
cacheWriteTokens,
}
}
Do you intend to try to help solve this bug with your own PR? No, because I do not have time to dig into it. The hunk above is the fix as far as I can tell; I won't be sending a PR.
- I agree to follow this project's Code of Conduct
- I understand that if my bug cannot be reliably reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.
- Ngôn ngữ chính
- TypeScript
- Star
- 3.2k
- Fork
- 361
- Merge trung bình
- 1 ngày 13 giờ
- Pull request đã merge (30 ngày)
- 241
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của TanStack/ai
-
decide() drops billed usage when a call fails after the provider respondedCó thể đã có người làm @tombeckenham đã nhận 1 ngày trước. Đang mởhas-pr waiting-on: maintainer
TanStack/ai#1741 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
chat(): sign the state of a suspended run so a resume without persistence cannot change itCó thể đã có người làm @AlemTuzlak đã nhận 1 ngày trước. Đang mởwaiting-on: maintainer
TanStack/ai#1740 · 2 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
@tanstack/ai-anthropic: a stream that fails after message_start loses the call's input usageCó thể đã có người làm @AlemTuzlak đã nhận 1 ngày trước. Đang mởwaiting-on: maintainer
TanStack/ai#1735 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
summarize() sends temperature 0.3 to models that reject sampling parameters (e.g. claude-sonnet-5-5)Có thể đã có người làm @jherr đã nhận 4 ngày trước. Đang mởhas-pr waiting-on: maintainer
TanStack/ai#1703 · 1 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
ai-openrouter: malformed Chat Completions tool arguments execute as an empty objectCó thể đã có người làm @tombeckenham đã nhận 4 ngày trước. Đang mởhas-pr waiting-on: maintainer
TanStack/ai#1689 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
Maintainer thường phản hồi trong vòng 1 ngày
-
high priority
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
CI-CMG/deep-sea-corals-exb#84 · 1 bình luận ·
-
Create/import wallet form shows raw "password must be at least 1 characters" instead of the translated messageCó thể đã có người làm @CapThunder19 đã nhận hôm nay. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
joinmarket-webui/jam#1538 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
t0ggles
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
nolimits4web/swiper#8240 · 1 bình luận ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
Maintainer thường phản hồi trong vòng 1 ngày