litellm/litellm/main.py
Mateo Wang b39eadcb82
feat(openai)!: honor per-deployment workload identity on non-chat routes (#39966)
* feat(anthropic): workload identity federation and pluggable identity sources

Backend half of #38818 (internal copy of the fork PR #38013), rebuilt as one
commit on top of litellm_internal_staging without the dashboard changes.

Deployments on anthropic/ without a static api_key can exchange an OIDC
workload assertion for a short-lived sk-ant-oat01 token through a shared
RFC 7523 JWT-bearer engine. The assertion comes from a mounted token file,
an env token, a LiteLLM-signed issuer, or Keycloak, chosen per deployment,
per named credential, or through ANTHROPIC_IDENTITY_SOURCE. The federation
fields are server-owned: refused inline in request bodies and on
POST /model/new, proxy-admin only on credentials, and the token exchange
is pinned to api.anthropic.com unless LITELLM_ANTHROPIC_WIF_ALLOWED_HOSTS
adds a host. GET /credentials/{name}/jwks exports the public key set of a
LiteLLM-signed credential for the Claude Console.

The OpenAI federation trio from #39613 rides along on the backend side with
the same server-owned handling.

Fixes #28607
Resolves LIT-6107

Co-authored-by: derhornspieler <15236687+derhornspieler@users.noreply.github.com>

* fix(anthropic): let batch-result downloads mint from deployment params and accept host:port allowlist entries

The files handler enabled workload identity on batch-result downloads but never received the
deployment's litellm_params, so a deployment authenticating through a named credential could only
mint from process-wide env vars. It now threads litellm_params through to the auth header the way
the batch retrieve path already does.

LITELLM_ANTHROPIC_WIF_ALLOWED_HOSTS entries written as host:port were read by urlsplit as a scheme,
so the allowlist kept the raw entry while the exchange compared bare hostnames and refused the
gateway. Entries are now parsed as network locations whether or not they carry a scheme.

* fix(types): move the WIF kwargs key sets to a leaf module so the kwargs funnel imports without a cycle

* test(anthropic): pin case-insensitive matching of WIF exchange-host allowlist entries

* fix(anthropic): end workload identity federation errors without a period so the router suffix reads cleanly

* fix(proxy): decrypt stored litellm_params before the WIF write gate

* fix(proxy): hide WIF secret references from /health output

* fix(proxy): keep the proxy error shape on credential endpoint refusals

* fix(proxy): hide identity token file paths from /health output

* feat(openai): honor per-deployment workload identity on non-chat routes

Image generation, audio speech and transcription, moderation, text
completions, files, batches, and fine-tuning built their OpenAI client from
the env vars alone, so a keyless deployment carrying
openai_identity_provider_id, openai_service_account_id, and
openai_identity_token_file failed with the api_key error on every route
other than chat, Responses, and embeddings. Those handlers now build their
client through the shared workload identity resolver, and the managed batch
file-access credential extraction keeps the trio

* fix(openai): cache workload identity clients and let deployment identity outrank process-wide keys

Non-chat handlers built a fresh SDK client per call, so files, batches,
fine-tuning, text completion and sync moderation exchanged the OIDC token on
every request. The builders now reuse the cached workload identity client per
identity, base, timeout, retries and organization; static-key clients are
still built fresh.

A process-wide OPENAI_API_KEY (or litellm.api_key / litellm.openai_key) no
longer silently overrides a deployment's openai_identity_* params. An explicit
distinct api_key on the deployment or call still wins.

* fix(openai): keep shared workload identity clients on the process http session

The workload identity client is cached and shared across requests, so it must
never borrow the transport a single caller passed in. Static-key clients keep
using the caller's http client; federated clients always ride the process-wide
session. Also makes the http client helpers on BaseOpenAILLM public since the
builder now needs them from outside the class.

* test(openai): pin partial deployment identity beating the process key

* test(openai): type the managed-object invoke callback

* fix(anthropic): rename the federation workspace param so Bedrock's anthropic_workspace_id keeps working

The Bedrock Claude Platform route already reads anthropic_workspace_id from
optional_params, so banning that spelling as a server-owned federation
parameter broke a pre-existing client capability. The federation field is now
anthropic_federation_workspace_id (env ANTHROPIC_FEDERATION_WORKSPACE_ID),
which restores the base branch's behavior for Bedrock callers, drops the
Bedrock-specific hint from the refusal message, and deletes the unconditional
ban constant that no longer had a reader

* fix(auth): share one exchanged token across workers reading the same assertion

Anthropic accepts each identity assertion exactly once, so two uvicorn
workers reading the same token file both minting from it means the second
exchange is denied with jti_reused. Minted tokens now land in a per-user
0700 cache directory guarded by a file lock, so workers on the same host
reuse one exchange until the token expires or the assertion rotates. A 401
is only retried when the re-read assertion actually differs, and the denial
hint explains jti_reused. LITELLM_TOKEN_EXCHANGE_CACHE_DIR moves the cache
and an empty value disables it

* feat(openai): honor deployment workload identity on image edits, vector stores, containers, videos, and evals

The httpx-based OpenAI handlers built their Authorization header from the
deployment api_key or OPENAI_API_KEY alone, so a keyless deployment carrying
openai_identity_provider_id, openai_service_account_id, and
openai_identity_token_file sent "Bearer None". They now resolve the bearer
through resolve_openai_bearer_token, which exchanges the deployment's
identity token the same way the SDK-based routes do.

A deployment that carries only part of the identity trio now raises a 500
naming the missing field instead of silently falling back to the process
key, and the SDK client builders take a factory for the static-key http
client so the federated branch never touches litellm.client_session.

* fix: keep anthropic federation from being shadowed or leaked

An empty or whitespace-only ANTHROPIC_API_KEY counted as set, so a federated
deployment sent an empty x-api-key on every call instead of minting a token.
Blank values now read as unset, and a real static key on a federated deployment
logs once that it outranks federation and nothing is being federated.

The exchange-host allowlist matched hostnames only, so a second process on
another port of an allowed host was trusted with the workload's identity token.
An entry that names a port now trusts that port alone, while a bare host still
trusts every port.

The shared token store exists so the workers reading one projected token file do
not each spend its single-use jti. A source that mints its own assertion per
exchange shares nothing with another worker, so it no longer writes a live token
to disk for a lookup that can never hit.

* feat(openai): resolve per-deployment workload identity for the assistants routes

OpenAIAssistantsAPI built its OpenAI and AsyncOpenAI clients from a locals() scrape, so a deployment carrying openai_identity_provider_id, openai_service_account_id and openai_identity_token_file never exchanged a token. Thread litellm_params through the class and build both clients with the shared workload identity builders.

* fix: unlink a staged token file a failed write leaves behind

The 401 denial hint now also says federation ignores ANTHROPIC_WORKSPACE_ID, which the Bedrock Claude platform provider already reads.

* refactor: move anthropic jwks derivation behind a provider-owned tagged union

* feat(openai): resolve per-deployment workload identity for image variations

Build the image variations client through the shared workload identity
builders instead of scraping locals(), and give the async path the async
http session it was missing. Let a federation trio serve the model-less
batch fallback, and hold the standard LRU size of exchanged tokens.

* fix: unlink the staged token file when its write fails at close

A buffered write only reaches the disk when the handle closes, so a full disk surfaces at close and left the staging file behind holding a usable token.

* fix(anthropic): close the staging descriptor before writing the shared token file

* fix(wif): judge federation writes by what they set, not what is stored

The admin gate read the stored deployment, so a team admin lost edit, delete
and Test Connection on any deployment carrying federation params. It now
returns early unless the submitted fields touch the federation surface, and a
Test Connection probe that points the deployment at its own api_base is still
refused, with the 403 no longer wrapped into a 500

The rest of the same review pass: POST /model/new refuses only a blocking
value of `blocked`, so a client that always sends `blocked: false` is not
turned away; a request body can no longer pick which federated identity to
mint as by naming a stored credential; an advisory refresh the executor
refuses disarms the entry instead of wedging the identity until the follower
timeout; the static-key shadow warning resolves its env fallback inside the
cache instead of once per request; credential writes drop nulls before
storing them; the token exchange validates the endpoint URL before reading an
assertion and keeps refusing redirects across a client heal; /health hides
every server-owned federation field from non-admins; and the async create_file
and create_batch paths say which setting is missing when the provider resolves
no URL

* style(tests): keep two blank lines before the batch_cost_is_final block

* test(batches): type the workload identity fallback test fixtures

* fix(moderation): stop validating unrelated kwargs on the sync workload identity path

* fix(auth): refuse server-owned workload identity keys in array form and inside a client router config

* fix(openai): keep a deployment's own key ahead of workload identity on every route

Thread the caller's own api_key into the identity resolver for embedding, transcription, moderation,
image generation, and assistants so a deployment key equal to the process key still wins. A partial
identity trio now falls back to a configured static key, unset max_retries keeps the SDK default, and
/v1/decisions plus OpenAI count_tokens resolve the exchanged bearer for identity-only deployments

* fix(containers): pass deployment params to container file auth headers

Container file routes built their auth headers without the deployment's
litellm_params, so a keyless deployment with an OpenAI workload identity
sent Bearer None on upload, list, retrieve, delete and content calls

* fix(openai): keep process-wide key precedence and move token exchange off the event loop

Restore the merge base order where an explicit or process-wide OpenAI key wins over
federation, so exporting OPENAI_API_KEY keeps working the way it did before.

Run the header-building validate_environment calls (image edit, videos, containers,
vector stores, vector store files) and the decisions and System One request
preparation in a worker thread, so a slow token exchange no longer stalls the loop.

Federate realtime websocket sessions, live sessions, realtime client secrets and
transcription sessions, and the OpenAI moderation guardrail when no key is set.

* fix(openai): answer 401 for a partial identity trio and federate realtime health checks

A deployment with part of the workload identity trio and no static key now
fails as an auth error naming the missing params, so the router does not retry
it as a server error. The realtime health check sends the exchanged bearer for
a keyless federated OpenAI deployment, and API token counting reads the same
static keys as every other route before minting.

* fix(openai): keep local token counting without an identity trio and federate the moderation guardrail from its own config

* fix(openai): skip a partial-trio moderation guardrail and let vault keys win in token counting

* test(integration): refuse caller-chosen identity params in user_config and bracketed form keys

* fix(openai): send the honored secret manager key from SDK client builders

A deployment whose OPENAI_API_KEY lives only in the secret manager now sends that key
on image, assistants, files, batches, and other SDK-built routes instead of failing with
no api_key, matching what the workload identity resolver already treats as a static key

* test(openai): check the token exchange runs off the event loop instead of timing the loop

---------

Co-authored-by: derhornspieler <15236687+derhornspieler@users.noreply.github.com>
2026-10-16 22:25:15 +00:00

9117 lines
353 KiB
Python

# LiteLLM main module: public completion, embedding, streaming, and moderation entrypoints.
#
# +-----------------------------------------------+
# | |
# | Give Feedback / Get Help |
# | https://github.com/BerriAI/litellm/issues/new |
# | |
# +-----------------------------------------------+
#
# Thank you ! We ❤️ you! - Krrish & Ishaan
import asyncio
import contextvars
import datetime
import inspect
import json
import os
import random
import sys
import time
import traceback
from collections.abc import AsyncIterator, Callable, Coroutine, Iterable, Mapping, Sequence
from concurrent import futures
from concurrent.futures import FIRST_COMPLETED, ThreadPoolExecutor, wait
from copy import deepcopy
from functools import partial
from types import MappingProxyType
from typing import TYPE_CHECKING, Any, Final, Literal, Optional, Protocol, Union, cast, get_args
from litellm._logging import redact_string
from litellm._uuid import uuid
if TYPE_CHECKING:
from aiohttp import ClientSession
import dotenv
import httpx
import openai
from pydantic import BaseModel, TypeAdapter, ValidationError
from typing_extensions import assert_never, overload
import litellm
# client must be imported from litellm as it's a decorator used at function definition time
from litellm import client
from litellm.types.llms.base import LiteLLMBaseModel
# Other utils are imported directly to avoid circular imports
from litellm.utils import (
exception_type,
filter_out_litellm_params,
get_litellm_params,
get_optional_params,
peek_reasoning_summary_aliases,
reasoning_effort_with_summary_alias,
strip_reasoning_summary_aliases_from_optional_params,
)
if TYPE_CHECKING:
from litellm.router import Router
from litellm.types.utils import TokenCountResponse
from litellm.constants import (
AZURE_OPENAI_AUDIO_PROVIDERS,
DEFAULT_MOCK_RESPONSE_COMPLETION_TOKEN_COUNT,
DEFAULT_MOCK_RESPONSE_PROMPT_TOKEN_COUNT,
NADIR_DEFAULT_API_BASE,
OPENAI_AUDIO_TRANSCRIPTION_PROVIDERS,
)
from litellm.exceptions import LiteLLMUnknownProvider
from litellm.integrations.custom_logger import CustomLogger
from litellm.litellm_core_utils.asyncify import asyncify, run_async_function
from litellm.litellm_core_utils.audio_utils.utils import (
calculate_request_duration,
get_audio_file_for_health_check,
)
from litellm.litellm_core_utils.chat_completion_agentic_loop import (
maybe_run_chat_completion_agentic_loop,
)
from litellm.litellm_core_utils.completion_timeout import CompletionTimeout
from litellm.litellm_core_utils.dd_tracing import tracer
from litellm.litellm_core_utils.get_litellm_params import (
AWS_CREDENTIAL_KWARGS_KEYS,
OAUTH_TOKEN_EXCHANGE_KWARGS_KEYS,
OPTIONAL_KWARGS_KEYS,
PROVIDER_AFFINITY_HEADER_KWARG_KEY,
InvalidControlOption,
parse_control_options,
with_control_options,
)
from litellm.litellm_core_utils.get_llm_provider_logic import (
invalid_provider_routing_hints_message,
)
from litellm.litellm_core_utils.get_provider_specific_headers import (
ProviderSpecificHeaderUtils,
)
from litellm.litellm_core_utils.health_check_utils import (
_filter_model_params,
create_health_check_response,
)
from litellm.litellm_core_utils.hidden_params import HIDDEN_PARAMS_ATTR, get_hidden_params
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
from litellm.litellm_core_utils.mock_functions import (
mock_embedding,
mock_image_generation,
)
from litellm.litellm_core_utils.prompt_templates.common_utils import (
get_content_from_model_response as get_content_from_model_response, # noqa: PLC0414 # public re-export
)
from litellm.litellm_core_utils.provider_affinity import add_provider_affinity_header
from litellm.litellm_core_utils.request_timeout_resolver import (
get_configured_request_timeout,
)
from litellm.litellm_core_utils.tokenizer import Encoding as Tokenizer
from litellm.llms.base_llm import BaseConfig, BaseImageGenerationConfig
from litellm.llms.base_llm.base_model_iterator import (
convert_model_response_to_streaming,
)
from litellm.llms.base_llm.chat.transformation import with_attribution_headers
from litellm.llms.bedrock.common_utils import (
BedrockModelInfo,
bedrock_route_for_request,
without_bedrock_route_prefix,
)
from litellm.llms.bedrock_mantle.chat.claude_transformation import bedrock_mantle_chat_config
from litellm.llms.cohere.common_utils import CohereModelInfo
from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler, HTTPHandler, http2_enabled
from litellm.llms.openai.chat.gpt_5_transformation import OpenAIGPT5Config
from litellm.llms.openai_like.json_loader import JSONProviderRegistry
from litellm.llms.vertex_ai.common_utils import (
VertexAIModelRoute,
get_vertex_ai_model_route,
)
from litellm.realtime_api.main import realtime_health_check
from litellm.secret_managers.main import get_secret_bool, get_secret_str
from litellm.types.completion import (
CompletionDispatchContext,
_CompletionDispatchResult,
)
from litellm.types.litellm_params import ControlOptions, RetryStrategy
from litellm.types.llms.openai import AllMessageValues
from litellm.types.router import GenericLiteLLMParams
from litellm.types.utils import (
BaseUrlRoutingHint,
CustomPricingLiteLLMParams,
ModelResponseStream,
ProviderRoutingHints,
RawRequestTypedDict,
StreamingChoices,
is_decisions_model_mode,
)
from litellm.types.workload_identity import ANTHROPIC_WIF_KWARGS_KEYS, OPENAI_WIF_KWARGS_KEYS
from litellm.utils import (
Choices,
CustomStreamWrapper,
EmbeddingResponse,
Message,
ModelResponse,
ProviderConfigManager,
TextChoices,
TextCompletionResponse,
TextCompletionStreamWrapper,
TranscriptionResponse,
Usage,
add_provider_specific_params_to_optional_params,
async_mock_completion_streaming_obj,
convert_to_model_response_object,
create_pretrained_tokenizer,
create_tokenizer,
get_llm_provider,
get_model_info,
get_non_default_completion_params,
get_non_default_transcription_params,
get_optional_params_embeddings,
get_optional_params_image_gen,
get_optional_params_transcription,
get_requester_metadata,
get_secret,
get_standard_openai_params,
mock_completion_streaming_obj,
pre_process_non_default_params,
read_config_args,
should_run_mock_completion,
supports_httpx_timeout,
validate_and_fix_openai_messages,
validate_and_fix_openai_tools,
validate_and_fix_thinking_param,
validate_chat_completion_tool_choice,
validate_openai_optional_params,
)
from litellm.utils import (
token_counter as token_counter, # noqa: PLC0414 # public re-export
)
from ._logging import verbose_logger
from .caching.caching import disable_cache, enable_cache, update_cache
from .litellm_core_utils.core_helpers import normalize_drop_params, safe_deep_copy
from .litellm_core_utils.fallback_utils import (
async_completion_with_fallbacks,
completion_with_fallbacks,
)
from .litellm_core_utils.prompt_templates.common_utils import (
add_system_prompt_to_messages,
get_completion_messages,
update_messages_with_model_file_ids,
)
from .litellm_core_utils.prompt_templates.factory import (
custom_prompt,
function_call_prompt,
map_system_message_pt,
ollama_pt,
prompt_factory,
stringify_json_tool_call_content,
)
from .litellm_core_utils.streaming_chunk_builder_utils import (
ChunkProcessor as ChunkProcessor, # noqa: PLC0414 # public re-export
)
from .llms.anthropic.chat import AnthropicChatCompletion
from .llms.azure.audio_transcriptions import AzureAudioTranscription
from .llms.azure.azure import AzureChatCompletion, check_dynamic_azure_params
from .llms.azure.chat.o_series_handler import AzureOpenAIO1ChatCompletion
from .llms.azure.completion.handler import AzureTextCompletion
from .llms.azure_ai.anthropic.handler import AzureAnthropicChatCompletion
from .llms.azure_ai.embed import AzureAIEmbedding
from .llms.bedrock.chat import BedrockConverseLLM
from .llms.bedrock.embed.embedding import BedrockEmbedding
from .llms.bedrock.image_edit.handler import BedrockImageEdit
from .llms.bedrock.image_generation.image_handler import BedrockImageGeneration
from .llms.bytez.chat.transformation import BytezChatConfig
from .llms.clarifai.chat.transformation import ClarifaiConfig
from .llms.codestral.completion.handler import CodestralTextCompletion
from .llms.cohere.embed import handler as cohere_embed
from .llms.custom_httpx.aiohttp_handler import BaseLLMAIOHTTPHandler
from .llms.custom_httpx.llm_http_handler import BaseLLMHTTPHandler
from .llms.custom_llm import CustomLLM, custom_chat_llm_router
from .llms.databricks.embed.handler import DatabricksEmbeddingHandler
from .llms.deprecated_providers import aleph_alpha
from .llms.gdc.chat.transformation import GDCGeminiConfig
from .llms.gemini.common_utils import get_api_key_from_env
from .llms.groq.chat.handler import GroqChatCompletion
from .llms.heroku.chat.transformation import HerokuChatConfig
from .llms.huggingface.embedding.handler import HuggingFaceEmbedding
from .llms.lemonade.chat.transformation import LemonadeChatConfig
from .llms.nlp_cloud.chat.handler import completion as nlp_cloud_chat_completion
from .llms.nvidia_riva.audio_transcription.handler import (
NvidiaRivaAudioTranscription,
)
from .llms.nvidia_riva.audio_transcription.transformation import (
NvidiaRivaAudioTranscriptionConfig,
)
from .llms.oci.chat.transformation import OCIChatConfig
from .llms.ollama.completion import handler as ollama
from .llms.oobabooga.chat import oobabooga
from .llms.openai.completion.handler import OpenAITextCompletion
from .llms.openai.image_variations.handler import OpenAIImageVariationsHandler
from .llms.openai.openai import OpenAIChatCompletion
from .llms.openai.transcriptions.handler import OpenAIAudioTranscription
from .llms.openai.workload_identity import build_openai_client
from .llms.openai_like.chat.handler import OpenAILikeChatHandler
from .llms.openai_like.embedding.handler import OpenAILikeEmbeddingHandler
from .llms.ovhcloud.chat.transformation import OVHCloudChatConfig
from .llms.petals.completion import handler as petals_handler
from .llms.predibase.chat.handler import PredibaseChatCompletion
from .llms.replicate.chat.handler import completion as replicate_chat_completion
from .llms.sagemaker.chat.handler import SagemakerChatHandler
from .llms.sagemaker.completion.handler import SagemakerLLM
from .llms.sap.chat.handler import GenAIHubOrchestration
from .llms.vertex_ai import vertex_ai_non_gemini
from .llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import VertexLLM
from .llms.vertex_ai.gemini_embeddings.batch_embed_content_handler import (
GoogleBatchEmbeddings,
)
from .llms.vertex_ai.image_generation.image_generation_handler import (
VertexImageGeneration,
)
from .llms.vertex_ai.multimodal_embeddings.embedding_handler import (
VertexMultimodalEmbedding,
)
from .llms.vertex_ai.vertex_ai_partner_models.main import VertexAIPartnerModels
from .llms.vertex_ai.vertex_embeddings.embedding_handler import VertexEmbedding
from .llms.vertex_ai.vertex_gemma_models.main import VertexAIGemmaModels
from .llms.vertex_ai.vertex_model_garden.main import VertexAIModelGardenModels
from .llms.vllm.completion import handler as vllm_handler
from .llms.watsonx.chat.handler import WatsonXChatHandler
from .llms.watsonx.common_utils import IBMWatsonXMixin
from .types.llms.anthropic import AnthropicThinkingParam
from .types.llms.openai import (
ChatCompletionAssistantMessage,
ChatCompletionAudioParam,
ChatCompletionModality,
ChatCompletionPredictionContentParam,
ChatCompletionUserMessage,
HttpxBinaryResponseContent,
OpenAIModerationResponse,
OpenAIWebSearchOptions,
)
from .types.utils import (
AdapterCompletionStreamWrapper,
ChatCompletionMessageToolCall,
CompletionTokensDetails,
FileTypes,
HiddenParams,
LlmProviders,
PromptTokensDetails,
ProviderSpecificHeader,
)
####### ENVIRONMENT VARIABLES ###################
openai_chat_completions = OpenAIChatCompletion()
openai_text_completions: Final = OpenAITextCompletion()
openai_audio_transcriptions: Final = OpenAIAudioTranscription()
nvidia_riva_audio_transcriptions: Final = NvidiaRivaAudioTranscription()
openai_image_variations = OpenAIImageVariationsHandler()
groq_chat_completions: Final = GroqChatCompletion()
sap_gen_ai_hub_chat_completions: Final = GenAIHubOrchestration()
sap_gen_ai_hub_emb: Final = GenAIHubOrchestration()
azure_ai_embedding: Final = AzureAIEmbedding()
anthropic_chat_completions: Final = AnthropicChatCompletion()
azure_anthropic_chat_completions: Final = AzureAnthropicChatCompletion()
azure_chat_completions = AzureChatCompletion()
azure_o1_chat_completions: Final = AzureOpenAIO1ChatCompletion()
azure_text_completions: Final = AzureTextCompletion()
azure_audio_transcriptions: Final = AzureAudioTranscription()
huggingface_embed: Final = HuggingFaceEmbedding()
predibase_chat_completions: Final = PredibaseChatCompletion()
codestral_text_completions: Final = CodestralTextCompletion()
bedrock_converse_chat_completion: Final = BedrockConverseLLM()
bedrock_embedding: Final = BedrockEmbedding()
bedrock_image_generation = BedrockImageGeneration()
bedrock_image_edit = BedrockImageEdit()
vertex_chat_completion: Final = VertexLLM()
vertex_embedding: Final = VertexEmbedding()
vertex_multimodal_embedding: Final = VertexMultimodalEmbedding()
vertex_image_generation: Final = VertexImageGeneration()
google_batch_embeddings: Final = GoogleBatchEmbeddings()
vertex_partner_models_chat_completion: Final = VertexAIPartnerModels()
vertex_gemma_chat_completion: Final = VertexAIGemmaModels()
vertex_model_garden_chat_completion: Final = VertexAIModelGardenModels()
gdc_transformation: Final = GDCGeminiConfig()
# vertex_text_to_speech is now replaced by VertexAITextToSpeechConfig
sagemaker_llm: Final = SagemakerLLM()
watsonx_chat_completion: Final = WatsonXChatHandler()
openai_like_embedding: Final = OpenAILikeEmbeddingHandler()
openai_like_chat_completion: Final = OpenAILikeChatHandler()
databricks_embedding: Final = DatabricksEmbeddingHandler()
base_llm_http_handler = BaseLLMHTTPHandler()
base_llm_aiohttp_handler = BaseLLMAIOHTTPHandler()
sagemaker_chat_completion: Final = SagemakerChatHandler()
bytez_transformation: Final = BytezChatConfig()
heroku_transformation: Final = HerokuChatConfig()
oci_transformation: Final = OCIChatConfig()
ovhcloud_transformation: Final = OVHCloudChatConfig()
lemonade_transformation: Final = LemonadeChatConfig()
MOCK_RESPONSE_TYPE = str | Exception | dict | ModelResponse | ModelResponseStream
def _resolve_control_options(kwargs: Mapping[str, object], model: str) -> ControlOptions:
control: Final = parse_control_options(kwargs)
match control:
case ControlOptions():
return control
case InvalidControlOption(param=param, message=message):
if litellm.drop_params is True or normalize_drop_params(kwargs.get("drop_params")) is True:
return ControlOptions()
raise litellm.BadRequestError(message=message, model=model, llm_provider=None, body={"param": param})
case _:
return assert_never(control)
####### COMPLETION ENDPOINTS ################
class LiteLLM:
def __init__(
self,
*,
api_key=None,
organization: str | None = None,
base_url: str | None = None,
timeout: float | None = 600,
max_retries: int | None = litellm.num_retries,
default_headers: Mapping[str, str] | None = None,
):
self.params = locals()
self.chat = Chat(self.params, router_obj=None)
class Chat:
def __init__(self, params, router_obj: "Router | None"):
self.params = params
if self.params.get("acompletion", False) is True:
self.params.pop("acompletion")
self.completions: AsyncCompletions | Completions = AsyncCompletions(self.params, router_obj=router_obj)
else:
self.completions = Completions(self.params, router_obj=router_obj)
class Completions:
def __init__(self, params, router_obj: "Router | None"):
self.params = params
self.router_obj = router_obj
def create(self, messages, model=None, **kwargs):
for k, v in kwargs.items():
self.params[k] = v
model = model or self.params.get("model")
if self.router_obj is not None:
response = self.router_obj.completion(model=model, messages=messages, **self.params)
else:
response = completion(model=model, messages=messages, **self.params)
return response
class AsyncCompletions:
def __init__(self, params, router_obj: "Router | None"):
self.params = params
self.router_obj = router_obj
async def create(self, messages, model=None, **kwargs):
for k, v in kwargs.items():
self.params[k] = v
model = model or self.params.get("model")
if self.router_obj is not None:
response = await self.router_obj.acompletion(model=model, messages=messages, **self.params)
else:
response = await acompletion(model=model, messages=messages, **self.params)
return response
@tracer.wrap()
@client
async def acompletion(
model: str,
# Optional OpenAI params: see https://platform.openai.com/docs/api-reference/chat/create
messages: list = [],
functions: list | None = None,
function_call: str | None = None,
timeout: float | httpx.Timeout | openai.Timeout | None = None,
temperature: float | None = None,
top_p: float | None = None,
n: int | None = None,
stream: bool | None = None,
stream_options: dict | None = None,
stop=None,
max_tokens: int | None = None,
max_completion_tokens: int | None = None,
modalities: list[ChatCompletionModality] | None = None,
prediction: ChatCompletionPredictionContentParam | None = None,
audio: ChatCompletionAudioParam | None = None,
presence_penalty: float | None = None,
frequency_penalty: float | None = None,
logit_bias: dict | None = None,
user: str | None = None,
# openai v1.0+ new params
response_format: dict | type[BaseModel] | None = None,
seed: int | None = None,
tools: list | None = None,
tool_choice: str | dict | None = None,
parallel_tool_calls: bool | None = None,
logprobs: bool | None = None,
top_logprobs: int | None = None,
deployment_id=None,
reasoning_effort: Literal["none", "minimal", "low", "medium", "high", "xhigh", "max", "default"] | None = None,
verbosity: Literal["low", "medium", "high"] | None = None,
safety_identifier: str | None = None,
service_tier: str | None = None,
store: bool | None = None,
prompt_cache_key: str | None = None,
# set api_base, api_version, api_key
base_url: str | None = None,
api_version: str | None = None,
api_key: str | None = None,
model_list: list | None = None, # pass in a list of api_base,keys, etc.
extra_headers: dict | None = None,
# Optional liteLLM function params
thinking: AnthropicThinkingParam | None = None,
web_search_options: OpenAIWebSearchOptions | None = None,
include_server_side_tool_invocations: bool | None = None,
# Session management
shared_session: Optional["ClientSession"] = None,
# Per-request JSON schema validation (overrides litellm.enable_json_schema_validation)
enable_json_schema_validation: bool | None = None,
**kwargs,
) -> ModelResponse | CustomStreamWrapper:
"""
Asynchronously executes a litellm.completion() call for any of litellm supported llms (example gpt-4, gpt-3.5-turbo, claude-2, command-nightly)
Parameters:
model (str): The name of the language model to use for text completion. see all supported LLMs: https://docs.litellm.ai/docs/providers/
messages (List): A list of message objects representing the conversation context (default is an empty list).
OPTIONAL PARAMS
functions (List, optional): A list of functions to apply to the conversation messages (default is an empty list).
function_call (str, optional): The name of the function to call within the conversation (default is an empty string).
temperature (float, optional): The temperature parameter for controlling the randomness of the output (default is 1.0).
top_p (float, optional): The top-p parameter for nucleus sampling (default is 1.0).
n (int, optional): The number of completions to generate (default is 1).
stream (bool, optional): If True, return a streaming response (default is False).
stream_options (dict, optional): A dictionary containing options for the streaming response. Only use this if stream is True.
stop(string/list, optional): - Up to 4 sequences where the LLM API will stop generating further tokens.
max_tokens (integer, optional): The maximum number of tokens in the generated completion (default is infinity).
max_completion_tokens (integer, optional): An upper bound for the number of tokens that can be generated for a completion, including visible output tokens and reasoning tokens.
modalities (List[ChatCompletionModality], optional): Output types that you would like the model to generate for this request. You can use `["text", "audio"]`
prediction (ChatCompletionPredictionContentParam, optional): Configuration for a Predicted Output, which can greatly improve response times when large parts of the model response are known ahead of time. This is most common when you are regenerating a file with only minor changes to most of the content.
audio (ChatCompletionAudioParam, optional): Parameters for audio output. Required when audio output is requested with modalities: ["audio"]
presence_penalty (float, optional): It is used to penalize new tokens based on their existence in the text so far.
frequency_penalty: It is used to penalize new tokens based on their frequency in the text so far.
logit_bias (dict, optional): Used to modify the probability of specific tokens appearing in the completion.
user (str, optional): A unique identifier representing your end-user. This can help the LLM provider to monitor and detect abuse.
metadata (dict, optional): Pass in additional metadata to tag your completion calls - eg. prompt version, details, etc.
api_base (str, optional): Base URL for the API (default is None).
api_version (str, optional): API version (default is None).
api_key (str, optional): API key (default is None).
model_list (list, optional): List of api base, version, keys
timeout (float, optional): The maximum execution time in seconds for the completion request.
LITELLM Specific Params
mock_response (str, optional): If provided, return a mock completion response for testing or debugging purposes (default is None).
custom_llm_provider (str, optional): Used for Non-OpenAI LLMs, Example usage for bedrock, set model="amazon.titan-tg1-large" and custom_llm_provider="bedrock"
Returns:
ModelResponse: A response object containing the generated completion and associated metadata.
Notes:
- This function is an asynchronous version of the `completion` function.
- The `completion` function is called using `run_in_executor` to execute synchronously in the event loop.
- If `stream` is True, the function returns an async generator that yields completion lines.
"""
fallbacks = kwargs.get("fallbacks", None)
mock_timeout = kwargs.get("mock_timeout", None)
if mock_timeout is True:
await _handle_mock_timeout_async(mock_timeout, timeout, model)
loop: Final = asyncio.get_event_loop()
custom_llm_provider = kwargs.get("custom_llm_provider", None)
_ = _resolve_control_options(kwargs, model)
## PROMPT MANAGEMENT HOOKS ##
#########################################################
#########################################################
litellm_logging_obj: Final = kwargs.get("litellm_logging_obj", None)
from litellm.integrations.anthropic_cache_control_hook import (
AnthropicCacheControlHook,
)
from litellm.types.llms.openai import AllMessageValues
AnthropicCacheControlHook.maybe_seed_default_injection_points(
non_default_params=kwargs,
messages=cast(list[AllMessageValues], messages), # cast-ok: acompletion types messages as a bare List
model=model,
custom_llm_provider=cast(str | None, custom_llm_provider), # cast-ok: read from untyped kwargs
tools=tools,
enable_prompt_caching=cast(bool | None, kwargs.get("enable_prompt_caching")), # cast-ok: untyped kwargs
api_base=kwargs.get("api_base") or base_url,
)
if isinstance(litellm_logging_obj, LiteLLMLoggingObj) and (
litellm_logging_obj.should_run_prompt_management_hooks(
prompt_id=kwargs.get("prompt_id", None),
non_default_params=kwargs,
tools=tools,
)
):
(
model,
messages,
_,
) = await litellm_logging_obj.async_get_chat_completion_prompt(
model=model,
messages=messages,
non_default_params=kwargs,
prompt_id=kwargs.get("prompt_id", None),
prompt_variables=kwargs.get("prompt_variables", None),
tools=tools,
prompt_label=kwargs.get("prompt_label", None),
prompt_version=kwargs.get("prompt_version", None),
request_kwargs=kwargs,
)
#########################################################
# if the chat completion logging hook removed all tools,
# set tools to None
# eg. in certain cases when users send vector stores as tools
# we don't want the tools to go to the upstream llm
# relevant issue: https://github.com/BerriAI/litellm/issues/11404
#########################################################
if tools is not None and len(tools) == 0:
tools = None
#########################################################
#########################################################
# Log shared session usage
if shared_session is not None:
verbose_logger.debug("🔄 SHARED SESSION: acompletion called with shared_session (ID: %s)", id(shared_session))
else:
verbose_logger.debug("🔄 NO SHARED SESSION: acompletion called without shared_session")
# Adjusted to use explicit arguments instead of *args and **kwargs
completion_kwargs: Final = {
"model": model,
"messages": messages,
"functions": functions,
"function_call": function_call,
"timeout": timeout,
"temperature": temperature,
"top_p": top_p,
"n": n,
"stream": stream,
"stream_options": stream_options,
"stop": stop,
"max_tokens": max_tokens,
"max_completion_tokens": max_completion_tokens,
"modalities": modalities,
"prediction": prediction,
"audio": audio,
"presence_penalty": presence_penalty,
"frequency_penalty": frequency_penalty,
"logit_bias": logit_bias,
"user": user,
"response_format": response_format,
"seed": seed,
"tools": tools,
"tool_choice": tool_choice,
"parallel_tool_calls": parallel_tool_calls,
"logprobs": logprobs,
"top_logprobs": top_logprobs,
"deployment_id": deployment_id,
"base_url": base_url,
"api_version": api_version,
"api_key": api_key,
"model_list": model_list,
"reasoning_effort": reasoning_effort,
"verbosity": verbosity,
"safety_identifier": safety_identifier,
"service_tier": service_tier,
"store": store,
"prompt_cache_key": prompt_cache_key,
"extra_headers": extra_headers,
"acompletion": True, # assuming this is a required parameter
"thinking": thinking,
"web_search_options": web_search_options,
"include_server_side_tool_invocations": include_server_side_tool_invocations,
"shared_session": shared_session,
"enable_json_schema_validation": enable_json_schema_validation,
}
if custom_llm_provider is None:
_supplemental: Final = cast( # cast-ok: kwargs values are request-scoped objects
"dict[str, object]", {k: kwargs[k] for k in OPTIONAL_KWARGS_KEYS if k in kwargs}
)
_, custom_llm_provider, _, _ = get_llm_provider(
model=model,
custom_llm_provider=custom_llm_provider,
api_base=cast( # cast-ok: api_base arrives as a str in the request kwargs
"str | None", kwargs.get("api_base")
)
or base_url,
litellm_params=(GenericLiteLLMParams.model_validate(_supplemental) if _supplemental else None),
)
fallbacks = fallbacks or litellm.model_fallbacks
if fallbacks is not None:
response = await async_completion_with_fallbacks(**completion_kwargs, kwargs={"fallbacks": fallbacks, **kwargs})
if response is None:
raise Exception(
"No response from fallbacks. Got none. Turn on `litellm.set_verbose=True` to see more details."
)
return response
### APPLY MOCK DELAY ###
mock_delay: Final = kwargs.get("mock_delay")
mock_response: Final = kwargs.get("mock_response")
mock_tool_calls: Final = kwargs.get("mock_tool_calls")
mock_timeout = kwargs.get("mock_timeout")
if mock_delay and should_run_mock_completion(
mock_response=mock_response,
mock_tool_calls=mock_tool_calls,
mock_timeout=mock_timeout,
):
await asyncio.sleep(mock_delay)
try:
# Use a partial function to pass your keyword arguments
kwargs.pop("acompletion", None)
func: Final = partial(completion, **completion_kwargs, **kwargs)
# Add the context to the function
ctx: Final = contextvars.copy_context()
func_with_context: Final = partial(ctx.run, func)
init_response: Final = await loop.run_in_executor(None, func_with_context)
if isinstance(init_response, dict) or isinstance(init_response, ModelResponse): ## CACHING SCENARIO
if isinstance(init_response, dict):
response = _model_response_from_cached_dict(init_response)
response = init_response
elif asyncio.iscoroutine(init_response):
response = await _resolve_dispatched_chat_response(init_response)
else:
response = init_response
if (
custom_llm_provider == "text-completion-openai"
or custom_llm_provider == "text-completion-codestral"
or custom_llm_provider == "text-completion-inception"
) and isinstance(response, TextCompletionResponse):
response = litellm.OpenAITextCompletionConfig().convert_to_chat_model_response_object(
response_object=response,
model_response_object=litellm.ModelResponse(),
)
# Provider-agnostic dispatch point for the chat-completions agentic loop
# (code-interpreter interception, etc). Chat routing forks per provider
# before this (OpenAI goes through the OpenAI SDK in openai.py, others
# through the shared httpx handler), so a dispatch inside any single
# provider handler would miss the others. Here is where every fork
# reconverges, so the loop runs once for all providers. Responses needs
# no equivalent: every provider already funnels through one shared
# handler where the loop is dispatched.
if isinstance(response, litellm.ModelResponse):
looped: Final = await maybe_run_chat_completion_agentic_loop(
response=response,
model=model,
messages=messages,
optional_params={
k: v
for k, v in completion_kwargs.items()
if v is not None
and k
not in (
"model",
"messages",
"stream",
"acompletion",
"deployment_id",
)
},
kwargs=kwargs,
logging_obj=kwargs.get("litellm_logging_obj"),
custom_llm_provider=custom_llm_provider,
stream=bool(stream),
)
if looped is not None:
response = looped
if isinstance(response, CustomStreamWrapper):
response.set_logging_event_loop(
loop=loop
) # sets the logging event loop if the user does sync streaming (e.g. on proxy for sagemaker calls)
return response
except Exception as e:
custom_llm_provider = custom_llm_provider or "openai"
raise exception_type(
model=model,
custom_llm_provider=custom_llm_provider,
original_exception=e,
completion_kwargs=completion_kwargs,
extra_kwargs=kwargs,
)
async def _resolve_dispatched_chat_response(
pending: Coroutine[object, object, ModelResponse | CustomStreamWrapper],
) -> ModelResponse | CustomStreamWrapper:
return await pending
def _model_response_from_cached_dict(cached_response_dict: Mapping[str, object]) -> ModelResponse:
return ModelResponse(**cached_response_dict)
def _transcription_response_from_cached_dict(cached_response_dict: Mapping[str, object]) -> TranscriptionResponse:
return TranscriptionResponse(**cached_response_dict)
async def _async_streaming(response, model, custom_llm_provider, args):
try:
print_verbose(f"received response in _async_streaming: {response}")
if asyncio.iscoroutine(response):
response = await response
async for line in response:
print_verbose(f"line in async streaming: {line}")
yield line
except Exception as e:
custom_llm_provider = custom_llm_provider or "openai"
raise exception_type(
model=model,
custom_llm_provider=custom_llm_provider,
original_exception=e,
)
def _handle_mock_potential_exceptions(
mock_response: str | Exception,
model: str,
custom_llm_provider: str | None = None,
):
if isinstance(mock_response, Exception):
if isinstance(mock_response, openai.APIError):
raise mock_response
raise litellm.MockException(
status_code=getattr(mock_response, "status_code", 500),
message=getattr(mock_response, "text", str(mock_response)),
llm_provider=getattr(mock_response, "llm_provider", custom_llm_provider or "openai"),
model=model,
request=httpx.Request(method="POST", url="https://api.openai.com/v1/"),
)
elif isinstance(mock_response, str) and mock_response == "litellm.RateLimitError":
raise litellm.RateLimitError(
message="this is a mock rate limit error",
llm_provider=getattr(mock_response, "llm_provider", custom_llm_provider or "openai"),
model=model,
)
elif isinstance(mock_response, str) and mock_response == "litellm.ContextWindowExceededError":
raise litellm.ContextWindowExceededError(
message="this is a mock context window exceeded error",
llm_provider=getattr(mock_response, "llm_provider", custom_llm_provider or "openai"),
model=model,
)
elif isinstance(mock_response, str) and mock_response == "litellm.InternalServerError":
raise litellm.InternalServerError(
message="this is a mock internal server error",
llm_provider=getattr(mock_response, "llm_provider", custom_llm_provider or "openai"),
model=model,
)
elif isinstance(mock_response, str) and mock_response.startswith("Exception: content_filter_policy"):
raise litellm.MockException(
status_code=400,
message=mock_response,
llm_provider="azure",
model=model,
request=httpx.Request(method="POST", url="https://api.openai.com/v1/"),
)
def _handle_mock_timeout(
mock_timeout: bool | None,
timeout: float | str | httpx.Timeout | None,
model: str,
):
if mock_timeout is True and timeout is not None:
_sleep_for_timeout(timeout)
raise litellm.Timeout(
message="This is a mock timeout error",
llm_provider="openai",
model=model,
)
async def _handle_mock_timeout_async(
mock_timeout: bool | None,
timeout: float | str | httpx.Timeout | None,
model: str,
):
if mock_timeout is True and timeout is not None:
await _sleep_for_timeout_async(timeout)
raise litellm.Timeout(
message="This is a mock timeout error",
llm_provider="openai",
model=model,
)
def _sleep_for_timeout(timeout: float | str | httpx.Timeout):
if isinstance(timeout, float):
time.sleep(timeout)
elif isinstance(timeout, str):
time.sleep(float(timeout))
elif isinstance(timeout, httpx.Timeout) and timeout.connect is not None:
time.sleep(timeout.connect)
async def _sleep_for_timeout_async(timeout: float | str | httpx.Timeout):
if isinstance(timeout, float):
await asyncio.sleep(timeout)
elif isinstance(timeout, str):
await asyncio.sleep(float(timeout))
elif isinstance(timeout, httpx.Timeout) and timeout.connect is not None:
await asyncio.sleep(timeout.connect)
class _AdmissionReservation(LiteLLMBaseModel):
input_tokens: int | None = None
class _AdmissionMetadata(LiteLLMBaseModel):
user_api_key_budget_reservation: _AdmissionReservation | None = None
def admission_input_tokens(kwargs: Mapping[str, object]) -> int | None:
reservations: Final = (
_AdmissionMetadata.model_validate(kwargs.get(key) or {}).user_api_key_budget_reservation
for key in ("litellm_metadata", "metadata")
)
return next(
(
reservation.input_tokens
for reservation in reservations
if reservation and reservation.input_tokens is not None
),
None,
)
def admitted_prompt_token_counter(prompt_tokens: int | None) -> Callable[[], int] | None:
if prompt_tokens is None:
return None
return lambda: prompt_tokens
def mock_completion(
model: str,
messages: list,
stream: bool | None = False,
n: int | None = None,
mock_response: MOCK_RESPONSE_TYPE | None = "This is a mock request",
mock_tool_calls: list | None = None,
mock_timeout: bool | None = False,
logging=None,
custom_llm_provider=None,
timeout: float | str | httpx.Timeout | None = None,
prompt_tokens: int | None = None,
**kwargs,
):
"""
Generate a mock completion response for testing or debugging purposes.
This is a helper function that simulates the response structure of the OpenAI completion API.
Parameters:
model (str): The name of the language model for which the mock response is generated.
messages (List): A list of message objects representing the conversation context.
stream (bool, optional): If True, returns a mock streaming response (default is False).
mock_response (str, optional): The content of the mock response (default is "This is a mock request").
mock_timeout (bool, optional): If True, the mock response will be a timeout error (default is False).
timeout (float, optional): The timeout value to use for the mock response (default is None).
**kwargs: Additional keyword arguments that can be used but are not required.
Returns:
litellm.ModelResponse: A ModelResponse simulating a completion response with the specified model, messages, and mock response.
Raises:
Exception: If an error occurs during the generation of the mock completion response.
Note:
- This function is intended for testing or debugging purposes to generate mock completion responses.
- If 'stream' is True, it returns a response that mimics the behavior of a streaming completion.
"""
try:
is_acompletion: Final = kwargs.get("acompletion") or False
if mock_response is None:
mock_response = "This is a mock request"
_handle_mock_timeout(mock_timeout=mock_timeout, timeout=timeout, model=model)
## LOGGING
if logging is not None:
logging.pre_call(
input=messages,
api_key="mock-key",
)
if isinstance(mock_response, str) or isinstance(mock_response, Exception):
_handle_mock_potential_exceptions(
mock_response=mock_response,
model=model,
custom_llm_provider=custom_llm_provider,
)
mock_response = cast(
str | dict | ModelResponse | ModelResponseStream, mock_response
) # after this point, mock_response is a string, dict, ModelResponse, or ModelResponseStream
if isinstance(mock_response, str) and mock_response.startswith("Exception: mock_streaming_error"):
mock_response = litellm.MockException(
message="This is a mock error raised mid-stream",
llm_provider="anthropic",
model=model,
status_code=529,
)
time_delay: Final = kwargs.get("mock_delay", None)
if time_delay is not None and not is_acompletion:
time.sleep(time_delay)
if isinstance(mock_response, dict):
return ModelResponse(**mock_response)
if isinstance(mock_response, ModelResponse):
if not stream:
return mock_response
# convert to ModelResponseStream
mock_response = convert_model_response_to_streaming(mock_response)
model_response: ModelResponse | ModelResponseStream = ModelResponse()
if stream is True:
model_response = ModelResponseStream()
count_prompt_tokens: Final = admitted_prompt_token_counter(prompt_tokens)
# don't try to access stream object,
if kwargs.get("acompletion", False) is True:
return CustomStreamWrapper(
completion_stream=async_mock_completion_streaming_obj(
model_response, mock_response=mock_response, model=model, n=n, prompt_tokens=prompt_tokens
),
model=model,
custom_llm_provider="openai",
logging_obj=logging,
count_prompt_tokens=count_prompt_tokens,
)
return CustomStreamWrapper(
completion_stream=mock_completion_streaming_obj(
model_response, mock_response=mock_response, model=model, n=n, prompt_tokens=prompt_tokens
),
model=model,
custom_llm_provider="openai",
logging_obj=logging,
count_prompt_tokens=count_prompt_tokens,
)
if isinstance(mock_response, litellm.MockException):
raise mock_response
# At this point, mock_response must be a string (all other types have been handled or returned early)
mock_response = cast(str, mock_response)
if n is None:
model_response.choices[0].message.content = mock_response
else:
_all_choices: Final = []
for i in range(n):
_choice = litellm.utils.Choices(
index=i,
message=litellm.utils.Message(content=mock_response, role="assistant"),
)
_all_choices.append(_choice)
model_response.choices = _all_choices
model_response.created = int(time.time())
model_response.model = model
if mock_tool_calls:
model_response.choices[0].message.tool_calls = [
ChatCompletionMessageToolCall(**tool_call) for tool_call in mock_tool_calls
]
usage_prompt_tokens: Final = (
prompt_tokens if prompt_tokens is not None else DEFAULT_MOCK_RESPONSE_PROMPT_TOKEN_COUNT
)
setattr(
model_response,
"usage",
Usage(
prompt_tokens=usage_prompt_tokens,
completion_tokens=DEFAULT_MOCK_RESPONSE_COMPLETION_TOKEN_COUNT,
total_tokens=usage_prompt_tokens + DEFAULT_MOCK_RESPONSE_COMPLETION_TOKEN_COUNT,
),
)
if custom_llm_provider is not None:
model_response.hidden_params["custom_llm_provider"] = custom_llm_provider
else:
try:
_, inferred_provider, _, _ = litellm.utils.get_llm_provider(model=model)
model_response.hidden_params["custom_llm_provider"] = inferred_provider
except Exception:
# dont let setting a hidden param block a mock_respose
pass
if logging is not None:
logging.post_call(
input=messages,
api_key="my-secret-key",
original_response="my-original-response",
)
return model_response
except Exception as e:
if isinstance(e, openai.APIError):
raise e
raise Exception(f"Mock completion response failed - {e}")
from litellm.responses.bridge_check import ( # noqa: E402 # re-export at the old definition site
_resolve_openai_api_base as _resolve_openai_api_base, # pyright: ignore[reportPrivateUsage] # noqa: PLC0414 # re-export of moved helper
)
from litellm.responses.bridge_check import ( # noqa: E402 # re-export at the old definition site
responses_api_bridge_check as responses_api_bridge_check, # pyright: ignore[reportUnknownVariableType] # noqa: PLC0414 # re-export of moved function
)
_ANTHROPIC_ONLY_TOOL_KEYS: Final = frozenset({"input_examples", "eager_input_streaming"})
def _is_claude_tool_target(custom_llm_provider: str | None, model: str) -> bool:
if custom_llm_provider == "anthropic":
return True
model_lower: Final = model.lower()
if custom_llm_provider == "bedrock":
return "claude" in model_lower or ("arn:" in model_lower and ":bedrock:" in model_lower)
if custom_llm_provider == "azure_ai" or custom_llm_provider == "vertex_ai":
return "claude" in model_lower
return False
def _history_without_unanswered_tool_search_calls(
messages: Sequence[object], custom_llm_provider: str | None, provider_config: BaseConfig
) -> tuple[object, ...] | None:
from litellm.responses.litellm_completion_transformation.tool_search import (
chat_messages_without_tool_search_calls,
chat_route_rejects_unanswered_tool_calls,
unanswered_tool_search_call_ids,
)
if not chat_route_rejects_unanswered_tool_calls(custom_llm_provider, provider_config):
return None
unanswered_search_call_ids: Final = unanswered_tool_search_call_ids(messages)
if not unanswered_search_call_ids:
return None
return chat_messages_without_tool_search_calls(messages, unanswered_search_call_ids)
def _without_anthropic_only_tool_keys(tool: dict[str, object]) -> dict[str, object]:
kept: Final = {key: value for key, value in tool.items() if key not in _ANTHROPIC_ONLY_TOOL_KEYS}
function: Final = tool.get("function")
if not isinstance(function, dict):
return kept
return {
**kept,
"function": {key: value for key, value in function.items() if key not in _ANTHROPIC_ONLY_TOOL_KEYS},
}
def _drop_anthropic_only_tool_keys(tools: list[dict[str, object]] | None) -> list[dict[str, object]] | None:
if tools is None:
return None
return [_without_anthropic_only_tool_keys(tool) if isinstance(tool, dict) else tool for tool in tools]
class _ProxyAuthHeadersProvider(Protocol):
def get_auth_headers(self) -> Mapping[str, str]: ...
def _proxy_auth_headers(proxy_auth: _ProxyAuthHeadersProvider) -> Mapping[str, str]:
return proxy_auth.get_auth_headers()
def _provider_config_items(config: Mapping[str, object]) -> Iterable[tuple[str, object]]:
return config.items()
def _locals_snapshot(values: Mapping[str, object]) -> Mapping[str, object]:
return values
def _build_custom_pricing_entry(
custom_llm_provider: str,
kwargs: dict,
model_info: dict | None = None,
) -> dict:
"""Build a complete model cost entry from kwargs and model_info.
Collects all CustomPricingLiteLLMParams fields present in kwargs and
merges metadata from model_info (mode, supports_prompt_caching, max_tokens)
so that register_model() receives the full pricing configuration.
"""
entry: Final[dict] = {"litellm_provider": custom_llm_provider}
for field_name in CustomPricingLiteLLMParams.model_fields:
value = kwargs.get(field_name)
if value is not None:
entry[field_name] = value
if model_info and isinstance(model_info, dict):
for key in ("mode", "supports_prompt_caching", "max_tokens"):
if key in model_info and model_info[key] is not None:
entry.setdefault(key, model_info[key])
return entry
def _get_router_deployment_id(kwargs: dict) -> str | None:
for metadata_key in ("litellm_metadata", "metadata"):
metadata = kwargs.get(metadata_key) or {}
if not isinstance(metadata, dict):
continue
deployment_model_info = metadata.get("model_info") or {}
if not isinstance(deployment_model_info, dict):
continue
deployment_id = deployment_model_info.get("id")
if deployment_id is not None:
return str(deployment_id)
return None
def _register_custom_pricing_for_request(
model: str,
custom_llm_provider: str,
kwargs: dict,
model_info: dict | None,
) -> None:
"""Register per-request custom pricing in litellm.model_cost.
Router-originated requests (identified by the deployment id the router puts
in metadata) get their full pricing registered under that unique id only;
the shared ``{provider}/{model}`` key receives the entry with pricing fields
stripped, mirroring Router._create_deployment. This keeps one deployment's
pricing overrides (e.g. a zero-cost wildcard) from clobbering built-in
pricing used by sibling deployments of the same backend model. Direct SDK
calls keep the legacy behavior of registering the shared key with pricing.
"""
entry: Final = _build_custom_pricing_entry(
custom_llm_provider=custom_llm_provider,
kwargs=kwargs,
model_info=model_info,
)
shared_key: Final = f"{custom_llm_provider}/{model}"
deployment_id: Final = _get_router_deployment_id(kwargs)
if deployment_id is None:
litellm.register_model({shared_key: entry}, persist_across_reloads=False)
return
litellm.register_model(
{deployment_id: entry},
persist_across_reloads=False,
warning_display_name=shared_key,
custom_llm_provider=custom_llm_provider,
add_to_provider_model_sets=False,
)
litellm.register_model(
{shared_key: CustomPricingLiteLLMParams.strip_custom_pricing_fields(entry)},
persist_across_reloads=False,
warning_display_name=shared_key,
custom_llm_provider=custom_llm_provider,
add_to_provider_model_sets=False,
)
def _dispatch_metadata(ctx: CompletionDispatchContext) -> Mapping[str, object] | None:
return ctx.metadata
def _dispatch_client_http(ctx: CompletionDispatchContext) -> HTTPHandler | AsyncHTTPHandler | None:
return ctx.client
def _dispatch_client_azure(
ctx: CompletionDispatchContext,
) -> openai.AzureOpenAI | openai.AsyncAzureOpenAI | HTTPHandler | AsyncHTTPHandler | None:
return ctx.client
def _dispatch_client_openai(ctx: CompletionDispatchContext) -> openai.OpenAI | openai.AsyncOpenAI | None:
return ctx.client
def _complete_azure(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
_azure_detection_model: Final = ctx._azure_detection_model
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
api_version = ctx.api_version
client: Final = _dispatch_client_azure(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
extra_headers: Final = ctx.extra_headers
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
max_retries: Final = ctx.max_retries
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
timeout: Final = ctx.timeout
dynamic_params = False
if client is not None and (isinstance(client, openai.AzureOpenAI) or isinstance(client, openai.AsyncAzureOpenAI)):
dynamic_params = check_dynamic_azure_params(
azure_client_params={"api_version": api_version},
azure_client=client,
)
api_type: Final = get_secret("AZURE_API_TYPE") or "azure"
api_base = api_base or litellm.api_base or get_secret("AZURE_API_BASE")
api_version = (
api_version or litellm.api_version or get_secret_str("AZURE_API_VERSION") or litellm.AZURE_DEFAULT_API_VERSION
)
api_key = (
api_key
or litellm.api_key
or litellm.azure_key
or get_secret_str("AZURE_OPENAI_API_KEY")
or get_secret_str("AZURE_API_KEY")
)
azure_ad_token: Final = optional_params.get("extra_body", {}).pop("azure_ad_token", None) or get_secret_str(
"AZURE_AD_TOKEN"
)
azure_ad_token_provider_value: Final = litellm_params.get("azure_ad_token_provider", None)
azure_ad_token_provider: Final = azure_ad_token_provider_value if callable(azure_ad_token_provider_value) else None
headers = headers or litellm.headers
if extra_headers is not None:
optional_params["extra_headers"] = extra_headers
if max_retries is not None:
optional_params["max_retries"] = max_retries
if litellm.AzureOpenAIO1Config().is_o_series_model(model=_azure_detection_model):
## LOAD CONFIG - if set
config = litellm.AzureOpenAIO1Config.get_config()
for k, v in _provider_config_items(config):
if (
k not in optional_params
): # completion(top_k=3) > azure_config(top_k=3) <- allows for dynamic variables to be passed in
optional_params[k] = v
response = azure_o1_chat_completions.completion(
model=model,
messages=messages,
headers=headers,
api_key=api_key,
api_base=api_base,
api_version=api_version,
dynamic_params=dynamic_params,
azure_ad_token=azure_ad_token,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
logging_obj=logging,
acompletion=acompletion,
timeout=timeout,
client=client, # pass AsyncAzureOpenAI, AzureOpenAI client
custom_llm_provider=custom_llm_provider,
)
else:
## LOAD CONFIG - if set
config = litellm.AzureOpenAIConfig.get_config()
for k, v in _provider_config_items(config):
if (
k not in optional_params
): # completion(top_k=3) > azure_config(top_k=3) <- allows for dynamic variables to be passed in
optional_params[k] = v
## COMPLETION CALL
response = azure_chat_completions.completion(
model=model,
messages=messages,
headers=headers,
api_key=api_key,
api_base=api_base,
api_version=api_version,
api_type=api_type,
dynamic_params=dynamic_params,
azure_ad_token=azure_ad_token,
azure_ad_token_provider=azure_ad_token_provider,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
logging_obj=logging,
acompletion=acompletion,
timeout=timeout,
client=client, # pass AsyncAzureOpenAI, AzureOpenAI client
)
if optional_params.get("stream", False):
## LOGGING
logging.post_call(
input=messages,
api_key=api_key,
original_response=response,
additional_args={
"headers": headers,
"api_version": api_version,
"api_base": api_base,
},
)
return response # pyright: ignore[reportReturnType] # provider SDK return type is broader than the dispatch contract
def _complete_azure_text(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
api_version = ctx.api_version
client: Final = _dispatch_client_azure(ctx)
extra_headers: Final = ctx.extra_headers
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
timeout: Final = ctx.timeout
api_type: Final = get_secret_str("AZURE_API_TYPE") or "azure"
api_base = api_base or litellm.api_base or get_secret_str("AZURE_API_BASE")
if api_base is None:
raise ValueError(
"api_base is required for Azure OpenAI LLM provider. Either set it dynamically or set the AZURE_API_BASE environment variable."
)
api_version = api_version or litellm.api_version or get_secret_str("AZURE_API_VERSION")
api_key = (
api_key
or litellm.api_key
or litellm.azure_key
or get_secret_str("AZURE_OPENAI_API_KEY")
or get_secret_str("AZURE_API_KEY")
)
azure_ad_token: Final = optional_params.get("extra_body", {}).pop("azure_ad_token", None) or get_secret_str(
"AZURE_AD_TOKEN"
)
azure_ad_token_provider_value: Final = litellm_params.get("azure_ad_token_provider", None)
azure_ad_token_provider: Final = azure_ad_token_provider_value if callable(azure_ad_token_provider_value) else None
headers = headers or litellm.headers
if extra_headers is not None:
optional_params["extra_headers"] = extra_headers
## LOAD CONFIG - if set
config: Final = litellm.AzureOpenAIConfig.get_config()
for k, v in _provider_config_items(config):
if (
k not in optional_params
): # completion(top_k=3) > azure_config(top_k=3) <- allows for dynamic variables to be passed in
optional_params[k] = v
## COMPLETION CALL
response: Final = azure_text_completions.completion(
model=model,
messages=messages,
headers=headers,
api_key=api_key,
api_base=api_base,
api_version=cast(str, api_version),
api_type=api_type,
azure_ad_token=azure_ad_token,
azure_ad_token_provider=azure_ad_token_provider,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
logging_obj=logging,
acompletion=acompletion,
timeout=timeout,
client=client, # pass AsyncAzureOpenAI, AzureOpenAI client
)
if optional_params.get("stream", False) or acompletion is True:
## LOGGING
logging.post_call(
input=messages,
api_key=api_key,
original_response=response,
additional_args={
"headers": headers,
"api_version": api_version,
"api_base": api_base,
},
)
return response
def _complete_deepseek(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
try:
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=provider_config,
)
except Exception as e:
## LOGGING - log the original exception returned
logging.post_call(
input=messages,
api_key=api_key,
original_response=str(e),
additional_args={"headers": headers},
)
raise e
return response
def _complete_azure_ai(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
extra_headers: Final = ctx.extra_headers
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
from litellm.llms.azure_ai.common_utils import AzureFoundryModelInfo
azure_ai_route: Final = AzureFoundryModelInfo.get_azure_ai_route(model)
# Check if this is an agents route - model format: azure_ai/agents/<agent_id>
if azure_ai_route == "agents":
from litellm.llms.azure_ai.agents import AzureAIAgentsConfig
api_base = AzureFoundryModelInfo.get_api_base(api_base)
if api_base is None:
raise ValueError(
"Azure AI Agents requests require an api_base. Set `api_base` or the AZURE_AI_API_BASE env var."
)
api_key = AzureFoundryModelInfo.get_api_key(api_key)
response = AzureAIAgentsConfig.completion(
model=model,
messages=messages,
api_base=api_base,
api_key=api_key,
model_response=model_response,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
timeout=timeout,
acompletion=acompletion,
stream=stream,
headers=headers or litellm.headers,
)
# Check if this is a Claude model - route to Azure Anthropic handler
elif "claude" in model.lower():
# Use Azure Anthropic handler for Claude models
api_base = AzureFoundryModelInfo.get_api_base(api_base)
if api_base is None:
raise ValueError(
"Azure Anthropic requests require an api_base. Set `api_base` or the AZURE_AI_API_BASE env var."
)
api_key = AzureFoundryModelInfo.get_api_key(api_key)
# Ensure the URL ends with /v1/messages for Anthropic
if api_base:
api_base = api_base.rstrip("/")
if not api_base.endswith("/v1/messages"):
if "/anthropic" in api_base:
parts: Final = api_base.split("/anthropic", 1)
api_base = parts[0] + "/anthropic"
else:
api_base = api_base + "/anthropic"
api_base = api_base + "/v1/messages"
response = azure_anthropic_chat_completions.completion(
model=model,
messages=messages,
api_base=api_base,
acompletion=acompletion,
custom_prompt_dict=litellm.custom_prompt_dict,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging,
headers=headers,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
)
if optional_params.get("stream", False) or acompletion is True:
## LOGGING
logging.post_call(
input=messages,
api_key=api_key,
original_response=response,
)
response = response
else:
# Non-Claude models use standard Azure AI flow
api_base = AzureFoundryModelInfo.get_api_base(api_base)
# set API KEY
api_key = AzureFoundryModelInfo.get_api_key(api_key)
headers = headers or litellm.headers
if extra_headers is not None:
optional_params["extra_headers"] = extra_headers
## FOR COHERE
if "command-r" in model: # make sure tool call in messages are str
messages = stringify_json_tool_call_content(messages=messages)
## COMPLETION CALL
try:
response = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
timeout=timeout,
client=client, # pass AsyncOpenAI, OpenAI client
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
)
except Exception as e:
## LOGGING - log the original exception returned
logging.post_call(
input=messages,
api_key=api_key,
original_response=str(e),
additional_args={"headers": headers},
)
raise e
if optional_params.get("stream", False):
## LOGGING
logging.post_call(
input=messages,
api_key=api_key,
original_response=response,
additional_args={"headers": headers},
)
return response
def _complete_text_completion_openai(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_openai(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
text_completion: Final = ctx.text_completion
timeout: Final = ctx.timeout
openai.api_type = "openai"
api_base = (
api_base
or litellm.api_base
or get_secret("OPENAI_BASE_URL")
or get_secret("OPENAI_API_BASE")
or "https://api.openai.com/v1"
)
openai.api_version = None
# set API KEY
api_key = api_key or litellm.api_key or litellm.openai_key or get_secret("OPENAI_API_KEY")
headers = headers or litellm.headers
## LOAD CONFIG - if set
config: Final = litellm.OpenAITextCompletionConfig.get_config()
for k, v in _provider_config_items(config):
if (
k not in optional_params
): # completion(top_k=3) > openai_text_config(top_k=3) <- allows for dynamic variables to be passed in
optional_params[k] = v
if litellm.organization:
openai.organization = litellm.organization
## COMPLETION CALL
_response = openai_text_completions.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
print_verbose=print_verbose,
api_key=api_key,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
acompletion=acompletion,
client=client, # pass AsyncOpenAI, OpenAI client
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
timeout=timeout,
)
if optional_params.get("stream", False) is False and acompletion is False and text_completion is False:
# convert to chat completion response
_response = litellm.OpenAITextCompletionConfig().convert_to_chat_model_response_object(
response_object=_response, model_response_object=model_response
)
if optional_params.get("stream", False) or acompletion is True:
## LOGGING
logging.post_call(
input=messages,
api_key=api_key,
original_response=_response,
additional_args={"headers": headers},
)
return _response # pyright: ignore[reportReturnType] # provider SDK return type is broader than the dispatch contract
def _complete_fireworks_ai(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
optional_params: Final = (
provider_config.map_extra_body_params(optional_params=ctx.optional_params, model=model)
if isinstance(provider_config, litellm.FireworksAIConfig)
else ctx.optional_params
)
try:
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=provider_config,
)
except Exception as e:
## LOGGING - log the original exception returned
logging.post_call(
input=messages,
api_key=api_key,
original_response=str(e),
additional_args={"headers": headers},
)
raise e
return response
def _complete_together_ai(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
try:
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=provider_config,
)
except Exception as e:
logging.post_call(
input=messages,
api_key=api_key,
original_response=str(e),
additional_args=MappingProxyType({"headers": headers}),
)
raise
return response
def _complete_heroku(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
try:
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=provider_config,
)
except Exception as e:
logging.post_call(
input=messages,
api_key=api_key,
original_response=str(e),
additional_args={"headers": headers},
)
raise e
return response
def _complete_ragflow(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
try:
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=provider_config,
)
except Exception as e:
logging.post_call(
input=messages,
api_key=api_key,
original_response=str(e),
additional_args={"headers": headers},
)
raise e
return response
def _complete_scaledown(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
try:
return base_llm_http_handler.completion(
model=ctx.model,
messages=ctx.messages,
headers=ctx.headers,
model_response=ctx.model_response,
api_key=ctx.api_key,
api_base=ctx.api_base,
acompletion=ctx.acompletion,
logging_obj=ctx.logging,
optional_params=ctx.optional_params,
litellm_params=ctx.litellm_params,
shared_session=ctx.shared_session,
timeout=cast( # cast-ok: CompletionTimeout.resolve normalizes this value
float | httpx.Timeout, ctx.timeout
),
client=_dispatch_client_http(ctx),
custom_llm_provider=ctx.custom_llm_provider,
encoding=_get_encoding(),
stream=ctx.stream,
provider_config=ctx.provider_config,
)
except Exception as exc:
ctx.logging.post_call(
input=ctx.messages,
api_key=ctx.api_key,
original_response=str(exc),
additional_args={"headers": ctx.headers},
)
raise
def _complete_xai(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
try:
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=provider_config,
)
except Exception as e:
## LOGGING - log the original exception returned
logging.post_call(
input=messages,
api_key=api_key,
original_response=str(e),
additional_args={"headers": headers},
)
raise e
return response
def _complete_groq(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_base = (
api_base # for deepinfra/perplexity/anyscale/groq/friendliai we check in get_llm_provider and pass in the api base from there
or litellm.api_base
or get_secret("GROQ_API_BASE")
or "https://api.groq.com/openai/v1"
)
# set API KEY
api_key = (
api_key
or litellm.api_key # for deepinfra/perplexity/anyscale/friendliai we check in get_llm_provider and pass in the api key from there
or litellm.groq_key
or get_secret("GROQ_API_KEY")
)
headers = headers or litellm.headers
## LOAD CONFIG - if set
config: Final = litellm.GroqChatConfig.get_config()
for k, v in _provider_config_items(config):
if (
k not in optional_params
): # completion(top_k=3) > openai_config(top_k=3) <- allows for dynamic variables to be passed in
optional_params[k] = v
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider=custom_llm_provider,
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
client=client,
)
def _complete_bedrock_mantle(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_base = api_base or litellm.api_base or get_secret("BEDROCK_MANTLE_API_BASE")
api_key = api_key or litellm.api_key or get_secret("BEDROCK_MANTLE_API_KEY")
headers = headers or litellm.headers
config: Final = bedrock_mantle_chat_config(model).get_config()
for k, v in _provider_config_items(config):
if k not in optional_params:
optional_params[k] = v
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider=custom_llm_provider,
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging,
client=client,
)
def _complete_a2a(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
(
api_base,
api_key,
headers,
) = litellm.A2AConfig.resolve_agent_config_from_registry(
agent_name=model,
api_base=api_base,
api_key=api_key,
headers=headers,
optional_params=optional_params,
)
# Fall back to environment variables and defaults
api_base = api_base or litellm.api_base or get_secret_str("A2A_API_BASE")
if api_base is None:
raise Exception(
"api_base is required for A2A provider. "
"Either provide api_base parameter, set A2A_API_BASE environment variable, "
"or register the agent in the proxy with model='a2a/<agent-name>'."
)
headers = headers or litellm.headers
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider=custom_llm_provider,
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging,
client=client,
provider_config=provider_config,
)
def _complete_gigachat(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_key = (
api_key
or litellm.api_key
or litellm.gigachat_key
or get_secret("GIGACHAT_API_KEY")
or get_secret("GIGACHAT_CREDENTIALS")
)
headers = headers or litellm.headers or {}
## COMPLETION CALL
try:
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=provider_config,
)
except Exception as e:
## LOGGING - log the original exception returned
logging.post_call(
input=messages,
api_key=api_key,
original_response=str(e),
additional_args={"headers": headers},
)
raise e
return response
def _complete_sap(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
headers = headers or litellm.headers
## LOAD CONFIG - if set
config: Final = litellm.GenAIHubOrchestrationConfig.get_config()
for k, v in _provider_config_items(config):
if (
k not in optional_params
): # completion(top_k=3) > openai_config(top_k=3) <- allows for dynamic variables to be passed in
optional_params[k] = v
return sap_gen_ai_hub_chat_completions.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
timeout=timeout,
shared_session=shared_session,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
api_key=api_key,
api_base=api_base,
stream=stream,
)
def _complete_aiohttp_openai(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
if http2_enabled():
verbose_logger.warning(
"litellm.http2 is enabled but aiohttp_openai/ always uses aiohttp, which has no HTTP/2 client; this request stays on HTTP/1.1"
)
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
extra_headers: Final = ctx.extra_headers
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_base = (
api_base # for deepinfra/perplexity/anyscale/groq/friendliai we check in get_llm_provider and pass in the api base from there
or litellm.api_base
or get_secret("OPENAI_BASE_URL")
or get_secret("OPENAI_API_BASE")
or "https://api.openai.com/v1"
)
# set API KEY
api_key = (
api_key
or litellm.api_key # for deepinfra/perplexity/anyscale/friendliai we check in get_llm_provider and pass in the api key from there
or litellm.openai_key
or get_secret("OPENAI_API_KEY")
)
headers = headers or litellm.headers
if extra_headers is not None:
optional_params["extra_headers"] = extra_headers
return base_llm_aiohttp_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
)
def _complete_cometapi(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_key = api_key or litellm.cometapi_key or get_secret_str("COMETAPI_KEY") or litellm.api_key
api_base = api_base or litellm.api_base or get_secret_str("COMETAPI_API_BASE") or "https://api.cometapi.com/v1"
## COMPLETION CALL
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=provider_config,
)
## LOGGING
logging.post_call(input=messages, api_key=api_key, original_response=response)
return response
def _complete_minimax(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_key = api_key or get_secret_str("MINIMAX_API_KEY") or litellm.api_key
api_base = api_base or litellm.api_base or get_secret_str("MINIMAX_API_BASE") or "https://api.minimax.io/v1"
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
api_base=api_base,
custom_llm_provider=custom_llm_provider,
model_response=model_response,
encoding=_get_encoding(),
logging_obj=logging,
optional_params=optional_params,
timeout=timeout,
litellm_params=litellm_params,
shared_session=shared_session,
acompletion=acompletion,
stream=stream,
api_key=api_key,
headers=headers,
client=client,
provider_config=provider_config,
)
logging.post_call(input=messages, api_key=api_key, original_response=response)
return response
def _complete_hosted_vllm(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_base = api_base or litellm.api_base or get_secret_str("HOSTED_VLLM_API_BASE")
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
api_base=api_base,
custom_llm_provider=custom_llm_provider,
model_response=model_response,
encoding=_get_encoding(),
logging_obj=logging,
optional_params=optional_params,
timeout=timeout,
litellm_params=litellm_params,
shared_session=shared_session,
acompletion=acompletion,
stream=stream,
api_key=api_key,
headers=headers,
client=client,
provider_config=provider_config,
)
logging.post_call(input=messages, api_key=api_key, original_response=response)
return response
def _complete_custom_openai(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
custom_prompt_dict: Final = ctx.custom_prompt_dict
extra_headers = ctx.extra_headers
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
metadata: Final = _dispatch_metadata(ctx)
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
organization = ctx.organization
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
# for deepinfra/perplexity/anyscale/groq/friendliai we check in get_llm_provider and pass in the api base from there
api_base = _resolve_openai_api_base(api_base)
organization = (
organization
or litellm.organization
or get_secret("OPENAI_ORGANIZATION")
or None # default - https://github.com/openai/openai-python/blob/284c1799070c723c6a553337134148a7ab088dd8/openai/util.py#L105
)
openai.organization = organization
# set API KEY
api_key = (
api_key
or litellm.api_key # for deepinfra/perplexity/anyscale/friendliai we check in get_llm_provider and pass in the api key from there
or litellm.openai_key
or get_secret("OPENAI_API_KEY")
)
headers = headers or litellm.headers
outbound_headers: Final = (
headers
if provider_config is None
else with_attribution_headers(provider_config.get_attribution_headers(), headers)
)
# Add GitHub Copilot headers (same as /responses endpoint does)
if custom_llm_provider == "github_copilot":
from litellm.llms.github_copilot.authenticator import Authenticator
from litellm.llms.github_copilot.common_utils import (
get_copilot_default_headers,
pin_session_authorization,
)
from litellm.llms.github_copilot.per_user_auth import (
require_github_copilot_user_session,
)
user_session: Final = require_github_copilot_user_session(litellm_params)
copilot_headers: Final = get_copilot_default_headers(
user_session.token if user_session is not None else Authenticator().get_api_key()
)
if extra_headers:
copilot_headers.update(
cast("dict[str, str]", extra_headers) # cast-ok: extra_headers is a str-valued request dict
)
if user_session is not None:
pin_session_authorization(copilot_headers, user_session.token)
extra_headers = copilot_headers
use_base_llm_http_handler: Final = get_secret_bool("EXPERIMENTAL_OPENAI_BASE_LLM_HTTP_HANDLER")
if extra_headers is not None and not use_base_llm_http_handler:
optional_params["extra_headers"] = extra_headers
if litellm.enable_preview_features and metadata is not None: # [PREVIEW] allow metadata to be passed to OPENAI
openai_metadata: Final = get_requester_metadata(metadata)
if openai_metadata is not None:
optional_params["metadata"] = openai_metadata
## LOAD CONFIG - if set
config: Final = litellm.OpenAIConfig.get_config()
for k, v in _provider_config_items(config):
if (
k not in optional_params
): # completion(top_k=3) > openai_config(top_k=3) <- allows for dynamic variables to be passed in
optional_params[k] = v
## COMPLETION CALL
try:
if use_base_llm_http_handler:
response = base_llm_http_handler.completion(
model=model,
messages=messages,
api_base=api_base,
custom_llm_provider=custom_llm_provider,
model_response=model_response,
encoding=_get_encoding(),
logging_obj=logging,
optional_params=optional_params,
timeout=timeout,
litellm_params=litellm_params,
shared_session=shared_session,
acompletion=acompletion,
stream=stream,
api_key=api_key,
headers=outbound_headers,
client=client,
provider_config=provider_config,
)
else:
response = openai_chat_completions.completion(
model=model,
messages=messages,
headers=outbound_headers,
model_response=model_response,
print_verbose=print_verbose,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
timeout=timeout,
custom_prompt_dict=custom_prompt_dict,
client=client, # pass AsyncOpenAI, OpenAI client
organization=organization,
custom_llm_provider=custom_llm_provider,
shared_session=shared_session,
)
except Exception as e:
## LOGGING - log the original exception returned
logging.post_call(
input=messages,
api_key=api_key,
original_response=str(e),
additional_args={"headers": outbound_headers},
)
raise e
if optional_params.get("stream", False):
## LOGGING
logging.post_call(
input=messages,
api_key=api_key,
original_response=response,
additional_args={"headers": outbound_headers},
)
return response # pyright: ignore[reportReturnType] # provider SDK return type is broader than the dispatch contract
def _complete_mistral(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_key = api_key or litellm.api_key or get_secret("MISTRAL_API_KEY")
api_base = api_base or litellm.api_base or get_secret("MISTRAL_API_BASE") or "https://api.mistral.ai/v1"
return base_llm_http_handler.completion(
model=model,
messages=messages,
api_base=api_base,
custom_llm_provider=custom_llm_provider,
model_response=model_response,
encoding=_get_encoding(),
logging_obj=logging,
optional_params=optional_params,
timeout=timeout,
litellm_params=litellm_params,
shared_session=shared_session,
acompletion=acompletion,
stream=stream,
api_key=api_key,
headers=headers,
client=client,
provider_config=provider_config,
)
def _complete_replicate(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key: Final = ctx.api_key
custom_prompt_dict = ctx.custom_prompt_dict
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response = ctx.model_response
optional_params: Final = ctx.optional_params
replicate_key: Final = (
api_key
or litellm.replicate_key
or litellm.api_key
or get_secret("REPLICATE_API_KEY")
or get_secret("REPLICATE_API_TOKEN")
)
api_base = api_base or litellm.api_base or get_secret("REPLICATE_API_BASE") or "https://api.replicate.com/v1"
custom_prompt_dict = custom_prompt_dict or litellm.custom_prompt_dict
model_response = replicate_chat_completion(
model=model,
messages=messages,
api_base=api_base,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(), # for calculating input/output tokens
api_key=replicate_key,
logging_obj=logging,
custom_prompt_dict=custom_prompt_dict,
acompletion=acompletion,
headers=headers,
)
if optional_params.get("stream", False) is True:
## LOGGING
logging.post_call(
input=messages,
api_key=replicate_key,
original_response=model_response,
)
return model_response
def _complete_anthropic_text(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
custom_prompt_dict = ctx.custom_prompt_dict
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_key = api_key or litellm.anthropic_key or litellm.api_key or os.environ.get("ANTHROPIC_API_KEY")
custom_prompt_dict = custom_prompt_dict or litellm.custom_prompt_dict
api_base = cast(
str | None,
api_base
or litellm.api_base
or get_secret("ANTHROPIC_API_BASE")
or get_secret("ANTHROPIC_BASE_URL")
or "https://api.anthropic.com/v1/complete",
)
# Check if we should disable automatic URL suffix appending
disable_url_suffix: Final = get_secret_bool("LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX")
if api_base is not None and not disable_url_suffix and not api_base.endswith("/v1/complete"):
api_base += "/v1/complete"
elif disable_url_suffix:
verbose_logger.debug("LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX is set, skipping /v1/complete suffix")
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider="anthropic_text",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
)
def _complete_anthropic(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
custom_prompt_dict = ctx.custom_prompt_dict
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
timeout: Final = ctx.timeout
api_key = api_key or litellm.anthropic_key or litellm.api_key or os.environ.get("ANTHROPIC_API_KEY")
custom_prompt_dict = custom_prompt_dict or litellm.custom_prompt_dict
# call /messages
# default route for all anthropic models
api_base = cast(
str | None,
api_base
or litellm.api_base
or get_secret("ANTHROPIC_API_BASE")
or get_secret("ANTHROPIC_BASE_URL")
or "https://api.anthropic.com/v1/messages",
)
# Check if we should disable automatic URL suffix appending
disable_url_suffix: Final = get_secret_bool("LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX")
if api_base is not None and not disable_url_suffix and not api_base.endswith("/v1/messages"):
api_base += "/v1/messages"
elif disable_url_suffix:
verbose_logger.debug("LITELLM_ANTHROPIC_DISABLE_URL_SUFFIX is set, skipping /v1/messages suffix")
response: Final = anthropic_chat_completions.completion(
model=model,
messages=messages,
api_base=api_base,
acompletion=acompletion,
custom_prompt_dict=litellm.custom_prompt_dict,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(), # for calculating input/output tokens
api_key=api_key,
logging_obj=logging,
headers=headers,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
)
if optional_params.get("stream", False) or acompletion is True:
## LOGGING
logging.post_call(
input=messages,
api_key=api_key,
original_response=response,
)
return response
def _complete_nlp_cloud(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key: Final = ctx.api_key
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
nlp_cloud_key: Final = api_key or litellm.nlp_cloud_key or get_secret("NLP_CLOUD_API_KEY") or litellm.api_key
api_base = api_base or litellm.api_base or get_secret("NLP_CLOUD_API_BASE") or "https://api.nlpcloud.io/v1/gpu/"
response = nlp_cloud_chat_completion(
model=model,
messages=messages,
api_base=api_base,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
api_key=nlp_cloud_key,
logging_obj=logging,
)
if "stream" in optional_params and optional_params["stream"] is True:
# don't try to access stream object,
response = CustomStreamWrapper(
response,
model,
custom_llm_provider="nlp_cloud",
logging_obj=logging,
)
if optional_params.get("stream", False) or acompletion is True:
## LOGGING
logging.post_call(
input=messages,
api_key=api_key,
original_response=response,
)
return response # pyright: ignore[reportReturnType] # provider SDK return type is broader than the dispatch contract
def _complete_aleph_alpha(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
api_base = ctx.api_base
api_key: Final = ctx.api_key
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response = ctx.model_response
optional_params: Final = ctx.optional_params
aleph_alpha_key: Final = (
api_key
or litellm.aleph_alpha_key
or get_secret("ALEPH_ALPHA_API_KEY")
or get_secret("ALEPHALPHA_API_KEY")
or litellm.api_key
)
api_base = (
api_base or litellm.api_base or get_secret("ALEPH_ALPHA_API_BASE") or "https://api.aleph-alpha.com/complete"
)
model_response = aleph_alpha.completion(
model=model,
messages=messages,
api_base=api_base,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
default_max_tokens_to_sample=litellm.max_tokens,
api_key=aleph_alpha_key,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
)
if "stream" in optional_params and optional_params["stream"] is True:
# don't try to access stream object,
return CustomStreamWrapper(
model_response,
model,
custom_llm_provider="aleph_alpha",
logging_obj=logging,
)
return model_response # pyright: ignore[reportReturnType] # provider SDK return type is broader than the dispatch contract
def _complete_cohere_chat(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key: Final = ctx.api_key
extra_headers: Final = ctx.extra_headers
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
cohere_key: Final = (
api_key
or litellm.cohere_key
or get_secret_str("COHERE_API_KEY")
or get_secret_str("CO_API_KEY")
or litellm.api_key
)
cohere_route: Final = CohereModelInfo.get_cohere_route(model)
verbose_logger.debug("Cohere route: %s", cohere_route)
# Set API base based on route
if cohere_route == "v2":
api_base = api_base or litellm.api_base or get_secret_str("COHERE_API_BASE") or "https://api.cohere.com/v2/chat"
# Remove v2/ prefix from model name for the actual API call
if "v2/" in model:
model = model.replace("v2/", "")
else:
api_base = api_base or litellm.api_base or get_secret_str("COHERE_API_BASE") or "https://api.cohere.ai/v1/chat"
headers = headers or litellm.headers or {}
if headers is None:
headers = {}
if extra_headers is not None:
headers.update(extra_headers)
verbose_logger.debug("Model: %s, API Base: %s", model, api_base)
verbose_logger.debug("Provider Config: %s", provider_config)
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider="cohere_chat",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=cohere_key,
provider_config=provider_config,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
)
def _complete_maritalk(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
api_base = ctx.api_base
api_key: Final = ctx.api_key
custom_prompt_dict: Final = ctx.custom_prompt_dict
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
maritalk_key: Final = api_key or litellm.maritalk_key or get_secret("MARITALK_API_KEY") or litellm.api_key
api_base = api_base or litellm.api_base or get_secret("MARITALK_API_BASE") or "https://chat.maritaca.ai/api"
return openai_like_chat_completion.completion(
model=model,
messages=messages,
api_base=api_base,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
api_key=maritalk_key,
logging_obj=logging,
custom_llm_provider="maritalk",
custom_prompt_dict=custom_prompt_dict,
)
def _complete_amazon_nova(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
api_base = ctx.api_base
api_key = ctx.api_key
custom_llm_provider: Final = ctx.custom_llm_provider
custom_prompt_dict: Final = ctx.custom_prompt_dict
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
timeout: Final = ctx.timeout
api_key = api_key or litellm.amazon_nova_api_key or get_secret_str("AMAZON_NOVA_API_KEY") or litellm.api_key
api_base = (
api_base or litellm.api_base or get_secret_str("AMAZON_NOVA_API_BASE") or "https://api.nova.amazon.com/v1"
)
return openai_like_chat_completion.completion(
model=model,
messages=messages,
api_base=api_base,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging,
timeout=timeout,
custom_llm_provider=custom_llm_provider,
custom_prompt_dict=custom_prompt_dict,
)
def _complete_huggingface(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
stream: Final = ctx.stream
timeout: Final = ctx.timeout
huggingface_key: Final = (
api_key
or litellm.huggingface_key
or os.environ.get("HF_TOKEN")
or os.environ.get("HUGGINGFACE_API_KEY")
or litellm.api_key
)
hf_headers: Final = headers or litellm.headers
return base_llm_http_handler.completion(
model=model,
messages=messages,
headers=hf_headers,
model_response=model_response,
api_key=huggingface_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
)
def _complete_oci(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
stream: Final = ctx.stream
timeout: Final = ctx.timeout
return base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
)
def _complete_compactifai(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_key = api_key or get_secret_str("COMPACTIFAI_API_KEY") or litellm.api_key
api_base = api_base or "https://api.compactif.ai/v1"
## COMPLETION CALL
return base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=provider_config,
)
def _complete_oobabooga(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
api_base: Final = ctx.api_base
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response = ctx.model_response
optional_params: Final = ctx.optional_params
model_response = oobabooga.completion(
model=model,
messages=messages,
model_response=model_response,
api_base=api_base,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
api_key=None,
logger_fn=logger_fn,
encoding=_get_encoding(),
logging_obj=logging,
)
if "stream" in optional_params and optional_params["stream"] is True:
# don't try to access stream object,
return CustomStreamWrapper(
model_response,
model,
custom_llm_provider="oobabooga",
logging_obj=logging,
)
return model_response # pyright: ignore[reportReturnType] # provider SDK return type is broader than the dispatch contract
def _complete_databricks(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_base = (
api_base # for databricks we check in get_llm_provider and pass in the api base from there
or litellm.api_base
or os.getenv("DATABRICKS_API_BASE")
)
# set API KEY
api_key = (
api_key
or litellm.api_key # for databricks we check in get_llm_provider and pass in the api key from there
or litellm.databricks_key
or get_secret("DATABRICKS_API_KEY")
)
headers = headers or litellm.headers
## COMPLETION CALL
try:
response: Final = base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
custom_llm_provider="databricks",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
client=client,
)
except Exception as e:
## LOGGING - log the original exception returned
logging.post_call(
input=messages,
api_key=api_key,
original_response=str(e),
additional_args={"headers": headers},
)
raise e
if optional_params.get("stream", False):
## LOGGING
logging.post_call(
input=messages,
api_key=api_key,
original_response=response,
additional_args={"headers": headers},
)
return response
def _complete_datarobot(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config: Final = ctx.provider_config
stream: Final = ctx.stream
timeout: Final = ctx.timeout
return base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=provider_config,
)
def _complete_openrouter(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_base = api_base or litellm.api_base or get_secret_str("OPENROUTER_API_BASE") or "https://openrouter.ai/api/v1"
api_key = (
api_key
or litellm.api_key
or litellm.openrouter_key
or get_secret_str("OPENROUTER_API_KEY")
or get_secret_str("OR_API_KEY")
)
openrouter_site_url: Final = get_secret("OR_SITE_URL") or "https://litellm.ai"
openrouter_app_name: Final = get_secret("OR_APP_NAME") or "liteLLM"
openrouter_headers: Final = {
"HTTP-Referer": openrouter_site_url,
"X-Title": openrouter_app_name,
}
_headers: Final = headers or litellm.headers
if _headers:
openrouter_headers.update(_headers)
headers = openrouter_headers
## Load Config
config: Final = litellm.OpenrouterConfig.get_config()
for k, v in _provider_config_items(config):
if k == "extra_body":
# we use openai 'extra_body' to pass openrouter specific params - transforms, route, models
if "extra_body" in optional_params:
optional_params[k].update(v)
else:
optional_params[k] = v
elif k not in optional_params:
optional_params[k] = v
## COMPLETION CALL
response: Final = base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider="openrouter",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
client=client,
)
## LOGGING
logging.post_call(input=messages, api_key=openai.api_key, original_response=response)
return response
def _complete_nadir(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
api_base: Final = ctx.api_base or litellm.api_base or get_secret_str("NADIR_API_BASE") or NADIR_DEFAULT_API_BASE
api_key: Final = ctx.api_key
response: Final = base_llm_http_handler.completion(
model=ctx.model,
stream=ctx.stream,
messages=ctx.messages,
acompletion=ctx.acompletion,
api_base=api_base,
model_response=ctx.model_response,
optional_params=ctx.optional_params,
litellm_params=ctx.litellm_params,
shared_session=ctx.shared_session,
custom_llm_provider="nadir",
timeout=ctx.timeout,
headers=ctx.headers or litellm.headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=ctx.logging,
client=ctx.client,
)
ctx.logging.post_call(input=ctx.messages, api_key=api_key, original_response=response)
return response
def _complete_vercel_ai_gateway(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_base = (
api_base
or litellm.api_base
or get_secret_str("VERCEL_AI_GATEWAY_API_BASE")
or "https://ai-gateway.vercel.sh/v1"
)
api_key = api_key or litellm.api_key or get_secret("VERCEL_AI_GATEWAY_API_KEY")
vercel_site_url: Final = get_secret("VERCEL_SITE_URL") or "https://litellm.ai"
vercel_app_name: Final = get_secret("VERCEL_APP_NAME") or "liteLLM"
vercel_headers: Final = {
"http-referer": vercel_site_url,
"x-title": vercel_app_name,
}
_headers: Final = headers or litellm.headers
if _headers:
vercel_headers.update(_headers)
headers = vercel_headers
## Load Config
config: Final = litellm.VercelAIGatewayConfig.get_config()
for k, v in _provider_config_items(config):
if k == "extra_body":
# we use openai 'extra_body' to pass vercel specific params - providerOptions
if "extra_body" in optional_params:
optional_params[k].update(v)
else:
optional_params[k] = v
elif k not in optional_params:
optional_params[k] = v
## COMPLETION CALL
response: Final = base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider="vercel_ai_gateway",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
client=client,
)
## LOGGING
logging.post_call(input=messages, api_key=openai.api_key, original_response=response)
return response
def _complete_edenai(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
api_base: Final = litellm.EdenAIChatConfig.get_api_base(ctx.api_base)
api_key: Final = litellm.EdenAIChatConfig.get_api_key(ctx.api_key or litellm.api_key)
response: Final = base_llm_http_handler.completion(
model=ctx.model,
messages=ctx.messages,
api_base=api_base,
custom_llm_provider="edenai",
model_response=ctx.model_response,
encoding=_get_encoding(),
logging_obj=ctx.logging,
optional_params=ctx.optional_params,
timeout=ctx.timeout,
litellm_params=ctx.litellm_params,
shared_session=ctx.shared_session,
acompletion=ctx.acompletion,
stream=ctx.stream,
api_key=api_key,
headers=ctx.headers or litellm.headers,
client=_dispatch_client_http(ctx),
provider_config=ctx.provider_config,
)
ctx.logging.post_call(input=ctx.messages, api_key=api_key, original_response=response)
return response
def _complete_fal_ai(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
if ctx.stream:
raise litellm.FalAIError(
status_code=400,
message="fal_ai chat completions do not support streaming",
)
api_base: Final = litellm.FalAIChatConfig.get_api_base(ctx.api_base)
api_key: Final = litellm.FalAIChatConfig.get_api_key(ctx.api_key or litellm.api_key)
response: Final = base_llm_http_handler.completion(
model=ctx.model,
messages=ctx.messages,
api_base=api_base,
custom_llm_provider="fal_ai",
model_response=ctx.model_response,
encoding=_get_encoding(),
logging_obj=ctx.logging,
optional_params=ctx.optional_params,
timeout=ctx.timeout,
litellm_params=ctx.litellm_params,
shared_session=ctx.shared_session,
acompletion=ctx.acompletion,
stream=ctx.stream,
api_key=api_key,
headers=ctx.headers or litellm.headers,
client=_dispatch_client_http(ctx),
provider_config=ctx.provider_config,
)
ctx.logging.post_call(input=ctx.messages, api_key=api_key, original_response=response)
return response
def _complete_vertex_ai_beta(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
timeout: Final = ctx.timeout
vertex_ai_project: Final = (
optional_params.pop("vertex_project", None)
or optional_params.pop("vertex_ai_project", None)
or litellm.vertex_project
or get_secret("VERTEXAI_PROJECT")
)
vertex_ai_location: Final = (
optional_params.pop("vertex_location", None)
or optional_params.pop("vertex_ai_location", None)
or litellm.vertex_location
or get_secret("VERTEXAI_LOCATION")
)
vertex_credentials: Final = (
optional_params.pop("vertex_credentials", None)
or optional_params.pop("vertex_ai_credentials", None)
or get_secret("VERTEXAI_CREDENTIALS")
)
gemini_api_key: Final = (
api_key
or get_api_key_from_env()
or get_secret("PALM_API_KEY") # older palm api key should also work
or litellm.api_key
)
api_base = api_base or litellm.api_base or get_secret("GEMINI_API_BASE")
new_params: Final = safe_deep_copy(optional_params or {})
return vertex_chat_completion.completion(
model=model,
messages=messages,
model_response=model_response,
print_verbose=print_verbose,
optional_params=new_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
vertex_location=vertex_ai_location,
vertex_project=vertex_ai_project,
vertex_credentials=vertex_credentials,
gemini_api_key=gemini_api_key,
logging_obj=logging,
acompletion=acompletion,
timeout=timeout,
custom_llm_provider=custom_llm_provider,
client=client,
api_base=api_base,
extra_headers=headers,
)
def _complete_vertex_ai(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
custom_prompt_dict: Final = ctx.custom_prompt_dict
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response = ctx.model_response
optional_params: Final = ctx.optional_params
stream: Final = ctx.stream
timeout: Final = ctx.timeout
vertex_ai_project: Final = (
optional_params.pop("vertex_project", None)
or optional_params.pop("vertex_ai_project", None)
or litellm.vertex_project
or get_secret("VERTEXAI_PROJECT")
)
vertex_ai_location: Final = (
optional_params.pop("vertex_location", None)
or optional_params.pop("vertex_ai_location", None)
or litellm.vertex_location
or get_secret("VERTEXAI_LOCATION")
)
vertex_credentials: Final = (
optional_params.pop("vertex_credentials", None)
or optional_params.pop("vertex_ai_credentials", None)
or get_secret("VERTEXAI_CREDENTIALS")
)
api_base = api_base or litellm.api_base or get_secret("VERTEXAI_API_BASE")
new_params: Final = safe_deep_copy(optional_params or {})
model_route: Final = get_vertex_ai_model_route(model=model, litellm_params=litellm_params)
if model_route == VertexAIModelRoute.PARTNER_MODELS:
model_response = vertex_partner_models_chat_completion.completion(
model=model,
messages=messages,
model_response=model_response,
print_verbose=print_verbose,
optional_params=new_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
api_base=api_base,
vertex_location=vertex_ai_location,
vertex_project=vertex_ai_project,
vertex_credentials=vertex_credentials,
logging_obj=logging,
acompletion=acompletion,
headers=headers,
custom_prompt_dict=custom_prompt_dict,
timeout=timeout,
client=client,
)
elif model_route == VertexAIModelRoute.GEMINI:
model_response = vertex_chat_completion.completion(
model=model,
messages=messages,
model_response=model_response,
print_verbose=print_verbose,
optional_params=new_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
vertex_location=vertex_ai_location,
vertex_project=vertex_ai_project,
vertex_credentials=vertex_credentials,
gemini_api_key=None,
logging_obj=logging,
acompletion=acompletion,
timeout=timeout,
custom_llm_provider=custom_llm_provider,
client=client,
api_base=api_base,
extra_headers=headers,
)
elif model_route == VertexAIModelRoute.GEMMA:
# Vertex Gemma Models with custom prediction endpoint
model_response = vertex_gemma_chat_completion.completion(
model=model,
messages=messages,
model_response=model_response,
print_verbose=print_verbose,
optional_params=new_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
api_base=api_base,
vertex_location=vertex_ai_location,
vertex_project=vertex_ai_project,
vertex_credentials=vertex_credentials,
logging_obj=logging,
acompletion=acompletion,
headers=headers,
custom_prompt_dict=custom_prompt_dict,
timeout=timeout,
client=client,
)
elif model_route == VertexAIModelRoute.MODEL_GARDEN:
# Vertex Model Garden - OpenAI compatible models
model_response = vertex_model_garden_chat_completion.completion(
model=model,
messages=messages,
model_response=model_response,
print_verbose=print_verbose,
optional_params=new_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
api_base=api_base,
vertex_location=vertex_ai_location,
vertex_project=vertex_ai_project,
vertex_credentials=vertex_credentials,
logging_obj=logging,
acompletion=acompletion,
headers=headers,
custom_prompt_dict=custom_prompt_dict,
timeout=timeout,
client=client,
)
elif model_route == VertexAIModelRoute.AGENT_ENGINE:
# Vertex AI Agent Engine (Reasoning Engines)
from litellm.llms.vertex_ai.agent_engine.transformation import (
VertexAgentEngineConfig,
)
vertex_agent_engine_config: Final = VertexAgentEngineConfig()
# Update litellm_params with vertex credentials
litellm_params["vertex_project"] = vertex_ai_project
litellm_params["vertex_location"] = vertex_ai_location
litellm_params["vertex_credentials"] = vertex_credentials
model_response = base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
model_response=model_response,
optional_params=new_params,
litellm_params=litellm_params,
encoding=_get_encoding(),
api_key=None,
api_base=api_base,
logging_obj=logging,
acompletion=acompletion,
timeout=timeout,
client=client,
custom_llm_provider="vertex_ai",
provider_config=vertex_agent_engine_config,
headers=headers or {},
)
else: # VertexAIModelRoute.NON_GEMINI
model_response = vertex_ai_non_gemini.completion(
model=model,
messages=messages,
model_response=model_response,
print_verbose=print_verbose,
optional_params=new_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
vertex_location=vertex_ai_location,
vertex_project=vertex_ai_project,
vertex_credentials=vertex_credentials,
logging_obj=logging,
acompletion=acompletion,
)
if "stream" in optional_params and optional_params["stream"] is True and acompletion is False:
return CustomStreamWrapper(
model_response,
model,
custom_llm_provider="vertex_ai",
logging_obj=logging,
)
return model_response # pyright: ignore[reportReturnType] # provider SDK return type is broader than the dispatch contract
def _complete_predibase(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
custom_prompt_dict: Final = ctx.custom_prompt_dict
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
timeout: Final = ctx.timeout
tenant_id: Final = (
optional_params.pop("tenant_id", None)
or optional_params.pop("predibase_tenant_id", None)
or litellm.predibase_tenant_id
or get_secret("PREDIBASE_TENANT_ID")
)
if tenant_id is None:
raise ValueError(
"Missing Predibase Tenant ID - Required for making the request. Set dynamically (e.g. `completion(..tenant_id=<MY-ID>)`) or in env - `PREDIBASE_TENANT_ID`."
)
api_base = (
api_base
or optional_params.pop("api_base", None)
or optional_params.pop("base_url", None)
or litellm.api_base
or get_secret("PREDIBASE_API_BASE")
)
api_key = api_key or litellm.api_key or litellm.predibase_key or get_secret("PREDIBASE_API_KEY")
_model_response: Final = predibase_chat_completions.completion(
model=model,
messages=messages,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
logging_obj=logging,
acompletion=acompletion,
api_base=api_base,
custom_prompt_dict=custom_prompt_dict,
api_key=api_key,
tenant_id=tenant_id,
timeout=timeout,
)
if "stream" in optional_params and optional_params["stream"] is True and acompletion is False:
return _model_response
return _model_response
def _complete_text_completion_codestral(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
custom_prompt_dict: Final = ctx.custom_prompt_dict
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
optional_params: Final = ctx.optional_params
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_base = (
api_base
or optional_params.pop("api_base", None)
or optional_params.pop("base_url", None)
or litellm.api_base
or "https://codestral.mistral.ai/v1/fim/completions"
)
api_key = api_key or litellm.api_key or get_secret("CODESTRAL_API_KEY")
text_completion_model_response: Final = litellm.TextCompletionResponse(stream=stream)
_model_response: Final = codestral_text_completions.completion(
model=model,
messages=messages,
model_response=text_completion_model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
logging_obj=logging,
acompletion=acompletion,
api_base=api_base,
custom_prompt_dict=custom_prompt_dict,
api_key=api_key,
timeout=timeout,
)
if "stream" in optional_params and optional_params["stream"] is True and acompletion is False:
return _model_response # pyright: ignore[reportReturnType] # provider SDK return type is broader than the dispatch contract
return _model_response # pyright: ignore[reportReturnType] # provider SDK return type is broader than the dispatch contract
def _complete_text_completion_inception(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_openai(ctx)
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
text_completion: Final = ctx.text_completion
timeout: Final = ctx.timeout
passed_api_base: Final = api_base or optional_params.pop("api_base", None) or optional_params.pop("base_url", None)
api_base = passed_api_base or get_secret_str("INCEPTION_API_BASE") or "https://api.inceptionlabs.ai/v1"
# FIM is served at `/v1/fim/completions`; the OpenAI client appends
# `/completions`, so point it at the `/v1/fim` base.
api_base = api_base.rstrip("/")
if not api_base.endswith("/fim"):
api_base += "/fim"
# Don't forward the server-managed Inception key to a caller-supplied
# api_base; only resolve it for the default/server base, or when the
# caller passes their own key.
if passed_api_base is None or api_key:
api_key = api_key or litellm.inception_key or get_secret_str("INCEPTION_API_KEY")
_response = openai_text_completions.completion(
model=model,
messages=messages,
model_response=model_response,
print_verbose=print_verbose,
api_key=api_key,
custom_llm_provider="text-completion-inception",
api_base=api_base,
acompletion=acompletion,
client=client,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
timeout=timeout,
)
if optional_params.get("stream", False) is False and acompletion is False and text_completion is False:
_response = litellm.OpenAITextCompletionConfig().convert_to_chat_model_response_object(
response_object=_response, model_response_object=model_response
)
if optional_params.get("stream", False) or acompletion is True:
logging.post_call(
input=messages,
api_key=api_key,
original_response=_response,
additional_args={"headers": headers},
)
return _response # pyright: ignore[reportReturnType] # provider SDK return type is broader than the dispatch contract
def _complete_sagemaker_chat(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
stream: Final = ctx.stream
timeout: Final = ctx.timeout
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
custom_llm_provider=custom_llm_provider,
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
client=client,
)
def _complete_sagemaker(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
custom_prompt_dict: Final = ctx.custom_prompt_dict
hf_model_name: Final = ctx.hf_model_name
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
return sagemaker_llm.completion(
model=model,
messages=messages,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
custom_prompt_dict=custom_prompt_dict,
hf_model_name=hf_model_name,
logger_fn=logger_fn,
encoding=_get_encoding(),
logging_obj=logging,
acompletion=acompletion,
)
_ADDITIONAL_DROP_PARAMS_ADAPTER: Final = TypeAdapter(list[str])
_OPTIONAL_PARAMS_ADAPTER: Final = TypeAdapter(dict[str, object])
_REQUEST_KWARGS_ADAPTER: Final = TypeAdapter(Mapping[str, object])
_PROVIDER_ROUTING_HINTS: Final = TypeAdapter(ProviderRoutingHints)
_BASE_URL_HINT: Final = TypeAdapter(BaseUrlRoutingHint)
def _complete_bedrock(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_prompt_dict = ctx.custom_prompt_dict
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
provider_config = ctx.provider_config
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
custom_prompt_dict = custom_prompt_dict or litellm.custom_prompt_dict
if "aws_bedrock_client" in optional_params:
verbose_logger.warning(
"'aws_bedrock_client' is a deprecated param. Please move to another auth method - https://docs.litellm.ai/docs/providers/bedrock#boto3---authentication."
)
# Extract credentials for legacy boto3 client and pass thru to httpx
aws_bedrock_client: Final = optional_params.pop("aws_bedrock_client")
creds: Final = aws_bedrock_client._get_credentials().get_frozen_credentials()
if creds.access_key:
optional_params["aws_access_key_id"] = creds.access_key
if creds.secret_key:
optional_params["aws_secret_access_key"] = creds.secret_key
if creds.token:
optional_params["aws_session_token"] = creds.token
if "aws_region_name" not in optional_params or optional_params["aws_region_name"] is None:
optional_params["aws_region_name"] = aws_bedrock_client.meta.region_name
additional_drop_params: Final = (
_ADDITIONAL_DROP_PARAMS_ADAPTER.validate_python(ctx.kwargs["additional_drop_params"])
if ctx.kwargs.get("additional_drop_params") is not None
else None
)
bedrock_route: Final = bedrock_route_for_request(model, ctx.request_params, additional_drop_params)
if bedrock_route == "claude_platform":
provider_config = ProviderConfigManager.get_provider_chat_config(
model=model,
provider=LlmProviders.BEDROCK,
)
model = BedrockModelInfo.get_claude_platform_model(model)
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider="bedrock",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging,
client=client,
provider_config=provider_config,
)
elif bedrock_route == "converse":
model = without_bedrock_route_prefix(model)
response = bedrock_converse_chat_completion.completion(
model=model,
messages=messages,
custom_prompt_dict=custom_prompt_dict,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
logging_obj=logging,
extra_headers=headers, # Use merged headers instead of original extra_headers
timeout=timeout,
acompletion=acompletion,
client=client,
api_base=api_base,
api_key=api_key,
)
elif bedrock_route == "converse_like":
model = model.replace("converse_like/", "")
response = base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
custom_llm_provider="bedrock",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
client=client,
)
else:
response = base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
custom_llm_provider="bedrock",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging,
client=client,
)
return response
def _complete_watsonx(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_prompt_dict: Final = ctx.custom_prompt_dict
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
timeout: Final = ctx.timeout
return watsonx_chat_completion.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
print_verbose=print_verbose,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
timeout=timeout,
custom_prompt_dict=custom_prompt_dict,
client=client, # pass AsyncOpenAI, OpenAI client
encoding=_get_encoding(),
custom_llm_provider="watsonx",
)
def _complete_watsonx_text(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_key = (
api_key
or optional_params.pop("apikey", None)
or get_secret_str("WATSONX_APIKEY")
or get_secret_str("WATSONX_API_KEY")
or get_secret_str("WX_API_KEY")
)
api_base = (
api_base
or optional_params.pop(
"url",
optional_params.pop("api_base", optional_params.pop("base_url", None)),
)
or get_secret_str("WATSONX_API_BASE")
or get_secret_str("WATSONX_URL")
or get_secret_str("WX_URL")
or get_secret_str("WML_URL")
)
wx_credentials: Final = optional_params.pop(
"wx_credentials",
optional_params.pop("watsonx_credentials", None), # follow {provider}_credentials, same as vertex ai
)
token: str | None = None
if wx_credentials is not None:
api_base = wx_credentials.get("url", api_base)
api_key = wx_credentials.get("apikey", wx_credentials.get("api_key", api_key))
token = wx_credentials.get(
"token",
wx_credentials.get(
"watsonx_token", None
), # follow format of {provider}_token, same as azure - e.g. 'azure_ad_token=..'
)
if token is not None:
optional_params["token"] = token
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider="watsonx_text",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
client=client,
)
def _complete_vllm(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
custom_prompt_dict = ctx.custom_prompt_dict
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response = ctx.model_response
optional_params: Final = ctx.optional_params
custom_prompt_dict = custom_prompt_dict or litellm.custom_prompt_dict
model_response = vllm_handler.completion(
model=model,
messages=messages,
custom_prompt_dict=custom_prompt_dict,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
logging_obj=logging,
)
if "stream" in optional_params and optional_params["stream"] is True: ## [BETA]
# don't try to access stream object,
return CustomStreamWrapper(
model_response,
model,
custom_llm_provider="vllm",
logging_obj=logging,
)
## RESPONSE OBJECT
return model_response
def _complete_ollama(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key: Final = ctx.api_key
client: Final = _dispatch_client_http(ctx)
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_base = litellm.api_base or api_base or get_secret("OLLAMA_API_BASE") or "http://localhost:11434"
if api_key is not None and "Authorization" not in headers:
headers["Authorization"] = f"Bearer {api_key}"
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider="ollama",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
client=client,
)
def _complete_ollama_chat(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_base = litellm.api_base or api_base or get_secret("OLLAMA_API_BASE") or "http://localhost:11434"
api_key = api_key or litellm.ollama_key or os.environ.get("OLLAMA_API_KEY") or litellm.api_key
if api_key is not None and "Authorization" not in headers:
headers["Authorization"] = f"Bearer {api_key}"
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider="ollama_chat",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
client=client,
)
def _complete_triton(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key: Final = ctx.api_key
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_base = litellm.api_base or api_base
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider=custom_llm_provider,
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging,
)
def _complete_cloudflare(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
custom_prompt_dict = ctx.custom_prompt_dict
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_key = api_key or litellm.cloudflare_api_key or litellm.api_key or get_secret("CLOUDFLARE_API_KEY")
api_base = api_base or litellm.api_base or get_secret("CLOUDFLARE_API_BASE")
custom_prompt_dict = custom_prompt_dict or litellm.custom_prompt_dict
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider="cloudflare",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging, # model call logging done inside the class as we make need to modify I/O to fit aleph alpha's requirements
)
def _complete_petals(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
api_base = ctx.api_base
client: Final = _dispatch_client_http(ctx)
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response = ctx.model_response
optional_params: Final = ctx.optional_params
stream = ctx.stream
api_base = api_base or litellm.api_base
stream = optional_params.pop("stream", False)
model_response = petals_handler.completion(
model=model,
messages=messages,
api_base=api_base,
model_response=model_response,
print_verbose=print_verbose,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
encoding=_get_encoding(),
logging_obj=logging,
client=client,
)
if stream is True: ## [BETA]
# Fake streaming for petals
resp_string: Final = model_response["choices"][0]["message"]["content"]
return CustomStreamWrapper(
resp_string,
model,
custom_llm_provider="petals",
logging_obj=logging,
)
return model_response
def _complete_snowflake(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
injected_client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
client: Final = (
injected_client if injected_client is not None else (HTTPHandler(timeout=timeout) if stream is False else None)
) # Keep this here, otherwise, the httpx.client closes and streaming is impossible
try:
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
)
except Exception as e:
## LOGGING - log the original exception returned
logging.post_call(
input=messages,
api_key=api_key,
original_response=str(e),
additional_args={"headers": headers},
)
raise e
return response
def _complete_gradient_ai(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key: Final = ctx.api_key
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_base = litellm.api_base or api_base
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider="gradient_ai",
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging,
)
def _complete_gdc(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_key = api_key or litellm.gdc_key or get_secret_str("GDC_API_KEY") or litellm.api_key
api_base = api_base or litellm.gdc_api_base or get_secret_str("GDC_API_BASE") or litellm.api_base
return base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=gdc_transformation,
)
def _complete_bytez(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_key = api_key or litellm.bytez_key or get_secret_str("BYTEZ_API_KEY") or litellm.api_key
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=bytez_transformation,
)
return response
def _complete_lemonade(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_key = api_key or litellm.lemonade_key or get_secret_str("LEMONADE_API_KEY") or litellm.api_key
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=lemonade_transformation,
)
return response
def _complete_ovhcloud(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers: Final = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
stream: Final = ctx.stream
timeout: Final = ctx.timeout
api_key = api_key or litellm.ovhcloud_key or get_secret_str("OVHCLOUD_API_KEY") or litellm.api_key
api_base = (
api_base
or litellm.api_base
or get_secret_str("OVHCLOUD_API_BASE")
or "https://oai.endpoints.kepler.ai.cloud.ovh.net/v1"
)
response: Final = base_llm_http_handler.completion(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
timeout=timeout,
client=client,
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
provider_config=ovhcloud_transformation,
)
return response
def _custom_api_first_output(resp: httpx.Response | None) -> str:
return resp.json()["data"][0]["output"][0]
def _complete_custom(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
api_base: Final = ctx.api_base
headers: Final = ctx.headers
kwargs: Final = ctx.kwargs
max_tokens: Final = ctx.max_tokens
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
temperature: Final = ctx.temperature
top_p: Final = ctx.top_p
url: Final = litellm.api_base or api_base or ""
if url is None or url == "":
raise ValueError("api_base not set. Set api_base or litellm.api_base for custom endpoints")
"""
assume input to custom LLM api bases follow this format:
resp = litellm.module_level_client.post(
api_base,
json={
'model': 'meta-llama/Llama-2-13b-hf', # model name
'params': {
'prompt': ["The capital of France is P"],
'max_tokens': 32,
'temperature': 0.7,
'top_p': 1.0,
'top_k': 40,
}
}
)
"""
prompt: Final = " ".join([message["content"] for message in messages])
resp: Final = litellm.module_level_client.post(
url,
headers=headers,
json={
"model": model,
"params": {
"prompt": [prompt],
"max_tokens": max_tokens,
"temperature": temperature,
"top_p": top_p,
"top_k": kwargs.get("top_k"),
},
**kwargs.get("extra_body", {}),
},
)
"""
assume all responses from custom api_bases of this format:
{
'data': [
{
'prompt': 'The capital of France is P',
'output': ['The capital of France is PARIS.\nThe capital of France is PARIS.\nThe capital of France is PARIS.\nThe capital of France is PARIS.\nThe capital of France is PARIS.\nThe capital of France is PARIS.\nThe capital of France is PARIS.\nThe capital of France is PARIS.\nThe capital of France is PARIS.\nThe capital of France is PARIS.\nThe capital of France is PARIS.\nThe capital of France is PARIS.\nThe capital of France is PARIS.\nThe capital of France'],
'params': {'temperature': 0.7, 'top_k': 40, 'top_p': 1}}],
'message': 'ok'
}
]
}
"""
string_response: Final = _custom_api_first_output(resp)
## RESPONSE OBJECT
model_response.choices[0].message.content = string_response
model_response.created = int(time.time())
model_response.model = model
return model_response
def _complete_custom_providers(
ctx: CompletionDispatchContext,
) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base: Final = ctx.api_base
api_key: Final = ctx.api_key
client: Final = ctx.client
custom_llm_provider: Final = ctx.custom_llm_provider
custom_prompt_dict: Final = ctx.custom_prompt_dict
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logger_fn: Final = ctx.logger_fn
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
stream: Final = ctx.stream
timeout: Final = ctx.timeout
custom_handler: CustomLLM | None = None
for item in litellm.custom_provider_map:
if item["provider"] == custom_llm_provider:
custom_handler = item["custom_handler"]
if custom_handler is None:
raise LiteLLMUnknownProvider(model=model, custom_llm_provider=custom_llm_provider)
## ROUTE LLM CALL ##
handler_fn: Final = custom_chat_llm_router(async_fn=acompletion, stream=stream, custom_llm=custom_handler)
headers = headers or litellm.headers or {}
## CALL FUNCTION
response: Final = handler_fn(
model=model,
messages=messages,
headers=headers,
model_response=model_response,
print_verbose=print_verbose,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
logger_fn=logger_fn,
timeout=timeout,
custom_prompt_dict=custom_prompt_dict,
client=client, # pass AsyncOpenAI, OpenAI client
encoding=_get_encoding(),
)
if stream is True:
return CustomStreamWrapper(
completion_stream=response,
model=model,
custom_llm_provider=custom_llm_provider,
logging_obj=logging,
)
return response # pyright: ignore[reportReturnType] # provider SDK return type is broader than the dispatch contract
def _complete_langgraph(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
from litellm.llms.langgraph.chat.transformation import LangGraphConfig
(
api_base,
api_key,
) = LangGraphConfig().get_openai_compatible_provider_info(
api_base=api_base or litellm.api_base,
api_key=api_key or litellm.api_key,
)
headers = headers or litellm.headers
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider=custom_llm_provider,
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging,
client=client,
)
def _complete_microsoft_365_copilot(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
from litellm.llms.microsoft_365_copilot.chat.handler import acompletion, completion
from litellm.llms.microsoft_365_copilot.common_utils import as_secret_fields
messages: Final[Sequence[AllMessageValues]] = cast( # cast-ok: dispatch messages are prevalidated
Sequence[AllMessageValues],
ctx.messages,
)
optional_params_value: Final[object] = cast( # cast-ok: dispatch params are validated below
object,
ctx.optional_params,
)
optional_params: Final = TypeAdapter(Mapping[str, object]).validate_python(optional_params_value)
kwargs_value: Final[object] = cast( # cast-ok: dispatch kwargs are validated below
object,
ctx.kwargs,
)
kwargs: Final = TypeAdapter(Mapping[str, object]).validate_python(kwargs_value)
secret_fields: Final = as_secret_fields(kwargs.get("secret_fields"))
client: Final = _dispatch_client_http(ctx)
if ctx.acompletion:
async_client: Final = client if isinstance(client, AsyncHTTPHandler) else None
return acompletion(
model=ctx.model,
messages=messages,
api_key=ctx.api_key,
litellm_params=ctx.litellm_params,
optional_params=optional_params,
secret_fields=secret_fields,
stream=ctx.stream is True,
timeout=ctx.timeout,
logging_obj=ctx.logging,
client=async_client,
shared_session=ctx.shared_session,
)
sync_client: Final = client if isinstance(client, HTTPHandler) else None
return completion(
model=ctx.model,
messages=messages,
api_key=ctx.api_key,
litellm_params=ctx.litellm_params,
optional_params=optional_params,
secret_fields=secret_fields,
stream=ctx.stream is True,
timeout=ctx.timeout,
logging_obj=ctx.logging,
client=sync_client,
)
def _complete_langflow(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
acompletion: Final = ctx.acompletion
api_base = ctx.api_base
api_key = ctx.api_key
client: Final = _dispatch_client_http(ctx)
custom_llm_provider: Final = ctx.custom_llm_provider
headers = ctx.headers
litellm_params: Final = ctx.litellm_params
logging: Final = ctx.logging
messages: Final = ctx.messages
model: Final = ctx.model
model_response: Final = ctx.model_response
optional_params: Final = ctx.optional_params
shared_session: Final = ctx.shared_session
stream: Final = ctx.stream
timeout: Final = ctx.timeout
from litellm.llms.langflow.chat.transformation import LangFlowConfig
(
api_base,
api_key,
) = LangFlowConfig().get_openai_compatible_provider_info(
api_base=api_base or litellm.api_base,
api_key=api_key or litellm.api_key,
)
headers = headers or litellm.headers
return base_llm_http_handler.completion(
model=model,
stream=stream,
messages=messages,
acompletion=acompletion,
api_base=api_base,
model_response=model_response,
optional_params=optional_params,
litellm_params=litellm_params,
shared_session=shared_session,
custom_llm_provider=custom_llm_provider,
timeout=timeout,
headers=headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=logging,
client=client,
)
def _complete_databricks_agent(ctx: CompletionDispatchContext) -> _CompletionDispatchResult:
from litellm.llms.databricks.agent.transformation import DatabricksAgentConfig
api_base, api_key = DatabricksAgentConfig.resolve_api_base_and_key(
api_base=ctx.api_base or litellm.api_base,
api_key=ctx.api_key or litellm.api_key,
)
return base_llm_http_handler.completion(
model=ctx.model,
stream=ctx.stream,
messages=ctx.messages,
acompletion=ctx.acompletion,
api_base=api_base,
model_response=ctx.model_response,
optional_params=ctx.optional_params,
litellm_params={**ctx.litellm_params, "api_base": api_base},
shared_session=ctx.shared_session,
custom_llm_provider=ctx.custom_llm_provider,
timeout=ctx.timeout,
headers=ctx.headers or litellm.headers,
encoding=_get_encoding(),
api_key=api_key,
logging_obj=ctx.logging,
client=_dispatch_client_http(ctx),
)
@tracer.wrap()
@client
def completion(
model: str,
# Optional OpenAI params: see https://platform.openai.com/docs/api-reference/chat/create
messages: list = [],
timeout: float | str | httpx.Timeout | openai.Timeout | None = None,
temperature: float | None = None,
top_p: float | None = None,
n: int | None = None,
stream: bool | None = None,
stream_options: dict | None = None,
stop=None,
max_completion_tokens: int | None = None,
max_tokens: int | None = None,
modalities: list[ChatCompletionModality] | None = None,
prediction: ChatCompletionPredictionContentParam | None = None,
audio: ChatCompletionAudioParam | None = None,
presence_penalty: float | None = None,
frequency_penalty: float | None = None,
logit_bias: dict | None = None,
user: str | None = None,
# openai v1.0+ new params
reasoning_effort: Literal["none", "minimal", "low", "medium", "high", "xhigh", "max", "default"] | None = None,
verbosity: Literal["low", "medium", "high"] | None = None,
response_format: dict | type[BaseModel] | None = None,
seed: int | None = None,
tools: list | None = None,
tool_choice: str | dict | None = None,
logprobs: bool | None = None,
top_logprobs: int | None = None,
parallel_tool_calls: bool | None = None,
web_search_options: OpenAIWebSearchOptions | None = None,
include_server_side_tool_invocations: bool | None = None,
deployment_id=None,
extra_headers: dict | None = None,
safety_identifier: str | None = None,
service_tier: str | None = None,
store: bool | None = None,
prompt_cache_key: str | None = None,
# soon to be deprecated params by OpenAI
functions: list | None = None,
function_call: str | None = None,
# set api_base, api_version, api_key
base_url: str | None = None,
api_version: str | None = None,
api_key: str | None = None,
model_list: list | None = None, # pass in a list of api_base,keys, etc.
# Optional liteLLM function params
thinking: AnthropicThinkingParam | None = None,
# Session management
shared_session: Optional["ClientSession"] = None,
# Per-request JSON schema validation (overrides litellm.enable_json_schema_validation)
enable_json_schema_validation: bool | None = None,
**kwargs,
) -> ModelResponse | CustomStreamWrapper:
"""
Perform a completion() using any of litellm supported llms (example gpt-4, gpt-3.5-turbo, claude-2, command-nightly)
Parameters:
model (str): The name of the language model to use for text completion. see all supported LLMs: https://docs.litellm.ai/docs/providers/
messages (List): A list of message objects representing the conversation context (default is an empty list).
OPTIONAL PARAMS
functions (List, optional): A list of functions to apply to the conversation messages (default is an empty list).
function_call (str, optional): The name of the function to call within the conversation (default is an empty string).
temperature (float, optional): The temperature parameter for controlling the randomness of the output (default is 1.0).
top_p (float, optional): The top-p parameter for nucleus sampling (default is 1.0).
n (int, optional): The number of completions to generate (default is 1).
stream (bool, optional): If True, return a streaming response (default is False).
stream_options (dict, optional): A dictionary containing options for the streaming response. Only set this when you set stream: true.
stop(string/list, optional): - Up to 4 sequences where the LLM API will stop generating further tokens.
max_tokens (integer, optional): The maximum number of tokens in the generated completion (default is infinity).
max_completion_tokens (integer, optional): An upper bound for the number of tokens that can be generated for a completion, including visible output tokens and reasoning tokens.
modalities (List[ChatCompletionModality], optional): Output types that you would like the model to generate for this request.. You can use `["text", "audio"]`
prediction (ChatCompletionPredictionContentParam, optional): Configuration for a Predicted Output, which can greatly improve response times when large parts of the model response are known ahead of time. This is most common when you are regenerating a file with only minor changes to most of the content.
audio (ChatCompletionAudioParam, optional): Parameters for audio output. Required when audio output is requested with modalities: ["audio"]
presence_penalty (float, optional): It is used to penalize new tokens based on their existence in the text so far.
frequency_penalty: It is used to penalize new tokens based on their frequency in the text so far.
logit_bias (dict, optional): Used to modify the probability of specific tokens appearing in the completion.
user (str, optional): A unique identifier representing your end-user. This can help the LLM provider to monitor and detect abuse.
logprobs (bool, optional): Whether to return log probabilities of the output tokens or not. If true, returns the log probabilities of each output token returned in the content of message
top_logprobs (int, optional): An integer between 0 and 5 specifying the number of most likely tokens to return at each token position, each with an associated log probability. logprobs must be set to true if this parameter is used.
metadata (dict, optional): Pass in additional metadata to tag your completion calls - eg. prompt version, details, etc.
api_base (str, optional): Base URL for the API (default is None).
api_version (str, optional): API version (default is None).
api_key (str, optional): API key (default is None).
model_list (list, optional): List of api base, version, keys
extra_headers (dict, optional): Additional headers to include in the request.
LITELLM Specific Params
mock_response (str, optional): If provided, return a mock completion response for testing or debugging purposes (default is None).
custom_llm_provider (str, optional): Used for Non-OpenAI LLMs, Example usage for bedrock, set model="amazon.titan-tg1-large" and custom_llm_provider="bedrock"
max_retries (int, optional): The number of retries to attempt (default is 0).
Returns:
ModelResponse: A response object containing the generated completion and associated metadata.
Note:
- This function is used to perform completions() using the specified language model.
- It supports various optional parameters for customizing the completion behavior.
- If 'mock_response' is provided, a mock completion response is returned for testing or debugging.
"""
### VALIDATE Request ###
if model is None:
raise ValueError("model param not passed in.")
# validate messages
messages = validate_and_fix_openai_messages(messages=messages)
tools = validate_and_fix_openai_tools(tools=tools)
# validate tool_choice
tool_choice = validate_chat_completion_tool_choice(tool_choice=tool_choice, model=model)
# validate optional params
stop = validate_openai_optional_params(stop=stop)
thinking = validate_and_fix_thinking_param(thinking=thinking)
######### unpacking kwargs #####################
args: Final = _locals_snapshot(locals())
# Set by the responses->completion fallback so completion() does not bridge
# back to the Responses API: that round-trip mutually recurses forever for a
# model whose model_cost mode is "responses" but whose provider has no
# Responses API config (get_provider_responses_api_config -> None).
skip_responses_api_bridge: Final = kwargs.pop("_skip_responses_api_bridge", False)
control_options: Final = _resolve_control_options(kwargs, model)
skip_mcp_handler: Final = kwargs.pop("_skip_mcp_handler", False)
if not skip_mcp_handler and tools:
from litellm.responses.mcp.chat_completions_handler import acompletion_with_mcp
from litellm.responses.mcp.litellm_proxy_mcp_handler import (
LiteLLM_Proxy_MCP_Handler,
)
from litellm.types.llms.openai import ToolParam
# Check if MCP tools are present (following responses pattern)
# Cast tools to Optional[Iterable[ToolParam]] for type checking
tools_for_mcp: Final = cast(Iterable[ToolParam] | None, tools)
if LiteLLM_Proxy_MCP_Handler.should_use_litellm_mcp_gateway(tools=tools_for_mcp):
return acompletion_with_mcp( # pyright: ignore[reportReturnType] # MCP path returns a coroutine that acompletion() awaits; completion()'s sync return type omits it
model=model,
messages=messages,
functions=functions,
function_call=function_call,
timeout=timeout,
temperature=temperature,
top_p=top_p,
n=n,
stream=stream,
stream_options=stream_options,
stop=stop,
max_tokens=max_tokens,
max_completion_tokens=max_completion_tokens,
modalities=modalities,
prediction=prediction,
audio=audio,
presence_penalty=presence_penalty,
frequency_penalty=frequency_penalty,
logit_bias=logit_bias,
user=user,
response_format=response_format,
seed=seed,
tools=tools,
tool_choice=tool_choice,
parallel_tool_calls=parallel_tool_calls,
logprobs=logprobs,
top_logprobs=top_logprobs,
deployment_id=deployment_id,
reasoning_effort=reasoning_effort,
verbosity=verbosity,
safety_identifier=safety_identifier,
service_tier=service_tier,
store=store,
prompt_cache_key=prompt_cache_key,
base_url=base_url,
api_version=api_version,
api_key=api_key,
model_list=model_list,
extra_headers=extra_headers,
thinking=thinking,
web_search_options=web_search_options,
shared_session=shared_session,
enable_json_schema_validation=enable_json_schema_validation,
**kwargs,
)
api_base = kwargs.get("api_base", None)
mock_response: Final[MOCK_RESPONSE_TYPE | None] = kwargs.get("mock_response", None)
mock_tool_calls: Final = kwargs.get("mock_tool_calls", None)
mock_timeout: Final = cast(bool | None, kwargs.get("mock_timeout", None))
force_timeout: Final = kwargs.get("force_timeout", 600) ## deprecated
logger_fn: Final = kwargs.get("logger_fn", None)
verbose: Final = kwargs.get("verbose", False)
custom_llm_provider = kwargs.get("custom_llm_provider", None)
litellm_logging_obj: Final = kwargs.get("litellm_logging_obj", None)
id: Final = kwargs.get("id", None)
metadata: Final = kwargs.get("metadata", None)
model_info: Final = kwargs.get("model_info", None)
proxy_server_request: Final = kwargs.get("proxy_server_request", None)
fallbacks = kwargs.get("fallbacks", None)
provider_specific_header: Final = cast(
ProviderSpecificHeader | Sequence[ProviderSpecificHeader] | None,
kwargs.get("provider_specific_header", None),
)
headers = kwargs.get("headers", None) or extra_headers
ensure_alternating_roles: Final[bool | None] = kwargs.get("ensure_alternating_roles", None)
user_continue_message: Final[ChatCompletionUserMessage | None] = kwargs.get("user_continue_message", None)
assistant_continue_message: ChatCompletionAssistantMessage | None = kwargs.get("assistant_continue_message", None)
headers = {} if headers is None else dict(headers)
if extra_headers is not None:
headers.update(extra_headers)
# Inject proxy auth headers if configured
if litellm.proxy_auth is not None:
try:
proxy_headers: Final = _proxy_auth_headers(litellm.proxy_auth)
headers.update(proxy_headers)
except Exception as e:
verbose_logger.warning("Failed to get proxy auth headers: %s", e)
num_retries: Final = kwargs.get(
"num_retries", None
) ## alt. param for 'max_retries'. Use this to pass retries w/ instructor.
max_retries = kwargs.get("max_retries", None)
cooldown_time: Final = kwargs.get("cooldown_time", None)
context_window_fallback_dict: Final = kwargs.get("context_window_fallback_dict", None)
organization: Final = kwargs.get("organization", None)
### VERIFY SSL ###
ssl_verify: Final = kwargs.get("ssl_verify", None)
### CUSTOM MODEL COST ###
input_cost_per_token: Final = kwargs.get("input_cost_per_token", None)
output_cost_per_token: Final = kwargs.get("output_cost_per_token", None)
cost_per_second: Final = kwargs.get("cost_per_second", None)
input_cost_per_second: Final = kwargs.get("input_cost_per_second", None)
output_cost_per_second: Final = kwargs.get("output_cost_per_second", None)
### CUSTOM PROMPT TEMPLATE ###
initial_prompt_value: Final = kwargs.get("initial_prompt_value", None)
roles: Final = kwargs.get("roles", None)
final_prompt_value: Final = kwargs.get("final_prompt_value", None)
bos_token: Final = kwargs.get("bos_token", None)
eos_token: Final = kwargs.get("eos_token", None)
preset_cache_key: Final = kwargs.get("preset_cache_key", None)
hf_model_name: Final = kwargs.get("hf_model_name", None)
supports_system_message: Final = kwargs.get("supports_system_message", None)
base_model: Final = kwargs.get("base_model", None) or (
model_info.get("base_model") if isinstance(model_info, dict) else None
)
### DISABLE FLAGS ###
disable_add_transform_inline_image_block: Final = kwargs.get("disable_add_transform_inline_image_block", None)
### TEXT COMPLETION CALLS ###
text_completion: Final = kwargs.get("text_completion", False)
atext_completion: Final = kwargs.get("atext_completion", False)
### ASYNC CALLS ###
acompletion: Final = kwargs.get("acompletion", False)
client: Final = kwargs.get("client", None)
### Admin Controls ###
no_log: Final = kwargs.get("no-log", False)
### PROMPT MANAGEMENT ###
prompt_id: Final = cast(str | None, kwargs.get("prompt_id", None))
prompt_variables: Final = cast(dict | None, kwargs.get("prompt_variables", None))
litellm_system_prompt: Final = kwargs.get("litellm_system_prompt", None)
### COPY MESSAGES ### - related issue https://github.com/BerriAI/litellm/discussions/4489
messages = get_completion_messages(
messages=messages,
ensure_alternating_roles=ensure_alternating_roles or False,
user_continue_message=user_continue_message,
assistant_continue_message=assistant_continue_message,
)
######## end of unpacking kwargs ###########
non_default_params: Final = get_non_default_completion_params(kwargs=kwargs)
## PROMPT MANAGEMENT HOOKS ##
from litellm.integrations.anthropic_cache_control_hook import (
AnthropicCacheControlHook,
)
from litellm.types.llms.openai import AllMessageValues
AnthropicCacheControlHook.maybe_seed_default_injection_points(
non_default_params=non_default_params,
messages=cast(list[AllMessageValues], messages), # cast-ok: completion types messages as a bare List
model=model,
custom_llm_provider=cast(str | None, kwargs.get("custom_llm_provider")), # cast-ok: untyped kwargs
tools=tools,
enable_prompt_caching=cast(bool | None, kwargs.get("enable_prompt_caching")), # cast-ok: untyped kwargs
api_base=kwargs.get("api_base") or base_url,
)
if isinstance(litellm_logging_obj, LiteLLMLoggingObj) and (
litellm_logging_obj.should_run_prompt_management_hooks(
prompt_id=prompt_id, non_default_params=non_default_params
)
):
(
model,
messages,
optional_params,
) = litellm_logging_obj.get_chat_completion_prompt(
model=model,
messages=messages,
non_default_params=non_default_params,
prompt_id=prompt_id,
prompt_variables=prompt_variables,
prompt_label=kwargs.get("prompt_label", None),
prompt_version=kwargs.get("prompt_version", None),
request_kwargs=kwargs,
)
### LITELLM SYSTEM PROMPT ###
if litellm_system_prompt:
messages = add_system_prompt_to_messages(
messages=messages,
system_prompt=litellm_system_prompt,
merge_with_first_system=True,
)
try:
if base_url is not None:
api_base = base_url
is_router_call: Final = any("model_group" in (kwargs.get(k) or ()) for k in ("metadata", "litellm_metadata"))
if is_router_call:
max_retries = 0
elif num_retries is not None:
max_retries = num_retries
logging: Final[LiteLLMLoggingObj] = cast(LiteLLMLoggingObj, litellm_logging_obj)
fallbacks = fallbacks or litellm.model_fallbacks
if fallbacks is not None:
return completion_with_fallbacks( # pyright: ignore[reportReturnType] # fallback runner is untyped; resolves to ModelResponse|CustomStreamWrapper at runtime
**args
)
if model_list is not None:
deployments: Final = [m["litellm_params"] for m in model_list if m["model_name"] == model]
return litellm.batch_completion_models( # pyright: ignore[reportReturnType] # batch path returns a list of responses, outside completion()'s single-response return type
deployments=deployments, **args
)
if litellm.model_alias_map and model in litellm.model_alias_map:
model = litellm.model_alias_map[
model
] # update the model to the actual value if an alias has been passed in
model_response: Final = ModelResponse()
setattr(model_response, "usage", litellm.Usage())
if (
kwargs.get("azure", False) is True
): # don't remove flag check, to remain backwards compatible for repos like Codium
custom_llm_provider = "azure"
if deployment_id is not None: # azure llms
model = deployment_id
custom_llm_provider = "azure"
_supplemental_provider_params: Final = {k: kwargs[k] for k in OPTIONAL_KWARGS_KEYS if k in kwargs}
model, custom_llm_provider, dynamic_api_key, api_base = get_llm_provider(
model=model,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
litellm_params=(
GenericLiteLLMParams.model_validate(_supplemental_provider_params)
if _supplemental_provider_params
else None
),
)
## RESPONSES API BRIDGE LOGIC ## - check early and normalize model name
responses_api_model_info, model = responses_api_bridge_check(
model=model,
custom_llm_provider=custom_llm_provider,
web_search_options=web_search_options,
api_base=api_base,
)
if not _is_claude_tool_target(custom_llm_provider=custom_llm_provider, model=model):
tools = _drop_anthropic_only_tool_keys(tools=tools)
if provider_specific_header is not None:
headers.update(
ProviderSpecificHeaderUtils.get_provider_specific_headers(
provider_specific_header=provider_specific_header,
custom_llm_provider=custom_llm_provider,
)
)
if model_response is not None and hasattr(model_response, HIDDEN_PARAMS_ATTR):
model_response_hidden_params: Final = cast( # cast-ok: preserve dynamic mapping behavior
dict[str, object], getattr(model_response, HIDDEN_PARAMS_ATTR)
)
model_response_hidden_params["custom_llm_provider"] = custom_llm_provider
model_response_hidden_params["region_name"] = kwargs.get(
"aws_region_name", None
) # support region-based pricing for bedrock
### TIMEOUT LOGIC ###
timeout = CompletionTimeout.resolve(
timeout,
kwargs,
custom_llm_provider,
global_timeout=get_configured_request_timeout(),
supports_httpx_timeout=supports_httpx_timeout,
)
### REGISTER CUSTOM MODEL PRICING -- IF GIVEN ###
if (
(input_cost_per_token is not None and output_cost_per_token is not None)
or input_cost_per_second is not None
or output_cost_per_second is not None
or cost_per_second is not None
):
_register_custom_pricing_for_request(
model=model,
custom_llm_provider=custom_llm_provider,
kwargs=kwargs,
model_info=model_info,
)
### BUILD CUSTOM PROMPT TEMPLATE -- IF GIVEN ###
custom_prompt_dict = {}
if initial_prompt_value or roles or final_prompt_value or bos_token or eos_token:
custom_prompt_dict = {model: {}}
if initial_prompt_value:
custom_prompt_dict[model]["initial_prompt_value"] = initial_prompt_value
if roles:
custom_prompt_dict[model]["roles"] = roles
if final_prompt_value:
custom_prompt_dict[model]["final_prompt_value"] = final_prompt_value
if bos_token:
custom_prompt_dict[model]["bos_token"] = bos_token
if eos_token:
custom_prompt_dict[model]["eos_token"] = eos_token
messages = update_messages_with_model_file_ids(
messages=messages,
model_id=(kwargs.get("model_info") or {}).get("id", None),
model_file_id_mapping=cast(
dict[str, dict[str, str]],
kwargs.get("model_file_id_mapping") or {},
),
)
provider_config: BaseConfig | None = None
if custom_llm_provider is not None and custom_llm_provider in [provider.value for provider in LlmProviders]:
provider_config = ProviderConfigManager.get_provider_chat_config(
model=model,
provider=LlmProviders(custom_llm_provider),
base_model=base_model,
)
if provider_config is not None:
translated_messages: Final = provider_config.translate_developer_role_to_system_role(messages=messages)
history_for_route: Final = _history_without_unanswered_tool_search_calls(
translated_messages, custom_llm_provider, provider_config
)
messages = ( # rebind-ok: completion() rewrites messages step by step for the provider
translated_messages if history_for_route is None else list(history_for_route)
)
if (
supports_system_message is not None
and isinstance(supports_system_message, bool)
and supports_system_message is False
):
messages = map_system_message_pt(messages=messages)
if dynamic_api_key is not None:
api_key = dynamic_api_key
# check if user passed in any of the OpenAI optional params
bridges_to_responses_api: Final = (
responses_api_model_info.get("mode") == "responses" and not skip_responses_api_bridge
)
allowed_openai_params: Final[list[str] | None] = (
[*(kwargs.get("allowed_openai_params") or []), "reasoning_effort"]
if bridges_to_responses_api
else kwargs.get("allowed_openai_params")
)
optional_param_args: Final = {
"functions": functions,
"function_call": function_call,
"temperature": temperature,
"top_p": top_p,
"n": n,
"stream": stream,
"stream_options": stream_options,
"stop": stop,
"max_tokens": max_tokens,
"max_completion_tokens": max_completion_tokens,
"modalities": modalities,
"prediction": prediction,
"audio": audio,
"presence_penalty": presence_penalty,
"frequency_penalty": frequency_penalty,
"logit_bias": logit_bias,
"user": user,
# params to identify the model
"model": model,
"custom_llm_provider": custom_llm_provider,
"response_format": response_format,
"seed": seed,
"tools": tools,
"tool_choice": tool_choice,
"max_retries": max_retries,
"logprobs": logprobs,
"top_logprobs": top_logprobs,
"api_version": api_version,
"parallel_tool_calls": parallel_tool_calls,
"messages": messages,
"reasoning_effort": reasoning_effort,
"verbosity": verbosity,
"thinking": thinking,
"web_search_options": web_search_options,
"include_server_side_tool_invocations": (
include_server_side_tool_invocations
if include_server_side_tool_invocations is not None
else kwargs.get("include_server_side_tool_invocations")
),
"safety_identifier": safety_identifier,
"service_tier": service_tier,
"store": store,
"prompt_cache_key": prompt_cache_key,
"allowed_openai_params": allowed_openai_params,
"base_model": base_model,
}
provider_reasoning_effort: Final = reasoning_effort_with_summary_alias(
reasoning_effort,
non_default_params,
accepts_summary=provider_config is not None
and provider_config.accepts_reasoning_summary_in_reasoning_effort,
)
optional_params = get_optional_params(
**{**optional_param_args, "reasoning_effort": provider_reasoning_effort}, **non_default_params
)
processed_non_default_params: Final = pre_process_non_default_params(
model=model,
passed_params=optional_param_args,
special_params=non_default_params,
custom_llm_provider=custom_llm_provider,
additional_drop_params=kwargs.get("additional_drop_params"),
remove_sensitive_keys=True,
add_provider_specific_params=True,
provider_config=provider_config,
)
if litellm.add_function_to_prompt and optional_params.get(
"functions_unsupported_model", None
): # if user opts to add it to prompt, when API doesn't support function calling
functions_unsupported_model: Final[list[object]] = TypeAdapter(list[object]).validate_python(
optional_params.pop("functions_unsupported_model")
)
request_kwargs: Final = _REQUEST_KWARGS_ADAPTER.validate_python(kwargs)
messages = function_call_prompt(
messages=messages,
functions=functions_unsupported_model,
model=model,
llm_provider=custom_llm_provider,
drop_params=litellm.drop_params is True
or normalize_drop_params(request_kwargs.get("drop_params")) is True,
)
# For logging - save the values of the litellm-specific params passed in
requested_litellm_params: Final = get_litellm_params(
acompletion=acompletion,
api_key=api_key,
force_timeout=force_timeout,
logger_fn=logger_fn,
verbose=verbose,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
litellm_call_id=kwargs.get("litellm_call_id", None),
model_alias_map=litellm.model_alias_map,
completion_call_id=id,
metadata=metadata,
model_info=model_info,
proxy_server_request=proxy_server_request,
preset_cache_key=preset_cache_key,
no_log=no_log,
cost_per_second=cost_per_second,
input_cost_per_second=input_cost_per_second,
input_cost_per_token=input_cost_per_token,
output_cost_per_second=output_cost_per_second,
output_cost_per_token=output_cost_per_token,
cooldown_time=cooldown_time,
text_completion=kwargs.get("text_completion"),
azure_ad_token_provider=kwargs.get("azure_ad_token_provider"),
user_continue_message=kwargs.get("user_continue_message"),
base_model=base_model,
litellm_trace_id=kwargs.get("litellm_trace_id"),
litellm_session_id=kwargs.get("litellm_session_id"),
hf_model_name=hf_model_name,
custom_prompt_dict=custom_prompt_dict,
litellm_metadata=kwargs.get("litellm_metadata"),
disable_add_transform_inline_image_block=disable_add_transform_inline_image_block,
drop_params=kwargs.get("drop_params"),
prompt_id=prompt_id,
prompt_variables=prompt_variables,
ssl_verify=ssl_verify,
merge_reasoning_content_in_choices=kwargs.get("merge_reasoning_content_in_choices", None),
use_litellm_proxy=kwargs.get("use_litellm_proxy", False),
api_version=api_version,
azure_ad_token=kwargs.get("azure_ad_token"),
tenant_id=kwargs.get("tenant_id"),
client_id=kwargs.get("client_id"),
client_secret=kwargs.get("client_secret"),
azure_username=kwargs.get("azure_username"),
azure_password=kwargs.get("azure_password"),
azure_scope=kwargs.get("azure_scope"),
max_retries=max_retries,
timeout=timeout,
litellm_request_debug=kwargs.get("litellm_request_debug", False),
tpm=kwargs.get("tpm"),
rpm=kwargs.get("rpm"),
use_xai_oauth=kwargs.get("use_xai_oauth", False),
gigachat_scope=kwargs.get("gigachat_scope"),
gigachat_auth_url=kwargs.get("gigachat_auth_url"),
gigachat_access_token=kwargs.get("gigachat_access_token"),
**{
key: kwargs[key]
for key in (
*AWS_CREDENTIAL_KWARGS_KEYS,
*ANTHROPIC_WIF_KWARGS_KEYS,
*OPENAI_WIF_KWARGS_KEYS,
*OAUTH_TOKEN_EXCHANGE_KWARGS_KEYS,
"github_copilot_auth_type",
"github_copilot_user_session",
PROVIDER_AFFINITY_HEADER_KWARG_KEY,
"fireworks_forward_user_id",
"responses_api_version",
)
if key in kwargs
},
)
litellm_params: Final = with_control_options(requested_litellm_params, control_options)
if litellm_params.get("provider_affinity_header") is not None:
try:
headers = add_provider_affinity_header(
headers=headers or litellm.headers or MappingProxyType({}),
litellm_params=MappingProxyType(
{
"provider_affinity_header": litellm_params["provider_affinity_header"],
"litellm_session_id": kwargs.get("litellm_session_id"),
"session_id": kwargs.get("session_id"),
"metadata": metadata,
"litellm_metadata": kwargs.get("litellm_metadata"),
}
),
)
except ValueError as affinity_error:
raise litellm.BadRequestError(
message=str(affinity_error), model=model, llm_provider=custom_llm_provider
) from affinity_error
logging.update_environment_variables(
model=model,
user=user,
optional_params=processed_non_default_params, # [IMPORTANT] - using processed_non_default_params ensures consistent params logged to langfuse for finetuning / eval datasets.
litellm_params=litellm_params,
custom_llm_provider=custom_llm_provider,
)
if mock_response or mock_tool_calls or mock_timeout:
kwargs.pop("mock_timeout", None) # remove for any fallbacks triggered
return mock_completion(
model,
messages,
stream=stream,
n=n,
mock_response=mock_response,
mock_tool_calls=mock_tool_calls,
logging=logging,
acompletion=acompletion,
mock_delay=kwargs.get("mock_delay", None),
custom_llm_provider=custom_llm_provider,
mock_timeout=mock_timeout,
timeout=timeout,
prompt_tokens=admission_input_tokens(
cast(Mapping[str, object], kwargs) # cast-ok: completion's **kwargs is untyped
),
)
## RESPONSES API BRIDGE LOGIC ## - check if model has 'mode: responses' in litellm.model_cost map
# Only run the second bridge check if the first one didn't already
# detect responses mode (e.g. via the "responses/" prefix). The second
# check handles cases like gpt-5.4+ with tools+reasoning_effort or
# reasoningSummary/reasoning_summary without tools (AI SDK) that the first
# (early) check doesn't cover.
_reasoning_summary_for_bridge: Final = peek_reasoning_summary_aliases(optional_params)
if responses_api_model_info.get("mode") != "responses":
responses_api_model_info, model = responses_api_bridge_check(
model=model,
custom_llm_provider=custom_llm_provider,
web_search_options=web_search_options,
tools=tools,
reasoning_effort=reasoning_effort,
reasoning_summary=_reasoning_summary_for_bridge,
api_base=api_base,
)
# Use base_model (the true underlying model) for Azure model-type
# detection when the deployment name differs from the model name.
_azure_detection_model: Final = base_model or model
if responses_api_model_info.get("mode") == "responses" and not skip_responses_api_bridge:
from litellm.completion_extras import responses_api_bridge
optional_params, rs_val = strip_reasoning_summary_aliases_from_optional_params(optional_params)
if isinstance(reasoning_effort, dict) and "summary" in reasoning_effort:
optional_params["reasoning_effort"] = reasoning_effort
elif rs_val is not None:
eff: Final = optional_params.get("reasoning_effort", reasoning_effort)
if isinstance(eff, dict):
optional_params["reasoning_effort"] = {**eff, "summary": rs_val}
elif eff is not None:
optional_params["reasoning_effort"] = {
"effort": eff,
"summary": rs_val,
}
else:
optional_params["reasoning_effort"] = {"summary": rs_val}
return responses_api_bridge.completion( # pyright: ignore[reportReturnType] # bridge returns a coroutine on the acompletion path; awaited by the async caller
model=model,
messages=messages,
headers=headers,
model_response=model_response,
api_key=api_key,
api_base=api_base,
acompletion=acompletion,
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params,
timeout=timeout,
client=client, # pass AsyncOpenAI, OpenAI client
custom_llm_provider=custom_llm_provider,
encoding=_get_encoding(),
stream=stream,
cache=kwargs.get("cache"),
)
elif (custom_llm_provider == "openai" and OpenAIGPT5Config.is_model_gpt_5_model(model)) or (
custom_llm_provider == "azure"
and litellm.AzureOpenAIGPT5Config.is_model_gpt_5_model(_azure_detection_model)
):
optional_params, _ = strip_reasoning_summary_aliases_from_optional_params(optional_params)
_dispatch_ctx: Final = CompletionDispatchContext(
_azure_detection_model=_azure_detection_model,
acompletion=acompletion,
api_base=api_base,
api_key=api_key,
api_version=api_version,
client=client,
custom_llm_provider=custom_llm_provider,
custom_prompt_dict=custom_prompt_dict,
extra_headers=extra_headers,
headers=headers,
hf_model_name=hf_model_name,
kwargs=kwargs,
litellm_params=litellm_params,
logger_fn=logger_fn,
logging=logging,
max_retries=max_retries,
max_tokens=max_tokens,
messages=messages,
metadata=metadata,
model=model,
model_response=model_response,
optional_params=optional_params,
organization=organization,
provider_config=provider_config,
request_params=MappingProxyType(
_OPTIONAL_PARAMS_ADAPTER.validate_python({**optional_param_args, **non_default_params})
),
shared_session=shared_session,
stream=stream,
temperature=temperature,
text_completion=text_completion,
timeout=timeout,
top_p=top_p,
)
if custom_llm_provider == "azure":
# azure configs
## check dynamic params ##
response = _complete_azure(_dispatch_ctx)
elif custom_llm_provider == "azure_text":
# azure configs
response = _complete_azure_text(_dispatch_ctx)
elif custom_llm_provider == "deepseek":
## COMPLETION CALL
response = _complete_deepseek(_dispatch_ctx)
elif custom_llm_provider == "azure_ai":
response = _complete_azure_ai(_dispatch_ctx)
elif (
custom_llm_provider == "text-completion-openai"
or "ft:babbage-002" in model
or "ft:davinci-002" in model # support for finetuned completion models
or custom_llm_provider in litellm.openai_text_completion_compatible_providers
and kwargs.get("text_completion") is True
):
response = _complete_text_completion_openai(_dispatch_ctx)
elif custom_llm_provider == "fireworks_ai":
## COMPLETION CALL
response = _complete_fireworks_ai(_dispatch_ctx)
elif custom_llm_provider == "together_ai":
response = _complete_together_ai(_dispatch_ctx)
elif custom_llm_provider == "heroku":
response = _complete_heroku(_dispatch_ctx)
elif custom_llm_provider == "ragflow":
## COMPLETION CALL - RAGFlow uses HTTP handler to support custom URL paths
response = _complete_ragflow(_dispatch_ctx)
elif custom_llm_provider == "scaledown":
response = _complete_scaledown(_dispatch_ctx) # rebind-ok: shared provider return
elif custom_llm_provider == "xai":
## COMPLETION CALL
response = _complete_xai(_dispatch_ctx)
elif custom_llm_provider == "groq":
response = _complete_groq(_dispatch_ctx)
elif custom_llm_provider == "bedrock_mantle":
response = _complete_bedrock_mantle(_dispatch_ctx)
elif custom_llm_provider == "a2a":
# A2A (Agent-to-Agent) Protocol
# Resolve agent configuration from registry if model format is "a2a/<agent-name>"
response = _complete_a2a(_dispatch_ctx)
elif custom_llm_provider == "gigachat":
# GigaChat - Sber AI's LLM (Russia)
response = _complete_gigachat(_dispatch_ctx)
elif custom_llm_provider == "sap":
response = _complete_sap(_dispatch_ctx)
elif custom_llm_provider == "aiohttp_openai":
# NEW aiohttp provider for 10-100x higher RPS
response = _complete_aiohttp_openai(_dispatch_ctx)
elif custom_llm_provider == "cometapi":
response = _complete_cometapi(_dispatch_ctx)
elif custom_llm_provider == "minimax":
response = _complete_minimax(_dispatch_ctx)
elif custom_llm_provider == "hosted_vllm":
response = _complete_hosted_vllm(_dispatch_ctx)
elif custom_llm_provider == "edenai":
response = _complete_edenai(_dispatch_ctx) # rebind-ok: dispatch chain binds response per branch
elif custom_llm_provider == "fal_ai":
response = _complete_fal_ai(_dispatch_ctx) # rebind-ok: dispatch chain binds response per branch
elif (
# A known OpenAI model name only decides the route when nothing else
# resolved a provider. get_llm_provider() already maps these names to
# "openai", so a different value here was asked for explicitly (or came
# from a register_model entry), and the provider config built for it
# would be handed to the OpenAI handler.
(model in litellm.open_ai_chat_completion_models and custom_llm_provider in (None, "openai"))
or custom_llm_provider == "custom_openai"
or custom_llm_provider == "deepinfra"
or custom_llm_provider == "perplexity"
or custom_llm_provider == "nvidia_nim"
or custom_llm_provider == "cerebras"
or custom_llm_provider == "baseten"
or custom_llm_provider == "sambanova"
or custom_llm_provider == "volcengine"
or custom_llm_provider == "anyscale"
or custom_llm_provider == "openai"
or custom_llm_provider == "nebius"
or custom_llm_provider == "wandb"
or custom_llm_provider == "clarifai"
or custom_llm_provider in litellm.openai_compatible_providers
or JSONProviderRegistry.exists(custom_llm_provider) # JSON-configured providers
or "ft:gpt-3.5-turbo" in model # finetune gpt-3.5-turbo
): # allow user to make an openai call with a custom base
# note: if a user sets a custom base - we should ensure this works
# allow for the setting of dynamic and stateful api-bases
response = _complete_custom_openai(_dispatch_ctx)
elif custom_llm_provider == "mistral":
response = _complete_mistral(_dispatch_ctx)
elif "replicate" in model or custom_llm_provider == "replicate" or model in litellm.replicate_models:
# Setting the relevant API KEY for replicate, replicate defaults to using os.environ.get("REPLICATE_API_TOKEN")
response = _complete_replicate(_dispatch_ctx)
elif "clarifai" in model or custom_llm_provider == "clarifai" or model in litellm.clarifai_models:
pass # Deprecated - handled in the openai compatible provider section above
elif custom_llm_provider == "anthropic_text":
response = _complete_anthropic_text(_dispatch_ctx)
elif custom_llm_provider == "anthropic":
response = _complete_anthropic(_dispatch_ctx)
elif custom_llm_provider == "nlp_cloud":
response = _complete_nlp_cloud(_dispatch_ctx)
elif custom_llm_provider == "aleph_alpha":
response = _complete_aleph_alpha(_dispatch_ctx)
elif custom_llm_provider == "cohere_chat" or custom_llm_provider == "cohere":
response = _complete_cohere_chat(_dispatch_ctx)
elif custom_llm_provider == "maritalk":
response = _complete_maritalk(_dispatch_ctx)
elif custom_llm_provider == "amazon_nova":
response = _complete_amazon_nova(_dispatch_ctx)
elif custom_llm_provider == "huggingface":
response = _complete_huggingface(_dispatch_ctx)
elif custom_llm_provider == "oci":
response = _complete_oci(_dispatch_ctx)
elif custom_llm_provider == "compactifai":
response = _complete_compactifai(_dispatch_ctx)
elif custom_llm_provider == "oobabooga":
response = _complete_oobabooga(_dispatch_ctx)
elif custom_llm_provider == "databricks":
response = _complete_databricks(_dispatch_ctx)
elif custom_llm_provider == "datarobot":
response = _complete_datarobot(_dispatch_ctx)
elif custom_llm_provider == "openrouter":
response = _complete_openrouter(_dispatch_ctx)
elif custom_llm_provider == "nadir":
response = _complete_nadir(_dispatch_ctx) # rebind-ok: mirrors sibling provider branches
elif custom_llm_provider == "vercel_ai_gateway":
response = _complete_vercel_ai_gateway(_dispatch_ctx)
elif custom_llm_provider == "palm":
raise ValueError(
"Palm was decommisioned on October 2024. Please use the `gemini/` route for Gemini Google AI Studio Models. Announcement: https://ai.google.dev/palm_docs/palm?hl=en"
)
elif custom_llm_provider == "vertex_ai_beta" or custom_llm_provider == "gemini":
response = _complete_vertex_ai_beta(_dispatch_ctx)
elif custom_llm_provider == "vertex_ai":
response = _complete_vertex_ai(_dispatch_ctx)
elif custom_llm_provider == "predibase":
response = _complete_predibase(_dispatch_ctx)
elif custom_llm_provider == "text-completion-codestral":
response = _complete_text_completion_codestral(_dispatch_ctx)
elif custom_llm_provider == "text-completion-inception":
response = _complete_text_completion_inception(_dispatch_ctx)
elif custom_llm_provider in ("sagemaker_chat", "sagemaker_nova"):
# boto3 reads keys from .env
# sagemaker_chat: HF Messages API endpoints
# sagemaker_nova: Nova models on SageMaker (OpenAI-compatible)
response = _complete_sagemaker_chat(_dispatch_ctx)
elif custom_llm_provider == "sagemaker":
# boto3 reads keys from .env
response = _complete_sagemaker(_dispatch_ctx)
elif custom_llm_provider == "bedrock":
# boto3 reads keys from .env
response = _complete_bedrock(_dispatch_ctx)
elif custom_llm_provider == "watsonx":
response = _complete_watsonx(_dispatch_ctx)
elif custom_llm_provider == "watsonx_text":
response = _complete_watsonx_text(_dispatch_ctx)
elif custom_llm_provider == "vllm":
response = _complete_vllm(_dispatch_ctx)
elif custom_llm_provider == "ollama":
response = _complete_ollama(_dispatch_ctx)
elif custom_llm_provider == "ollama_chat":
response = _complete_ollama_chat(_dispatch_ctx)
elif custom_llm_provider == "triton":
response = _complete_triton(_dispatch_ctx)
elif custom_llm_provider == "cloudflare":
response = _complete_cloudflare(_dispatch_ctx)
elif custom_llm_provider == "petals" or model in litellm.petals_models:
response = _complete_petals(_dispatch_ctx)
elif custom_llm_provider == "snowflake" or model in litellm.snowflake_models:
response = _complete_snowflake(_dispatch_ctx)
elif custom_llm_provider == "gradient_ai":
response = _complete_gradient_ai(_dispatch_ctx)
elif custom_llm_provider == "gdc":
response = _complete_gdc(_dispatch_ctx)
elif custom_llm_provider == "bytez":
response = _complete_bytez(_dispatch_ctx)
elif custom_llm_provider == "lemonade":
response = _complete_lemonade(_dispatch_ctx)
elif custom_llm_provider == "ovhcloud" or model in litellm.ovhcloud_models:
response = _complete_ovhcloud(_dispatch_ctx)
elif custom_llm_provider == "custom":
response = _complete_custom(_dispatch_ctx)
elif custom_llm_provider in litellm._custom_providers: # Assume custom LLM provider
# Get the Custom Handler
response = _complete_custom_providers(_dispatch_ctx)
elif custom_llm_provider == "langgraph":
# LangGraph - Agent Runtime Provider
response = _complete_langgraph(_dispatch_ctx)
elif custom_llm_provider == "microsoft_365_copilot":
response = _complete_microsoft_365_copilot(_dispatch_ctx) # rebind-ok: shared provider return
elif custom_llm_provider == "langflow":
# LangFlow - Visual AI Agent Platform
response = _complete_langflow(_dispatch_ctx)
elif custom_llm_provider == "databricks_agent":
response = _complete_databricks_agent(_dispatch_ctx) # rebind-ok: dispatch chain binds response per branch
else:
raise LiteLLMUnknownProvider(model=model, custom_llm_provider=custom_llm_provider)
return response
except Exception as e:
## Map to OpenAI Exception
raise exception_type(
model=model,
custom_llm_provider=custom_llm_provider,
original_exception=e,
completion_kwargs=args,
extra_kwargs=kwargs,
)
def completion_with_retries(*args, **kwargs):
"""
Executes a litellm.completion() with 3 retries
"""
try:
import tenacity
except Exception as e:
raise Exception(f"tenacity import failed please run `pip install tenacity`. Error{e}")
num_retries: Final = kwargs.pop("num_retries", 3)
# reset retries in .completion()
kwargs["max_retries"] = 0
kwargs["num_retries"] = 0
retry_strategy: Final[RetryStrategy] = kwargs.pop("retry_strategy", "constant_retry")
original_function: Final = kwargs.pop("original_function", completion)
if retry_strategy == "exponential_backoff_retry":
retryer = tenacity.Retrying(
wait=tenacity.wait_exponential(multiplier=1, max=10),
stop=tenacity.stop_after_attempt(num_retries),
reraise=True,
)
else:
retryer = tenacity.Retrying(stop=tenacity.stop_after_attempt(num_retries), reraise=True)
return retryer(original_function, *args, **kwargs)
async def acompletion_with_retries(*args, **kwargs):
"""
[DEPRECATED]. Use 'acompletion' or router.acompletion instead!
Executes a litellm.completion() with 3 retries
"""
try:
import tenacity
except Exception as e:
raise Exception(f"tenacity import failed please run `pip install tenacity`. Error{e}")
num_retries: Final = kwargs.pop("num_retries", 3)
kwargs["max_retries"] = 0
kwargs["num_retries"] = 0
retry_strategy: Final[RetryStrategy] = kwargs.pop("retry_strategy", "constant_retry")
original_function: Final = kwargs.pop("original_function", completion)
if retry_strategy == "exponential_backoff_retry":
retryer = tenacity.AsyncRetrying(
wait=tenacity.wait_exponential(multiplier=1, max=10),
stop=tenacity.stop_after_attempt(num_retries),
reraise=True,
)
else:
retryer = tenacity.AsyncRetrying(stop=tenacity.stop_after_attempt(num_retries), reraise=True)
return await retryer(original_function, *args, **kwargs)
def responses_with_retries(*args, **kwargs):
"""
Executes a litellm.responses() with retries
"""
try:
import tenacity
except Exception as e:
raise Exception(f"tenacity import failed please run `pip install tenacity`. Error{e}")
from litellm.responses.dispatch import responses
num_retries: Final = kwargs.pop("num_retries", 3)
# reset retries in .responses()
kwargs["max_retries"] = 0
kwargs["num_retries"] = 0
retry_strategy: Final[RetryStrategy] = kwargs.pop("retry_strategy", "constant_retry")
original_function: Final = kwargs.pop("original_function", responses)
if retry_strategy == "exponential_backoff_retry":
retryer = tenacity.Retrying(
wait=tenacity.wait_exponential(multiplier=1, max=10),
stop=tenacity.stop_after_attempt(num_retries),
reraise=True,
)
else:
retryer = tenacity.Retrying(stop=tenacity.stop_after_attempt(num_retries), reraise=True)
return retryer(original_function, *args, **kwargs)
async def aresponses_with_retries(*args, **kwargs):
"""
Executes a litellm.aresponses() with retries
"""
try:
import tenacity
except Exception as e:
raise Exception(f"tenacity import failed please run `pip install tenacity`. Error{e}")
from litellm.responses.dispatch import aresponses
num_retries: Final = kwargs.pop("num_retries", 3)
kwargs["max_retries"] = 0
kwargs["num_retries"] = 0
retry_strategy: Final[RetryStrategy] = kwargs.pop("retry_strategy", "constant_retry")
original_function: Final = kwargs.pop("original_function", aresponses)
if retry_strategy == "exponential_backoff_retry":
retryer = tenacity.AsyncRetrying(
wait=tenacity.wait_exponential(multiplier=1, max=10),
stop=tenacity.stop_after_attempt(num_retries),
reraise=True,
)
else:
retryer = tenacity.AsyncRetrying(stop=tenacity.stop_after_attempt(num_retries), reraise=True)
return await retryer(original_function, *args, **kwargs)
### EMBEDDING ENDPOINTS ####################
@client
async def aembedding(*args, **kwargs) -> EmbeddingResponse:
"""
Asynchronously calls the `embedding` function with the given arguments and keyword arguments.
Parameters:
- `args` (tuple): Positional arguments to be passed to the `embedding` function.
- `kwargs` (dict): Keyword arguments to be passed to the `embedding` function.
Returns:
- `response` (Any): The response returned by the `embedding` function.
"""
loop: Final = asyncio.get_event_loop()
model: Final = args[0] if len(args) > 0 else kwargs["model"]
### PASS ARGS TO Embedding ###
kwargs["aembedding"] = True
custom_llm_provider = kwargs.get("custom_llm_provider", None)
try:
# Use a partial function to pass your keyword arguments
func: Final = partial(embedding, *args, **kwargs)
# Add the context to the function
ctx: Final = contextvars.copy_context()
func_with_context: Final = partial(ctx.run, func)
_, custom_llm_provider, _, _ = get_llm_provider(
model=model,
custom_llm_provider=custom_llm_provider,
api_base=kwargs.get("api_base", None),
)
# Await normally
init_response: Final = await loop.run_in_executor(None, func_with_context)
response: EmbeddingResponse | None = None
if isinstance(init_response, dict):
response = EmbeddingResponse(**init_response)
elif isinstance(init_response, EmbeddingResponse): ## CACHING SCENARIO
response = init_response
elif asyncio.iscoroutine(init_response):
response = await init_response
if response is not None and isinstance(response, EmbeddingResponse) and hasattr(response, "_hidden_params"):
response_hidden_params: Final = get_hidden_params(response)
if response_hidden_params is not None:
response_hidden_params["custom_llm_provider"] = custom_llm_provider
if response is None:
raise ValueError("Unable to get Embedding Response. Please pass a valid llm_provider.")
return response
except Exception as e:
custom_llm_provider = custom_llm_provider or "openai"
raise exception_type(
model=model,
custom_llm_provider=custom_llm_provider,
original_exception=e,
completion_kwargs=args,
extra_kwargs=kwargs,
)
# fmt: off
# Overload for when aembedding=True (returns coroutine)
@overload
def embedding(
model,
input=[],
# Optional params
dimensions: int | None = None,
encoding_format: str | None = None,
timeout: float = 600, # default to 10 minutes
# set api_base, api_version, api_key
api_base: str | None = None,
api_version: str | None = None,
api_key: str | None = None,
api_type: str | None = None,
caching: bool = False,
user: str | None = None,
custom_llm_provider=None,
litellm_call_id=None,
logger_fn=None,
*,
aembedding: Literal[True],
**kwargs,
) -> Coroutine[object, object, EmbeddingResponse]:
...
# Overload for when aembedding=False or not specified (returns EmbeddingResponse)
@overload
def embedding(
model,
input=[],
# Optional params
dimensions: int | None = None,
encoding_format: str | None = None,
timeout: float = 600, # default to 10 minutes
# set api_base, api_version, api_key
api_base: str | None = None,
api_version: str | None = None,
api_key: str | None = None,
api_type: str | None = None,
caching: bool = False,
user: str | None = None,
custom_llm_provider=None,
litellm_call_id=None,
logger_fn=None,
*,
aembedding: Literal[False] = False,
**kwargs,
) -> EmbeddingResponse:
...
# fmt: on
@client
def embedding(
model,
input=[],
# Optional params
dimensions: int | None = None,
encoding_format: str | None = None,
timeout: float = 600, # default to 10 minutes
# set api_base, api_version, api_key
api_base: str | None = None,
api_version: str | None = None,
api_key: str | None = None,
api_type: str | None = None,
caching: bool = False,
user: str | None = None,
custom_llm_provider=None,
litellm_call_id=None,
logger_fn=None,
**kwargs,
) -> EmbeddingResponse | Coroutine[object, object, EmbeddingResponse]:
"""
Embedding function that calls an API to generate embeddings for the given input.
Parameters:
- model: The embedding model to use.
- input: The input for which embeddings are to be generated.
- encoding_format: Optional[str] The format to return the embeddings in. Can be either `float` or `base64`
- dimensions: The number of dimensions the resulting output embeddings should have. Only supported in text-embedding-3 and later models.
- timeout: The timeout value for the API call, default 10 mins
- litellm_call_id: The call ID for litellm logging.
- litellm_logging_obj: The litellm logging object.
- logger_fn: The logger function.
- api_base: Optional. The base URL for the API.
- api_version: Optional. The version of the API.
- api_key: Optional. The API key to use.
- api_type: Optional. The type of the API.
- caching: A boolean indicating whether to enable caching.
- custom_llm_provider: The custom llm provider.
Returns:
- response: The response received from the API call.
Raises:
- exception_type: If an exception occurs during the API call.
"""
azure: Final = kwargs.get("azure", None)
client: Final = kwargs.pop("client", None)
drop_params_kwarg: Final = (
cast(object, kwargs["drop_params"]) if "drop_params" in kwargs else None # cast-ok: untyped request kwargs
)
drop_unsupported_params: Final = litellm.drop_params is True or normalize_drop_params(drop_params_kwarg) is True
shared_session: Final = kwargs.get("shared_session", None)
max_retries: Final = kwargs.get("max_retries", None)
litellm_logging_obj: Final[LiteLLMLoggingObj] = kwargs.get("litellm_logging_obj")
mock_response: Final[list[float] | None] = kwargs.get("mock_response", None)
azure_ad_token_provider: Final = kwargs.get("azure_ad_token_provider", None)
aembedding: Final[bool | None] = kwargs.get("aembedding", None)
extra_headers: Final = kwargs.get("extra_headers", None)
headers = kwargs.get("headers", None) or extra_headers
if headers is None:
headers = {}
if extra_headers is not None:
headers.update(extra_headers)
# Inject proxy auth headers if configured
if litellm.proxy_auth is not None:
try:
proxy_headers: Final = _proxy_auth_headers(litellm.proxy_auth)
headers.update(proxy_headers)
except Exception as e:
verbose_logger.warning("Failed to get proxy auth headers: %s", e)
### CUSTOM MODEL COST ###
input_cost_per_token: Final = kwargs.get("input_cost_per_token", None)
output_cost_per_token: Final = kwargs.get("output_cost_per_token", None)
cost_per_second: Final = kwargs.get("cost_per_second", None)
input_cost_per_second: Final = kwargs.get("input_cost_per_second", None)
output_cost_per_second: Final = kwargs.get("output_cost_per_second", None)
openai_params: Final = [
"user",
"dimensions",
"request_timeout",
"api_base",
"api_version",
"api_key",
"deployment_id",
"organization",
"base_url",
"default_headers",
"timeout",
"max_retries",
"encoding_format",
]
default_params: Final = [*openai_params, "aembedding", "extra_headers"]
non_default_params: Final = filter_out_litellm_params(kwargs, excluding=default_params)
litellm_params_dict: Final = get_litellm_params(**kwargs)
model, custom_llm_provider, dynamic_api_key, api_base = get_llm_provider(
model=model,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
litellm_params=GenericLiteLLMParams(**kwargs),
)
if dynamic_api_key is not None:
api_key = dynamic_api_key
allowed_openai_params: Final[list[str] | None] = (
cast( # cast-ok: allowed_openai_params arrives as a str list in the request kwargs
"list[str] | None", kwargs.get("allowed_openai_params", None)
)
)
optional_params: Final = get_optional_params_embeddings(
model=model,
user=user,
dimensions=dimensions,
encoding_format=encoding_format,
custom_llm_provider=custom_llm_provider,
allowed_openai_params=allowed_openai_params,
**non_default_params,
)
### REGISTER CUSTOM MODEL PRICING -- IF GIVEN ###
if (
(input_cost_per_token is not None and output_cost_per_token is not None)
or input_cost_per_second is not None
or output_cost_per_second is not None
or cost_per_second is not None
):
_register_custom_pricing_for_request(
model=model,
custom_llm_provider=custom_llm_provider,
kwargs=kwargs,
model_info=kwargs.get("model_info"),
)
logging: Final[LiteLLMLoggingObj] = litellm_logging_obj
logging.update_environment_variables(
model=model,
user=user,
optional_params=optional_params,
litellm_params=litellm_params_dict,
custom_llm_provider=custom_llm_provider,
)
if mock_response is not None:
return mock_embedding(model=model, mock_response=mock_response)
try:
response: EmbeddingResponse | Coroutine[object, object, EmbeddingResponse] | None = None
if azure is True or custom_llm_provider == "azure":
# azure configs
api_base = api_base or litellm.api_base or get_secret_str("AZURE_API_BASE")
api_version = (
api_version
or litellm.api_version
or get_secret_str("AZURE_API_VERSION")
or litellm.AZURE_DEFAULT_API_VERSION
)
azure_ad_token: Final = optional_params.pop("azure_ad_token", None) or get_secret_str("AZURE_AD_TOKEN")
api_key = api_key or litellm.api_key or litellm.azure_key or get_secret_str("AZURE_API_KEY")
if api_base is None:
raise ValueError("No API Base provided for Azure OpenAI LLM provider. Set 'AZURE_API_BASE' in .env")
## EMBEDDING CALL
response = azure_chat_completions.embedding(
model=model,
input=input,
api_base=api_base,
api_key=api_key,
api_version=api_version,
azure_ad_token=azure_ad_token,
azure_ad_token_provider=azure_ad_token_provider,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
max_retries=max_retries,
headers=headers or extra_headers,
litellm_params=litellm_params_dict,
)
elif custom_llm_provider == "github_copilot":
api_key = api_key or litellm.api_key
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params=litellm_params_dict,
)
elif (
custom_llm_provider == "openai"
or custom_llm_provider == "together_ai"
or custom_llm_provider == "nvidia_nim"
or custom_llm_provider == "litellm_proxy"
or (model in litellm.open_ai_embedding_models and custom_llm_provider is None)
):
api_base = (
api_base
or litellm.api_base
or get_secret_str("OPENAI_BASE_URL")
or get_secret_str("OPENAI_API_BASE")
or "https://api.openai.com/v1"
)
openai.organization = (
litellm.organization
or get_secret_str("OPENAI_ORGANIZATION")
or None # default - https://github.com/openai/openai-python/blob/284c1799070c723c6a553337134148a7ab088dd8/openai/util.py#L105
)
# set API KEY
api_key = api_key or litellm.api_key or litellm.openai_key or get_secret_str("OPENAI_API_KEY")
if headers is not None and headers != {}:
optional_params["extra_headers"] = headers
requested_encoding_format: Final = (
encoding_format
or optional_params.get("encoding_format")
or get_secret_str("LITELLM_DEFAULT_EMBEDDING_ENCODING_FORMAT")
)
if requested_encoding_format is None or requested_encoding_format.strip().lower() == "none":
optional_params.pop("encoding_format", None)
else:
optional_params["encoding_format"] = requested_encoding_format
api_version = None
## EMBEDDING CALL
response = openai_chat_completions.embedding(
model=model,
input=input,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
max_retries=max_retries,
shared_session=shared_session,
litellm_params=litellm_params_dict,
)
elif custom_llm_provider == "databricks":
api_base = api_base or litellm.api_base or get_secret("DATABRICKS_API_BASE")
# set API KEY
api_key = api_key or litellm.api_key or litellm.databricks_key or get_secret("DATABRICKS_API_KEY")
## EMBEDDING CALL
response = databricks_embedding.embedding(
model=model,
input=input,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
)
elif custom_llm_provider == "hosted_vllm":
api_base = api_base or litellm.api_base or get_secret_str("HOSTED_VLLM_API_BASE")
# set API KEY
if api_key is None:
api_key = litellm.api_key or get_secret_str("HOSTED_VLLM_API_KEY")
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params=litellm_params_dict,
headers=headers or {},
)
elif custom_llm_provider == "edenai":
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params=litellm_params_dict,
headers=headers,
)
elif (
custom_llm_provider == "openai_like"
or custom_llm_provider == "llamafile"
or custom_llm_provider == "lm_studio"
):
api_base = api_base or litellm.api_base or get_secret_str("OPENAI_LIKE_API_BASE")
# set API KEY
if api_key is None:
api_key = api_key or litellm.api_key or litellm.openai_like_key or get_secret_str("OPENAI_LIKE_API_KEY")
if headers is not None and headers != {}:
optional_params["extra_headers"] = headers
## EMBEDDING CALL
response = openai_like_embedding.embedding(
model=model,
input=input,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
)
elif custom_llm_provider == "oci":
if headers is None:
headers = {}
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params=litellm_params_dict,
headers=headers,
)
elif custom_llm_provider == "cohere" or custom_llm_provider == "cohere_chat":
cohere_key: Final = (
api_key
or litellm.cohere_key
or get_secret_str("COHERE_API_KEY")
or get_secret_str("CO_API_KEY")
or litellm.api_key
)
# Use the merged headers variable (already merged at the top of the function)
# Don't overwrite it with just extra_headers
if headers is None:
headers = {}
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=cohere_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params=litellm_params_dict,
headers=headers,
)
elif custom_llm_provider == "openrouter":
api_base = (
api_base or litellm.api_base or get_secret_str("OPENROUTER_API_BASE") or "https://openrouter.ai/api/v1"
)
api_key = (
api_key
or litellm.api_key
or litellm.openrouter_key
or get_secret_str("OPENROUTER_API_KEY")
or get_secret_str("OR_API_KEY")
)
openrouter_site_url: Final = get_secret("OR_SITE_URL") or "https://litellm.ai"
openrouter_app_name: Final = get_secret("OR_APP_NAME") or "liteLLM"
openrouter_headers: Final = {
"HTTP-Referer": openrouter_site_url,
"X-Title": openrouter_app_name,
}
_headers: Final = headers or litellm.headers
if _headers:
openrouter_headers.update(_headers)
headers = openrouter_headers
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params=litellm_params_dict,
headers=headers,
)
elif custom_llm_provider == "vercel_ai_gateway":
api_base = (
api_base
or litellm.api_base
or get_secret_str("VERCEL_AI_GATEWAY_API_BASE")
or "https://ai-gateway.vercel.sh/v1"
)
api_key = (
api_key
or litellm.api_key
or get_secret_str("VERCEL_AI_GATEWAY_API_KEY")
or get_secret_str("VERCEL_OIDC_TOKEN")
)
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params=litellm_params_dict,
headers=headers,
)
elif custom_llm_provider == "huggingface":
api_key = api_key or litellm.huggingface_key or get_secret("HUGGINGFACE_API_KEY") or litellm.api_key
response = huggingface_embed.embedding(
model=model,
input=input,
encoding=_load_module_encoding(),
api_key=api_key,
api_base=api_base,
logging_obj=logging,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params=litellm_params_dict,
headers=headers,
)
elif custom_llm_provider == "bedrock":
if isinstance(input, str):
transformed_input = [input]
else:
transformed_input = input
response = bedrock_embedding.embeddings(
model=model,
input=transformed_input,
encoding=_get_encoding(),
logging_obj=logging,
optional_params=optional_params,
model_response=EmbeddingResponse(),
client=client,
timeout=timeout,
aembedding=aembedding,
litellm_params=litellm_params_dict,
api_base=api_base,
print_verbose=print_verbose,
extra_headers=headers,
api_key=api_key,
)
elif custom_llm_provider == "triton":
if api_base is None:
raise ValueError("api_base is required for triton. Please pass `api_base`")
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params={},
)
elif custom_llm_provider == "gemini":
gemini_api_key: Final = api_key or get_api_key_from_env() or litellm.api_key
api_base = api_base or litellm.api_base or get_secret_str("GEMINI_API_BASE")
response = google_batch_embeddings.batch_embeddings(
model=model,
input=input,
encoding=_get_encoding(),
logging_obj=logging,
optional_params=optional_params,
model_response=EmbeddingResponse(),
vertex_project=None,
vertex_location=None,
vertex_credentials=None,
aembedding=aembedding,
print_verbose=print_verbose,
custom_llm_provider="gemini",
api_key=gemini_api_key,
api_base=api_base,
client=client,
extra_headers=headers,
drop_params=drop_unsupported_params,
)
elif custom_llm_provider == "vertex_ai":
vertex_ai_project: Final = (
optional_params.pop("vertex_project", None)
or optional_params.pop("vertex_ai_project", None)
or litellm.vertex_project
or get_secret_str("VERTEXAI_PROJECT")
or get_secret_str("VERTEX_PROJECT")
)
vertex_ai_location: Final = (
optional_params.pop("vertex_location", None)
or optional_params.pop("vertex_ai_location", None)
or litellm.vertex_location
or get_secret_str("VERTEXAI_LOCATION")
or get_secret_str("VERTEX_LOCATION")
)
vertex_credentials: Final = (
optional_params.pop("vertex_credentials", None)
or optional_params.pop("vertex_ai_credentials", None)
or get_secret_str("VERTEXAI_CREDENTIALS")
or get_secret_str("VERTEX_CREDENTIALS")
)
api_base = (
api_base or litellm.api_base or get_secret_str("VERTEXAI_API_BASE") or get_secret_str("VERTEX_API_BASE")
)
try:
model_info: Final = get_model_info(model=model, custom_llm_provider="vertex_ai")
uses_embed_content = model_info.get("uses_embed_content", False)
except Exception:
uses_embed_content = False
if uses_embed_content:
response = google_batch_embeddings.batch_embeddings(
model=model,
input=input,
encoding=_get_encoding(),
logging_obj=logging,
optional_params=optional_params,
model_response=EmbeddingResponse(),
vertex_project=vertex_ai_project,
vertex_location=vertex_ai_location,
vertex_credentials=vertex_credentials,
aembedding=aembedding,
print_verbose=print_verbose,
custom_llm_provider="vertex_ai",
api_key=None,
api_base=api_base,
client=client,
extra_headers=headers,
drop_params=drop_unsupported_params,
)
elif (
"image" in optional_params
or "video" in optional_params
or model in vertex_multimodal_embedding.SUPPORTED_MULTIMODAL_EMBEDDING_MODELS
):
response = vertex_multimodal_embedding.multimodal_embedding(
model=model,
input=input,
encoding=_get_encoding(),
logging_obj=logging,
optional_params=optional_params,
litellm_params=litellm_params_dict,
model_response=EmbeddingResponse(),
vertex_project=vertex_ai_project,
vertex_location=vertex_ai_location,
vertex_credentials=vertex_credentials,
aembedding=aembedding,
print_verbose=print_verbose,
custom_llm_provider="vertex_ai",
client=client,
api_base=api_base,
)
else:
response = vertex_embedding.embedding(
model=model,
input=input,
encoding=_get_encoding(),
logging_obj=logging,
optional_params=optional_params,
model_response=EmbeddingResponse(),
vertex_project=vertex_ai_project,
vertex_location=vertex_ai_location,
vertex_credentials=vertex_credentials,
custom_llm_provider="vertex_ai",
timeout=timeout,
aembedding=aembedding,
print_verbose=print_verbose,
api_key=api_key,
api_base=api_base,
client=client,
litellm_params=litellm_params_dict,
)
elif custom_llm_provider == "oobabooga":
response = oobabooga.embedding(
model=model,
input=input,
encoding=_get_encoding(),
api_base=api_base,
logging_obj=logging,
optional_params=optional_params,
model_response=EmbeddingResponse(),
api_key=api_key,
)
elif custom_llm_provider == "ollama":
api_base = litellm.api_base or api_base or get_secret_str("OLLAMA_API_BASE") or "http://localhost:11434"
if isinstance(input, str):
input = [input]
if not all(isinstance(item, str) for item in input):
raise litellm.BadRequestError(
message=f"Invalid input for ollama embeddings. input={input}",
model=model,
llm_provider="ollama",
)
ollama_embeddings_fn: Final = ollama.ollama_aembeddings if aembedding is True else ollama.ollama_embeddings
response = ollama_embeddings_fn(
api_base=api_base,
model=model,
prompts=input,
encoding=_get_encoding(),
logging_obj=logging,
optional_params=optional_params,
model_response=EmbeddingResponse(),
)
elif custom_llm_provider == "sagemaker":
response = sagemaker_llm.embedding(
model=model,
input=input,
encoding=_get_encoding(),
logging_obj=logging,
optional_params=optional_params,
model_response=EmbeddingResponse(),
print_verbose=print_verbose,
)
elif custom_llm_provider == "mistral":
api_key = api_key or litellm.api_key or get_secret_str("MISTRAL_API_KEY")
response = openai_chat_completions.embedding(
model=model,
input=input,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
)
elif custom_llm_provider == "fireworks_ai":
api_key = api_key or litellm.api_key or get_secret_str("FIREWORKS_AI_API_KEY")
response = openai_chat_completions.embedding(
model=model,
input=input,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
)
elif custom_llm_provider == "nebius":
api_key = api_key or litellm.api_key or get_secret_str("NEBIUS_API_KEY")
api_base = api_base or litellm.api_base or get_secret_str("NEBIUS_API_BASE") or "api.studio.nebius.ai/v1"
response = openai_chat_completions.embedding(
model=model,
input=input,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
)
elif custom_llm_provider == "wandb":
api_key = api_key or litellm.api_key or get_secret_str("WANDB_API_KEY")
api_base = (
api_base or litellm.api_base or get_secret_str("WANDB_API_BASE") or "https://api.inference.wandb.ai/v1"
)
response = openai_chat_completions.embedding(
model=model,
input=input,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
)
elif custom_llm_provider == "sambanova":
api_key = api_key or litellm.api_key or get_secret_str("SAMBANOVA_API_KEY")
api_base = (
api_base or litellm.api_base or get_secret_str("SAMBANOVA_API_BASE") or "https://api.sambanova.ai/v1"
)
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params={},
)
elif custom_llm_provider == "voyage" or custom_llm_provider == "infinity":
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params={},
)
elif custom_llm_provider == "watsonx":
credentials: Final = IBMWatsonXMixin.get_watsonx_credentials(
optional_params=optional_params, api_key=api_key, api_base=api_base
)
api_key = credentials["api_key"]
api_base = credentials["api_base"]
if "token" in credentials:
optional_params["token"] = credentials["token"]
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
litellm_params={},
client=client,
aembedding=aembedding,
)
elif custom_llm_provider == "xinference":
api_key = (
api_key or litellm.api_key or get_secret_str("XINFERENCE_API_KEY") or "stub-xinference-key"
) # xinference does not need an api key, pass a stub key if user did not set one
api_base = (
api_base or litellm.api_base or get_secret_str("XINFERENCE_API_BASE") or "http://127.0.0.1:9997/v1"
)
response = openai_chat_completions.embedding(
model=model,
input=input,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
)
elif custom_llm_provider == "sap":
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
litellm_params={},
client=client,
aembedding=aembedding,
)
elif custom_llm_provider == "azure_ai":
from litellm.llms.azure_ai.common_utils import get_azure_ai_entra_token
api_base = (
api_base # for deepinfra/perplexity/anyscale/groq/friendliai we check in get_llm_provider and pass in the api base from there
or litellm.api_base
or get_secret_str("AZURE_AI_API_BASE")
)
# set API KEY
api_key = (
api_key
or litellm.api_key # for deepinfra/perplexity/anyscale/friendliai we check in get_llm_provider and pass in the api key from there
or get_secret_str("AZURE_AI_API_KEY")
or get_azure_ai_entra_token(litellm_params=litellm_params_dict)
)
## EMBEDDING CALL
response = azure_ai_embedding.embedding(
model=model,
input=input,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
)
elif custom_llm_provider == "jina_ai":
if isinstance(input, str):
transformed_input = [input]
else:
transformed_input = input
response = base_llm_http_handler.embedding(
model=model,
input=transformed_input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
litellm_params={},
client=client,
aembedding=aembedding,
)
elif custom_llm_provider == "volcengine":
volcengine_key: Final = (
api_key or litellm.api_key or get_secret_str("ARK_API_KEY") or get_secret_str("VOLCENGINE_API_KEY")
)
if volcengine_key is None:
raise ValueError(
"Missing API key for Volcengine. Set ARK_API_KEY or VOLCENGINE_API_KEY environment variable or pass api_key parameter."
)
if extra_headers is not None and isinstance(extra_headers, dict):
headers = extra_headers
else:
headers = {}
response = base_llm_http_handler.embedding(
model=model,
input=input,
timeout=timeout,
custom_llm_provider=custom_llm_provider,
logging_obj=logging,
api_base=api_base,
optional_params=optional_params,
litellm_params={},
model_response=EmbeddingResponse(),
api_key=volcengine_key,
client=client,
aembedding=aembedding,
headers=headers,
)
elif custom_llm_provider in ("dashscope", "qwencloud", "qwen_ai_platform"):
from litellm.llms.dashscope.common_utils import (
missing_dashscope_family_key_message,
resolve_dashscope_family_api_key,
)
dashscope_key: Final = resolve_dashscope_family_api_key(
custom_llm_provider=custom_llm_provider,
api_key=api_key or litellm.api_key,
)
if dashscope_key is None:
raise ValueError(missing_dashscope_family_key_message(custom_llm_provider))
if extra_headers is not None and isinstance(extra_headers, dict):
headers = extra_headers
else:
headers = {}
response = base_llm_http_handler.embedding(
model=model,
input=input,
timeout=timeout,
custom_llm_provider=custom_llm_provider,
logging_obj=logging,
api_base=api_base,
optional_params=optional_params,
litellm_params={},
model_response=EmbeddingResponse(),
api_key=dashscope_key,
client=client,
aembedding=aembedding,
headers=headers,
)
elif custom_llm_provider == "ovhcloud":
api_key = api_key or litellm.api_key or get_secret_str("OVHCLOUD_API_KEY")
api_base = (
api_base
or litellm.api_base
or get_secret_str("OVHCLOUD_API_BASE")
or "https://oai.endpoints.kepler.ai.cloud.ovh.net/v1"
)
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params={},
)
elif custom_llm_provider == "cometapi":
api_key = api_key or litellm.cometapi_key or get_secret_str("COMETAPI_KEY") or litellm.api_key
api_base = (
api_base or litellm.api_base or get_secret_str("COMETAPI_API_BASE") or "https://api.cometapi.com/v1"
)
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params={},
)
elif custom_llm_provider in litellm._custom_providers:
custom_handler: CustomLLM | None = None
for item in litellm.custom_provider_map:
if item["provider"] == custom_llm_provider:
custom_handler = item["custom_handler"]
if custom_handler is None:
raise LiteLLMUnknownProvider(model=model, custom_llm_provider=custom_llm_provider)
handler_fn: Final = custom_handler.embedding if not aembedding else custom_handler.aembedding
response = handler_fn(
model=model,
input=input,
logging_obj=logging,
api_base=api_base,
api_key=api_key,
timeout=timeout,
optional_params=optional_params,
model_response=EmbeddingResponse(),
print_verbose=print_verbose,
litellm_params=litellm_params_dict,
)
elif custom_llm_provider == "snowflake":
api_key = api_key or get_secret_str("SNOWFLAKE_JWT")
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params={},
)
elif custom_llm_provider == "gigachat":
api_key = (
api_key
or litellm.api_key
or litellm.gigachat_key
or get_secret_str("GIGACHAT_CREDENTIALS")
or get_secret_str("GIGACHAT_API_KEY")
)
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params={"ssl_verify": kwargs.get("ssl_verify", None)},
)
elif custom_llm_provider == "perplexity":
response = base_llm_http_handler.embedding(
model=model,
input=input,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
api_key=api_key,
logging_obj=logging,
timeout=timeout,
model_response=EmbeddingResponse(),
optional_params=optional_params,
client=client,
aembedding=aembedding,
litellm_params={},
)
else:
raise LiteLLMUnknownProvider(model=model, custom_llm_provider=custom_llm_provider)
if response is not None and hasattr(response, "_hidden_params") and isinstance(response, EmbeddingResponse):
response_hidden_params: Final = get_hidden_params(response)
if response_hidden_params is not None:
response_hidden_params["custom_llm_provider"] = custom_llm_provider
if response is None:
raise LiteLLMUnknownProvider(model=model, custom_llm_provider=custom_llm_provider)
return response
except Exception as e:
## LOGGING
litellm_logging_obj.post_call(
input=input,
api_key=api_key,
original_response=str(e),
)
## Map to OpenAI Exception
raise exception_type(
model=model,
original_exception=e,
custom_llm_provider=custom_llm_provider,
extra_kwargs=kwargs,
)
###### Text Completion ################
async def _resolve_dispatched_text_completion_response(
pending: Coroutine[
object,
object,
TextCompletionResponse | ModelResponse | CustomStreamWrapper | TextCompletionStreamWrapper,
],
) -> TextCompletionResponse | ModelResponse | CustomStreamWrapper | TextCompletionStreamWrapper:
return await pending
async def _resolve_pending_chat_response(pending: Coroutine[object, object, ModelResponse]) -> ModelResponse:
return await pending
@client
async def atext_completion(*args, **kwargs) -> TextCompletionResponse | TextCompletionStreamWrapper:
"""
Implemented to handle async streaming for the text completion endpoint
"""
loop: Final = asyncio.get_event_loop()
model: Final = args[0] if len(args) > 0 else kwargs["model"]
### PASS ARGS TO COMPLETION ###
kwargs["acompletion"] = True
custom_llm_provider = None
try:
# Use a partial function to pass your keyword arguments
func: Final = partial(text_completion, *args, **kwargs)
# Add the context to the function
ctx: Final = contextvars.copy_context()
func_with_context: Final = partial(ctx.run, func)
init_response: Final = await loop.run_in_executor(None, func_with_context)
if isinstance(init_response, dict) or isinstance(init_response, TextCompletionResponse): ## CACHING SCENARIO
if isinstance(init_response, dict):
response = TextCompletionResponse(**init_response)
else:
response = init_response
elif asyncio.iscoroutine(init_response):
response = await _resolve_dispatched_text_completion_response(init_response)
else:
response = init_response
if (
kwargs.get("stream", False) is True
or isinstance(response, TextCompletionStreamWrapper)
or isinstance(response, CustomStreamWrapper)
): # return an async generator
return TextCompletionStreamWrapper(
completion_stream=_async_streaming(
response=response,
model=model,
custom_llm_provider=custom_llm_provider,
args=args,
),
model=model,
custom_llm_provider=custom_llm_provider,
stream_options=kwargs.get("stream_options"),
)
else:
## OpenAI / Azure Text Completion Returns here
if isinstance(response, TextCompletionResponse):
return response
elif asyncio.iscoroutine(response):
response = await _resolve_pending_chat_response(response)
text_completion_response = TextCompletionResponse()
text_completion_response = litellm.utils.LiteLLMResponseObjectHandler.convert_chat_to_text_completion(
text_completion_response=text_completion_response,
response=response,
custom_llm_provider=custom_llm_provider,
)
return text_completion_response
except Exception as e:
custom_llm_provider = custom_llm_provider or "openai"
raise exception_type(
model=model,
custom_llm_provider=custom_llm_provider,
original_exception=e,
completion_kwargs=args,
extra_kwargs=kwargs,
)
@client
def text_completion(
prompt: str | list[str | list[str | list[int]]], # Required: The prompt(s) to generate completions for.
model: str | None = None, # Optional: either `model` or `engine` can be set
best_of: int | None = None, # Optional: Generates best_of completions server-side.
echo: bool | None = None, # Optional: Echo back the prompt in addition to the completion.
frequency_penalty: float | None = None, # Optional: Penalize new tokens based on their existing frequency.
logit_bias: dict[int, int] | None = None, # Optional: Modify the likelihood of specified tokens.
logprobs: int | None = None, # Optional: Include the log probabilities on the most likely tokens.
max_tokens: int | None = None, # Optional: The maximum number of tokens to generate in the completion.
n: int | None = None, # Optional: How many completions to generate for each prompt.
presence_penalty: float
| None = None, # Optional: Penalize new tokens based on whether they appear in the text so far.
stop: str | list[str] | None = None, # Optional: Sequences where the API will stop generating further tokens.
stream: bool | None = None, # Optional: Whether to stream back partial progress.
stream_options: dict | None = None,
suffix: str | None = None, # Optional: The suffix that comes after a completion of inserted text.
temperature: float | None = None, # Optional: Sampling temperature to use.
top_p: float | None = None, # Optional: Nucleus sampling parameter.
user: str | None = None, # Optional: A unique identifier representing your end-user.
# set api_base, api_version, api_key
api_base: str | None = None,
api_version: str | None = None,
api_key: str | None = None,
model_list: list | None = None, # pass in a list of api_base,keys, etc.
# Optional liteLLM function params
custom_llm_provider: str | None = None,
*args,
**kwargs,
):
import copy
"""
Generate text completions using the OpenAI API.
Args:
model (str): ID of the model to use.
prompt (Union[str, List[Union[str, List[Union[str, List[int]]]]]): The prompt(s) to generate completions for.
best_of (Optional[int], optional): Generates best_of completions server-side. Defaults to 1.
echo (Optional[bool], optional): Echo back the prompt in addition to the completion. Defaults to False.
frequency_penalty (Optional[float], optional): Penalize new tokens based on their existing frequency. Defaults to 0.
logit_bias (Optional[Dict[int, int]], optional): Modify the likelihood of specified tokens. Defaults to None.
logprobs (Optional[int], optional): Include the log probabilities on the most likely tokens. Defaults to None.
max_tokens (Optional[int], optional): The maximum number of tokens to generate in the completion. Defaults to 16.
n (Optional[int], optional): How many completions to generate for each prompt. Defaults to 1.
presence_penalty (Optional[float], optional): Penalize new tokens based on whether they appear in the text so far. Defaults to 0.
stop (Optional[Union[str, List[str]]], optional): Sequences where the API will stop generating further tokens. Defaults to None.
stream (Optional[bool], optional): Whether to stream back partial progress. Defaults to False.
suffix (Optional[str], optional): The suffix that comes after a completion of inserted text. Defaults to None.
temperature (Optional[float], optional): Sampling temperature to use. Defaults to 1.
top_p (Optional[float], optional): Nucleus sampling parameter. Defaults to 1.
user (Optional[str], optional): A unique identifier representing your end-user.
Returns:
TextCompletionResponse: A response object containing the generated completion and associated metadata.
Example:
Your example of how to use this function goes here.
"""
if "engine" in kwargs:
_engine: Final = kwargs["engine"]
if model is None and isinstance(_engine, str):
# only use engine when model not passed
model = _engine
kwargs.pop("engine")
text_completion_response = TextCompletionResponse()
optional_params: Final[dict[str, Any]] = {}
# default values for all optional params are none, litellm only passes them to the llm when they are set to non None values
if best_of is not None:
optional_params["best_of"] = best_of
if echo is not None:
optional_params["echo"] = echo
if frequency_penalty is not None:
optional_params["frequency_penalty"] = frequency_penalty
if logit_bias is not None:
optional_params["logit_bias"] = logit_bias
if logprobs is not None:
optional_params["logprobs"] = logprobs
if max_tokens is not None:
optional_params["max_tokens"] = max_tokens
if n is not None:
optional_params["n"] = n
if presence_penalty is not None:
optional_params["presence_penalty"] = presence_penalty
if stop is not None:
optional_params["stop"] = stop
if stream is not None:
optional_params["stream"] = stream
if stream_options is not None:
optional_params["stream_options"] = stream_options
if suffix is not None:
optional_params["suffix"] = suffix
if temperature is not None:
optional_params["temperature"] = temperature
if top_p is not None:
optional_params["top_p"] = top_p
if user is not None:
optional_params["user"] = user
if api_base is not None:
optional_params["api_base"] = api_base
if api_version is not None:
optional_params["api_version"] = api_version
if api_key is not None:
optional_params["api_key"] = api_key
if custom_llm_provider is not None:
optional_params["custom_llm_provider"] = custom_llm_provider
# get custom_llm_provider
_model, custom_llm_provider, dynamic_api_key, api_base = get_llm_provider(
model=model,
custom_llm_provider=custom_llm_provider,
api_base=api_base,
)
if custom_llm_provider == "huggingface":
# if echo == True, for TGI llms we need to set top_n_tokens to 3
if echo is True:
# for tgi llms
if "top_n_tokens" not in kwargs:
kwargs["top_n_tokens"] = 3
# processing prompt - users can pass raw tokens to OpenAI Completion()
if isinstance(prompt, list):
import concurrent.futures
from litellm.rust_bridge.tokenizer import get_encoding
tokenizer: Final = get_encoding("p50k_base")
## if it's a 2d list - each element in the list is a text_completion() request
if len(prompt) > 0 and isinstance(prompt[0], list):
responses: Final = [None for x in prompt] # init responses
def process_prompt(i, individual_prompt):
decoded_prompt: Final = tokenizer.decode(individual_prompt)
all_params: Final = {**kwargs, **optional_params}
response: Final[TextCompletionResponse] = text_completion(
model=model,
prompt=decoded_prompt,
num_retries=3, # ensure this does not fail for the batch
*args,
**all_params,
)
text_completion_response["id"] = response.get("id", None)
text_completion_response["object"] = "text_completion"
text_completion_response["created"] = response.get("created", None)
text_completion_response["model"] = response.get("model", None)
return response["choices"][0]
with concurrent.futures.ThreadPoolExecutor() as executor:
completed_futures: Final = [
executor.submit(process_prompt, i, individual_prompt)
for i, individual_prompt in enumerate(prompt)
]
for i, future in enumerate(concurrent.futures.as_completed(completed_futures)):
responses[i] = future.result()
text_completion_response.choices = responses
return text_completion_response
# else:
# check if non default values passed in for best_of, echo, logprobs, suffix
# these are the params supported by Completion() but not ChatCompletion
# default case, non OpenAI requests go through here
# handle prompt formatting if prompt is a string vs. list of strings
messages = []
if isinstance(prompt, list) and len(prompt) > 0 and isinstance(prompt[0], str):
for p in prompt:
message = {"role": "user", "content": p}
messages.append(message)
elif isinstance(prompt, str):
messages = [{"role": "user", "content": prompt}]
elif (
(
custom_llm_provider == "openai"
or custom_llm_provider == "azure"
or custom_llm_provider == "azure_text"
or custom_llm_provider == "text-completion-codestral"
or custom_llm_provider == "text-completion-openai"
)
and isinstance(prompt, list)
and len(prompt) > 0
and (isinstance(prompt[0], list) or isinstance(prompt[0], int))
):
# Support for token IDs as prompt (list of integers or list of lists of integers)
messages = [{"role": "user", "content": prompt}]
else:
raise Exception(
f"Unmapped prompt format. Your prompt is neither a list of strings nor a string. prompt={prompt}. File an issue - https://github.com/BerriAI/litellm/issues"
)
kwargs.pop("prompt", None)
if (
_model is not None and (custom_llm_provider == "openai")
): # for openai compatible endpoints - e.g. vllm, call the native /v1/completions endpoint for text completion calls
if _model not in litellm.open_ai_chat_completion_models:
model = "text-completion-openai/" + _model
optional_params.pop("custom_llm_provider", None)
if model is None:
raise ValueError("model is not set. Set either via 'model' or 'engine' param.")
kwargs["text_completion"] = True
response = completion(
model=model,
messages=messages,
*args,
**kwargs,
**optional_params,
)
if kwargs.get("acompletion", False) is True:
return response
if stream is True or kwargs.get("stream", False) is True or isinstance(response, CustomStreamWrapper):
response = TextCompletionStreamWrapper(
completion_stream=response,
model=model,
stream_options=stream_options,
custom_llm_provider=custom_llm_provider,
)
return response
elif isinstance(response, TextCompletionStreamWrapper):
return response
# OpenAI Text / Azure Text will return here
if isinstance(response, TextCompletionResponse):
return response
text_completion_response = litellm.utils.LiteLLMResponseObjectHandler.convert_chat_to_text_completion(
response=response,
text_completion_response=text_completion_response,
)
return text_completion_response
###### Adapter Completion ################
async def aadapter_completion(*, adapter_id: str, **kwargs) -> BaseModel | AdapterCompletionStreamWrapper | None:
"""
Implemented to handle async calls for adapter_completion()
"""
try:
translation_obj: CustomLogger | None = None
for item in litellm.adapters:
if item["id"] == adapter_id:
translation_obj = item["adapter"]
if translation_obj is None:
raise ValueError(
f"No matching adapter given. Received 'adapter_id'={adapter_id}, litellm.adapters={litellm.adapters}"
)
new_kwargs: Final = translation_obj.translate_completion_input_params(kwargs=kwargs)
response: Final[ModelResponse | CustomStreamWrapper] = await acompletion(**new_kwargs)
translated_response: BaseModel | AdapterCompletionStreamWrapper | None = None
if isinstance(response, ModelResponse):
translated_response = translation_obj.translate_completion_output_params(response=response)
if isinstance(response, CustomStreamWrapper):
translated_response = translation_obj.translate_completion_output_params_streaming(
completion_stream=response
)
return translated_response
except Exception as e:
raise e
async def aadapter_generate_content(
**kwargs,
) -> dict[str, object] | AsyncIterator[bytes]:
from litellm.google_genai.adapters.handler import GenerateContentToCompletionHandler
coro: Final = cast(
Coroutine[object, object, dict[str, object] | AsyncIterator[bytes]],
GenerateContentToCompletionHandler.generate_content_handler(**kwargs, _is_async=True),
)
return await coro
def adapter_completion(*, adapter_id: str, **kwargs) -> BaseModel | AdapterCompletionStreamWrapper | None:
translation_obj: CustomLogger | None = None
for item in litellm.adapters:
if item["id"] == adapter_id:
translation_obj = item["adapter"]
if translation_obj is None:
raise ValueError(
f"No matching adapter given. Received 'adapter_id'={adapter_id}, litellm.adapters={litellm.adapters}"
)
new_kwargs: Final = translation_obj.translate_completion_input_params(kwargs=kwargs)
response: Final[ModelResponse | CustomStreamWrapper] = completion(**new_kwargs)
translated_response: BaseModel | AdapterCompletionStreamWrapper | None = None
if isinstance(response, ModelResponse):
translated_response = translation_obj.translate_completion_output_params(response=response)
elif isinstance(response, CustomStreamWrapper) or inspect.isgenerator(response):
translated_response = translation_obj.translate_completion_output_params_streaming(completion_stream=response)
return translated_response
##### Moderation #######################
def moderation(input: str, model: str | None = None, api_key: str | None = None, **kwargs) -> OpenAIModerationResponse:
static_api_key: Final = api_key or litellm.api_key or litellm.openai_key or get_secret_str("OPENAI_API_KEY")
api_base: Final = kwargs.get("api_base", None)
openai_client: Final = kwargs.get("client", None) or build_openai_client(
api_key=static_api_key,
api_base=api_base,
litellm_params=kwargs,
)
if model is not None:
response = openai_client.moderations.create(input=input, model=model)
else:
response = openai_client.moderations.create(input=input)
response_dict: Final[dict] = response.model_dump()
return litellm.utils.LiteLLMResponseObjectHandler.convert_to_moderation_response(
response_object=response_dict,
)
@client
async def amoderation(
input: str,
model: str | None = None,
api_key: str | None = None,
custom_llm_provider: str | None = None,
**kwargs,
) -> OpenAIModerationResponse:
from openai import AsyncOpenAI
static_api_key: Final = api_key or litellm.api_key or litellm.openai_key or get_secret_str("OPENAI_API_KEY")
optional_params: Final = GenericLiteLLMParams.model_validate(kwargs)
litellm_logging_obj: Final[LiteLLMLoggingObj | None] = kwargs.get("litellm_logging_obj", None)
_dynamic_api_base = None
try:
(
model,
custom_llm_provider,
_dynamic_api_key,
_dynamic_api_base,
) = litellm.get_llm_provider(
model=model or "",
custom_llm_provider=custom_llm_provider,
api_base=optional_params.api_base,
api_key=optional_params.api_key,
)
except litellm.BadRequestError:
# `model` is optional field for moderation - get_llm_provider will throw BadRequestError if model is not set / not recognized
pass
openai_client: Final = kwargs.get("client", None)
if openai_client is None or not isinstance(openai_client, AsyncOpenAI):
# call helper to get OpenAI client
# _get_openai_client maintains in-memory caching logic for OpenAI clients
_openai_client: AsyncOpenAI = openai_chat_completions.get_openai_client(
is_async=True,
api_key=static_api_key,
api_base=optional_params.api_base or _dynamic_api_base,
litellm_params=optional_params.model_dump(exclude_none=True),
)
else:
_openai_client = openai_client
# update litellm_logging_obj with environment variables
custom_llm_provider = custom_llm_provider or litellm.LlmProviders.OPENAI.value
if litellm_logging_obj is not None:
litellm_logging_obj.update_environment_variables(
model=model,
user=kwargs.get("user", None),
optional_params={},
litellm_params={
**kwargs,
},
custom_llm_provider=custom_llm_provider,
)
moderation_request: Final = {"input": input, "model": model}
litellm_logging_obj.pre_call(
input=input,
api_key=static_api_key,
additional_args={
"complete_input_dict": moderation_request,
"api_base": str(_openai_client.base_url),
},
)
if model is not None:
response = await _openai_client.moderations.create(input=input, model=model)
else:
response = await _openai_client.moderations.create(input=input)
response_dict: Final[dict] = response.model_dump()
return litellm.utils.LiteLLMResponseObjectHandler.convert_to_moderation_response(
response_object=response_dict,
)
##### Transcription #######################
@client
async def atranscription(*args, **kwargs) -> TranscriptionResponse:
"""
Calls openai + azure whisper endpoints.
Allows router to load balance between them
"""
loop: Final = asyncio.get_event_loop()
model: Final = args[0] if len(args) > 0 else kwargs["model"]
### PASS ARGS TO Image Generation ###
kwargs["atranscription"] = True
file: Final = kwargs.get("file", None)
try:
provider_hints: Final = _PROVIDER_ROUTING_HINTS.validate_python(kwargs)
api_base_hint: Final = provider_hints.get("api_base") or _BASE_URL_HINT.validate_python(kwargs).get("base_url")
except ValidationError as error:
raise litellm.BadRequestError(
message=invalid_provider_routing_hints_message(error), model=model, llm_provider=""
) from error
custom_llm_provider = None
try:
# Use a partial function to pass your keyword arguments
func: Final = partial(transcription, *args, **kwargs)
# Add the context to the function
ctx: Final = contextvars.copy_context()
func_with_context: Final = partial(ctx.run, func)
_, custom_llm_provider, _, _ = get_llm_provider(
model=model,
custom_llm_provider=provider_hints.get("custom_llm_provider"),
api_base=api_base_hint,
)
# Await normally
init_response: Final = await loop.run_in_executor(None, func_with_context)
if isinstance(init_response, dict):
response = _transcription_response_from_cached_dict(init_response)
elif isinstance(init_response, TranscriptionResponse): ## CACHING SCENARIO
response = init_response
elif asyncio.iscoroutine(init_response):
response = await init_response
else:
# Call the synchronous function using run_in_executor
response = await loop.run_in_executor(None, func_with_context)
if not isinstance(response, TranscriptionResponse):
raise ValueError(
f"Invalid response from transcription provider, expected TranscriptionResponse, but got {type(response)}"
)
# Store duration in _hidden_params for cost calculation without
# exposing it in the response body. Adding duration to the response
# tricks the OpenAI SDK's "best match deserialization" into thinking
# a plain Transcription is a TranscriptionVerbose/Diarized type.
if response is not None and not isinstance(response, Coroutine) and file is not None:
existing_duration: Final = getattr(response, "duration", None)
if existing_duration is None:
calculated_duration: Final = calculate_request_duration(file)
if calculated_duration is not None:
response.hidden_params["audio_transcription_duration"] = calculated_duration
return response
except Exception as e:
custom_llm_provider = custom_llm_provider or "openai"
raise exception_type(
model=model,
custom_llm_provider=custom_llm_provider,
original_exception=e,
completion_kwargs=args,
extra_kwargs=kwargs,
)
@client
def transcription(
model: str,
file: FileTypes,
## OPTIONAL OPENAI PARAMS ##
language: str | None = None,
prompt: str | None = None,
response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | None = None,
timestamp_granularities: list[Literal["word", "segment"]] | None = None,
temperature: int | None = None, # openai defaults this to 0
## LITELLM PARAMS ##
user: str | None = None,
timeout=600, # default to 10 minutes
api_key: str | None = None,
api_base: str | None = None,
api_version: str | None = None,
max_retries: int | None = None,
custom_llm_provider=None,
base_url: str | None = None,
**kwargs,
) -> TranscriptionResponse | Coroutine[object, object, TranscriptionResponse]:
"""
Calls openai + azure whisper endpoints.
Allows router to load balance between them
"""
litellm_call_id: Final = kwargs.get("litellm_call_id", None)
proxy_server_request: Final = kwargs.get("proxy_server_request", None)
model_info: Final = kwargs.get("model_info", None)
metadata: Final = kwargs.get("metadata", None)
atranscription: Final = kwargs.pop("atranscription", False)
litellm_logging_obj: Final[LiteLLMLoggingObj] = kwargs.get("litellm_logging_obj")
extra_headers: Final = kwargs.get("extra_headers", None)
shared_session: Final = kwargs.get("shared_session", None)
kwargs.pop("tags", [])
non_default_params: Final = get_non_default_transcription_params(kwargs)
client: openai.AsyncOpenAI | openai.OpenAI | openai.AzureOpenAI | openai.AsyncAzureOpenAI | None = kwargs.pop(
"client", None
)
if litellm_logging_obj:
litellm_logging_obj.model_call_details["client"] = str(client)
if max_retries is None:
max_retries = openai.DEFAULT_MAX_RETRIES
model_response: Final = litellm.utils.TranscriptionResponse()
model, custom_llm_provider, dynamic_api_key, api_base = get_llm_provider(
model=model,
custom_llm_provider=custom_llm_provider,
api_base=api_base or base_url,
api_key=api_key,
)
api_key = dynamic_api_key if dynamic_api_key is not None else api_key
optional_params: Final = get_optional_params_transcription(
model=model,
language=language,
prompt=prompt,
response_format=response_format,
timestamp_granularities=timestamp_granularities,
temperature=temperature,
custom_llm_provider=custom_llm_provider,
**non_default_params,
)
litellm_params_dict: Final = get_litellm_params(**kwargs)
litellm_logging_obj.update_environment_variables(
model=model,
user=user,
optional_params={},
litellm_params={
"litellm_call_id": litellm_call_id,
"proxy_server_request": proxy_server_request,
"model_info": model_info,
"metadata": metadata,
"preset_cache_key": None,
"stream_response": {},
**kwargs,
},
custom_llm_provider=custom_llm_provider,
)
response: TranscriptionResponse | Coroutine[object, object, TranscriptionResponse] | None = None
provider_config: Final = ProviderConfigManager.get_provider_audio_transcription_config(
model=model,
provider=LlmProviders(custom_llm_provider),
)
uses_openai_transport: Final = custom_llm_provider in OPENAI_AUDIO_TRANSCRIPTION_PROVIDERS and not (
provider_config is not None and provider_config.has_native_transcription_endpoint
)
if custom_llm_provider in AZURE_OPENAI_AUDIO_PROVIDERS and provider_config is None:
# azure configs
api_base = api_base or litellm.api_base or get_secret_str("AZURE_API_BASE")
api_version = api_version or litellm.api_version or get_secret_str("AZURE_API_VERSION")
azure_ad_token: Final = kwargs.pop("azure_ad_token", None) or get_secret_str("AZURE_AD_TOKEN")
api_key = api_key or litellm.api_key or litellm.azure_key or get_secret_str("AZURE_API_KEY")
optional_params["extra_headers"] = extra_headers
response = azure_audio_transcriptions.audio_transcriptions(
model=model,
audio_file=file,
optional_params=optional_params,
model_response=model_response,
atranscription=atranscription,
client=client,
timeout=timeout,
logging_obj=litellm_logging_obj,
api_base=api_base,
api_key=api_key,
api_version=api_version,
azure_ad_token=azure_ad_token,
max_retries=max_retries,
litellm_params=litellm_params_dict,
custom_llm_provider=custom_llm_provider,
)
elif uses_openai_transport:
api_base = (
api_base
or litellm.api_base
or get_secret("OPENAI_BASE_URL")
or get_secret("OPENAI_API_BASE")
or "https://api.openai.com/v1"
)
openai.organization = (
litellm.organization
or get_secret("OPENAI_ORGANIZATION")
or None # default - https://github.com/openai/openai-python/blob/284c1799070c723c6a553337134148a7ab088dd8/openai/util.py#L105
)
static_api_key: Final = api_key or litellm.api_key or litellm.openai_key or get_secret("OPENAI_API_KEY")
response = openai_audio_transcriptions.audio_transcriptions(
model=model,
audio_file=file,
optional_params=optional_params,
model_response=model_response,
atranscription=atranscription,
client=client,
timeout=timeout,
logging_obj=litellm_logging_obj,
max_retries=max_retries,
api_base=api_base,
api_key=static_api_key,
provider_config=provider_config,
litellm_params=litellm_params_dict,
shared_session=shared_session,
)
elif custom_llm_provider == "nvidia_riva":
# NVIDIA Riva is gRPC-based, not HTTP. It has its own dedicated handler
# rather than going through base_llm_http_handler.
response = nvidia_riva_audio_transcriptions.audio_transcriptions(
model=model,
audio_file=file,
optional_params=optional_params,
litellm_params=litellm_params_dict,
model_response=model_response,
atranscription=atranscription,
timeout=timeout,
logging_obj=litellm_logging_obj,
api_base=api_base,
api_key=api_key,
provider_config=(
provider_config if isinstance(provider_config, NvidiaRivaAudioTranscriptionConfig) else None
),
)
elif custom_llm_provider == "soniox":
from litellm.llms.soniox.audio_transcription.handler import (
SonioxAudioTranscriptionHandler,
)
response = SonioxAudioTranscriptionHandler().audio_transcriptions(
model=model,
audio_file=file,
optional_params=optional_params,
litellm_params=litellm_params_dict,
model_response=model_response,
atranscription=atranscription,
client=(
client
if client is not None and (isinstance(client, HTTPHandler) or isinstance(client, AsyncHTTPHandler))
else None
),
timeout=timeout,
max_retries=max_retries,
logging_obj=litellm_logging_obj,
api_base=api_base,
api_key=api_key,
headers=extra_headers,
provider_config=provider_config,
)
elif custom_llm_provider == "bedrock":
from litellm.llms.bedrock.audio_transcription import BedrockAudioTranscriptionRustDispatch
dispatch: Final = BedrockAudioTranscriptionRustDispatch()
if atranscription:
response = dispatch.async_audio_transcriptions(
model=model,
audio_file=file,
api_key=api_key,
api_base=api_base,
custom_llm_provider=custom_llm_provider,
extra_headers=extra_headers,
optional_params=optional_params,
timeout=timeout,
)
else:
response = dispatch.audio_transcriptions(
model=model,
audio_file=file,
api_key=api_key,
api_base=api_base,
custom_llm_provider=custom_llm_provider,
extra_headers=extra_headers,
optional_params=optional_params,
timeout=timeout,
)
elif provider_config is not None:
response = base_llm_http_handler.audio_transcriptions(
model=model,
audio_file=file,
optional_params=optional_params,
litellm_params=litellm_params_dict,
model_response=model_response,
atranscription=atranscription,
client=(
client
if client is not None and (isinstance(client, HTTPHandler) or isinstance(client, AsyncHTTPHandler))
else None
),
timeout=timeout,
max_retries=max_retries,
logging_obj=litellm_logging_obj,
api_base=api_base,
api_key=api_key,
custom_llm_provider=custom_llm_provider,
headers={},
provider_config=provider_config,
shared_session=shared_session,
)
# Store duration in _hidden_params for cost calculation without
# exposing it in the response body (see sync path comment above).
if response is not None and not isinstance(response, Coroutine):
existing_duration: Final = getattr(response, "duration", None)
if existing_duration is None:
calculated_duration: Final = calculate_request_duration(file)
if calculated_duration is not None:
response_hidden_params: Final = cast( # cast-ok: preserve dynamic mapping behavior
dict[str, object], getattr(response, HIDDEN_PARAMS_ATTR)
)
response_hidden_params["audio_transcription_duration"] = calculated_duration
if response is None:
raise ValueError("Unmapped provider passed in. Unable to get the response.")
return response
@client
async def aspeech(*args, **kwargs) -> HttpxBinaryResponseContent:
"""
Calls openai tts endpoints.
"""
loop: Final = asyncio.get_event_loop()
model: Final = args[0] if len(args) > 0 else kwargs["model"]
### PASS ARGS TO Image Generation ###
kwargs["aspeech"] = True
try:
provider_hints: Final = _PROVIDER_ROUTING_HINTS.validate_python(kwargs)
api_base_hint: Final = provider_hints.get("api_base") or _BASE_URL_HINT.validate_python(kwargs).get("base_url")
except ValidationError as error:
raise litellm.BadRequestError(
message=invalid_provider_routing_hints_message(error), model=model, llm_provider=""
) from error
custom_llm_provider = provider_hints.get("custom_llm_provider")
try:
# Use a partial function to pass your keyword arguments
func: Final = partial(speech, *args, **kwargs)
# Add the context to the function
ctx: Final = contextvars.copy_context()
func_with_context: Final = partial(ctx.run, func)
_, custom_llm_provider, _, _ = get_llm_provider(
model=model,
custom_llm_provider=provider_hints.get("custom_llm_provider"),
api_base=api_base_hint,
)
# Await normally
init_response: Final = await loop.run_in_executor(None, func_with_context)
if asyncio.iscoroutine(init_response):
response = await init_response
else:
# Call the synchronous function using run_in_executor
response = await loop.run_in_executor(None, func_with_context)
return response
except Exception as e:
custom_llm_provider = custom_llm_provider or "openai"
raise exception_type(
model=model,
custom_llm_provider=custom_llm_provider,
original_exception=e,
completion_kwargs=args,
extra_kwargs=kwargs,
)
@client
def speech(
model: str,
input: str,
voice: str | dict | None = None,
api_key: str | None = None,
api_base: str | None = None,
api_version: str | None = None,
organization: str | None = None,
project: str | None = None,
max_retries: int | None = None,
metadata: dict | None = None,
timeout: float | httpx.Timeout | openai.Timeout | None = None,
response_format: str | None = None,
speed: int | None = None,
instructions: str | None = None,
client=None,
headers: dict | None = None,
custom_llm_provider: str | None = None,
aspeech: bool | None = None,
base_url: str | None = None,
**kwargs,
) -> HttpxBinaryResponseContent | Coroutine[object, object, HttpxBinaryResponseContent]:
user: Final = kwargs.get("user", None)
litellm_call_id: Final[str | None] = kwargs.get("litellm_call_id", None)
proxy_server_request: Final = kwargs.get("proxy_server_request", None)
extra_headers: Final = kwargs.get("extra_headers", None)
model_info: Final = kwargs.get("model_info", None)
shared_session: Final = kwargs.get("shared_session", None)
model, custom_llm_provider, dynamic_api_key, api_base = get_llm_provider(
model=model, custom_llm_provider=custom_llm_provider, api_base=api_base or base_url
)
kwargs.pop("tags", [])
optional_params = {}
if response_format is not None:
optional_params["response_format"] = response_format
if speed is not None:
optional_params["speed"] = speed
if instructions is not None:
optional_params["instructions"] = instructions
timeout_or_default: Final = litellm.request_timeout if timeout is None else timeout
http_timeout: Final = (
CompletionTimeout.normalize(timeout_or_default)
if isinstance(timeout_or_default, openai.Timeout)
else timeout_or_default
)
if max_retries is None:
max_retries = litellm.num_retries or openai.DEFAULT_MAX_RETRIES
litellm_params_dict: Final = get_litellm_params(metadata=metadata, api_key=api_key or dynamic_api_key, **kwargs)
# Get provider-specific text-to-speech config and map parameters
text_to_speech_provider_config = ProviderConfigManager.get_provider_text_to_speech_config(
model=model,
provider=litellm.LlmProviders(custom_llm_provider),
)
# Map OpenAI params to provider-specific params if config exists
if text_to_speech_provider_config is not None:
voice, optional_params = text_to_speech_provider_config.map_openai_params(
model=model,
optional_params=optional_params,
voice=voice,
drop_params=False,
kwargs=kwargs,
)
logging_obj: Final[LiteLLMLoggingObj] = cast(LiteLLMLoggingObj, kwargs.get("litellm_logging_obj"))
logging_obj.update_environment_variables(
model=model,
user=user,
optional_params=optional_params,
litellm_params={
"litellm_call_id": litellm_call_id,
"proxy_server_request": proxy_server_request,
"model_info": model_info,
"metadata": metadata,
"preset_cache_key": None,
"stream_response": {},
**kwargs,
},
custom_llm_provider=custom_llm_provider,
)
response: HttpxBinaryResponseContent | Coroutine[object, object, HttpxBinaryResponseContent] | None = None
if custom_llm_provider == "edenai":
litellm_params_dict["api_base"] = api_base
response = base_llm_http_handler.text_to_speech_handler(
model=model,
input=input,
voice=voice if isinstance(voice, str) else None,
text_to_speech_provider_config=text_to_speech_provider_config or litellm.EdenAITextToSpeechConfig(),
text_to_speech_optional_params=optional_params,
custom_llm_provider=custom_llm_provider,
litellm_params=litellm_params_dict,
logging_obj=logging_obj,
timeout=http_timeout,
extra_headers=extra_headers,
client=client,
_is_async=aspeech or False,
)
elif custom_llm_provider == "openai" or (
custom_llm_provider in litellm.openai_compatible_providers
and custom_llm_provider not in AZURE_OPENAI_AUDIO_PROVIDERS
):
if voice is None or not (isinstance(voice, str)):
raise litellm.BadRequestError(
message="'voice' is required to be passed as a string for OpenAI TTS",
model=model,
llm_provider=custom_llm_provider,
)
api_base = (
api_base # for deepinfra/perplexity/anyscale/groq/friendliai we check in get_llm_provider and pass in the api base from there
or litellm.api_base
or get_secret("OPENAI_BASE_URL")
or get_secret("OPENAI_API_BASE")
or "https://api.openai.com/v1"
)
# set API KEY
api_key = (
api_key
or litellm.api_key # for deepinfra/perplexity/anyscale we check in get_llm_provider and pass in the api key from there
or litellm.openai_key
or get_secret("OPENAI_API_KEY")
)
organization = (
organization
or litellm.organization
or get_secret("OPENAI_ORGANIZATION")
or None # default - https://github.com/openai/openai-python/blob/284c1799070c723c6a553337134148a7ab088dd8/openai/util.py#L105
)
project = (
project
or litellm.project
or get_secret("OPENAI_PROJECT")
or None # default - https://github.com/openai/openai-python/blob/284c1799070c723c6a553337134148a7ab088dd8/openai/util.py#L105
)
headers = headers or litellm.headers
response = openai_chat_completions.audio_speech(
model=model,
input=input,
voice=voice,
optional_params=optional_params,
api_key=api_key,
api_base=api_base,
organization=organization,
project=project,
max_retries=max_retries,
timeout=http_timeout,
logging_obj=logging_obj,
client=client, # pass AsyncOpenAI, OpenAI client
aspeech=aspeech,
shared_session=shared_session,
litellm_params=litellm_params_dict,
)
elif custom_llm_provider in AZURE_OPENAI_AUDIO_PROVIDERS:
# Check if this is Azure Speech Service (Cognitive Services TTS)
if model.startswith("speech/"):
from litellm.llms.azure.text_to_speech.transformation import (
AzureAVATextToSpeechConfig,
)
# Azure AVA (Cognitive Services) Text-to-Speech
if text_to_speech_provider_config is None:
raise litellm.BadRequestError(
message="Azure Speech Service configuration not found",
model=model,
llm_provider=custom_llm_provider,
)
# Cast to specific Azure config type to access dispatch method
azure_config: Final = cast(AzureAVATextToSpeechConfig, text_to_speech_provider_config)
response = azure_config.dispatch_text_to_speech(
model=model,
input=input,
voice=voice,
optional_params=optional_params,
litellm_params_dict=litellm_params_dict,
logging_obj=logging_obj,
timeout=http_timeout,
extra_headers=extra_headers,
base_llm_http_handler=base_llm_http_handler,
aspeech=aspeech or False,
api_base=api_base,
api_key=api_key,
**kwargs,
)
else:
# Azure OpenAI TTS
if voice is None or not (isinstance(voice, str)):
raise litellm.BadRequestError(
message="'voice' is required to be passed as a string for Azure TTS",
model=model,
llm_provider=custom_llm_provider,
)
api_base = api_base or litellm.api_base or get_secret("AZURE_API_BASE")
api_version = api_version or litellm.api_version or get_secret("AZURE_API_VERSION")
api_key = (
api_key
or litellm.api_key
or litellm.azure_key
or get_secret("AZURE_OPENAI_API_KEY")
or get_secret("AZURE_API_KEY")
)
azure_ad_token: Final[str | None] = optional_params.get("extra_body", {}).pop(
"azure_ad_token", None
) or get_secret("AZURE_AD_TOKEN")
azure_ad_token_provider: Final = kwargs.get("azure_ad_token_provider", None)
if extra_headers:
optional_params["extra_headers"] = extra_headers
response = azure_chat_completions.audio_speech(
model=model,
input=input,
voice=voice,
optional_params=optional_params,
api_key=api_key,
api_base=api_base,
api_version=api_version,
azure_ad_token=azure_ad_token,
azure_ad_token_provider=azure_ad_token_provider,
organization=organization,
max_retries=max_retries,
timeout=http_timeout,
logging_obj=logging_obj,
client=client, # pass AsyncOpenAI, OpenAI client
aspeech=aspeech,
litellm_params=litellm_params_dict,
)
elif custom_llm_provider == "elevenlabs":
from litellm.llms.elevenlabs.text_to_speech.transformation import (
ElevenLabsTextToSpeechConfig,
)
if text_to_speech_provider_config is None:
text_to_speech_provider_config = ElevenLabsTextToSpeechConfig()
elevenlabs_config: Final = cast(ElevenLabsTextToSpeechConfig, text_to_speech_provider_config)
voice_id = voice if isinstance(voice, str) else None
if voice_id is None or not voice_id.strip():
raise litellm.BadRequestError(
message="'voice' must resolve to an ElevenLabs voice id for ElevenLabs TTS",
model=model,
llm_provider=custom_llm_provider,
)
voice_id = voice_id.strip()
query_params: Final = kwargs.pop(ElevenLabsTextToSpeechConfig.ELEVENLABS_QUERY_PARAMS_KEY, None)
if isinstance(query_params, dict):
litellm_params_dict[ElevenLabsTextToSpeechConfig.ELEVENLABS_QUERY_PARAMS_KEY] = query_params
litellm_params_dict[ElevenLabsTextToSpeechConfig.ELEVENLABS_VOICE_ID_KEY] = voice_id
if api_base is not None:
litellm_params_dict["api_base"] = api_base
if api_key is not None:
litellm_params_dict["api_key"] = api_key
response = base_llm_http_handler.text_to_speech_handler(
model=model,
input=input,
voice=voice_id,
text_to_speech_provider_config=elevenlabs_config,
text_to_speech_optional_params=optional_params,
custom_llm_provider=custom_llm_provider,
litellm_params=litellm_params_dict,
logging_obj=logging_obj,
timeout=http_timeout,
extra_headers=extra_headers,
client=client,
_is_async=aspeech or False,
)
elif custom_llm_provider == "vertex_ai" or custom_llm_provider == "vertex_ai_beta":
from litellm.llms.vertex_ai.text_to_speech.transformation import (
VertexAILyriaTextToSpeechConfig,
VertexAITextToSpeechConfig,
)
generic_optional_params: Final = GenericLiteLLMParams.model_validate(kwargs)
# Handle Gemini models separately (they use speech_to_completion_bridge)
if "gemini" in model:
from .endpoints.speech.speech_to_completion_bridge.handler import (
speech_to_completion_bridge_handler,
)
return speech_to_completion_bridge_handler.speech(
model=model,
input=input,
voice=voice,
optional_params=optional_params,
litellm_params=litellm_params_dict,
headers=headers or {},
logging_obj=logging_obj,
custom_llm_provider=custom_llm_provider,
)
# Vertex AI Text-to-Speech (Google Cloud TTS)
if text_to_speech_provider_config is None:
text_to_speech_provider_config = ( # rebind-ok: model metadata selects the Vertex TTS implementation
VertexAILyriaTextToSpeechConfig()
if VertexAILyriaTextToSpeechConfig.is_lyria_model(model)
else VertexAITextToSpeechConfig()
)
# Cast to specific Vertex AI config type to access dispatch method
vertex_config: Final = cast(VertexAITextToSpeechConfig, text_to_speech_provider_config)
# Store Vertex AI specific params in litellm_params_dict
litellm_params_dict.update(
{
"vertex_project": generic_optional_params.vertex_project,
"vertex_location": generic_optional_params.vertex_location,
"vertex_credentials": generic_optional_params.vertex_credentials,
}
)
response = vertex_config.dispatch_text_to_speech(
model=model,
input=input,
voice=voice,
optional_params=optional_params,
litellm_params_dict=litellm_params_dict,
logging_obj=logging_obj,
timeout=http_timeout,
extra_headers=headers,
base_llm_http_handler=base_llm_http_handler,
aspeech=aspeech or False,
api_base=api_base,
api_key=None, # Vertex AI uses OAuth, not API key
**kwargs,
)
elif custom_llm_provider == "gemini":
from .endpoints.speech.speech_to_completion_bridge.handler import (
speech_to_completion_bridge_handler,
)
return speech_to_completion_bridge_handler.speech(
model=model,
input=input,
voice=voice,
optional_params=optional_params,
litellm_params=litellm_params_dict,
headers=headers or {},
logging_obj=logging_obj,
custom_llm_provider=custom_llm_provider,
)
elif custom_llm_provider == "runwayml":
from litellm.llms.runwayml.text_to_speech.transformation import (
RunwayMLTextToSpeechConfig,
)
# RunwayML Text-to-Speech
if text_to_speech_provider_config is None:
raise litellm.BadRequestError(
message="RunwayML Text-to-Speech configuration not found",
model=model,
llm_provider=custom_llm_provider,
)
# Cast to specific RunwayML config type to access dispatch method
runwayml_config: Final = cast(RunwayMLTextToSpeechConfig, text_to_speech_provider_config)
response = runwayml_config.dispatch_text_to_speech(
model=model,
input=input,
voice=voice,
optional_params=optional_params,
litellm_params_dict=litellm_params_dict,
logging_obj=logging_obj,
timeout=http_timeout,
extra_headers=extra_headers,
base_llm_http_handler=base_llm_http_handler,
aspeech=aspeech or False,
api_base=api_base,
api_key=api_key,
**kwargs,
)
elif custom_llm_provider == "minimax":
from litellm.llms.minimax.text_to_speech.transformation import (
MinimaxTextToSpeechConfig,
)
# MiniMax Text-to-Speech
if text_to_speech_provider_config is None:
text_to_speech_provider_config = MinimaxTextToSpeechConfig()
minimax_config: Final = cast(MinimaxTextToSpeechConfig, text_to_speech_provider_config)
if api_base is not None:
litellm_params_dict["api_base"] = api_base
if api_key is not None:
litellm_params_dict["api_key"] = api_key
# Convert voice to string if it's a dict (minimax handler expects Optional[str])
voice_str: str | None = None
if isinstance(voice, str):
voice_str = voice
elif isinstance(voice, dict):
# Extract voice_id from dict if needed
voice_str = voice.get("voice_id") or voice.get("id") or voice.get("name")
response = base_llm_http_handler.text_to_speech_handler(
model=model,
input=input,
voice=voice_str,
text_to_speech_provider_config=minimax_config,
text_to_speech_optional_params=optional_params,
custom_llm_provider=custom_llm_provider,
litellm_params=litellm_params_dict,
logging_obj=logging_obj,
timeout=http_timeout,
extra_headers=extra_headers,
client=client,
_is_async=aspeech or False,
)
elif custom_llm_provider == "mistral":
from litellm.llms.mistral.audio_speech.transformation import (
MistralTextToSpeechConfig,
)
mistral_tts_config: Final = text_to_speech_provider_config or MistralTextToSpeechConfig()
if api_base is not None:
litellm_params_dict["api_base"] = api_base
if api_key is not None:
litellm_params_dict["api_key"] = api_key
mistral_voice: Final[str | None] = voice if isinstance(voice, str) else None
response = base_llm_http_handler.text_to_speech_handler(
model=model,
input=input,
voice=mistral_voice,
text_to_speech_provider_config=mistral_tts_config,
text_to_speech_optional_params=optional_params,
custom_llm_provider=custom_llm_provider,
litellm_params=litellm_params_dict,
logging_obj=logging_obj,
timeout=http_timeout,
extra_headers=extra_headers,
client=client,
_is_async=aspeech or False,
)
elif custom_llm_provider == "aws_polly":
from litellm.llms.aws_polly.text_to_speech.transformation import (
AWSPollyTextToSpeechConfig,
)
# AWS Polly Text-to-Speech
if text_to_speech_provider_config is None:
text_to_speech_provider_config = AWSPollyTextToSpeechConfig()
# Cast to specific AWS Polly config type to access dispatch method
aws_polly_config: Final = cast(AWSPollyTextToSpeechConfig, text_to_speech_provider_config)
response = aws_polly_config.dispatch_text_to_speech(
model=model,
input=input,
voice=voice,
optional_params=optional_params,
litellm_params_dict=litellm_params_dict,
logging_obj=logging_obj,
timeout=http_timeout,
extra_headers=extra_headers,
base_llm_http_handler=base_llm_http_handler,
aspeech=aspeech or False,
api_base=api_base,
api_key=api_key,
**kwargs,
)
if response is None:
raise Exception(
f"Unable to map the custom llm provider={custom_llm_provider} to a known provider={litellm.provider_list}."
)
return response
##### Health Endpoints #######################
async def ahealth_check(
model_params: dict,
mode: str | None = None,
prompt: str | None = None,
input: list | None = None,
):
"""
Support health checks for different providers. Return remaining rate limit, etc.
Returns:
{
"x-ratelimit-remaining-requests": int,
"x-ratelimit-remaining-tokens": int,
"x-ms-region": str,
}
"""
from litellm.litellm_core_utils.cached_imports import get_litellm_logging_class
from litellm.litellm_core_utils.health_check_helpers import HealthCheckHelpers, default_health_check_mode
from litellm.litellm_core_utils.health_check_utils import OPTIONAL_STR
# Use cached import helper to lazy-load Logging class (only loads when function is called)
Logging: Final = get_litellm_logging_class()
# Map modes to their corresponding health check calls
#########################################################
# Init request with tracking information
#########################################################
litellm_logging_obj: Final = Logging(
model="",
messages=[],
stream=False,
call_type="acompletion",
litellm_call_id=str(uuid.uuid4()),
start_time=datetime.datetime.now(),
function_id=str(uuid.uuid4()),
log_raw_request_response=True,
)
model_params["litellm_logging_obj"] = litellm_logging_obj
model_params = HealthCheckHelpers.update_model_params_with_health_check_tracking_information(
model_params=model_params
)
#########################################################
try:
requested_model: Final = OPTIONAL_STR.validate_python(model_params.get("model", None))
if requested_model is None:
raise Exception("model not set")
custom_llm_provider_from_params: Final = model_params.get("custom_llm_provider", None)
api_base_from_params: Final = model_params.get("api_base", None)
api_key_from_params: Final = model_params.get("api_key", None)
model, custom_llm_provider, _, _ = get_llm_provider(
model=requested_model,
custom_llm_provider=custom_llm_provider_from_params,
api_base=api_base_from_params,
api_key=api_key_from_params,
)
model_params["cache"] = {"no-cache": True} # don't used cached responses for making health check calls
mode = mode or default_health_check_mode(
requested_model=requested_model, model=model, custom_llm_provider=custom_llm_provider
)
if "*" in model:
return await HealthCheckHelpers.ahealth_check_wildcard_models(
model=model,
custom_llm_provider=custom_llm_provider,
model_params=model_params,
litellm_logging_obj=litellm_logging_obj,
)
mode_handlers: Final = HealthCheckHelpers.get_mode_handlers(
model=model,
custom_llm_provider=custom_llm_provider,
model_params=model_params,
prompt=prompt,
input=input,
)
handler_mode: Final = "decisions" if is_decisions_model_mode(mode) else mode
if handler_mode in mode_handlers:
_response: Final = await mode_handlers[handler_mode]()
_response_headers: Final = cast( # cast-ok: provider headers are stored as a string-keyed mapping
Mapping[str, object], (get_hidden_params(_response) or {}).get("headers", {}) or {}
)
return create_health_check_response(_response_headers)
else:
raise Exception(f"Mode {mode} not supported. See modes here: https://docs.litellm.ai/docs/proxy/health")
except Exception as e:
stack_trace = redact_string(traceback.format_exc())
if isinstance(stack_trace, str):
stack_trace = stack_trace[:1000]
error_to_return: Final = str(e) + "\nstack trace: " + stack_trace
raw_request_typed_dict: Final = litellm_logging_obj.model_call_details.get("raw_request_typed_dict")
return {
"error": error_to_return,
"raw_request_typed_dict": raw_request_typed_dict,
"exception": e,
}
####### HELPER FUNCTIONS ################
## Set verbose to true -> ```litellm.set_verbose = True```
def print_verbose(print_statement):
try:
verbose_logger.debug(print_statement)
if litellm.set_verbose:
print(print_statement) # noqa: T201
except Exception:
pass
def config_completion(**kwargs):
if litellm.config_path is not None:
config_args: Final = read_config_args(litellm.config_path)
# overwrite any args passed in with config args
return completion(**kwargs, **config_args)
else:
raise ValueError(
"No config path set, please set a config path using `litellm.config_path = 'path/to/config.json'`"
)
from litellm.litellm_core_utils.streaming_chunk_builder_utils import ( # noqa: E402 # re-export after the move
stream_chunk_builder as stream_chunk_builder, # noqa: PLC0414 # pyright: ignore[reportUnknownVariableType] # chunks is an untyped list
)
from litellm.litellm_core_utils.streaming_chunk_builder_utils import ( # noqa: E402 # re-export after the move
stream_chunk_builder_text_completion as stream_chunk_builder_text_completion, # noqa: PLC0414 # pyright: ignore[reportUnknownVariableType] # chunks is an untyped list
)
########## Token Counting API ##########
async def acount_tokens(
model: str,
messages: list[dict[str, object]] | None = None,
tools: list[dict[str, Any]] | None = None,
system: str | None = None,
api_key: str | None = None,
api_base: str | None = None,
) -> "TokenCountResponse":
"""
Count tokens for a given model and messages using provider-specific APIs.
Routes to the appropriate provider's token counting API (OpenAI, Anthropic, etc.)
for exact token counts. Falls back to local tiktoken-based counting for unsupported providers.
Args:
model: The model identifier (e.g., "openai/gpt-4o", "anthropic/claude-3-5-sonnet-20241022")
messages: The messages to count tokens for (standard chat format)
tools: Optional tools/functions to include in token count
system: Optional system message/instructions
api_key: Optional API key (falls back to environment variable)
api_base: Optional custom API base URL
Returns:
TokenCountResponse with total_tokens and metadata
"""
from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider
from litellm.types.utils import LlmProviders, TokenCountResponse
from litellm.utils import ProviderConfigManager
# Determine provider from model string
(
resolved_model,
custom_llm_provider,
dynamic_api_key,
dynamic_api_base,
) = get_llm_provider(
model=model,
api_base=api_base,
api_key=api_key,
)
# Use dynamic key/base if not explicitly provided
if api_key is None:
api_key = dynamic_api_key
if api_base is None:
api_base = dynamic_api_base
# Build deployment dict for the token counter
deployment: Final[dict[str, object]] = {
"litellm_params": {
"model": model,
"api_key": api_key,
"api_base": api_base,
}
}
# Try to get provider-specific token counter
try:
llm_provider_enum: Final = LlmProviders(custom_llm_provider)
provider_model_info = ProviderConfigManager.get_provider_model_info(model=model, provider=llm_provider_enum)
if provider_model_info is not None:
token_counter_instance: Final = provider_model_info.get_token_counter()
if token_counter_instance is not None and token_counter_instance.should_use_token_counting_api(
custom_llm_provider
):
result: Final = await token_counter_instance.count_tokens(
model_to_use=resolved_model,
messages=messages,
contents=None,
deployment=deployment,
request_model=model,
tools=tools,
system=system,
)
if result is not None and not result.error:
return result
except Exception as e:
verbose_logger.debug("Provider token counting failed for model=%s, falling back to local: %s", model, e)
# Fallback to local token counting
fallback_messages = messages or []
if system and fallback_messages:
fallback_messages = [{"role": "system", "content": system}] + fallback_messages
local_count: Final = await asyncify(litellm.token_counter)(
model=model,
messages=fallback_messages,
tools=tools,
)
return TokenCountResponse(
total_tokens=local_count,
request_model=model,
model_used=resolved_model,
tokenizer_type="local_tokenizer",
)
# Cache for encoding to avoid repeated __getattr__ calls
_encoding_cache: Tokenizer | None = None
def _load_module_encoding() -> Tokenizer:
from litellm import main as litellm_main
return litellm_main.encoding
def _get_encoding() -> Tokenizer:
"""Get encoding, loading it lazily if needed."""
global _encoding_cache
if _encoding_cache is None:
# Access via module to trigger __getattr__ if not cached
_encoding_cache = _load_module_encoding()
return _encoding_cache
def _load_default_encoding() -> Tokenizer:
from litellm._lazy_imports import get_default_encoding
return get_default_encoding()
def __getattr__(name: str) -> Tokenizer:
"""Lazy import handler for main module"""
if name == "encoding":
_encoding: Final = _load_default_encoding()
# Cache it in the module's __dict__ for subsequent accesses
sys.modules[__name__].__dict__["encoding"] = _encoding
global _encoding_cache
_encoding_cache = _encoding
return _encoding
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")