From edc597ab23149ed698f6a641600513d9cc2ce71f Mon Sep 17 00:00:00 2001 From: LaoYueHanNi Date: Tue, 9 Jun 2026 20:30:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20Completions=E8=BD=ACAnthro?= =?UTF-8?q?pic=E6=97=B6=E4=B8=8D=E8=AE=B0=E5=BD=95=E5=AE=9E=E9=99=85?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E6=A8=A1=E5=9E=8B=E3=80=81Input=20token?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98=20(#2774?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(proxy): 修复completions转claude格式流式响应未记录实际命中模型 * style: cargo fmt fix * fix(proxy): 修复completions转claude格式时input与cache_read重复计费 * fix(proxy): 修复完全缓存命中时input_tokens计算错误 * test: 更新input_tokens期望值匹配去重逻辑 --- src-tauri/src/proxy/handlers.rs | 7 ++++--- src-tauri/src/proxy/providers/streaming.rs | 15 ++++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src-tauri/src/proxy/handlers.rs b/src-tauri/src/proxy/handlers.rs index 93a51e65c..9b216a123 100644 --- a/src-tauri/src/proxy/handlers.rs +++ b/src-tauri/src/proxy/handlers.rs @@ -333,7 +333,7 @@ async fn handle_claude_transform( let usage_collector = if usage_logging_enabled(state) { let state = state.clone(); let provider_id = ctx.provider.id.clone(); - let model = ctx.request_model.clone(); + let request_model = ctx.request_model.clone(); let status_code = status.as_u16(); let start_time = ctx.start_time; let session_id = ctx.session_id.clone(); @@ -343,11 +343,12 @@ async fn handle_claude_transform( Some(claude_stream_usage_event_filter), move |events, first_token_ms| { if let Some(usage) = TokenUsage::from_claude_stream_events(&events) { + let model = usage.model.clone().unwrap_or(request_model.clone()); let latency_ms = start_time.elapsed().as_millis() as u64; let state = state.clone(); let provider_id = provider_id.clone(); - let model = model.clone(); let session_id = session_id.clone(); + let request_model = request_model.clone(); tokio::spawn(async move { log_usage( @@ -355,7 +356,7 @@ async fn handle_claude_transform( &provider_id, "claude", &model, - &model, + &request_model, usage, latency_ms, first_token_ms, diff --git a/src-tauri/src/proxy/providers/streaming.rs b/src-tauri/src/proxy/providers/streaming.rs index 150d29f99..b68a2d522 100644 --- a/src-tauri/src/proxy/providers/streaming.rs +++ b/src-tauri/src/proxy/providers/streaming.rs @@ -100,11 +100,14 @@ struct ToolBlockState { const INFINITE_WHITESPACE_THRESHOLD: usize = 500; fn build_anthropic_usage_json(usage: &Usage) -> Value { + // OpenAI prompt_tokens 含缓存,Anthropic input_tokens 不含,需减去 + let cached = extract_cache_read_tokens(usage).unwrap_or(0); + let input_tokens = usage.prompt_tokens.saturating_sub(cached); let mut usage_json = json!({ - "input_tokens": usage.prompt_tokens, + "input_tokens": input_tokens, "output_tokens": usage.completion_tokens }); - if let Some(cached) = extract_cache_read_tokens(usage) { + if cached > 0 { usage_json["cache_read_input_tokens"] = json!(cached); } if let Some(created) = usage.cache_creation_input_tokens { @@ -223,8 +226,10 @@ pub fn create_anthropic_sse_stream( "output_tokens": 0 }); if let Some(u) = &chunk.usage { - start_usage["input_tokens"] = json!(u.prompt_tokens); - if let Some(cached) = extract_cache_read_tokens(u) { + let cached = extract_cache_read_tokens(u).unwrap_or(0); + let input = u.prompt_tokens.saturating_sub(cached); + start_usage["input_tokens"] = json!(input); + if cached > 0 { start_usage["cache_read_input_tokens"] = json!(cached); } if let Some(created) = u.cache_creation_input_tokens { @@ -1022,7 +1027,7 @@ mod tests { message_delta .pointer("/usage/input_tokens") .and_then(|v| v.as_u64()), - Some(13312) + Some(13212) ); assert_eq!( message_delta