diff --git a/litellm/llms/gemini/common_utils.py b/litellm/llms/gemini/common_utils.py index f20f904596d..0ad95ee57db 100644 --- a/litellm/llms/gemini/common_utils.py +++ b/litellm/llms/gemini/common_utils.py @@ -511,11 +511,15 @@ class GoogleAIStudioTokenCounter(BaseTokenCounter): "model": model_to_use, "contents": payload.contents if payload is not None else contents, **( - {"system_instruction": payload.system_instruction} + {"system_instruction": payload.system_instruction} # mutable-ok: kwargs dict for acount_tokens if payload is not None and payload.system_instruction is not None - else {} + else {} # mutable-ok: kwargs dict for acount_tokens + ), + **( + {"tools": payload.tools} # mutable-ok: kwargs dict for acount_tokens + if payload is not None and payload.tools is not None + else {} # mutable-ok: kwargs dict for acount_tokens ), - **({"tools": payload.tools} if payload is not None and payload.tools is not None else {}), } count_tokens_params_request.update(count_tokens_params) try: diff --git a/litellm/llms/gemini/count_tokens/handler.py b/litellm/llms/gemini/count_tokens/handler.py index d055b7ce5ff..ed75c9d5507 100644 --- a/litellm/llms/gemini/count_tokens/handler.py +++ b/litellm/llms/gemini/count_tokens/handler.py @@ -135,14 +135,16 @@ class GoogleAIStudioTokenCounter: # Prepare request body - clean up contents to remove unsupported fields cleaned_contents: Final = self._clean_contents_for_gemini_api(contents) request_body: Final = ( - {"contents": cleaned_contents} + {"contents": cleaned_contents} # mutable-ok: httpx json body takes a plain dict if system_instruction is None and tools is None - else { - "generateContentRequest": { + else { # mutable-ok: httpx json body takes a plain dict + "generateContentRequest": { # mutable-ok: httpx json body takes a plain dict "model": f"models/{model}", "contents": cleaned_contents, - **({"systemInstruction": system_instruction} if system_instruction is not None else {}), - **({"tools": tools} if tools is not None else {}), + **( # mutable-ok: httpx json body takes a plain dict + {"systemInstruction": system_instruction} if system_instruction is not None else {} + ), + **({"tools": tools} if tools is not None else {}), # mutable-ok: httpx json body takes a plain dict } } ) diff --git a/litellm/llms/gemini/count_tokens/transformation.py b/litellm/llms/gemini/count_tokens/transformation.py index 25380ab625a..8e2c4a66ee2 100644 --- a/litellm/llms/gemini/count_tokens/transformation.py +++ b/litellm/llms/gemini/count_tokens/transformation.py @@ -30,13 +30,13 @@ def build_count_tokens_payload( system: object | None, tools: Sequence[Mapping[str, object]] | None, ) -> GeminiCountTokensPayload: - anthropic_request: Final[AnthropicMessagesRequest] = cast( - AnthropicMessagesRequest, # cast-ok: untrusted client payload, adapter reads the anthropic-shape keys only - { + anthropic_request: Final[AnthropicMessagesRequest] = cast( # cast-ok: adapter reads only the keys supplied + AnthropicMessagesRequest, + { # mutable-ok: transient request dict for the anthropic adapter "model": model, - "messages": list(messages), - **({"system": system} if system else {}), - **({"tools": list(tools)} if tools else {}), + "messages": list(messages), # mutable-ok: adapter contract takes a list of messages + **({"system": system} if system else {}), # mutable-ok: transient request dict for the anthropic adapter + **({"tools": list(tools)} if tools else {}), # mutable-ok: transient request dict for the anthropic adapter }, ) openai_request, _ = LiteLLMAnthropicMessagesAdapter().translate_anthropic_to_openai( @@ -44,7 +44,7 @@ def build_count_tokens_payload( ) system_instruction, remaining_messages = _transform_system_message( supports_system_message=True, - messages=list(openai_request["messages"]), + messages=list(openai_request["messages"]), # mutable-ok: helper pops the leading system message ) contents: Final = _gemini_convert_messages_with_history( messages=remaining_messages, @@ -52,10 +52,16 @@ def build_count_tokens_payload( custom_llm_provider="gemini", ) openai_tools: Final = openai_request.get("tools") + gemini_tools: Final = ( + VertexGeminiConfig()._map_function( + value=[dict(tool) for tool in openai_tools], # mutable-ok: _map_function takes plain tool dicts + optional_params={}, # mutable-ok: _map_function signature takes a dict + ) + if openai_tools + else None + ) return GeminiCountTokensPayload( contents=contents, system_instruction=system_instruction, - tools=VertexGeminiConfig()._map_function(value=[dict(tool) for tool in openai_tools], optional_params={}) - if openai_tools - else None, + tools=gemini_tools, )