diff --git a/src-tauri/src/proxy/providers/streaming_gemini.rs b/src-tauri/src/proxy/providers/streaming_gemini.rs index 67f2f7852..0a81d0c4c 100644 --- a/src-tauri/src/proxy/providers/streaming_gemini.rs +++ b/src-tauri/src/proxy/providers/streaming_gemini.rs @@ -5,8 +5,8 @@ use super::gemini_shadow::{GeminiShadowStore, GeminiToolCallMeta}; use super::transform_gemini::{ - is_synthesized_tool_call_id, rectify_tool_call_parts, synthesize_tool_call_id, - AnthropicToolSchemaHints, + build_anthropic_usage, is_synthesized_tool_call_id, rectify_tool_call_parts, + synthesize_tool_call_id, AnthropicToolSchemaHints, }; use crate::proxy::sse::{append_utf8_safe, strip_sse_field, take_sse_block}; use bytes::Bytes; @@ -15,39 +15,6 @@ use serde_json::{json, Value}; use std::collections::HashSet; use std::sync::Arc; -fn anthropic_usage_from_gemini(usage: Option<&Value>) -> Value { - let Some(usage) = usage else { - return json!({ - "input_tokens": 0, - "output_tokens": 0 - }); - }; - - let input_tokens = usage - .get("promptTokenCount") - .and_then(|value| value.as_u64()) - .unwrap_or(0); - let total_tokens = usage - .get("totalTokenCount") - .and_then(|value| value.as_u64()) - .unwrap_or(0); - let output_tokens = total_tokens.saturating_sub(input_tokens); - - let mut result = json!({ - "input_tokens": input_tokens, - "output_tokens": output_tokens - }); - - if let Some(cached) = usage - .get("cachedContentTokenCount") - .and_then(|value| value.as_u64()) - { - result["cache_read_input_tokens"] = json!(cached); - } - - result -} - fn map_finish_reason(reason: Option<&str>, has_tool_use: bool, blocked: bool) -> &'static str { if blocked { return "refusal"; @@ -309,7 +276,7 @@ pub fn create_anthropic_sse_stream_from_gemini) -> Result, ProxyEr } } -fn build_anthropic_usage(usage: Option<&Value>) -> Value { +/// Convert a Gemini `usageMetadata` object into an Anthropic-style `usage` +/// object. Used by both the streaming SSE converter and the non-streaming +/// transform path so the two emit identical shapes. +pub(crate) fn build_anthropic_usage(usage: Option<&Value>) -> Value { let Some(usage) = usage else { return json!({ "input_tokens": 0,