|
17 | 17 | import base64
|
18 | 18 | import json
|
19 | 19 | import logging
|
| 20 | +import os |
| 21 | +import re |
20 | 22 | from typing import Any
|
21 | 23 | from typing import AsyncGenerator
|
22 | 24 | from typing import cast
|
|
29 | 31 | from typing import Tuple
|
30 | 32 | from typing import TypedDict
|
31 | 33 | from typing import Union
|
| 34 | +import warnings |
32 | 35 |
|
33 | 36 | from google.genai import types
|
34 | 37 | import litellm
|
@@ -672,6 +675,67 @@ def _build_request_log(req: LlmRequest) -> str:
|
672 | 675 | """
|
673 | 676 |
|
674 | 677 |
|
| 678 | +def _is_litellm_gemini_model(model_string: str) -> bool: |
| 679 | + """Check if the model is a Gemini model accessed via LiteLLM. |
| 680 | +
|
| 681 | + Args: |
| 682 | + model_string: A LiteLLM model string (e.g., "gemini/gemini-2.5-pro" or |
| 683 | + "vertex_ai/gemini-1.5-flash") |
| 684 | +
|
| 685 | + Returns: |
| 686 | + True if it's a Gemini model accessed via LiteLLM, False otherwise |
| 687 | + """ |
| 688 | + # Matches "gemini/gemini-*" (Google AI Studio) or "vertex_ai/gemini-*" (Vertex AI). |
| 689 | + pattern = r"^(gemini|vertex_ai)/gemini-" |
| 690 | + return bool(re.match(pattern, model_string)) |
| 691 | + |
| 692 | + |
| 693 | +def _extract_gemini_model_from_litellm(litellm_model: str) -> str: |
| 694 | + """Extract the pure Gemini model name from a LiteLLM model string. |
| 695 | +
|
| 696 | + Args: |
| 697 | + litellm_model: LiteLLM model string like "gemini/gemini-2.5-pro" |
| 698 | +
|
| 699 | + Returns: |
| 700 | + Pure Gemini model name like "gemini-2.5-pro" |
| 701 | + """ |
| 702 | + # Remove LiteLLM provider prefix |
| 703 | + if "/" in litellm_model: |
| 704 | + return litellm_model.split("/", 1)[1] |
| 705 | + return litellm_model |
| 706 | + |
| 707 | + |
| 708 | +def _warn_gemini_via_litellm(model_string: str) -> None: |
| 709 | + """Warn if Gemini is being used via LiteLLM. |
| 710 | +
|
| 711 | + This function logs a warning suggesting users use Gemini directly rather than |
| 712 | + through LiteLLM for better performance and features. |
| 713 | +
|
| 714 | + Args: |
| 715 | + model_string: The LiteLLM model string to check |
| 716 | + """ |
| 717 | + if not _is_litellm_gemini_model(model_string): |
| 718 | + return |
| 719 | + |
| 720 | + # Check if warning should be suppressed via environment variable |
| 721 | + if os.environ.get( |
| 722 | + "ADK_SUPPRESS_GEMINI_LITELLM_WARNINGS", "" |
| 723 | + ).strip().lower() in ("1", "true", "yes", "on"): |
| 724 | + return |
| 725 | + |
| 726 | + warnings.warn( |
| 727 | + f"[GEMINI_VIA_LITELLM] {model_string}: You are using Gemini via LiteLLM." |
| 728 | + " For better performance, reliability, and access to latest features," |
| 729 | + " consider using Gemini directly through ADK's native Gemini" |
| 730 | + f" integration. Replace LiteLlm(model='{model_string}') with" |
| 731 | + f" Gemini(model='{_extract_gemini_model_from_litellm(model_string)}')." |
| 732 | + " Set ADK_SUPPRESS_GEMINI_LITELLM_WARNINGS=true to suppress this" |
| 733 | + " warning.", |
| 734 | + category=UserWarning, |
| 735 | + stacklevel=3, |
| 736 | + ) |
| 737 | + |
| 738 | + |
675 | 739 | class LiteLlm(BaseLlm):
|
676 | 740 | """Wrapper around litellm.
|
677 | 741 |
|
@@ -708,6 +772,8 @@ def __init__(self, model: str, **kwargs):
|
708 | 772 | **kwargs: Additional arguments to pass to the litellm completion api.
|
709 | 773 | """
|
710 | 774 | super().__init__(model=model, **kwargs)
|
| 775 | + # Warn if using Gemini via LiteLLM |
| 776 | + _warn_gemini_via_litellm(model) |
711 | 777 | self._additional_args = kwargs
|
712 | 778 | # preventing generation call with llm_client
|
713 | 779 | # and overriding messages, tools and stream which are managed internally
|
|
0 commit comments