open-webui/backend/open_webui/utils
Claude c98e8decd4
fix: correct cache-token accounting and stream_options handling in Anthropic-compat usage
Adversarial review of the previous commit surfaced three defects:

- Cached tokens were double counted: OpenAI's prompt_tokens includes
  cached tokens while Anthropic's input_tokens excludes them (total
  input = input_tokens + cache_creation_input_tokens +
  cache_read_input_tokens). The converter passed the inclusive count
  through as input_tokens while also emitting the cache fields, so a
  {prompt_tokens: 1000, cached_tokens: 800} response claimed 1800 input
  tokens to Anthropic clients. Cache counts are now subtracted whenever
  the input count is derived from prompt_tokens; an Anthropic-native
  input_tokens key is taken as already exclusive.
- A model with stream_response=Off flips the stream flag after the
  payload conversion injected stream_options, and upstreams like OpenAI
  and vLLM reject stream:false requests carrying stream_options with
  HTTP 400. The OpenAI router now drops stream_options from any
  non-streaming payload before sending; this also covers the
  pre-existing variant where the web UI sends stream_options for models
  with the usage capability enabled.
- The streaming usage capture lacked the null/zero hardening the
  non-streaming path already had: explicit null token values leaked
  JSON null into message_delta usage (breaking schema-validating
  Anthropic SDK clients), and a reported 0 (e.g. Ollama omitting
  prompt_eval_count for KV-cached prompts) clobbered the pre-counted
  input_tokens. Both paths now share one hardened extraction helper
  that treats missing/null/0 counts as unreported.

Ref: https://github.com/open-webui/docs/issues/1328

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119K4sbiCAFKq9rFaS6i5ij
2026-07-21 15:02:45 +00:00
..
access_control chore: format 2026-07-20 22:11:42 -04:00
images refac 2026-07-01 02:48:29 -05:00
mcp refac 2026-06-29 11:56:00 -05:00
telemetry refac(telemetry): drop deprecated semconv SpanAttributes subclass (#25784) 2026-06-29 02:05:34 -05:00
actions.py refac 2026-07-09 17:28:34 -05:00
anthropic.py fix: correct cache-token accounting and stream_options handling in Anthropic-compat usage 2026-07-21 15:02:45 +00:00
asgi_middleware.py refac 2026-06-17 02:52:35 +02:00
audit.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
auth.py refac 2026-07-20 19:49:34 -04:00
automations.py refac 2026-07-16 01:34:50 -04:00
calendar.py feat: add repeat/recurrence dropdown to calendar event modal (#25865) 2026-06-29 02:16:19 -05:00
channels.py refac 2026-03-17 17:58:01 -05:00
chat.py Enforce per-model access on arena fallback before bypass_filter dispatch (#26046) 2026-06-16 22:45:42 +02:00
code_interpreter.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
context_compaction.py chore: format 2026-07-20 22:11:42 -04:00
embeddings.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
files.py perf(images): offload validate_url() DNS resolution with asyncio.to_thread (#25825) 2026-06-29 02:31:24 -05:00
filter.py refac 2026-07-09 17:28:34 -05:00
groups.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
headers.py feat: forward client User-Agent to model backends via {{USER_AGENT}} placeholder (#26333) 2026-06-29 05:58:19 -05:00
logger.py chore: format 2026-06-01 13:56:55 -07:00
memory.py refac 2026-07-01 03:35:46 -05:00
middleware.py refac 2026-07-16 02:47:51 -04:00
misc.py refac 2026-06-29 13:03:14 -05:00
models.py refac 2026-07-09 17:28:34 -05:00
notifications.py refac 2026-07-16 01:37:21 -04:00
oauth.py refac 2026-07-01 02:57:29 -05:00
payload.py refac 2026-06-29 00:18:40 -05:00
pdf_generator.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
plugin.py refac 2026-07-09 17:28:34 -05:00
rate_limit.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
redis.py fix(redis): use await asyncio.sleep() instead of time.sleep() in async generator (#25823) 2026-06-29 02:25:46 -05:00
response.py refac 2026-06-23 23:35:44 +02:00
sanitize.py refac 2026-03-17 17:58:01 -05:00
security_headers.py fix: convert SecurityHeadersMiddleware to pure ASGI (#26924) 2026-07-10 13:29:14 -05:00
session_pool.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
subagents.py chore: format 2026-07-20 22:11:42 -04:00
task.py refac 2026-06-19 00:16:06 +02:00
terminals.py refac 2026-07-10 18:32:21 -05:00
timers.py chore: format 2026-07-20 22:11:42 -04:00
tools.py refac 2026-07-16 00:58:34 -04:00
validate.py chore: format 2026-06-01 13:56:55 -07:00
valves.py refac 2026-06-29 12:29:10 -05:00
webhook.py refac 2026-06-29 13:03:14 -05:00