diff --git a/backend/app/services/llm_service.py b/backend/app/services/llm_service.py index 12d58931..01014486 100755 --- a/backend/app/services/llm_service.py +++ b/backend/app/services/llm_service.py @@ -188,19 +188,25 @@ class LLMService: @staticmethod def _extract_usage_metadata(response, provider: str) -> dict: """Extract token counts from a provider response. All fields default to 0.""" + _log = logging.getLogger(__name__) if provider == 'gemini': um = getattr(response, 'usage_metadata', None) if um is None: + _log.warning("Gemini response missing usage_metadata — token counts will be 0, cost recorded as $0") return {'prompt': 0, 'completion': 0, 'cached': 0, 'reasoning': 0} + # thoughts_token_count (thinking models) is already included in candidates_token_count. + # Capture it separately so the stored event can show the split. + thoughts = getattr(um, 'thoughts_token_count', 0) or 0 return { 'prompt': getattr(um, 'prompt_token_count', 0) or 0, 'completion': getattr(um, 'candidates_token_count', 0) or 0, 'cached': getattr(um, 'cached_content_token_count', 0) or 0, - 'reasoning': 0, + 'reasoning': thoughts, } elif provider == 'openai': usage = getattr(response, 'usage', None) if usage is None: + _log.warning("OpenAI response missing usage — token counts will be 0, cost recorded as $0") return {'prompt': 0, 'completion': 0, 'cached': 0, 'reasoning': 0} # Responses API (gpt-5.4-2026-03-05) if hasattr(usage, 'input_tokens'):