Skip to content

Commit

Permalink
Litellm remove circular imports (#7232)
Browse files Browse the repository at this point in the history
* fix(utils.py): initial commit to remove circular imports - moves llmproviders to utils.py

* fix(router.py): fix 'litellm.EmbeddingResponse' import from router.py

'

* refactor: fix litellm.ModelResponse import on pass through endpoints

* refactor(litellm_logging.py): fix circular import for custom callbacks literal

* fix(factory.py): fix circular imports inside prompt factory

* fix(cost_calculator.py): fix circular import for 'litellm.Usage'

* fix(proxy_server.py): fix potential circular import with `litellm.Router'

* fix(proxy/utils.py): fix potential circular import in `litellm.Router`

* fix: remove circular imports in 'auth_checks' and 'guardrails/'

* fix(prompt_injection_detection.py): fix router impor t

* fix(vertex_passthrough_logging_handler.py): fix potential circular imports in vertex pass through

* fix(anthropic_pass_through_logging_handler.py): fix potential circular imports

* fix(slack_alerting.py-+-ollama_chat.py): fix modelresponse import

* fix(base.py): fix potential circular import

* fix(handler.py): fix potential circular ref in codestral + cohere handler's

* fix(azure.py): fix potential circular imports

* fix(gpt_transformation.py): fix modelresponse import

* fix(litellm_logging.py): add logging base class - simplify typing

makes it easy for other files to type check the logging obj without introducing circular imports

* fix(azure_ai/embed): fix potential circular import on handler.py

* fix(databricks/): fix potential circular imports in databricks/

* fix(vertex_ai/): fix potential circular imports on vertex ai embeddings

* fix(vertex_ai/image_gen): fix import

* fix(watsonx-+-bedrock): cleanup imports

* refactor(anthropic-pass-through-+-petals): cleanup imports

* refactor(huggingface/): cleanup imports

* fix(ollama-+-clarifai): cleanup circular imports

* fix(openai_like/): fix impor t

* fix(openai_like/): fix embedding handler

cleanup imports

* refactor(openai.py): cleanup imports

* fix(sagemaker/transformation.py): fix import

* ci(config.yml): add circular import test to ci/cd
  • Loading branch information
krrishdholakia authored Dec 15, 2024
1 parent 0dbf712 commit 516c2a6
Show file tree
Hide file tree
Showing 48 changed files with 489 additions and 256 deletions.
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,7 @@ jobs:
- run: python ./tests/documentation_tests/test_api_docs.py
- run: python ./tests/code_coverage_tests/ensure_async_clients_test.py
- run: python ./tests/code_coverage_tests/enforce_llms_folder_style.py
- run: python ./tests/documentation_tests/test_circular_imports.py
- run: helm lint ./deploy/charts/litellm-helm

db_migration_disable_update_check:
Expand Down
3 changes: 0 additions & 3 deletions enterprise/enterprise_hooks/secret_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,12 +474,9 @@ async def async_pre_call_hook(
from detect_secrets import SecretsCollection
from detect_secrets.settings import default_settings

print("INSIDE SECRET DETECTION PRE-CALL HOOK!")

if await self.should_run_check(user_api_key_dict) is False:
return

print("RUNNING CHECK!")
if "messages" in data and isinstance(data["messages"], list):
for message in data["messages"]:
if "content" in message and isinstance(message["content"], str):
Expand Down
67 changes: 1 addition & 66 deletions litellm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
KeyManagementSettings,
LiteLLM_UpperboundKeyGenerateParams,
)
from litellm.types.utils import StandardKeyGenerationConfig
from litellm.types.utils import StandardKeyGenerationConfig, LlmProviders
import httpx
import dotenv
from enum import Enum
Expand Down Expand Up @@ -838,71 +838,6 @@ def add_known_models():
)


class LlmProviders(str, Enum):
OPENAI = "openai"
OPENAI_LIKE = "openai_like" # embedding only
JINA_AI = "jina_ai"
XAI = "xai"
CUSTOM_OPENAI = "custom_openai"
TEXT_COMPLETION_OPENAI = "text-completion-openai"
COHERE = "cohere"
COHERE_CHAT = "cohere_chat"
CLARIFAI = "clarifai"
ANTHROPIC = "anthropic"
ANTHROPIC_TEXT = "anthropic_text"
REPLICATE = "replicate"
HUGGINGFACE = "huggingface"
TOGETHER_AI = "together_ai"
OPENROUTER = "openrouter"
VERTEX_AI = "vertex_ai"
VERTEX_AI_BETA = "vertex_ai_beta"
GEMINI = "gemini"
AI21 = "ai21"
BASETEN = "baseten"
AZURE = "azure"
AZURE_TEXT = "azure_text"
AZURE_AI = "azure_ai"
SAGEMAKER = "sagemaker"
SAGEMAKER_CHAT = "sagemaker_chat"
BEDROCK = "bedrock"
VLLM = "vllm"
NLP_CLOUD = "nlp_cloud"
PETALS = "petals"
OOBABOOGA = "oobabooga"
OLLAMA = "ollama"
OLLAMA_CHAT = "ollama_chat"
DEEPINFRA = "deepinfra"
PERPLEXITY = "perplexity"
MISTRAL = "mistral"
GROQ = "groq"
NVIDIA_NIM = "nvidia_nim"
CEREBRAS = "cerebras"
AI21_CHAT = "ai21_chat"
VOLCENGINE = "volcengine"
CODESTRAL = "codestral"
TEXT_COMPLETION_CODESTRAL = "text-completion-codestral"
DEEPSEEK = "deepseek"
SAMBANOVA = "sambanova"
MARITALK = "maritalk"
VOYAGE = "voyage"
CLOUDFLARE = "cloudflare"
XINFERENCE = "xinference"
FIREWORKS_AI = "fireworks_ai"
FRIENDLIAI = "friendliai"
WATSONX = "watsonx"
WATSONX_TEXT = "watsonx_text"
TRITON = "triton"
PREDIBASE = "predibase"
DATABRICKS = "databricks"
EMPOWER = "empower"
GITHUB = "github"
CUSTOM = "custom"
LITELLM_PROXY = "litellm_proxy"
HOSTED_VLLM = "hosted_vllm"
LM_STUDIO = "lm_studio"
GALADRIEL = "galadriel"


provider_list: List[Union[LlmProviders, str]] = list(LlmProviders)


Expand Down
4 changes: 2 additions & 2 deletions litellm/adapters/anthropic_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
AnthropicResponse,
ContentBlockDelta,
)
from litellm.types.utils import AdapterCompletionStreamWrapper
from litellm.types.utils import AdapterCompletionStreamWrapper, ModelResponse


class AnthropicAdapter(CustomLogger):
Expand All @@ -41,7 +41,7 @@ def translate_completion_input_params(
return translated_body

def translate_completion_output_params(
self, response: litellm.ModelResponse
self, response: ModelResponse
) -> Optional[AnthropicResponse]:

return litellm.AnthropicExperimentalPassThroughConfig().translate_openai_response_to_anthropic(
Expand Down
4 changes: 2 additions & 2 deletions litellm/cost_calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,15 +484,15 @@ def completion_cost( # noqa: PLR0915
completion_characters: Optional[int] = None
cache_creation_input_tokens: Optional[int] = None
cache_read_input_tokens: Optional[int] = None
cost_per_token_usage_object: Optional[litellm.Usage] = _get_usage_object(
cost_per_token_usage_object: Optional[Usage] = _get_usage_object(
completion_response=completion_response
)
if completion_response is not None and (
isinstance(completion_response, BaseModel)
or isinstance(completion_response, dict)
): # tts returns a custom class

usage_obj: Optional[Union[dict, litellm.Usage]] = completion_response.get( # type: ignore
usage_obj: Optional[Union[dict, Usage]] = completion_response.get( # type: ignore
"usage", {}
)
if isinstance(usage_obj, BaseModel) and not isinstance(
Expand Down
3 changes: 2 additions & 1 deletion litellm/integrations/SlackAlerting/slack_alerting.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
VirtualKeyEvent,
WebhookEvent,
)
from litellm.router import Router
from litellm.types.integrations.slack_alerting import *
from litellm.types.router import LiteLLM_Params

Expand Down Expand Up @@ -93,7 +94,7 @@ def update_values(
alert_types: Optional[List[AlertType]] = None,
alert_to_webhook_url: Optional[Dict[AlertType, Union[List[str], str]]] = None,
alerting_args: Optional[Dict] = None,
llm_router: Optional[litellm.Router] = None,
llm_router: Optional[Router] = None,
):
if alerting is not None:
self.alerting = alerting
Expand Down
8 changes: 5 additions & 3 deletions litellm/litellm_core_utils/litellm_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import litellm
from litellm import (
_custom_logger_compatible_callbacks_literal,
json_logs,
log_raw_request_response,
turn_off_message_logging,
Expand All @@ -41,6 +42,7 @@
CallTypes,
EmbeddingResponse,
ImageResponse,
LiteLLMLoggingBaseClass,
ModelResponse,
StandardCallbackDynamicParams,
StandardLoggingAdditionalHeaders,
Expand Down Expand Up @@ -190,7 +192,7 @@ def set_cache(self, credentials: dict, service_name: str, logging_obj: Any) -> N
in_memory_dynamic_logger_cache = DynamicLoggingCache()


class Logging:
class Logging(LiteLLMLoggingBaseClass):
global supabaseClient, promptLayerLogger, weightsBiasesLogger, logfireLogger, capture_exception, add_breadcrumb, lunaryLogger, logfireLogger, prometheusLogger, slack_app
custom_pricing: bool = False
stream_options = None
Expand Down Expand Up @@ -2142,7 +2144,7 @@ def set_callbacks(callback_list, function_id=None): # noqa: PLR0915


def _init_custom_logger_compatible_class( # noqa: PLR0915
logging_integration: litellm._custom_logger_compatible_callbacks_literal,
logging_integration: _custom_logger_compatible_callbacks_literal,
internal_usage_cache: Optional[DualCache],
llm_router: Optional[
Any
Expand Down Expand Up @@ -2362,7 +2364,7 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915


def get_custom_logger_compatible_class( # noqa: PLR0915
logging_integration: litellm._custom_logger_compatible_callbacks_literal,
logging_integration: _custom_logger_compatible_callbacks_literal,
) -> Optional[CustomLogger]:
if logging_integration == "lago":
for callback in _in_memory_loggers:
Expand Down
36 changes: 16 additions & 20 deletions litellm/litellm_core_utils/prompt_templates/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import litellm
import litellm.types
import litellm.types.llms
import litellm.types.llms.vertex_ai
from litellm import verbose_logger
from litellm.llms.custom_httpx.http_handler import HTTPHandler
from litellm.types.completion import (
Expand All @@ -40,6 +39,9 @@
ChatCompletionUserMessage,
OpenAIMessageContentListBlock,
)
from litellm.types.llms.vertex_ai import FunctionCall as VertexFunctionCall
from litellm.types.llms.vertex_ai import FunctionResponse as VertexFunctionResponse
from litellm.types.llms.vertex_ai import PartType as VertexPartType
from litellm.types.utils import GenericImageParsingChunk

from .common_utils import convert_content_list_to_str, is_non_content_values_set
Expand Down Expand Up @@ -965,11 +967,11 @@ def infer_protocol_value(

def _gemini_tool_call_invoke_helper(
function_call_params: ChatCompletionToolCallFunctionChunk,
) -> Optional[litellm.types.llms.vertex_ai.FunctionCall]:
) -> Optional[VertexFunctionCall]:
name = function_call_params.get("name", "") or ""
arguments = function_call_params.get("arguments", "")
arguments_dict = json.loads(arguments)
function_call = litellm.types.llms.vertex_ai.FunctionCall(
function_call = VertexFunctionCall(
name=name,
args=arguments_dict,
)
Expand All @@ -978,7 +980,7 @@ def _gemini_tool_call_invoke_helper(

def convert_to_gemini_tool_call_invoke(
message: ChatCompletionAssistantMessage,
) -> List[litellm.types.llms.vertex_ai.PartType]:
) -> List[VertexPartType]:
"""
OpenAI tool invokes:
{
Expand Down Expand Up @@ -1019,22 +1021,20 @@ def convert_to_gemini_tool_call_invoke(
- json.load the arguments
"""
try:
_parts_list: List[litellm.types.llms.vertex_ai.PartType] = []
_parts_list: List[VertexPartType] = []
tool_calls = message.get("tool_calls", None)
function_call = message.get("function_call", None)
if tool_calls is not None:
for tool in tool_calls:
if "function" in tool:
gemini_function_call: Optional[
litellm.types.llms.vertex_ai.FunctionCall
] = _gemini_tool_call_invoke_helper(
function_call_params=tool["function"]
gemini_function_call: Optional[VertexFunctionCall] = (
_gemini_tool_call_invoke_helper(
function_call_params=tool["function"]
)
)
if gemini_function_call is not None:
_parts_list.append(
litellm.types.llms.vertex_ai.PartType(
function_call=gemini_function_call
)
VertexPartType(function_call=gemini_function_call)
)
else: # don't silently drop params. Make it clear to user what's happening.
raise Exception(
Expand All @@ -1047,11 +1047,7 @@ def convert_to_gemini_tool_call_invoke(
function_call_params=function_call
)
if gemini_function_call is not None:
_parts_list.append(
litellm.types.llms.vertex_ai.PartType(
function_call=gemini_function_call
)
)
_parts_list.append(VertexPartType(function_call=gemini_function_call))
else: # don't silently drop params. Make it clear to user what's happening.
raise Exception(
"function_call missing. Received tool call with 'type': 'function'. No function call in argument - {}".format(
Expand All @@ -1070,7 +1066,7 @@ def convert_to_gemini_tool_call_invoke(
def convert_to_gemini_tool_call_result(
message: Union[ChatCompletionToolMessage, ChatCompletionFunctionMessage],
last_message_with_tool_calls: Optional[dict],
) -> litellm.types.llms.vertex_ai.PartType:
) -> VertexPartType:
"""
OpenAI message with a tool result looks like:
{
Expand Down Expand Up @@ -1119,11 +1115,11 @@ def convert_to_gemini_tool_call_result(

# We can't determine from openai message format whether it's a successful or
# error call result so default to the successful result template
_function_response = litellm.types.llms.vertex_ai.FunctionResponse(
_function_response = VertexFunctionResponse(
name=name, response={"content": content_str} # type: ignore
)

_part = litellm.types.llms.vertex_ai.PartType(function_response=_function_response)
_part = VertexPartType(function_response=_function_response)

return _part

Expand Down
22 changes: 11 additions & 11 deletions litellm/llms/anthropic/experimental_pass_through/transformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
from openai.types.chat.chat_completion_chunk import Choice as OpenAIStreamingChoice

import litellm
from litellm.litellm_core_utils.prompt_templates.factory import (
anthropic_messages_pt,
custom_prompt,
prompt_factory,
)
from litellm.litellm_core_utils.streaming_handler import CustomStreamWrapper
from litellm.types.llms.anthropic import (
AllAnthropicToolsValues,
AnthopicMessagesAssistantMessageParam,
Expand Down Expand Up @@ -53,15 +59,9 @@
ChatCompletionUserMessage,
OpenAIMessageContent,
)
from litellm.types.utils import Choices, GenericStreamingChunk
from litellm.utils import CustomStreamWrapper, ModelResponse, Usage
from litellm.types.utils import Choices, GenericStreamingChunk, ModelResponse, Usage

from ...base import BaseLLM
from litellm.litellm_core_utils.prompt_templates.factory import (
anthropic_messages_pt,
custom_prompt,
prompt_factory,
)


class AnthropicExperimentalPassThroughConfig:
Expand Down Expand Up @@ -338,7 +338,7 @@ def _translate_openai_finish_reason_to_anthropic(
return "end_turn"

def translate_openai_response_to_anthropic(
self, response: litellm.ModelResponse
self, response: ModelResponse
) -> AnthropicResponse:
## translate content block
anthropic_content = self._translate_openai_content_to_anthropic(choices=response.choices) # type: ignore
Expand All @@ -347,7 +347,7 @@ def translate_openai_response_to_anthropic(
openai_finish_reason=response.choices[0].finish_reason # type: ignore
)
# extract usage
usage: litellm.Usage = getattr(response, "usage")
usage: Usage = getattr(response, "usage")
anthropic_usage = AnthropicResponseUsageBlock(
input_tokens=usage.prompt_tokens or 0,
output_tokens=usage.completion_tokens or 0,
Expand Down Expand Up @@ -393,7 +393,7 @@ def _translate_streaming_openai_chunk_to_anthropic(
return "text_delta", ContentTextBlockDelta(type="text_delta", text=text)

def translate_streaming_openai_response_to_anthropic(
self, response: litellm.ModelResponse
self, response: ModelResponse
) -> Union[ContentBlockDelta, MessageBlockDelta]:
## base case - final chunk w/ finish reason
if response.choices[0].finish_reason is not None:
Expand All @@ -403,7 +403,7 @@ def translate_streaming_openai_response_to_anthropic(
),
)
if getattr(response, "usage", None) is not None:
litellm_usage_chunk: Optional[litellm.Usage] = response.usage # type: ignore
litellm_usage_chunk: Optional[Usage] = response.usage # type: ignore
elif (
hasattr(response, "_hidden_params")
and "usage" in response._hidden_params
Expand Down
Loading

0 comments on commit 516c2a6

Please sign in to comment.