o
    ưi                    @   s?  U d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	Z	d dl
Z
d dlZd dlZd dlZd dlZd dlZd dlmZmZmZ d dlmZmZmZmZmZmZmZmZmZmZmZmZm Z m!Z! d dl"Z"d dl#Z#d dl$Z#d dl%m&Z&m'Z' d dl(m)Z) d dl*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9 d dl:m;Z; d dl<m=Z= d d	l>m?Z?m@Z@mAZAmBZBmCZCmDZDmEZEmFZFmGZGmHZHmIZImJZJmKZKmLZLmMZMmNZNmOZOmPZPmQZQmRZRmSZSmTZTmUZUmVZVmWZWmXZXmYZYmZZZm[Z[m\Z\m]Z] d d
l^m_Z_m`Z` d dlambZb d dlcmdZdmeZemfZfmgZg d dlhmiZimjZj er3d dlkmlZl d dlmmnZo d dlpmqZq eeoef ZnneZneZqddddZreesef etd< dddZueue_uejvdewd g Zxeyetd< ejz{d ejz|d zd dl}Z}d dl~Z~d dlZd dlZd dlZd dlmZ W n ey Z zede ddZ[ww g dZd d! Zd d"lmZ d d#lmZ d d$lmZ d dlZd d%lmZ d d&lmZmZ d d'lmZmZ d d(lmZ d d)l*mZmZmZmZmZmZmZmZmZmZmZmZmZmZ d d*lmZ d d+lmZ d d,lmZ d d-lmZ d d.lmZmZ d d/lmZ d d0l:mZ d d1lmZ d d2lmZmZ d d3lmZ d d4lmZ d d4lmZ d d4lmZ d d5lmZ d d6lmZ d d7l>T d d4lmZ d d8lmZ d d4lmZ d d9lmZmZ d d4lmZ d d:lmZ d d4lmZ d d4lmZ d d;lmZmZmZ d d<lmZ d d=lmZ d d>lmZ d d?lmZmZmZmZmZ d d@lmZmZmZ d d4lmZ d d4lmZ d dAlmZmZ d dBl^mZ d dClmZ d d4lmZ d dDlmZmZ d dElmZ d dFlmZmZm Z mZ d dGlmZmZ d dHlmZ d dIlmZ d dJl	m
Z
 d dKlmZ d d4lmZ d d4lmZ d dLlmZ d dMlmZ d dNlmZ d d4lmZ d dOlmZ d d4lmZ d d4lmZ d dPlmZm Z  d dQl!m"Z" d d4l#mZ$ d dRl%m&Z& d dSl'm(Z( d dTl)m*Z* d d4l+mZ, d dUl-m.Z. d d4l/mZ0 d d4l1mZ2 d d4l3mZ4 d d4l5mZ6 d d4l7mZ8 d dVl9m:Z:m;Z; d d4l<mZ= d d4l>mZ? d d4l@mZA d d4lBmZC d d4lDmZE d dWlDmFZF d d4lGmZH d dXlImJZJmKZKmLZL d d4lImZM d d4lNmZO d d4lPmZQ d dYlRmSZSmTZTmUZU d d4lRmZV d d4lWmZX d d4lYmZZ d d4l[mZ\ d d4l]mZ^ d dZl_m`Z` d d4lamZb d d4lcmZd d d4lemZf d d[lemgZgmhZh d d4limZj d d\lkmlZl d d4lkmZm d d4lnmZo d d4lpmZq d d]lrmsZs d d^ltmuZu d d_lvmwZw d d4lxmZy d d4lzmZ{ d d4l|mZ} d d`l|m~Z~ d dalmZ d d4lmZ d dblmZ d dclmZ d d4lmZ d d4lmZ d d4lmZ d d4lmZ d d4lmZ d d4lmZ d d4lmZ d d4lmZ d ddlmZ d d4lmZ d d4lmZ d d4lmZ d d4lmZ d delmZ d dflmZ d d4lmZ d dglmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZ d d4lmZ d d4lmZ d d4lmZ d d4lmZ d d4lmZ d dhlmZmZmZmÐZ d dilĐmŐZŐmƐZ d djlǐmȐZ d dklɐmʐZ d dllːm̐Z̐m͐Z͐mΐZΐmϐZ d dmlАmѐZ d dnlҐmӐZӐmԐZԐmՐZՐm֐Z d dolאmؐZ d dplِmڐZ d dqlېmܐZܐmݐZ d drlސmߐZ d dslmZ d dtlmZ d dulmZmZmZ d dvlmZ d dwlmZmZ d dxlcmZmZ d dtlcmZ d dylcmZmZ d dzlhmZ zd d{lmZ W n eyD   d|ZY nw d}e_d dlZd d~lmZ d dlmZmZmZmZmZmZmZmZmZm Z mZmZmZmZmZ d dlmZ d dlm	Z	 d dl
mZ d dlmZ d dlmZmZmZmZmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ e Zzd dlm   m!Z! W n ey2   zd dl!Z!W n ey/   Y nw Y nw z#d d4l"mZ# d dl$m%Z% e#Ze% Z&ee% etd< W n eyc   dZ&Y nw e Z'e a(t() a*e+etd< t(j,Z-ed etd< e.dZ/ees etd< e Z0e Z1e/du rdZ2e3etd< ne3e/Z2e.dZ4ees etd< e4du rdZ5e6etd< ne6e4Z5e' dZ7e' dZ8e' dZ9de7 de8 dZ:e:d7 Z:e:de9 d7 Z:e' dZ;e:de; d7 Z:dZ<t*	r&e.ddndZ=t*	r<e.dde< de: n	de< de: Z>dd Z?dd Z@dd ZAedefddZBee e e=e>ee'eBdZe ZCd dlmDZD dd ZEdd ZFe.dddk	rt*	reFeĐ_GneEeĐ_GG dd dejHZIeĐJeVdedeVfddZKe ZdgZLzejzMejz|eNZOejzPeOddġZQeQZRdŐZSdesdǐe+fddɄZTdesdǐe+fdd̄ZUdesdǐe+fddτZVdesdesdǐeWe+esf fddӄZXe.ddաY dkZZeZ
r3dאZ[neQZ[e.dؐe[Z\eUeQ
sRe]dِeQ dڝ e\eQkZ^e^
rҐeVe\Z_eTe\Z`e`
re_
readېe\  e\ZRn^e`
re_
sebdܐe\ dݝ e\ZRnFeadސe\ dߝ eXeQe\\ZcZ]ec
re\ZRn&ebde\ de] deQ d eQZRneadeQ  eQZReUeR
se]deR d e're'dkredeRejeZfefsebdeR d negeRD ]\ZhZiZjejD ]ZkejzPehekZlekmdrAq)zbeneldddZoeop ZqW d   n	1 s_w   Y  eqreS e' Zsesrde' dZseneldddZoeotes W d   n	1 sw   Y  W q) euevewfy   Y q)w qeĐjxdeejzPeRdddd eĐjxeS deejzPeRdddd eĐjxdeeRd}ddd desddfddZyzDeVeRZ_edeRejeZfe_readeR d n efs/ebdeR d neyeR eadeR  W nC evyb Z zezd eR de  W Y dZ[n&dZ[w ey Z zezdeR de  W Y dZ[ndZ[ww W n ey   Y nw ejzMejz|eNZOeĐj{e	eLd}dgdge8d eĐ{ew eĐ{eu dd Z|e|  e Z}e.dZ~ees etd< e}dkre~dureĐjdddd	d
 Zd dlmZ dadadadadadad}adZdadaees etd< d}Zdadaee etd< daeey etd< i aeetd< daeeeesef   etd< dZdZdaees etd< dZeee  etd< dadaee etd< daed etd< eeIjjdae&tdZeje daee etd< daeed ees e+f etd< g aees etd< dae3etd< dadadadadadadadadadai aeesee3eeesef  f f etd< dad ag Zeetd < d!Zeadaeed" ef etd#< eaeaeaeadadae Zdaee( etd$< dae+etd%< daeeq etd&< ett*d'adZdZdZdadadadaee etd(< defd)d*ZƐd+d, Zdefd-d.ZȐdؐd/e+fd0d1Zɐd2d3 Z	dِd4ees d5ees d6ees d7ees d8ee6 d9een d:eees  fd;d<Zːd=d> Zdee6 fd?d@ZdesfdAdBZΐdCeydDee+ dEee3 dFefdGdHZϐdCeydIeydJeyfdKdLZАdMdN ZG dOdP dPeZG dQdR dRZӐeӃ aԐdSdT Z									U			}	}				dڐdVdWZ֐dXdY ZאdZe]d[efd\d]Zؐd[edesfd^d_Zِd`edaesd[edbe+deee+f f
dcddZڐdZe]d[efdedfZېdZe]d[efdgdhZi fdiefdjdkZݐdldm Zސdndo ZG dpdq dqZejdreegdsgdtejdueegdsgdteedddddddfdZe]dvee+ d7ees dwee+ dxee+ dyee+ dzees d{ees fd|dCZejd}eegdsgdtejd~eegdsgdteefdesdZe]fddZejdeegdgdtejdeegdgdtejdeegdgdtejdeegdgdddiieddeefdede diees dZe]fddZejdeegdgdtejdeegdgdtejdeegdgdtejdeegdgdtdeefdede diees dZe]fddZejdeegedgdejdeegedgdejdeegedgdejdeegedgddeefdede diees dZe]fddZejdeegedgdejdeegedgdeefdede dZe]fddZdedeedf fddZejdeegdgdtejdeegdgdteefdede dZe]fddZejdeegdgdtejdeegdgdtedeefdede dedZe]fddZeĐdejdddejdddejdddeefdediees dees dees fddZeeddiesdees deeesesf df fddZeĐdeĐdejdddejdddeefdediesdesdees fddZejdeegdgdtejdĐeegdgdteefdede dZe]fdŐdƄZejdeegdgdtejdĐeegdgdteefdede dZe]fdǐdȄZejdɐeegdgdtejdʐeegdgdteefdedesde dZe]fd̐d̈́Zejdΐeegdgdtejdϐeegdgdteefdede dZe]fdАdфZejdҐeegdgdtejdӐeegdgdteefdedesde dZe]fdՐdքZejdאeegdgdtejdؐeegdgdteefdedesde dZe]fdِdڄZejdאeegdgdtejdؐeegdgdteefdedesde dZe]fdېd܄Zejdݐeegdgdtejdސeegdgdteefdedesde dZe]fdߐdZd dlmZ dedesdeee ees ees f fddZejddgeegegddde[de+fddZejddgeegddiesfddZejddgeegedde\fddZdee dZe]dee dee fddZdee deRdee fddZ dee dedZe]dee fddZdeeQ dedeesees f fddZdeees ed f dededeesees f fd dZdeRdedees fddZdZe]dededee dee f
ddZ	dېdieesef de+dee deesef fdd	Z	dِdeeesef  d
esde3de3dee dedees deeeesef  ee3 f fddZdedee fddZ	dܐdeeesef  dees desdeeesef  fddZ	deeesef  de3de3dee3 d
ees deesef fddZ
deeesef  d7esdededeeesef  f
ddZdesd
ees dǐeWeyee3 f fddZejdd dsgeegdd!eeejdd"dejdd#dejdd$dded%d&d%d'ed(d)d%d'ejdd*dejdd+dejdd,dejdd-dejdd.dfdZe]diees d/ee+ d0ee+ dee+ de3de3d
ees d1ees d2ees d3ees d4ees fd5d6Zejd7d8dsgdeegd9eedddfdZe]d:ees d;ee d<ee fd=d>Zejd?d@dsgdeegd9eedAddddfdZe]d:ees d;ee d<ee dBees dCees fdDdEZejdFdGdsgdeegd9eedAddddfdZe]d:ees d;ee d<ee dBees dCees fdHdIZejdJdKdsgdeegd9eedddddfdZe]d:ees d;ee d<ee dBees dCees fdLdMZdiedǐefdNdOZejdPdsgeegdejdQdsgeegdeedfdZe]dRees fdSdTZdedUees dVees dee fdWdXZejdYdsgeegdeedfdZe]dVees fdZd[Zejd\d]dsgeegdd!d^d_ Zejd`dadbgeegdd!eefdZe]fdcddZejdedfgeegddgdeefdede diees dZe]fdhdiZeĐjddfgddjdefdkdlZejdmdddefdndoZejdpdddefdqdrZeĐjdsdddtesdefdudvZeĐjdwdddxeJfdydzZeĐjd{ddd|d} ZeĐjd~dddd ZeĐjddddd Z ejddgeegeLddeefdxeMdZe]fddZ!ejddgeegeLddeefdesdZe]fddZ"ejddgeegeLddeefdxeNdZe]fddZ#ejddgeegeLddeefdxeKdZe]fddZ$ejddgeegddgdeGfddZ%	 ejddgeegddgeefdxeDdZe]fddZ&ejddgeegeCddeefdesdZe]fddZ'ejddgeegddgeefded dZe]deeF fddZ(ejddgeegddgeefdxeBdZe]fddZ)ejddgeegddgeefdxe?dZe]fddZ*ejddgdeegddd Z+ejddgeegddgdeGfddZ,ejddsgeegddgeefdZe]fddZ-ejddsgeegddgeefde3dZe]fddZ.ejddsgeegddgeefdZe]fddZ/ejddsgeegddgeefdZe]fddZ0ejddsgeegddgeefdZe]fddZ1ejddsgeegddgeefdZe]fddZ2ejddsgeegddgeefde3dZe]fdÐdĄZ3ejddsgeegddgeefdZe]fdŐdƄZ4ejdǐdsgeegddgeefdZe]fdȐdɄZ5ejdeegdʍdefdːd̄Z6ejd͐eegdʍdΐdτ Z7eĐ8e eĐ8e eĐ8e eĐ8e eĐ8e eĐ8ey eĐ8e eĐ8e eĐ8e eĐ8e eĐ8e, eĐ8e eĐ8e eĐ8e eĐ8e eĐ8e eĐ8e eĐ8eO eĐ8e eĐ8e֡ eĐ8eء eĐ8e{ eĐ8eԡ eĐ8e eĐ8e eĐ8e eĐ8e$ eĐ8eM eĐ8eE eĐ8ef eĐ8em eĐ8e` eĐ8eX eĐ8e\ eĐ8eA eĐ8e eĐ8e eĐ8e eĐ8eҡ eĐ8e eĐ8eZ eĐ8eo eĐ8e eĐ8e eĐ8e eĐ8e eĐ8e6 eĐ8e eĐ8e eĐ8e} eĐ8ed eĐ8eH eĐ8e2 eĐ8eV eĐ8eQ eĐ8eb eĐ8ej eĐ8e? eĐ8e^ eĐ8eC eĐ8e4 eĐ8e8 eĐ8eq eĐ8e eĐ8e eĐ8e͡ eĐ8e= eĐ8eɡ eĐ8e0 eĐj9dg dѢdҍdesdefdԐdՄZ:eĐjxe1eŐd֍ eĐ8e¡ eĐ8e dS (      N)datetime	timedeltatimezone)TYPE_CHECKINGAnyAsyncGeneratorDictListLiteralOptionalSetTupleUnioncastget_args
get_originget_type_hints)	BaseModelJson)uuid)AIOHTTP_CONNECTOR_LIMIT AIOHTTP_CONNECTOR_LIMIT_PER_HOSTAIOHTTP_KEEPALIVE_TIMEOUTAIOHTTP_NEEDS_CLEANUP_CLOSEDAIOHTTP_TTL_DNS_CACHEAUDIO_SPEECH_CHUNK_SIZEBASE_MCP_ROUTEDEFAULT_MAX_RECURSE_DEPTH$DEFAULT_SHARED_HEALTH_CHECK_LOCK_TTLDEFAULT_SHARED_HEALTH_CHECK_TTL DEFAULT_SLACK_ALERTING_THRESHOLD<LITELLM_EMBEDDING_PROVIDERS_SUPPORTING_INPUT_ARRAY_OF_TOKENS"LITELLM_SETTINGS_SAFE_DB_OVERRIDESLITELLM_UI_ALLOW_HEADERSLITELLM_UI_SESSION_DURATION)$_init_custom_logger_compatible_class)
safe_dumps)CallbackDeleteCallInfoCommonProxyErrorsConfigFieldDeleteConfigFieldInfoConfigFieldUpdateConfigGeneralSettings
ConfigList
ConfigYAMLEnterpriseLicenseDataFieldDetailInvitationClaimInvitationDeleteInvitationModelInvitationNewInvitationUpdateLitellm_EntityTypeLiteLLM_JWTAuthLiteLLM_TeamTableLiteLLM_UserTableLitellmUserRolesPassThroughGenericEndpointProxyErrorTypesProxyExceptionRoleBasedPermissionsSpecialModelNamesSupportedDBObjectTypeTeamDefaultSettingsTokenCountRequestTransformRequestBodyUserAPIKeyAuth)normalize_callback_namesprocess_callback_realtime_request_body)ModelResponseModelResponseStreamTextCompletionResponseTokenCountResponse)$_invalidate_model_cost_lowercase_mapload_credentials_from_list)ClientSession)Span)OpenTelemetryhttpPOSTz/v1/realtime)typemethodpathREALTIME_REQUEST_SCOPE_TEMPLATEc                 C   s8   | d| d|j  d|  d}|d ur|| d S d S )N:: 
)__name__write)messagecategoryfilenamelinenofilelineZtraceback_info rd   Q/home/app/Keep/.python/lib/python3.10/site-packages/litellm/proxy/proxy_server.pyshowwarning   s   rf   default)r_   messagesz../..)AsyncIOSchedulerzMissing dependency z$. Run `pip install 'litellm[proxy]'`)z%'The thing I wish you improved is...'z'A feature I really want is...'z*'The worst thing about this product is...'z$'This product would be better if...'z 'I don't like how this works...'z&'It would help me if you could add...'z/'This feature doesn't meet my needs because...'z&'I get frustrated when the product...'c                  C   s   d} t t}t  tdd|   d  tdd|   d  tdd|  tddd  tdd|   d  tdd|   d  t  td	 t  t  t  td
 t  t  d S )N<   z[1;37m#-z#[0m z[1;37mz# {:^59} #[0mz-https://github.com/BerriAI/litellm/issues/newz/ Thank you for using LiteLLM! - Krrish & IshaanzR[1;31mGive Feedback / Get Help: https://github.com/BerriAI/litellm/issues/new[0m)randomchoicelist_of_messagesprintformat)Z	box_widthr^   rd   rd   re   generate_feedback_box   s.   

rr   )defaultdict)asynccontextmanager)	lru_cache)Routerverbose_proxy_loggerverbose_router_logger)	DualCache
RedisCache)RedisClusterCache)_REALTIME_BODY_CACHE_SIZEAPSCHEDULER_COALESCEAPSCHEDULER_MAX_INSTANCESAPSCHEDULER_MISFIRE_GRACE_TIMEAPSCHEDULER_REPLACE_EXISTINGDAYS_IN_A_MONTHDEFAULT_HEALTH_CHECK_INTERVALDEFAULT_MODEL_CREATED_AT_TIMELITELLM_PROXY_ADMIN_NAME)PROMETHEUS_FALLBACK_STATS_SEND_TIME_HOURSPROXY_BATCH_POLLING_INTERVALPROXY_BATCH_WRITE_AT!PROXY_BUDGET_RESCHEDULER_MAX_TIME!PROXY_BUDGET_RESCHEDULER_MIN_TIME)RejectedRequestError)ModifyResponseException)CustomLogger)SlackAlerting)!_get_parent_otel_span_from_kwargs get_litellm_metadata_from_kwargs)CredentialAccessor)Logging)SensitiveDataMasker)AsyncHTTPHandlerHTTPHandler)
VertexBaserouter)app)global_mcp_tool_registry)*global_agent_registry)append_agents_to_model_groupappend_agents_to_model_info)claude_code_marketplace_router)ExperimentalUIJWTTokenget_team_objectlog_db_metrics)check_response_size_is_safe)
JWTHandler)LicenseCheck)get_all_fallbacksget_complete_model_listget_key_modelsget_mcp_server_idsget_team_models)+_fetch_global_spend_with_event_coordinationuser_api_key_authuser_api_key_auth_websocket)ProxyBaseLLMRequestProcessingcreate_response)initialize_callbacks_on_proxy)init_verbose_loggers)decrypt_value_helperencrypt_value_helper)build_ui_login_form)_read_request_body_safe_get_request_headerscheck_file_size_under_limitget_form_data)!get_config_file_contents_from_gcsget_file_contents_from_s3)%remove_sensitive_info_from_deployment)
ProxyState)ResetBudgetJob)ERROR_RESPONSESSpendLogCleanup)PrismaDBExceptionHandler)ui_discovery_endpoints_router)set_fine_tuning_config)init_guardrails_v2initialize_guardrails)perform_health_check)&_PROXY_VirtualKeyModelMaxBudgetLimiter)"_OPTIONAL_PromptInjectionDetection)_ProxyDBLogger)add_litellm_data_to_request)_user_has_admin_privilegesadmin_can_invite_user)user_update)delete_verification_tokensduration_in_secondsgenerate_key_helper_fn)_add_model_to_db_add_team_model_to_db"_deduplicate_litellm_router_models)scim_router)update_teamvalidate_membership),get_disabled_non_admin_personal_key_creation)create_audit_log_for_update)InFlightRequestsMiddleware)PrometheusAuthMiddleware)set_files_config)passthrough_endpoint_router$vertex_ai_live_websocket_passthrough)!initialize_pass_through_endpoints)route_request)get_logging_payloadget_instance_fn)PrismaClientProxyLoggingProxyUpdateSpend_cache_user_row_get_docs_url_get_projected_spend_over_limit_get_redoc_url_is_projected_spend_over_limit_is_valid_team_configsget_custom_urlget_error_message_strget_server_root_pathhandle_exception_on_proxy
hash_token model_dump_with_preserved_fieldsupdate_spend)AssistantsTypedDict
DeploymentLiteLLM_ParamsModelGroupInfo)FlowItem	Scheduler)load_aws_kms)load_google_kms)
get_secretget_secret_boolget_secret_strstr_to_bool)SlackAlertingArgs)AnthropicMessagesRequestAnthropicResponse!AnthropicResponseContentBlockTextAnthropicResponseUsageBlock)HttpxBinaryResponseContent)ModelGroupInfoProxy)DefaultTeamSSOParams#LiteLLM_UpperboundKeyGenerateParams)RealtimeQueryParams)DeploymentTypedDict)	ModelInfo)RouterGeneralSettingsSearchToolTypedDictupdateDeployment)DefaultPriorities)KeyManagementSettingsKeyManagementSystem)CredentialItemCustomHuggingfaceTokenizer)RawRequestTypedDictStandardLoggingPayload)-_add_custom_logger_callback_to_specific_event)versionz0.0.0T)r   )DependsFastAPIFileFormHeaderHTTPExceptionPathQueryRequestResponse
UploadFile	WebSocketWebSocketDisconnectapplicationsstatus)jsonable_encoder)CORSMiddlewareget_swagger_ui_html)get_openapi)FileResponseJSONResponseORJSONResponseRedirectResponseStreamingResponse)	APIRouter)OAuth2PasswordBearer)APIKeyHeader)StaticFiles)AgentConfig)EnterpriseProxyConfigenterprise_proxy_configpremium_userr0   premium_user_dataZ+LITELLM_GLOBAL_MAX_PARALLEL_REQUEST_RETRIES'global_max_parallel_request_retries_env   #global_max_parallel_request_retriesZ1LITELLM_GLOBAL_MAX_PARALLEL_REQUEST_RETRY_TIMEOUT-global_max_parallel_request_retry_timeout_envg      N@)global_max_parallel_request_retry_timeoutz/uiz/fallback/loginz/ui/model_hub_tableu(   👉 [```LiteLLM Admin Panel on /ui```](zI). Create, Edit Keys with SSO. Having issues? Try [```Fallback Login```]()uB   

💸 [```LiteLLM Model Cost Map```](https://models.litellm.ai/).u!   

🔎 [```LiteLLM Model Hub```](z[). See available models on the proxy. [**Docs**](https://docs.litellm.ai/docs/proxy/ai_hub)z/ui/chatu   

💬 [```LiteLLM Chat UI```](zN). ChatGPT-like interface for your users to chat with AI models and MCP tools.zr[**Customize Swagger Docs**](https://docs.litellm.ai/docs/proxy/enterprise#swagger-docs---custom-routes--branding)Z
DOCS_TITLEzLiteLLM APIZDOCS_DESCRIPTIONzJEnterprise Edition 

Proxy Server to call 100+ LLMs in the OpenAI format. 

z5Proxy Server to call 100+ LLMs in the OpenAI format. c                   C   s8   d a d ad ad ad ad ad ad ad ad a	d a
d ad ad S N)
master_keyuser_config_file_pathotel_logginguser_custom_authZuser_custom_auth_pathuser_custom_key_generateuser_custom_sso"user_custom_ui_sso_sign_in_handleruse_background_health_checksuse_shared_health_checkhealth_check_intervalhealth_check_concurrencyprisma_clientrd   rd   rd   re   cleanup_router_config_variables  s   rO  c                     s   t d trt d t I d H  tjd ur!tj I d H  t I d H  t	d ur3t	 I d H  dtj
v rSzddlm}  | d urH| j  W n	 tyR   Y nw t  d S )Nz"Shutting down LiteLLM Proxy ServerzDisconnecting from PrismaZlangfuser   langFuseLogger)rx   inforN  debugZ
disconnectlitellmcachejwt_handlerclosedb_writer_clientsuccess_callbacklitellm.utilsrQ  ZLangfuseflush	ExceptionrO  rP  rd   rd   re   proxy_shutdown_event  s(   





r]  c               
      s   zCddl m} m} ttd}trd|d< tdkrt|d< tdkr%t|d< |di |}| |d}t	d	t
| d
t dt d |W S  ty` } ztd| d W Y d}~dS d}~ww )zNInitialize shared aiohttp session for connection reuse with connection limits.r   )rP   TCPConnector)Zkeepalive_timeoutZttl_dns_cacheTZenable_cleanup_closedlimitZlimit_per_host)	connectorzJSESSION REUSE: Created shared aiohttp session for connection pooling (ID: z, limit=z, limit_per_host=r@  z)Failed to create shared aiohttp session: z#. Continuing without session reuse.Nrd   )aiohttprP   r^  r   r   r   r   r   rx   rR  idr\  warning)rP   r^  Zconnector_kwargsr`  sessionerd   rd   re   "_initialize_shared_aiohttp_session  s:   

rf  r   c                 C  s  dd l }t  tjdd}|ri|dD ]R}| }|sqz5d|vr,td| d|dd\}}t	
|}t||}t|rJ| I d H  n|  td	| W q tyh } ztd
||  d }~ww tdt tdu ryt atdatd}	td}
td|	 |
d urtj|
rtj|
drtjt|
dI d H \aa a!nd|	d urt"|	t#rtj|	rtj|	drtjt|	dI d H \aa a!n@tjdd urt"|	t#rtjt|	dI d H \aa a!n%t"|	t$rt%d-i |	I d H  n|&|	}	t"|	t$rt%d-i |	I d H  t'd u r"tdd }t(j)|t*t+dI d H a't(j,tt*t-d t(j.t!t-d z,td t/ }|di }tdt0|1   t(j2t|dI d H  td W n tyz } ztjd| dd W Y d }~nd }~ww t(j3t!t't+d  t4d urt4j5td! td"t' t'd urt6j7dkrt(j8t9d# t:;t(j<t9t+t'd$ t'd urt(j=t!t't>t?t@t*d%I d H  t(A I d H  t(B I d H  tCrt:;tD  t(E  t(F  tG I d H aHd V  tHd urztHI I d H  td& W n ty } ztd'|  W Y d }~nd }~ww t'd urRtJt'd(rRtJt'jKd)rRz
t'jKL I d H  W n tyQ } ztd*|  W Y d }~nd }~ww t'd urtJt'd+rz	t'M I d H  W n ty } ztd,|  W Y d }~nd }~ww tN I d H  d S ).Nr   ZLITELLM_WORKER_STARTUP_HOOKS ,rY   zInvalid hook spec 'z1': expected format is 'module.path:function_name'   z.Worker startup hook '%s' executed successfullyz#Worker startup hook '%s' failed: %szElitellm.proxy.proxy_server.py::startup() - CHECKING PREMIUM USER - {}FLITELLM_MASTER_KEYWORKER_CONFIGZCONFIG_FILE_PATHzworker_config: %sconfig_file_pathr   rm  LITELLM_CONFIG_BUCKET_NAMEZDATABASE_URL)database_urlproxy_logging_objuser_api_key_cache)
llm_routerrq  redis_usage_cache)general_settingsrt  z(About to initialize semantic tool filterlitellm_settingszlitellm_settings keys = )rs  rv  z)After semantic tool filter initializationzSemantic filter init failed: Texc_info)ru  rN  rr  r   zprisma_client: %s)litellm_proxy_budget_name)litellm_proxy_admin_namerr  rN  )ru  rN  !proxy_budget_rescheduler_min_time!proxy_budget_rescheduler_max_timeproxy_batch_write_atrq  z,SESSION REUSE: Closed shared aiohttp sessionz&Error closing shared aiohttp session: dbstop_token_refresh_taskz#Error stopping token refresh task: stop_db_health_watchdog_taskz(Error stopping DB health watchdog task: rd   )Ojsonr   osenvirongetsplitstrip
ValueErrorrsplit	importlibimport_modulegetattrinspectiscoroutinefunctionrx   rR  r\  errorrS  rq   r9  _license_check
is_premiumr   rC  r   rW   isfileproxy_configis_yamlload_configrs  llm_model_listru  
isinstancestrdict
initializeloadsrN  ProxyStartupEvent_setup_prisma_clientrq  rr  _initialize_startup_loggingrt  )_validate_redis_transaction_buffer_configget_config_statelistkeys _initialize_semantic_tool_filter_initialize_jwt_authprompt_injection_detection_objupdate_environmentrT  
max_budget_add_proxy_budget_to_dbrz  asynciocreate_task_warm_global_spend_cache$initialize_scheduled_background_jobsr{  r|  r}  "_update_default_team_member_budget%_sync_ui_settings_to_general_settingsrJ  _run_background_health_check_init_dd_tracer_init_pyroscoperf  shared_aiohttp_sessionrW  hasattrr~  r  r  r]  )r   r  Z_startup_hooks_envZ
_hook_specZ_module_pathZ
_func_name_moduleZ_hook_fnre  worker_configZenv_config_yamlZ_db_url_config_litellm_settingsrd   rd   re   proxy_startup_event  sj  







	






 

		


r  )docs_urlZ	redoc_urltitledescriptionr  	root_pathZlifespan)APIWebSocketRoutec            	   
   C   sT  t jrt jS ddlm}  | tt jt jt jt jd}dd t jD }|D ]g}|j	
dd d}g }z(t|drY|jd urYt|jd	g }|rY|D ]}||jd
|jddid qHW n ttfye   Y nw dd|jpl| dd|jpx|dd |dddiidgdi|d |< q#ddlm} ||}trddtd ig|d< |t _t jS )Nr   )get_openapi_schema_with_compat)Zget_openapi_funcr  r  r  routesc                 S   s   g | ]	}t |tr|qS rd   )r  r  ).0routerd   rd   re   
<listcomp>  s
    
z&get_openapi_schema.<locals>.<listcomp>{?	dependantquery_paramsqueryrU   string)nameinrequiredZschemar  zWebSocket: zWebSocket connection endpointZ
websocket_/_Z101r  zWebSocket Protocol Switchedr$  )summaryr  ZoperationId
parameters	responsestagspathsCustomOpenAPISpecurlservers)r   openapi_schemaZ0litellm.proxy.common_utils.openapi_schema_compatr  r,  r  r  r  r  rW   r  rstripr  r  r  appendr  r  AttributeError	TypeErrorreplace.litellm.proxy.common_utils.custom_openapi_specr  add_llm_api_request_schema_bodyserver_root_pathr  )	r  r  Zwebsocket_routesr  	base_pathr  r  paramr  rd   rd   re   get_openapi_schema  s`   	


r  c                  C   s   t jrt jS t } tjj}i }|D ]}|| d v r!| d | ||< q|| d< ddlm} || } t	r?ddt	
d ig| d< | t _t jS )Nr  r   r  r  r  r  )r   r  r  ZLiteLLMRoutesopenai_routesvaluer  r  r  r  r  )r  r  Zpaths_to_includer  r  rd   rd   re   custom_openapi.  s    
r  ZDOCS_FILTEREDFalseTruec                   @   s   e Zd ZdZdS )UserAPIKeyCacheTTLEnumrj   N)r\   
__module____qualname__in_memory_cache_ttlrd   rd   rd   re   r  O  s    r  requestexcc                    s4   |j }| }t|jrt|jntjd|i|dS )Nr  )status_codecontentheaders)r  to_dictr.  codeintr'  HTTP_500_INTERNAL_SERVER_ERROR)r  r  r  Z
error_dictrd   rd   re   openai_exception_handlerS  s   r  r   _experimentaloutz/litellm-asset-prefixrW   returnc                 C   s2   zt j| ott | W S  ty   Y dS w )NF)r  rW   isdiranyscandirFileNotFoundError)rW   rd   rd   re   _dir_has_contentl  s
   r  ui_pathc                 C   sL   t j| sdS t jt j| dsdS t j| d}t j|s$dS dS )a  
        Verify UI directory has minimum required structure.

        Checks for:
        - Directory exists
        - Has index.html (main entry point)
        - Has _next directory (Next.js assets)

        Returns True if UI directory appears valid and servable.
        F
index.html_nextT)r  rW   r  existsjoin)r  Znext_dirrd   rd   re   _validate_ui_directoryr  s   r  ui_dirc              
   C   s   t j| sdS t j| d}t j|rtd|  dS t jt j| ds,dS z1t | D ](}| rZ|j	
dsZt j|jd}t j|rZtd|j	 d  W dS q2W dS  ttfy} } ztd	|  d
|  W Y d}~dS d}~ww )ad  
        Detect if UI directory is already pre-restructured and ready to serve.

        Returns True if:
        1. Marker file .litellm_ui_ready exists (created by Dockerfile), OR
        2. Restructuring pattern detected (subdirectories with index.html inside)

        This allows skipping copy/restructure operations on read-only filesystems.
        Fz.litellm_ui_readyzFound UI ready marker: Tr  r  z,Detected restructured UI via pattern: found z/index.htmlzCould not scan z for restructuring detection: N)r  rW   r  r  r   rx   rS  r  is_dirr  
startswithPermissionErrorOSError)r  Zmarker_fileentryZ
index_pathre  rd   rd   re   _is_ui_pre_restructured  s6   
r	  source_pathtarget_pathc              
   C   s   z%t j|dd t|s#t| r#tj| |dd td|  W dS W dS  ttfy? } zdt	|fW  Y d}~S d}~ww )	z|
        Attempt to populate target UI directory from source.

        Returns: (success: bool, error_message: str)
        Texist_ok)dirs_exist_okzSuccessfully populated UI at )Trg  )Fz(Source or target directory state invalidFN)
r  makedirsr  shutilcopytreerx   rR  r  r  r  )r
  r  re  rd   rd   re   _try_populate_ui_directory  s   r  LITELLM_NON_ROOTrg  truez/var/lib/litellm/uiZLITELLM_UI_PATHzPackaged UI at z9 is invalid or incomplete. UI may not function correctly.zUsing pre-restructured UI at zUI at zT has content but is not properly restructured. Will attempt to restructure in place.zUI not found at z*. Attempting to populate from packaged UI.zFailed to populate UI at rZ   z!. Falling back to packaged UI at zm. For read-only deployments, pre-build UI in Dockerfile or set LITELLM_UI_PATH to a writable emptyDir volume.zUsing packaged UI directory: zSelected UI path z5 is invalid or incomplete. UI may not work correctly.r  z4Cannot apply server_root_path replacements to UI at zz: path is not writable. Ensure server_root_path is '/' or pre-process UI files in Dockerfile with custom server_root_path.)	z.pngz.jpgz.jpegz.gifz.icoz.woffz.woff2z.ttfz.eotrzutf-8)encodingz&/litellm/.well-known/litellm-ui-configz/.well-known/litellm-ui-configwz/_nextr  	directoryZnext_staticr  )r  htmlZuiui_rootc           
   
   C   s   t | D ]\\}}}t j|| }|dkrdn|t jd }|dv r$q|D ]:}|dr1|dkr2q&t j||}t j|d }t j|d}	t j	|dd zt 
||	 W q& ty`   Y q&w qd	S )
zCEnsure each exported HTML route is available as <route>/index.html..rg  r   >   zlitellm-asset-prefixr  z.htmlr  Tr  N)r  walkrW   relpathr  sependswithr  splitextr  r  r  )
r  Zcurrent_rootr  filesZrel_rootZfirst_segmentr`   	file_path
target_dirr  rd   rd   re   _restructure_ui_html_filesf  s&   r&  zSkipping UI restructuring: z is already pre-restructuredzCannot restructure UI at z: path is not writable. UI may not work correctly for extensionless routes. Pre-build and restructure UI in Dockerfile for read-only deployments.zRestructured UI directory: z2Permission error while restructuring UI directory z'Error while restructuring UI directory )Zallow_originsZallow_credentialsZallow_methodsZallow_headersZexpose_headersc                     sd   t jtd} td u rdnt}|ds|d }|d  tjdt| ddd  fdd}|t	_
d S )NZswaggerr  z/swaggerr  r  c                     s,   t | i |  d  d  ddS )Nz/swagger-ui-bundle.jsz/swagger-ui.cssz/favicon.png)Zswagger_js_urlZswagger_css_urlZswagger_favicon_urlr*  )argskwargsZcustom_root_path_swagger_pathrd   re   swagger_monkey_patch  s   
z.mount_swagger_ui.<locals>.swagger_monkey_patch)r  rW   r  current_dirr  r!  r   mountr5  r&  r+  )Zswagger_directoryZswagger_pathr*  rd   r)  re   mount_swagger_ui  s   

	r-  ZROOT_REDIRECT_URLroot_redirect_urlF)include_in_schemac                      s   t tdS )Nr  )r0  r.  rd   rd   rd   re   root_redirect  s   
r1  )r   rD  rs  r  ru  config_passthrough_endpointszapi_log.jsonrC  config_agentsrN  rP   r  )default_in_memory_ttl)Z
dual_cachert  allpolling_via_cache_enablednative_background_mode  polling_cache_ttlhealth_check_resultsqueuezlitellm-proxy-budget)Zadminr5  ui_access_moder  store_model_in_dbopen_telemetry_logger)rr  r9  rX  c                    sd   t   }t   | dk r0tdI dH  |  I dH r&|  tdddt   | dk sdS dS )am  
    Asynchronously checks if the request is disconnected at regular intervals.
    If the request is disconnected
    - cancel the litellm.router task
    - raises an HTTPException with status code 499 and detail "Client disconnected the request".

    Parameters:
    - request: Request: The request object to check for disconnection.
    Returns:
    - None
    X  ri  Ni  zClient disconnected the requestr  detail)timer  sleepZis_disconnectedcancelr  )r  Zllm_api_call_task
start_timerd   rd   re   check_request_disconnection/  s   rF  c                 C   s\   ddl m} t| }|tu r t| D ]}t||r|  S qdS t| tr,t| tr,| S dS )CResolve the actual TypedDict class from a potentially wrapped type.r   )_TypedDictMetaN)Ztyping_extensionsrH  r   r   r   r  rU   r  )typrH  originargrd   rd   re   _resolve_typed_dict_typeK  s   
rL  c                 C   sp   t | }g }|tu r)t| D ]}|dur&t|tds&dt|vr&|| q|S t| tr6t| tr6| gS |S )rG  NNoneType)r   r   r   r  rU   r  r  r   )rI  rJ  ZtypsrK  rd   rd   re   _resolve_pydantic_typeY  s   
rN  use_azure_key_vaultc              
   C   s   | du rd S z-ddl m} ddlm} tdd }|d u r!td| }|||d}|t_t	j
t_W d S  tyP } zt|}td| W Y d }~d S d }~ww )	NFr   )DefaultAzureCredential)SecretClientZAZURE_KEY_VAULT_URIzMError when loading keys from Azure Key Vault: AZURE_KEY_VAULT_URI is not set.)Z	vault_url
credentialztError when loading keys from Azure Key Vault: %s .Ensure you run `pip install azure-identity azure-keyvault-secrets`)Zazure.identityrP  Zazure.keyvault.secretsrQ  r  getenvr\  rT  Zsecret_manager_clientr  AZURE_KEY_VAULTZ_key_management_systemr  rx   	exception)rO  rP  rQ  ZKVUrirR  clientre  Z
_error_strrd   rd   re   load_from_azure_key_vaultj  s,   rW  c                   C   s,   t d urtjt  tjt  d S d S rB  )rN  rT  logging_callback_manageradd_litellm_callbackr   Z"add_litellm_async_success_callbackrd   rd   rd   re   cost_tracking  s   rZ  tokenuser_idend_user_idteam_idresponse_costparent_otel_spanr  c                    s   g dt dtffdd}fdd} fdd}	fd	d
}
fdd}| dur?dur?|| dI dH  durI| I dH   durS|	 I dH  dur]|
 I dH  durg| I dH  ttjd|d dS )z`
    Use this to update the cache with new user spend.

    Put any alerting logic in here.
    r[  r_  c              
      sl  t | tr| drt| d}n| }td| tj|dI d H }td|  |d u r0d S |j}|| }|j	du r~|j
d ur~t||j
d dd	u r~t||j
dd d\}}|j
dtd
}t|jpgd||j||j||tjd}	ttjd|	d |d urt|dd d ur|jpd}
|
| |_|d urt|dd d ur|jpd}|| |_||_ ||f d S )Nzsk-r[  z"_update_key_cache: hashed_token=%skeyz&_update_key_cache: existing_spend_obj=FZsoft_budget)Zcurrent_spendZsoft_budget_limitTinfrg  )r[  spend	key_aliasr  r\  projected_spendprojected_exceeded_dateZevent_groupZprojected_limit_exceeded)rU   Z	user_info
team_spendr   team_member_spend)r  r  r  r   rx   rS  rr  async_get_cachere  Zsoft_budget_cooldownZlitellm_budget_tabler   r   r  floatr(   r[  rf  r\  r7   ZKEYr  r  rq  Zbudget_alertsr  ri  rj  r  )r[  r_  Zhashed_tokenexisting_spend_objexisting_spend	new_spendrg  rh  Z
soft_limitZ	call_infoZexisting_team_spendZexisting_team_member_spend)values_to_update_in_cacherd   re   _update_key_cache  sv   

	
	


z'update_cache.<locals>._update_key_cachec                     sV  g} z| D ]Q}|d u rqt j|dI d H }|d u r W d S td| d   t|tr4|d }n|j}|  }t|trL||d< ||f q||_|| f qt jd	t
dI d H }|d u rlW d S  d ur|d ur|  }d	t
|f W d S W d S W d S  ty } ztd t|t  W Y d }~d S d }~ww )Nrb  z!_update_user_db: existing spend: ; response_cost: re  {}:spendzSpend tracking - failed to update user spend in cache. Budget enforcement may use stale spend values. user_id=%s, response_cost=%s - %s
%s)rr  rk  rx   rS  r  r  re  r  r  rq   rz  r\  rc  r  	traceback
format_exc)Zuser_ids_idrm  rn  ro  Zglobal_proxy_spend	incrementre  )r_  r\  rp  rd   re   _update_user_cache  sT   



z(update_cache.<locals>._update_user_cachec                     s   d u s	d u rd S d  } zUtj| dI d H }|d u r!W d S td| d  |d u r3d}nt|tr=|d }n|j}| }t|trW||d< | |f W d S ||_| |	 f W d S  t
y } ztd t|t  W Y d }~d S d }~ww )Nzend_user_id:{}rb  z%_update_end_user_db: existing spend: rr  r   re  zSpend tracking - failed to update end user spend in cache. Budget enforcement may use stale spend values. end_user_id=%s, response_cost=%s - %s
%s)rq   rr  rk  rx   rS  r  r  re  r  r  r\  rc  r  rt  ru  rv  rm  rn  ro  re  )r]  r_  rp  rd   re   _update_end_user_cache-  s@   



z,update_cache.<locals>._update_end_user_cachec                     s  d u s	 d u rd S d } zYtj| dI d H }|d u r!W d S td| d   |d u r3d}nt|tr=|d }n|j}|d u rFd}|  }t|tr]||d< | |f W d S ||_| |f W d S  t	y } zt
d t|t  W Y d }~d S d }~ww )Nz
team_id:{}rb  z!_update_team_db: existing spend: rr  g        re  zSpend tracking - failed to update team spend in cache. Budget enforcement may use stale spend values. team_id=%s, response_cost=%s - %s
%s)rq   rr  rk  rx   rS  r  r  re  r  r\  rc  r  rt  ru  ry  )r_  r^  rp  rd   re   _update_team_cacheY  sF   



z(update_cache.<locals>._update_team_cachec                     s$  du s	 du rdS zfD ]`} | rt | tsqd|  }tj|dI dH }|du r+qtd|  d| d   t |trG|ddpEd}nt|ddpNd}|  }t |trd||d< 	||f q||_
	||f qW dS  ty } ztd	 t|t  W Y d}~dS d}~ww )
z:
        Update the tag cache with the new spend.
        Nztag:rb  z*_update_tag_cache: existing spend for tag=rZ   rr  re  r   zSpend tracking - failed to update tag spend in cache. Budget enforcement may use stale spend values. tags=%s, response_cost=%s - %s
%s)r  r  rr  rk  rx   rS  r  r  r  r  re  r\  rc  rt  ru  )Ztag_name	cache_keyZexisting_tag_objrn  ro  re  )r_  r  rp  rd   re   _update_tag_cache  sH   


 z'update_cache.<locals>._update_tag_cacheN)r[  r_  rj   )Z
cache_listttlZlitellm_parent_otel_span)r  rl  r  r  rr  Zasync_set_cache_pipeline)r[  r\  r]  r^  r_  r`  r  rq  rx  rz  r{  r}  rd   )r]  r_  r  r^  r\  rp  re   update_cache  s0   S6,03r  c               
   C   s   z'ddg} t tjd}tj| ||d W d    W d S 1 s w   Y  W d S  tyC } ztd| d W Y d }~d S d }~ww )NollamaZserver  )stdoutstderrzd
            LiteLLM Warning: proxy started with `ollama` model
`ollama serve` failed with Exceptionz). 
Ensure you run `ollama serve`
        )openr  devnull
subprocessPopenr\  rx   rS  )commandr  re  rd   rd   re   run_ollama_serve  s   &r  c                  C   sR   zddl } | | jj}tjdkrt|d W S t|d W S  ty(   Y dS w )zj
    Get process RSS memory in MB.
    On Linux, ru_maxrss is in KB. On macOS, ru_maxrss is in bytes.
    r   Ndarwini   i   )resourceZ	getrusageZRUSAGE_SELF	ru_maxrsssysplatformrl  r\  )r  r  rd   rd   re   _get_process_rss_mb  s   
r  c                  C   s   t  } | d u r	dS | dS )Nunknown.2f)r  )Zrss_mbrd   rd   re   _rss_mb_for_log  s   r  
model_listdetailsmax_concurrencyinstrumentation_contextc              
      sb   zt | |||dI d H W S  ty0 } zdt|vr t | ||dI d H W  Y d }~S d }~ww )N)r  r  r  r  r  r  r  r  )r   r  r  )r  r  r  r  re  rd   rd   re   -_run_direct_health_check_with_instrumentation  s$   r  healthy_endpointsunhealthy_endpointsc           	   
   C   sX   | du rdS ddl }ddlm} |dur|jnd}|  }t|| |||||d dS )zKFire-and-forget: persist health check results to DB if prisma is available.Nr   )$_save_background_health_checks_to_dbZbackground_health_check)
checked_by)rB  0litellm.proxy.health_endpoints._health_endpointsr  Zpod_idr  r  )	rN  shared_health_managerr  r  r  Ztime_moduler  r  rE  rd   rd   re   )_schedule_background_health_check_db_save  s&   r  c                     sf  t du stt trt dkrdS trtdt tt datdt ttt	t
 t  d} trDtdurDddlm} |tttd} td 	 td	7 ad
t }t }ttpXg }t|}dd |D }t|}|}tttr|tdkr||dkr|t|t}td|||t t|| dut
 t 
 dd|d}t	durt	nd}	| durz| j||	tdI dH \}
}W n2 ty } ztdt| t|t	t|I dH \}
}W Y d}~nd}~ww t|t	t|I dH \}
}|
t d< |t d< t|
t d< t|t d< t | d }td||t|
t||t t
 t 	 |t d kr"td||t  t!t"| ||
| t#$t I dH  qE)z
    Periodically run health checks in the background on the endpoints.

    Update health_check_results, based on this.
    Uses shared health check state when Redis is available to coordinate across pods.
    Nr   zxbackground_health_check_loop_overlap_detected existing_loop_active=true interval_seconds=%s max_concurrency=%s shared=%sTzzbackground_health_check_loop_started interval_seconds=%s max_concurrency=%s shared=%s details=%s thread_count=%d rss_mb=%s)SharedHealthCheckManager)redis_cacheZhealth_check_ttlZlock_ttlz'Initialized shared health check managerri  zbg-c                 S   s$   g | ]}| d i  dds|qS )
model_infoZdisable_background_health_checkFr  r  mrd   rd   re   r  q  s    z0_run_background_health_check.<locals>.<listcomp>zbackground_health_check_cycle_start cycle_id=%s model_count_total=%d model_count_enabled=%d interval_seconds=%s max_concurrency=%s expected_peak_in_flight=%d shared=%s thread_count=%d rss_mb=%sZproxy_background_loop)enabledsourcecycle_idr  zEError in shared health check, falling back to direct health check: %sr  r  Zhealthy_countZunhealthy_counti  zbackground_health_check_cycle_complete cycle_id=%s model_count_enabled=%d healthy_count=%d unhealthy_count=%d duration_ms=%.2f interval_seconds=%s thread_count=%d rss_mb=%szibackground_health_check_cycle_duration_exceeded_interval cycle_id=%s duration_ms=%.2f interval_seconds=%s)%rL  r  r  #background_health_check_loop_activerx   rc  rM  rK  rR  health_check_details	threadingactive_countr  rt  Z<litellm.proxy.health_check_utils.shared_health_check_managerr  r   r   !background_health_check_cycle_seqrB  	monotoniccopydeepcopyr  lenminrS  Zperform_shared_health_checkr\  r  r  r  r:  r  rN  r  rC  )r  r  r  Zcycle_start_timeZ_llm_model_listZmodel_count_totalZmodel_count_enabledZexpected_peak_in_flightr  Zdetails_boolr  r  re  Zcycle_duration_msrd   rd   re   r  4  s
  


	
	r  c                   @   s   e Zd ZdS )StreamingCallbackErrorN)r\   r  r  rd   rd   rd   re   r    s    r  c                
   @   s  e Zd ZdZdddZdedefddZd	edefd
dZ		dde
e defddZdededefddZdefddZdefdedededefddZdedee defddZdefddZd efd!d"Zd#d$ Zdde
e defd%d&Zdefd'd(Zd)d* Zdedee fd+d,Zdede
ee  fd-d.Zdefd/d0Zd1e
ej  defd2d3Z!defd4d5Z"de
e d6e
d7 d8e
d9 fd:d;Z#d<efd=d>Z$	dd?e
e de
e fd@dAZ%dde&fdCdDZ'dEe(defdFdGZ)dEe(defdHdIZ*dJe(de(fdKdLZ+dJe
e, dMe-fdNdOZ.dPedQee/dR  dSe(ddfdTdUZ0dVeddfdWdXZ1	ddYedZe
e defd[d\Z2	BddYed]edefd^d_Z3d`edefdadbZ4e5dce6de
e fdddeZ7	ddfe
dg d6e
e8 dMe
dh de
e fdidjZ9dVed8e
e  d6e
e8 ddfdkdlZ:dVed<edMe-ddfdmdnZ;dodp Z<dqe
e, fdrdsZ=dtedue/dv dwe6defdxdyZ>d6e8dedze
e fd{d|Z?d}e@eeAf defd~dZBd6e8de(fddZCd6e8dMe-fddZDd6e8fddZEd6e8fddZFd6e8fddZGd6e8fddZHd6e8fddZId6e8fddZJdd ZKd6e8fddZLd6e8fddZMd6e8fddZNd6e8fddZOd6e8fddZPd6e8fddZQdd ZRd6e8fddZSd6e8fddZTdd ZUde@eeVf defddZWdee fddZXd6e8fddZYdS )ProxyConfigz}
    Abstraction class on top of config loading/updating logic. Gives us one place to control all config updating logic.
    r  Nc                 C   s   i | _ d | _d | _d S rB  )config_last_semantic_filter_config_last_hashicorp_vault_configselfrd   rd   re   __init__  s   
zProxyConfig.__init__rm  c                 C   s8   t j|sdS t j|\}}| dkp| dkS )NFz.yamlz.yml)r  rW   r  r"  lower)r  rm  r  Zfile_extensionrd   rd   re   r    s   zProxyConfig.is_yamlr$  c              
   C   sr   z t |d}t|pi W  d   W S 1 sw   Y  W dS  ty8 } ztd| dt| d}~ww )z,
        Load and parse a YAML file
        r  NzError loading yaml file rZ   )r  yaml	safe_loadr\  r  )r  r$  rb   re  rd   rd   re   _load_yaml_file  s   (zProxyConfig._load_yaml_filec                    s   |pt }|dur|a tj| r.t| d}t|}W d   n1 s(w   Y  n|dur9td| g i i i d}|du rHtd| j|tj	tj
|pTdd}|S )z
        Given a config file path, load the config from the file.
        Args:
            config_file_path (str): path to the config file
        Returns:
            dict: config
        Nr  zConfig file not found: )r  ru  router_settingsrv  zConfig cannot be None or Empty.rg  )r  base_dir)rD  r  rW   r   r  r  r  r\  _process_includesdirnameabspath)r  rm  r$  config_filer  rd   rd   re   _get_config_from_file  s,   z!ProxyConfig._get_config_from_filer  r  c                 C   s   d|vr|S t |d tstd|d D ]9}tj||}tj|s+td| | |}|	 D ]\}}t |trI||v rI|| 
| q4|||< q4q|d= |S )au  
        Process includes by appending their contents to the main config

        Handles nested config.yamls with `include` section

        Example config: This will get the contents from files in `include` and append it
        ```yaml
        include:
            - model_config.yaml

        litellm_settings:
            callbacks: ["prometheus"]
        ```
        includez&'include' must be a list of file pathszIncluded file not found: )r  r  r  r  rW   r  r   r  r  itemsextend)r  r  r  Zinclude_filer$  Zincluded_configrc  r  rd   rd   re   r  '	  s    

zProxyConfig._process_includes
new_configc                    s   	 t d ur?tdddu str?| }d|v r-|d r-| j|d dd}| j|d|d< |dd  t j|dd	I d H  d S t	t
 d
}tj||dd W d    d S 1 sYw   Y  d S )Nr=  FTenvironment_variables)r  return_original_valuer  r  r  )data
table_namer  )Zdefault_flow_style)rN  ru  r  r=  r  !_decrypt_and_set_db_env_variables_encrypt_env_variablespopZinsert_datar  rD  r  dump)r  r  Zconfig_to_savedecrypted_env_varsr  rd   rd   re   save_configN	  s,   
"zProxyConfig.save_configr   depth	max_depthc                 C   s   ||krt d| d |S | D ]@\}}t|tr)| j||d |d||< qt|trC|D ]}t|trA| j||d |d}q0qt|trS|drSt	|||< q|S )a  
        Check for os.environ/ variables in the config and replace them with the actual values.
        Includes a depth limit to prevent infinite recursion.

        Args:
            config (dict): The configuration dictionary to process.
            depth (int): Current recursion depth.
            max_depth (int): Maximum allowed recursion depth.

        Returns:
            dict: Processed configuration dictionary.
        zMaximum recursion depth (z") reached while processing config.ri  )r  r  r  os.environ/)
rx   rc  r  r  r  _check_for_os_environ_varsr  r  r  r   )r  r  r  r  rc  r  itemrd   rd   re   r  x	  s,   





z&ProxyConfig._check_for_os_environ_varsr^  all_teams_configc                 C   st   i }|D ]}d|vrt dt| ||d kr|} nq| D ]\}}t|tr7|dr7t|||< q#|S )Nr^  zteam_id missing from team: r  )r\  SENSITIVE_DATA_MASKERZ	mask_dictr  r  r  r  r   )r  r^  r  team_configteamkvrd   rd   re   _get_team_config	  s   zProxyConfig._get_team_configc                 C   s>   |   }|di }|dd}|du ri S | j||d}|S )z^
        - for a given team id
        - return the relevant completion() call params
        rv  default_team_settingsN)r^  r  )r  r  r  )r  r^  r  rv  r  r  rd   rd   re   load_team_config	  s   zProxyConfig.load_team_configcache_paramsc                 C   sp   ddl m} d|v r|d t _d|v r|d t _|di |t _t jd ur4tt jjttfr6t jjad S d S d S )Nr   Cacher4  default_redis_ttlrd   )	rT  r  r4  r  rU  r  r{   r|   rt  )r  r  r  rd   rd   re   _init_cache	  s   

zProxyConfig._init_cachec                 C   sD   ddl }tdur|jdurtjdur dt_td dS dS dS dS )z
        Enable caching on the router by setting cache_responses=True.
        This ensures caching works without needing caching=True in request body.
        Router passes caching=self.cache_responses to litellm.completion()
        r   NTz8Set router.cache_responses=True after initializing cache)rT  rs  rU  cache_responsesrx   rS  )r  rT  rd   rd   re   switch_on_llm_response_caching	  s   

z*ProxyConfig.switch_on_llm_response_cachingc                    s   t jddur?t jd}t jd}t jd}td|| |dkr0t||dI dH }nt||d}|du r>tdn	| j|d	I dH }t	dur[t
d
u r[| j|t	t
dI dH }t|}|dd | j|d}| j|d |S )a  
        Load config file
        Supports reading from:
        - .yaml file paths
        - LiteLLM connected DB
        - GCS
        - S3

        Args:
            config_file_path (str): path to the config file
        Returns:
            dict: config

        ro  NZ LITELLM_CONFIG_BUCKET_OBJECT_KEYZLITELLM_CONFIG_BUCKET_TYPEzbucket_name: %s, object_key: %sZgcs)bucket_name
object_keyz(Unable to load config from given source.rl  T)r  rN  r=  r  r  )r  r  r  rx   rS  r   r   r\  r  rN  r=  _update_config_from_dbr  r  r  r  update_config_state)r  rm  r  r  Zbucket_typer  Zprinted_yamlrd   rd   re   
get_config	  s<   
zProxyConfig.get_configc                 C   s
   || _ d S rB  r  )r  r  rd   rd   re   r  "
  s   
zProxyConfig.update_config_statec              
   C   sL   zt | jW S  ty% } ztd| j| i W  Y d}~S d}~ww )z
        Returns a deep copy of the config,

        Do this, to avoid mutating the config state outside of allowed methods
        z^ProxyConfig:get_config_state(): Error returning copy of config state. self.config={}
Error: {}N)r  r  r  r\  rx   rS  rq   )r  re  rd   rd   re   r  %
  s   zProxyConfig.get_config_statec                 C   s$   | d}g }|rdd |D }|S )z<
        Load the credential list from the database
        credential_listc                 S      g | ]	}t d i |qS rd   )r  r  credrd   rd   re   r  <
      z4ProxyConfig.load_credential_list.<locals>.<listcomp>r  )r  r  credential_list_dictr  rd   rd   re   load_credential_list5
  s
   
z ProxyConfig.load_credential_listc                 C   s@  | dd}|s| di }|r| dd}|sdS g }td |D ]w}| dd}| di  dd}td	| d
| d | di }|rl| D ]\}	}
t|
trg|
drg|
dd}t|}
|
||	< qK||d< ztdi |}|	| W q" t
y } ztd| dt|  W Y d}~q"d}~ww |r|S dS )a/  
        Parse and validate search tools from config.
        Loads environment variables and casts to SearchToolTypedDict.

        Args:
            config: Config dictionary containing search_tools

        Returns:
            List of validated SearchToolTypedDict or None if not configured
        search_toolsNru  z6[32mLiteLLM: Proxy initialized with Search Tools:[0msearch_tool_namerg  litellm_paramssearch_provider	[32m    z (z)[0mr  zError parsing search tool rZ   rd   )r  rp   r  r  r  r  r  r   r  r  r\  rx   r  )r  r  Zsearch_tools_rawru  Zsearch_tools_parsedZsearch_toolr  r  r  r  r  _vZsearch_tool_typedre  rd   rd   re   parse_search_tools?
  sJ   zProxyConfig.parse_search_toolsc                 C   s   | dd }|r@| D ]$\}}t|tr)|dr)t|d}|d ur(|tj|< qt|tj|< qd|v r@tdd t	_
t	 ad S )Nr  r  )Zsecret_nameZLITELLM_LICENSE)r  r  r  r  r  r   r  r  rS  r  license_strr  r9  )r  r  r  rc  r  Zresolved_secret_stringrd   rd   re   _load_environment_variablesx
  s   
	z'ProxyConfig._load_environment_variablesr   c           ?         s,  | j  dI dH }| j|d |di }|r|t_|dd}|du r'i }|rQd}d}| D ]\}}	|dkr|	d	u rt| d
 ddlm}
 i }d|v r[|d }|	| |dd}t
d| |dkso|dkrt| dkrtdd}tdd}d}|	|||d tdddurtdd}|	d|i t
d||| t
d||| t
d||| t
d||| | D ]\}}	t|	tr|	drt|	||< q| j|d tjdurt
| d|  q2|dkr|	du rq2|dkrt|	t |d }|t_q2|d!kr"dd"lm} ||	 t
| d#|  q2|d$kr<dd%lm} ||	 t
| d&|  q2|d'krVdd(lm} ||	 t
| d)|  q2|d*krjdd+lm} |di |	t_ q2|d,krxt!|	t |d- q2|d.krdd/l"m#} |di |	t_$q2|d0krt%|	 d1gt_&t
d2tj&  q2|d3krt'|	t_(q2|d4krt'|	t_)tj(du rtj)t_(q2|d5krdd6l*m+}  fd7d8|	D t_,|  q2|d9kr'g t_-|	D ]2}d:|v rtj./t%|d; qtj./| d<|v rdd=l0m1} |durt
d> |2  qt| d?tj- d@|  q2|dAkrYg t_3|	D ]}d:|v rCtj.4t%|d; q1tj.4| q1t| dBtj3 d@|  q2|dkr_q2|dCkr|	dDi }|dEda5|dFg a6|dGdHa7t
| dIt5 dJt6 dKt7 |  q2|dLkrt8|	D ]4\}}z
t9di | W q t:y   t|t;rt:dM| dN|  t:dM| dNt<| w t
| dO| dP|	 |  t=t||	 q2|dQkr|	durt|	t;r|	 D ]\}}t|tr|drt||	|< qt>di |	t_?q2t:dR|	 |dSkr;|	d	u r;d	t_@tA  t
| dT|  q2t
| dO| dP|	 |  t=t||	 q2|dUi }|du r^i }|r
|dVd} | durttBdi | t_C|dWd}!| jD|! dX |dYd}"tE|"dZ |d[d}#tF|#d\ | jG|d] |d^d}$|$r|$drt
d_ t|$}$t
d`|$ |datdbdaHtHrtHdrttHaHtHdurttHtrtItHaJnt
Kdc |ddd}%|%durtLjMt'|%dde |dfdaNtNdu rdaNtN|df< |dgd}&|&durt%|& d1aO|dhd}'|'dur-t%|' d1aP|did}(|(dur>t%|( d1aQ|djd})|)durOt%|) d1aRtSdur\tST|I dH  |dkddurs|dk aUtV|dk dlI dH  |dmdnaW|dod}*|*durtdu rtXdp|dqtYaY|drtZaZ|dst[a[|dtt\a\|dut]a]|dvda^|dwda_|dxt`aa|dydab|dzd	act
d{t^t_tatbtc |d|d}+|+durd}d8 |+D |d|< |d~durtd	urtXdtdjejf d|v r
|d tg_htgi adtjdui},|dd}-|-ro|-|,d< td |-D ]J}.|.d  D ]\}/}0t|0trD|0drDt|0|.d |/< q,td|.dd d |.d d }1|.d dd}2d|1v rm|2du rmtj  q$d}3|dd}4|4r|4d  D ]"\}/}0t|0tr|0dr|0kdd}tlm|}0|0|4d |/< qtndi |4}3| o|}5|dd}6tp|6d |dd}7tq|7d |dd}8trjs|8d |dd}9|9rt|9t;rddhfdd8tjtu D }:|9 D ]&\}/}0|/|:v r|0|,|/< q|/dv rtXd|/ dt
vd|/ d qtjtdi |,|3|5twd	dd	d}txdur?|jjydu r?|jztxd d};|durL|dd};|;rVt{|; |d | j||t}|dI dH  d}<|durn|dd}<|<r}ddl~m}= |=|< d | j|d}>|>t_| j|dI dH  || |fS )z<
        Load config values into proxy global state
        rl  Nr  callback_settingsrv  z[94mz[0mrU  Tz
Setting Cache on Proxyr   r  r  rU   Zrediszpassed cache type=%szredis-semanticZ
REDIS_HOSTZ
REDIS_PORT)rU   hostportZREDIS_PASSWORDpasswordz%sCache Type:%s %sz%sCache Host:%s %sz%sCache Port:%s %sz%sCache Password:%s %sr  )r  zSet Cache on LiteLLM ProxyF
guardrails)Zguardrails_configr9  rm  rv  Zglobal_prompt_directory)set_global_prompt_directoryz,Set Global Prompt Directory on LiteLLM ProxyZglobal_bitbucket_config)set_global_bitbucket_configz,Set Global BitBucket Config on LiteLLM ProxyZglobal_gitlab_config)set_global_gitlab_configz)Set Global Gitlab Config on LiteLLM Proxypriority_reservation_settings)PriorityReservationSettings	callbacks)r  r9  rm  rv  model_group_settings)ModelGroupSettingspost_call_rulesr  rm  zlitellm.post_call_rules: max_internal_user_budget default_max_internal_user_budgetcustom_provider_map)custom_llm_setupc                    s&   g | ]}|d  t |d  ddqS )providercustom_handlerr  )r  r  r   r  r  rl  rd   re   r  H  s    z+ProxyConfig.load_config.<locals>.<listcomp>rY  r  r  Z
prometheusPrometheusLoggerzmounting metrics endpointz! Initialized Success Callbacks - rl   failure_callbackz! Initialized Failure Callbacks - r  background_modeZpolling_via_cacher7  r~  r8  z( Initialized polling via cache: enabled=z, native_background_mode=z, ttl=r  z4team_id missing from default_team_settings at index=z
passed in value=z setting litellm.=upperbound_key_generate_paramsz=Invalid value set for upperbound_key_generate_params - value=	json_logsz  Enabled JSON logging via configru  key_management_settingskey_management_system)r  rm  use_google_kmsr   rO  rO  ru  rp  zGOING INTO LITELLM.GET_SECRET!zRETRIEVED DB URL: %srC  rj  zLITELLM_MASTER_KEY is not set! All requests will be treated as INTERNAL_USER with no admin access. Set LITELLM_MASTER_KEY for production use.user_api_key_cache_ttl)r4  r  r=  custom_authcustom_key_generate
custom_ssocustom_ui_sso_sign_in_handlerpass_through_endpointsr)  r<  r5  allowed_ipsz\allowed_ips is an Enterprise Feature. Please add a valid LITELLM_LICENSE to your envionment.r{  r|  proxy_batch_polling_intervalr}  disable_spend_logsZbackground_health_checksrK  rL  rM  r  zebackground_health_check_config enabled=%s shared=%s interval_seconds=%s max_concurrency=%s details=%sZrole_permissionsc                 S   r  r  )r?   )r  Zrole_permissionrd   rd   re   r  ^  s    Zenforced_paramszTrying to use `enforced_params`Zlitellm_licenser  r  z<[32mLiteLLM: Proxy initialized with Config, Set models:[0mr  r  
model_namerg  modelapi_baser  assistant_settingsZfinetune_settingsZfiles_settingsdefault_vertex_configr  r  c                    s   g | ]}| vr|qS rd   rd   )r  x)exclude_argsrd   re   r    s    >   rL  rM  'zQ' is NOT a valid router_settings parameter. Please move it to 'general_settings'.zKey 'zC' is not a valid argument for Router.__init__(). Ignoring this key.Zasync_only_mode)assistants_configr  router_general_settingsignore_invalid_deployments)rU  )Zall_guardrailsrm  rs  )r  rN  rs  prompts)init_prompts)Zall_promptsrm  rd   )r  r  r  rT  r   r  rp   litellm.caching.cachingr  updaterx   rS  r  r  r   r  r  r  r  rU  r   r9  guardrail_name_config_mapZlitellm.integrations.dotpromptr  rR  Zlitellm.integrations.bitbucketr  Zlitellm.integrations.gitlabr  litellm.types.utilsr	  r  r   litellm.types.routerr  r  r   r  rl  r  r  rZ  r  r  rY  rX  add_litellm_success_callbacklitellm.integrations.prometheusr  Z_mount_metrics_endpointr  add_litellm_failure_callbackr6  r7  r9  	enumeraterB   r\  r  rU   setattrr	  r  r  Z_turn_on_jsonr  _key_management_settingsinitialize_secret_managerr   rW  _load_alerting_settingsrC  r   litellm_master_key_hashcriticalrr  Zupdate_cache_ttlr=  rF  rG  rH  rI  r8  Zload_enterprise_configr2  r   r<  r  r{  r|  r,  r}  r-  rJ  rK  r   rL  rM  r  r)   Znot_premium_userr  r  r  r  r  r  r  rS  r   r  r   r   r   Zset_default_vertex_configrv   Zget_valid_argsrc  r  rt  r  Z_update_redis_cacher   _init_policy_enginerN  Z"litellm.proxy.prompts.init_promptsr;  r  r  _init_non_llm_configsget_model_list)?r  r   rm  r  r   rv  Zblue_color_codeZreset_color_coderc  r  r  r  Zcache_params_in_configZ
cache_typeZ
cache_hostZ
cache_portZcache_passwordr>  r  r  r  r	  r  r  callbackr  r  idxZteam_settingZ_kr  ru  r  r  r   rO  rp  r$  r%  r&  r'  r(  r+  Zrbac_role_permissionsZrouter_paramsr  r/  r  r  litellm_model_nameZlitellm_model_api_baser7  r1  r  Zfinetuning_configZfiles_configr2  r  Zavailable_argsZguardrails_v2r:  r;  r  rd   )rm  r4  re   r  
  s  






























































zProxyConfig.load_configc           
         s   | dd}|rt| | dd}|rt| | dd}|r>ddlm} | di }| dd}|||I dH  | d	d}|r[dd
lm	}	 t
jdu rU|	 t
_t
j| dS )zO
        Initialize non-LLM configs eg. MCP tools, vector stores, etc.
        Z	mcp_toolsNZ
agent_listZmcp_serversr   global_mcp_server_managerrv  mcp_aliasesvector_store_registryVectorStoreRegistry)r  r   Zload_tools_from_configr   Zload_agents_from_config9litellm.proxy._experimental.mcp_server.mcp_server_managerrR  Zload_servers_from_config+litellm.vector_stores.vector_store_registryrV  rT  rT  Zload_vector_stores_from_config)
r  r  Zmcp_tools_configagent_configZmcp_servers_configrR  rv  rS  Zvector_store_registry_configrV  rd   rd   re   rL    s0   



z!ProxyConfig._init_non_llm_configsrN  r   rs  rv   c                    s   ddl m} ddlm} |du rtd dS |dd}|s'td dS |dd}td	t| d
 |||||duddI dH  dS )a  
        Initialize the policy engine from config.

        Args:
            config: The proxy configuration dictionary
            prisma_client: Optional Prisma client for DB validation
            llm_router: Optional LLM router for model validation
        r   )init_policies)PolicyValidatorNz'Policy engine: config is None, skippingpoliciesz.Policy engine: no policies in config, skippingZpolicy_attachmentszPolicy engine: found z policies in configT)policies_configpolicy_attachments_configrN  Zvalidate_dbZfail_on_error)	Z)litellm.proxy.policy_engine.init_policiesrZ  Z,litellm.proxy.policy_engine.policy_validatorr[  rx   rS  r  rR  r  )r  r  rN  rs  rZ  r[  r]  r^  rd   rd   re   rK    s*   

zProxyConfig._init_policy_engineru  c              
   C   s   | dd}td|  |du rdS | dd}td|  tj|| dd| dd| dd| d	d| d
dtd |D ]$}|dkrKqD|tjv rht|ddd	| d	did}|durhtj	
| qDdS )z.
        Initialize alerting settings
        alertingNz_alerting_callbacks: z=_load_alerting_settings: Calling update_values with alerting=alerting_thresholdr?  alert_typesalert_to_webhook_urlalerting_argsalert_type_config)r_  r`  ra  rb  rc  rd  r  slack)Zlogging_integrationZinternal_usage_cachers  Zcustom_logger_init_args)r  rx   rS  rq  update_valuesrt  rT  )_known_custom_logger_compatible_callbacksr%   rX  rY  )r  ru  Z_alerting_callbacksZ_alerting_valueZ_alertZ_loggerrd   rd   re   rH  E  s@   






z#ProxyConfig._load_alerting_settingsr  c                 C   s  |dur|t jjkrtdd dS |t jjkrtdd dS |t jjkr4ddlm} |j	dt
jd dS |t jjkrAtdd dS |t jjkrRdd	lm} |  dS |t jjkrcdd
lm} |  dS |t jjkrtddlm} |  dS |t jjkrddlm} ||d dS tddS )z_
        Initialize the relevant secret manager if `key_management_system` is provided
        NTr"  r!  r   )AWSSecretsManagerV2)Zuse_aws_secret_managerr  )Zuse_aws_kms)GoogleSecretManager)HashicorpSecretManager)CyberArkSecretManager)load_custom_secret_managerrl  z&Invalid Key Management System selected)r  rT  r  rW  Z
GOOGLE_KMSr   ZAWS_SECRET_MANAGERZ-litellm.secret_managers.aws_secret_manager_v2rh  Zload_aws_secret_managerrT  rF  ZAWS_KMSr   ZGOOGLE_SECRET_MANAGERZ-litellm.secret_managers.google_secret_managerri  ZHASHICORP_VAULTZ0litellm.secret_managers.hashicorp_secret_managerrj  ZCYBERARKZ/litellm.secret_managers.cyberark_secret_managerrk  ZCUSTOMZ4litellm.secret_managers.custom_secret_manager_loaderrl  r  )r  r  rm  rh  ri  rj  rk  rl  rd   rd   re   rG  q  s:   



z%ProxyConfig.initialize_secret_managerFc                 C   s   t |dd}|dur||jd< d|jd< tdu r<t |dd|jd< t |dd|jd< t |dd|jd< t |d	d|jd	< |jdurmt|jtrmd|jvrR|j|jd< d|jv rc|jd d
u rc||jd< tdi |j}|S t|j|d}|S )z
        Common logic across add + delete router models
        Parameters:
        - deployment
        - db_model -> flag for differentiating model stored in db vs. config -> used on UI

        Return model info w/ id
        model_idNrb  Tdb_model
created_at
updated_at
created_by
updated_byF)rb  rn  rd   )r  r  r9  r  r  rm  RouterModelInfo)r  r/  rn  rv  _model_inford   rd   re   get_model_info_with_id  s$   	



z"ProxyConfig.get_model_info_with_id	db_modelsc              
      sp  g }t du st|dkrdS |D ]}| j|d}|jdur$||j qz| jtdI dH }W n tyK } zt	dt
| W Y d}~dS d}~ww |dd}|r|D ]B}|d  D ]\}	}
t|
t
rt|
drtt|
|d |	< q^|d	i d
d}|du rt j|d |d d}nt
|}|| qVt  }d}|D ]}||vrt j|d}|dur|d7 }q|S )a5  
        (Helper function of add deployment) -> combined to reduce prisma db calls

        - Create all up list of model id's (db + config)
        - Compare all up list to router model id's
        - Remove any that are missing

        Return:
        - int - returns number of deleted deployments
        Nr   r/  rl  zlFailed to load config in _delete_deployment: %s. Skipping deployment cleanup to avoid removing valid models.r  r  r  r  rb  r.  )model_groupr  rb  ri  )rs  r  ru  rb  r  r  rD  r\  rx   rc  r  r  r  r  r  r   Z_generate_model_idget_model_idsZdelete_deployment)r  rv  Zcombined_id_listr  r  r  re  r  r/  r  r  rm  Zrouter_model_idsZdeleted_deploymentsZ
is_deletedrd   rd   re   _delete_deployment  sV   
zProxyConfig._delete_deploymentc                 C   s   ddl }tdu r
dS d}|D ]O}|j}t|tr9| D ]\}}t|tr0t||dd}|||< qtd
i |}n	t	
d|  q| j|dd}	tjt|j||	dd}
|
dur]|d	7 }q|S )z
        Iterate through db models

        for any not in router - add them.

        Return - number of deployments added
        r   NTr  rc  r  HInvalid model added to proxy db. Invalid litellm params. litellm_params=)r/  rn  r.  r  r  )
deploymentri  rd   )base64rs  r  r  r  r  r  r   r   rx   r  ru  Zupsert_deploymentr   r.  )r  rv  r  Zadded_modelsr  _litellm_paramsr  r  _valuert  addedrd   rd   re   _add_deployment  sB   

zProxyConfig._add_deployment
new_modelsc           	      C   s   g }|D ]M}|j }t|tr| }t|tr3| D ]\}}t||dd}|||< qtdi |}n	t	d|  q| j
|d}|t|j||djdd q|S )NTr|  r}  rw  r~  exclude_nonerd   )r  r  r   
model_dumpr  r  r   r   rx   r  ru  r  r   r.  to_json)	r  r  _model_listr  r  r  r  decrypted_valuert  rd   rd   re   decrypt_model_list_from_db?  s6   


z&ProxyConfig.decrypt_model_list_from_dbrq  c              
      s  i }d }zt  I d H }| |}W n ty- } ztdt| W Y d }~nd }~ww zlt|tr6|ng }t	d u rut
d urutdt|  | j|d}t|dksX|rttd|  tj|tdd|dda	td	t	  n$tdt|  |d urt	d ur|t	_| j|d
I d H  | j|d
 W n ty } ztdt|  W Y d }~nd }~ww t	d urt	 a| | | j|t	tdI d H  | j|t|d d S )NziFailed to load config in _update_llm_router: %s. Proceeding with model loading using cached/empty config.zlen new_models: )r  r   z_model_list: Tr6  )r  r8  r  r9  zupdated llm_router: )rv  z+Error adding/deleting model to llm_router: )config_datars  rN  )r  ru  rq  )r  r  r  r\  rx   rc  r  r  r  rs  rC  rS  r  r  rT  rv   r  r  r{  r  rU  rM  r  _add_callbacks_from_db_config#_add_router_settings_from_db_configrN  $_add_general_settings_from_db_configru  )r  r  rq  r  r  re  Zmodels_listr  rd   rd   re   _update_llm_router^  sn   

zProxyConfig._update_llm_routerrN  event_types)successfailureexisting_callbacksc                 C   sr   |t jv r|D ]}t|| qdS ||vr7|dgkr"t j| dS |dgkr/t j| dS t j| dS dS )aQ  
        Helper method to add a single callback to litellm for specified event types.

        Args:
            callback: The callback name to add
            event_types: List of event types (e.g., ["success"], ["failure"], or ["success", "failure"])
            existing_callbacks: The existing callback list to check against
        r  r  N)rT  rg  r  rX  rA  rC  rY  )r  rN  r  r  Z
event_typerd   rd   re   4_add_callback_from_db_to_in_memory_litellm_callbacks  s   


z@ProxyConfig._add_callback_from_db_to_in_memory_litellm_callbacksr  c           	      C   s   | di pi }| dd}| dd}| dd}|dur2t|tr2|D ]}| j|dgtjd q%|durJt|trJ|D ]}| j|dgtjd q=|durct|tre|D ]}| j|ddgtjd qUdS dS dS )	z:
        Adds callbacks from DB config to litellm
        rv  rY  Nr  r
  r  )rN  r  r  r  )r  r  r  r  rT  rY  r  r
  )	r  r  rv  success_callbacksZfailure_callbacksr
  rY  r  rN  rd   rd   re   r    s6   z)ProxyConfig._add_callbacks_from_db_configr  new_encryption_keyc                 C   s.   i }|  D ]\}}t||d}|||< q|S )zR
        Encrypts a dictionary of environment variables and returns them.
        )r  r  )r  r   )r  r  r  Zencrypted_env_varsr  r  encrypted_valuerd   rd   re   r    s   
z"ProxyConfig._encrypt_env_variablesr  c                 C   s|   i }|  D ]5\}}zt|||d}|dur|tj|< |||< W q ty; } ztd|t| W Y d}~qd}~ww |S )a!  
        Decrypts a dictionary of environment variables and then sets them in the environment

        Args:
            environment_variables: dict - dictionary of environment variables to decrypt and set
            eg. `{"LANGFUSE_PUBLIC_KEY": "kFiKa1VZukMmD8RB6WXB9F......."}`
        r|  Nz#Error setting env variable: %s - %s)r  r   r  r  r\  rx   r  r  )r  r  r  r  r  r  r  re  rd   rd   re   r    s"   


z-ProxyConfig._decrypt_and_set_db_env_variablesvariables_dictc                 C   s0   i }|  D ]\}}t||dd}|||< q|S )zF
        Decrypts a dictionary of variables and returns them.
        Tr|  )r  r   )r  r  Zdecrypted_variablesr  r  r  rd   rd   re   _decrypt_db_variables	  s   
z!ProxyConfig._decrypt_db_variablesr  c                 C   s   | du rdS d}t | tr| }n0t | tr@ddl}zt| }W n tj|jfy?   z|| }W n
 |jy<   Y nw Y nw t |trI|rI|S dS )z
        Parse a router_settings value that may be a dict or a JSON/YAML string.

        Returns a non-empty dict if valid, otherwise None.
        Nr   )	r  r  r  r  r  r  Z	YAMLErrorJSONDecodeErrorr  )r  parsedr  rd   rd   re   _parse_router_settings_value  s(   

z(ProxyConfig._parse_router_settings_valueuser_api_key_dictrE   r   c                    s   |dur|  t|dd}|dur|S |durG|jdurGzt|j|t|dI dH }|  t|dd}|dur:|W S W dS  tyF   Y dS w dS )u  
        Get router_settings in priority order: Key > Team

        Uses the already-cached key object and the cached team lookup
        (get_team_object) to avoid direct DB queries on the hot path.

        Global router_settings are NOT looked up here — they are already
        applied to the Router object at config-load / DB-sync time.

        Returns:
            dict: router_settings, or None if no settings found
        Nr  )r^  rN  rr  rq  )r  r  r^  r   rr  r\  )r  r  rN  rq  Zkey_settingsZteam_objZteam_settingsrd   rd   re   !_get_hierarchical_router_settings1  s6   

z-ProxyConfig._get_hierarchical_router_settingsc                    s   |durc|dure|j jjddidI dH }|di }i }|dur>t|tr>|dur>t|jtr>ddlm} |||j}n|durJt|trJ|}n|durWt|jtrW|j}|rg|j	di | dS dS dS dS )z
        Adds router settings from DB config to litellm proxy

        1. Get router settings from DB
        2. Get router settings from config
        3. Combine both
        4. Update router settings
        N
param_namer  wherer   )_update_dictionaryrd   )
r~  litellm_config
find_firstr  r  r  param_valuerZ  r  Zupdate_settings)r  r  rs  rN  Zdb_router_settingsZconfig_router_settingsZcombined_router_settingsr  rd   rd   re   r  c  s:   


z/ProxyConfig._add_router_settings_from_db_configc                    s  | di }|durd|v r durs  dddurst d trs| dddurst|d trst d }t|d }t||}t d  fdd|d D  }td d  d|d  d|  | d< |j d d	 n( du ri  |d  d< |j d d	 nt tr|d  d< |j d d	 |durd
|v r|d
  d
<  d
 |_	|j
j d
 td |durd|v r|d  d< |j
j d td dS dS dS )z
        Adds general settings from DB config to litellm proxy

        Args:
            config_data: dict
            general_settings: dict - global general_settings currently in use
            proxy_logging_obj: ProxyLogging
        ru  Nr_  c                    s   g | ]
}| d  vr|qS r_  rd   r  r#  rd   re   r    s
    zDProxyConfig._add_general_settings_from_db_config.<locals>.<listcomp>zMerging alerting values: YAML=z, DB=z	, Merged=r  ra  )ra  rs  rb  )rb  rs  )r  r  r  setunionrx   rS  rf  r  ra  slack_alerting_instancers  )r  r  ru  rq  _general_settingsZ_yaml_alertingZ_db_alertingZ_merged_alertingrd   r#  re   r    sd   


z0ProxyConfig._add_general_settings_from_db_configc           
   	      sZ  t du rdS zt d td W n	 ty   Y nw td}|durddlm} | }td}|rlddl	m
} z||}t j|j|tgdd	td
 td|  W dS  tyk   td|  Y dS w ddlm} tdd}z#||}	t j|jd|	tdd tgdd	td td|  W dS  ty   td Y dS w dS )z
        Reschedule the spend log cleanup job based on current general_settings.
        This is called when maximum_spend_logs_retention_period is updated dynamically.
        If the retention period is None, the job will be removed.
        Nspend_log_cleanup_jobz&Removed existing spend log cleanup job#maximum_spend_logs_retention_periodr   r   maximum_spend_logs_cleanup_cronCronTriggerTr'  rb  replace_existingmisfire_grace_timez)Spend log cleanup rescheduled with cron: /Invalid maximum_spend_logs_cleanup_cron value: )r   %maximum_spend_logs_retention_interval1dintervalrj   secondsr'  rb  r  r  z-Spend log cleanup rescheduled with interval: 3Invalid maximum_spend_logs_retention_interval value)	schedulerZ
remove_jobrx   rR  r\  ru  r  7litellm.proxy.db.db_transaction_queue.spend_log_cleanupr   apscheduler.triggers.cronr  from_crontabadd_jobcleanup_old_spend_logsrN  r   r  r  Z*litellm.litellm_core_utils.duration_parserr   rm   randint)
r  Zretention_periodr   spend_log_cleanupcleanup_cronr  cron_triggerr   retention_intervalinterval_secondsrd   rd   re   !_reschedule_spend_log_cleanup_job  st   





	

z-ProxyConfig._reschedule_spend_log_cleanup_jobdb_general_settingsc                    s  |du rdS t |}d|v r|d td< d|v r|d td< d|v r2|d td< tjjtd d d|v rF|d td< ttd dI dH  d|v rP|d td< d	|v r|d	 }|du radtd	< nt|trk|td	< nt|try|	 d
ktd	< nt|td	< d|v r|d }|du rnt|tr|a
nt|tr|	 d
ka
nt|a
t
td< d|v rtd}|d }|td< ||kr|  I dH  dS dS dS )z;
        Pull from DB, read general settings value
        Nmax_parallel_requestsglobal_max_parallel_requestsrc  )rc  r)  r*  r<  store_prompts_in_spend_logsr  r=  r  )r  ru  rq  r  rf  r   r  boolr  r  r=  r  r  )r  r  r  r  	old_value	new_valuerd   rd   re   _update_general_settings#  sl   







z$ProxyConfig._update_general_settingscurrent_configr  ru  r  rv  r  db_param_valuec           
      C   s   dt dt ddfdd}|dkr=| j|dd	}i }| D ]\}}|||< | }	|||	< |tj|	< q|di | |S |d
krYt|t rY| D ]\}}|t	v rXt
t|| qJ||vrc|||< |S t|| t rxt|t rx||| | |S |||< |S )am  
        Updates the config fields with the new values from the DB

        Args:
            current_config (dict): Current configuration dictionary to update
            param_name (Literal): Name of the parameter to update
            db_param_value (Any): New value from the database

        Returns:
            dict: Updated configuration dictionary
        dstsrcr  Nc                 S   s   | |fg}|rF|  \}}| D ]0\}}|du rqt|tr&t|dkr&qt|tr=t||tr=||| |f q|||< q|sdS dS )z
            Deep-merge src into dst, skipping None values and empty lists from src.
            On conflicts, src (DB) wins, but empty lists are treated as "no value" and don't overwrite.
            Nr   )r  r  r  r  r  r  r  r  )r  r  stackdsr  r  rd   rd   re   _deep_merge_dicts  s   

z<ProxyConfig._update_config_fields.<locals>._deep_merge_dictsr  T)r  rv  )r  r  r  upperr  r  
setdefaultr=  r  r"   rE  rT  )
r  r  r  r  r  r  Zmerged_env_varsrc  r  Z	upper_keyrd   rd   re   _update_config_fieldsq  s<   z!ProxyConfig._update_config_fieldsr=  c                    s   |durt d |S g }g d}|D ]}|jd|dd}|| qtj| I d H }|D ].}|d u r5q.t|dd }	t|dd }
t d|	 d	|
  |	d ur\|
d ur\| j||	|
d
}q.|S )NTz4'store_model_in_db' is not True, skipping db updatesr  r  r  )rc  r  r  r  zparam_name=z, param_value=)r  r  r  )	rx   rR  Zget_generic_datar  r  gatherr  rS  r  )r  rN  r  r=  _tasksr  r  responser  r  r  rd   rd   re   r    s<   z"ProxyConfig._update_config_from_dbobject_typec                    sZ   t dd}|du rdS t|tstdt| d dS t| t fdd|D S )aD  
        Check if an object type should be loaded from the database based on general_settings.supported_db_objects.

        Args:
            object_type: Type of object to check (e.g., SupportedDBObjectType.MODELS, "models", etc.)

        Returns:
            True if the object should be loaded, False otherwise
        supported_db_objectsNTz(supported_db_objects is not a list, got z. Loading all objects.c                 3   s    | ]	}t | kV  qd S rB  )r  )r  objZobject_type_strrd   re   	<genexpr>  s    z5ProxyConfig._should_load_db_object.<locals>.<genexpr>)	ru  r  r  r  rx   rc  rU   r  r  )r  r  r  rd   r  re   _should_load_db_object  s   
z"ProxyConfig._should_load_db_objectc              
      sZ   z|j j I d H }W |S  ty, } ztdt| g }W Y d }~|S d }~ww )NzQlitellm.proxy_server.py::add_deployment() - Error getting new models from DB - {})r~  litellm_proxymodeltable	find_manyr\  rx   rU  rq   r  )r  rN  r  re  rd   rd   re   _get_models_from_db  s   	zProxyConfig._get_models_from_dbc              
      s   z@| j ddr| j|dI dH }| j||dI dH  |jjjddidI dH }|dur6| j|jd	I dH  | j|dI dH  W dS  t	y^ } zt
d
t| W Y d}~dS d}~ww )z{
        - Check db for new models
        - Check if model id's in router already
        - If not, add to router
        modelsr  rN  N)r  rq  r  ru  r  )r  z>litellm.proxy.proxy_server.py::ProxyConfig:add_deployment - {})r  r  r  r~  r  r  r  r  _init_non_llm_objects_in_dbr\  rx   rU  rq   r  )r  rN  rq  r  r  re  rd   rd   re   add_deployment!  s.   zProxyConfig.add_deploymentc                    s  | j ddr| j|dI dH  | j ddr| j|dI dH  | j ddr.| j|dI dH  | j ddr=| j|dI dH  | j ddrJ|  I dH  | j d	drY| j|dI dH  | j d
drf|  I dH  | j ddru| j|dI dH  | j ddr| j	|dI dH  | j ddr| j
|dI dH  | j ddr| j|dI dH  | j ddr| j|dI dH  | j ddr| j|dI dH  | j ddrddlm} |j|| dI dH  | j ddr| j|dI dH  | j ddr| j|dI dH  dS dS )z
        Use this to read non-llm objects from the db and initialize them

        ex. Vector Stores, Guardrails, MCP tools, etc.
        r  r  r  Nr\  vector_storesvector_store_indexesZmcpZagentsr)  r:  r  toolsmodel_cost_mapZanthropic_beta_headerssso_settingsZcache_settingsr   )CacheSettingsManager)rN  r  Zsemantic_filter_settingsZconfig_overrides)r  _init_guardrails_in_db_init_policies_in_db_init_vector_stores_in_db _init_vector_store_indexes_in_db_init_mcp_servers_in_db_init_agents_in_db"_init_pass_through_endpoints_in_db_init_prompts_in_db_init_search_tools_in_db_init_tool_policy_in_db _check_and_reload_model_cost_map(_check_and_reload_anthropic_beta_headers_init_sso_settings_in_db;litellm.proxy.management_endpoints.cache_settings_endpointsr  Zinit_cache_settings_in_db$_init_semantic_filter_settings_in_db%_init_hashicorp_vault_config_override)r  rN  r  rd   rd   re   r  K  sR   z'ProxyConfig._init_non_llm_objects_in_dbc              
      s  ddl }ddl}ddlm} z|jjjddidI dH }|du s&|jdu r)W dS |j}t|t	r6|
|}|dd}|du rCW dS t| drx| j|krx|j|}|rs|D ]}	t|	|rr|	jdurr|	jjdurrtd	  W dS qWtd
 |j|j| |ddr|j|tdI dH }
|
r|j|
 td ntd | | _W dS  ty } ztd|  W Y d}~dS d}~ww )z
        Initialize MCP semantic filter settings from database.
        Called periodically (approximately every 10 seconds) by background task to hot-reload settings across all pods.
        r   NSemanticToolFilterHookr  rv  r  mcp_semantic_tool_filterr  z=Semantic filter settings unchanged, skipping reinitializationzYSemantic filter settings unchanged, but hook is missing or uninitialized. Reinitializing.r  Fr  rs  z)MCP Semantic Filter reinitialized from DBzMCP Semantic Filter disabledz5Error initializing semantic filter settings from DB: )r  rT  'litellm.proxy.hooks.mcp_semantic_filterr  r~  r  find_uniquer  r  r  r  r  r  r  rX  Zget_custom_loggers_for_typefilterZtool_routerrx   rS  rR  Zremove_callbacks_by_typer
  initialize_from_configrs  rY  r  r\  rU  )r  rN  r  rT  r  config_recordrv  mcp_semantic_filter_configZactive_hooksZactive_hookhookre  rd   rd   re   r    sv   






z0ProxyConfig._init_semantic_filter_settings_in_dbc              
      s   z<|j jjddidI dH }|dur;|jdd |jdd |jdd dd	 |j D }| j|d
 W dS W dS  tyZ } zt	d
t| W Y d}~dS d}~ww )zS
        Initialize SSO settings from database into the router on startup.
        rb  Z
sso_configr  NZrole_mappingsZteam_mappingsr<  c                 S   s   i | ]	\}}|  |qS rd   )r  r  rc  r  rd   rd   re   
<dictcomp>  s    z8ProxyConfig._init_sso_settings_in_db.<locals>.<dictcomp>r  zHlitellm.proxy.proxy_server.py::ProxyConfig:_init_sso_settings_in_db - {})r~  Zlitellm_ssoconfigr	  r  r  r  r  r\  rx   rU  rq   r  )r  rN  r  Zuppercase_sso_settingsre  rd   rd   re   r     s0   z$ProxyConfig._init_sso_settings_in_dbc              
      s  ddl m}m}m}m}m} z^|jjjddidI dH }|du s&|j	du r2| j
dur/||  W dS ||j	}| j
|kr?W dS | |}	||}
||	 z| jdd W n ty`   ||
  w | | _
td W dS  ty } ztd	t| W Y d}~dS d}~ww )
z
        Load Hashicorp Vault config override from DB.
        Decrypts sensitive fields, sets HCP_VAULT_* env vars, and reinitializes the secret manager.
        Called periodically via _init_non_llm_objects_in_db to sync config across pods.
        r   )HASHICORP_ENV_VAR_MAPPING_clear_hashicorp_vault_state_get_current_env_values_parse_config_value_set_env_varsconfig_typeZhashicorp_vaultr  N)r  z.Hashicorp Vault config override loaded from DBz9Error loading Hashicorp Vault config override from DB: %s)<litellm.proxy.management_endpoints.config_override_endpointsr  r  r  r  r  r~  Zlitellm_configoverridesr	  Zconfig_valuer  r  rG  r\  r  rx   rS  rU  r  )r  rN  r  r  r  r  r  	db_recordr  Zdecrypted_dataZprevious_envre  rd   rd   re   r    sF   






z1ProxyConfig._init_hashicorp_vault_config_overridec              
      s
  z|j jjddidI dH }|du s|jdu rW dS |j}|d}|dd}|du r4|du r4W dS t }d}|rDd}td	 nO|durt	durz#t
t	}|| }	|	 d
 }
|
|krnd}td|
dd|  W n# ty } ztd|  d}W Y d}~nd}~ww d}td |rddlm} tj}||d}|t_t  tj|d | a	|j jjddidt|ddddt|ddiddI dH  td|rt|nd  W dS W dS  ty } ztdt|  W Y d}~dS d}~ww )z
        Check if model cost map needs to be reloaded based on database configuration.
        This function runs every 10 seconds as part of _init_non_llm_objects_in_db.
        r  model_cost_map_reload_configr  Ninterval_hoursforce_reloadFTz4Model cost map reload triggered by force reload flagr8  zFModel cost map reload triggered by interval. Hours since last reload: r  , Interval:  Error parsing last reload time: zBModel cost map reload triggered - no previous reload time recordedr   get_model_cost_mapr0  r  r  r  r  r  r  creater=  r  r  z4Model cost map reloaded successfully. Models count: z+Error in _check_and_reload_model_cost_map: )r~  r  r	  r  r  r   utcnowrx   rR  last_model_cost_map_reloadfromisoformattotal_secondsr\  rc  -litellm.litellm_core_utils.get_model_cost_mapr  rT  model_cost_map_url
model_costrN   add_known_models	isoformatupsertr&   r  rU  r  )r  rN  r  r  r  r  current_timeshould_reloadlast_reload_timetime_since_last_reloadhours_since_last_reloadre  r  r+  new_model_cost_maprd   rd   re   r  2  s   


	
'z,ProxyConfig._check_and_reload_model_cost_mapc              
      s  z|j jjddidI dH }|du s|jdu rW dS |j}|d}|dd}|du r4|du r4W dS t }d}|rDd}td	 nO|durt	durz#t
t	}|| }	|	 d
 }
|
|krnd}td|
dd|  W n# ty } ztd|  d}W Y d}~nd}~ww d}td |rddlm} | }| a	|j jjddidt|ddddt|ddiddI dH  tdd | D }td|  W dS W dS  ty } ztdt|  W Y d}~dS d}~ww )z
        Check if anthropic beta headers config needs to be reloaded based on database configuration.
        This function runs every 10 seconds as part of _init_non_llm_objects_in_db.
        r  $anthropic_beta_headers_reload_configr  Nr  r  FTz<Anthropic beta headers reload triggered by force reload flagr8  zNAnthropic beta headers reload triggered by interval. Hours since last reload: r  r  r  zJAnthropic beta headers reload triggered - no previous reload time recordedr   reload_beta_headers_configr!  r"  r  r#  r%  c                 s   s$    | ]}|d kr|dkrdV  qdS )provider_aliasesr  ri  Nrd   r  r  rd   rd   re   r    s    zGProxyConfig._check_and_reload_anthropic_beta_headers.<locals>.<genexpr>z@Anthropic beta headers config reloaded successfully. Providers: z3Error in _check_and_reload_anthropic_beta_headers: )r~  r  r	  r  r  r   r&  rx   rR  "last_anthropic_beta_headers_reloadr(  r)  r\  rc  &litellm.anthropic_beta_headers_managerr8  r.  r/  r&   sumr  rU  r  )r  rN  r  r  r  r  r0  r1  r2  r3  r4  re  r8  r  provider_countrd   rd   re   r    s   

	
&z4ProxyConfig._check_and_reload_anthropic_beta_headersc                 C   s   ddl m} ||dS )a5  
        Convert a DB prompt object to a PromptSpec object.

        Handles the versioning of the prompt, if the DB prompt has a version, it will be used to create the versioned prompt_id.

        Args:
            db_prompt: The DB prompt object

        Returns:
            The PromptSpec object
        r   )create_versioned_prompt_spec	db_prompt)&litellm.proxy.prompts.prompt_endpointsr?  )r  rA  r?  rd   rd   re   _get_prompt_spec_for_db_prompt  s   
z*ProxyConfig._get_prompt_spec_for_db_promptc              
      s   ddl m} ddlm} z|jj I d H }|D ]}| j|d}|j|d qW d S  t	yG } zt
dt| W Y d }~d S d }~ww )Nr   )IN_MEMORY_PROMPT_REGISTRY)
PromptSpecr@  )promptzClitellm.proxy.proxy_server.py::ProxyConfig:_init_prompts_in_db - {})Z%litellm.proxy.prompts.prompt_registryrD  Z"litellm.types.prompts.init_promptsrE  r~  Zlitellm_prompttabler  rC  Zinitialize_promptr\  rx   rS  rq   r  )r  rN  rD  rE  Zprompts_in_dbrF  Zprompt_specre  rd   rd   re   r    s"   zProxyConfig._init_prompts_in_dbc              
      s   ddl m}m}m} z"|j|dI d H }tdt| |D ]}|jt	||d qW d S  t
yJ } ztdt| W Y d }~d S d }~ww )Nr   )IN_MEMORY_GUARDRAIL_HANDLER	GuardrailGuardrailRegistryr  zguardrails from the DB %s)	guardrailzFlitellm.proxy.proxy_server.py::ProxyConfig:_init_guardrails_in_db - {})Z+litellm.proxy.guardrails.guardrail_registryrG  rH  rI  Zget_all_guardrails_from_dbrx   rS  r  Zsync_guardrail_from_dbr   r\  rU  rq   )r  rN  rG  rH  rI  Zguardrails_in_dbrJ  re  rd   rd   re   r  (  s.   
z"ProxyConfig._init_guardrails_in_dbc              
      s   ddl m} ddlm} z | }| }|j|dI dH  |j|dI dH  td W dS  tyJ } zt	d
t| W Y d}~dS d}~ww )zi
        Initialize policies and policy attachments from database into the in-memory registries.
        r   )get_attachment_registry)get_policy_registryr  Nz4Successfully synced policies and attachments from DBzDlitellm.proxy.proxy_server.py::ProxyConfig:_init_policies_in_db - {})Z/litellm.proxy.policy_engine.attachment_registryrK  Z+litellm.proxy.policy_engine.policy_registryrL  Zsync_policies_from_dbZsync_attachments_from_dbrx   rS  r\  rU  rq   r  )r  rN  rK  rL  Zpolicy_registryZattachment_registryre  rd   rd   re   r  C  s*   
z ProxyConfig._init_policies_in_dbc              
      sr   ddl m} z| }|j|dI dH  td W dS  ty8 } ztdt| W Y d}~dS d}~ww )z
        Initialize tool policy from database into the in-memory registry.
        Synced periodically by add_deployment -> _init_non_llm_objects_in_db.
        r   )get_tool_policy_registryr  Nz'Successfully synced tool policy from DBzGlitellm.proxy.proxy_server.py::ProxyConfig:_init_tool_policy_in_db - {})	Z%litellm.proxy.db.tool_registry_writerrM  Zsync_tool_policy_from_dbrx   rS  r\  rU  rq   r  )r  rN  rM  registryre  rd   rd   re   r  c  s   z#ProxyConfig._init_tool_policy_in_dbc              
         ddl m} z/|j|dI d H }t|dkrW d S tjd u r(||dt_W d S |D ]	}tjj|d q*W d S  tyS } zt	d
t| W Y d }~d S d }~ww )Nr   rU  r  )r  )vector_storeIlitellm.proxy.proxy_server.py::ProxyConfig:_init_vector_stores_in_db - {})rX  rV  Z_get_vector_stores_from_dbr  rT  rT  Zadd_vector_store_to_registryr\  rx   rU  rq   r  )r  rN  rV  r  rP  re  rd   rd   re   r  u  s2   
z%ProxyConfig._init_vector_stores_in_dbc              
      rO  )Nr   )VectorStoreIndexRegistryr  )r  )vector_store_indexrQ  )rX  rR  Z!_get_vector_store_indexes_from_dbr  rT  Zvector_store_index_registryZupsert_vector_store_indexr\  rx   rU  rq   r  )r  rN  rR  r  rS  re  rd   rd   re   r    s4   

z,ProxyConfig._init_vector_store_indexes_in_dbc              
      s~   ddl m} | std d S ddlm} z
| I d H  W d S  ty> } ztd	t
| W Y d }~d S d }~ww )Nr   )is_mcp_availablez<MCP module not available, skipping MCP server initializationrQ  zGlitellm.proxy.proxy_server.py::ProxyConfig:_init_mcp_servers_in_db - {})Z,litellm.proxy._experimental.mcp_server.utilsrT  rx   rS  rW  rR  Zreload_servers_from_databaser\  rU  rq   r  )r  rT  rR  re  rd   rd   re   r    s$   z#ProxyConfig._init_mcp_servers_in_dbc              
      sp   ddl m} z|j|dI d H }|j|td W d S  ty7 } ztdt	| W Y d }~d S d }~ww )Nr   r   r  )	db_agentsrY  zBlitellm.proxy.proxy_server.py::ProxyConfig:_init_agents_in_db - {})
,litellm.proxy.agent_endpoints.agent_registryr   Zget_all_agents_from_dbZload_agents_from_db_and_configr3  r\  rx   rU  rq   r  )r  rN  ZAGENT_REGISTRYrU  re  rd   rd   re   r    s"   zProxyConfig._init_agents_in_dbc              
      s   ddl m} ddlm} zF|j|dI dH }tdt| d t|dkrLtdurD|j	t|dI dH  td	t| d
 W dS t
d W dS t
d W dS  typ } ztdt| W Y d}~dS d}~ww )z
        Initialize search tools from database into the router on startup.
        Only updates router if there are tools in the database, otherwise preserves config-loaded tools.
        r   )SearchToolRegistry)SearchAPIRouterr  NzLoading z) search tool(s) from database into router)Zrouter_instancer  zSuccessfully loaded z search tool(s) into routerzMRouter not initialized yet, search tools will be added when router is createdzNNo search tools found in database, keeping config-loaded search tools (if any)zHlitellm.proxy.proxy_server.py::ProxyConfig:_init_search_tools_in_db - {})Z3litellm.proxy.search_endpoints.search_tool_registryrW  Z&litellm.router_utils.search_api_routerrX  Zget_all_search_tools_from_dbrx   rR  r  rs  Zupdate_router_search_toolsrS  r\  rU  rq   r  )r  rN  rW  rX  r  re  rd   rd   re   r    s@   


z$ProxyConfig._init_search_tools_in_dbc                    s   ddl m} | I d H  d S )Nr   )'initialize_pass_through_endpoints_in_db);litellm.proxy.pass_through_endpoints.pass_through_endpointsrY  )r  rY  rd   rd   re   r    s   z.ProxyConfig._init_pass_through_endpoints_in_dbrR  c                 C   sl   t |trtdi |}nt |trtdi | }i }|j D ]\}}t||dp-|||< q"||_|S )Nr  rc  rd   )r  r  r  r   r  Zcredential_valuesr  r   )r  rR  Zcredential_objectZdecrypted_credential_valuesr  r  rd   rd   re   decrypt_credentials  s   

zProxyConfig.decrypt_credentialsdb_credentialsc                    s   | j tdI dH }| j|d}|| }g }ttjD ]\}}|jdd |D vr.|| qt|ddD ]}tj	| q5dS )z
        Create all-up list of db credentials + local credentials
        Compare to the litellm.credential_list
        Delete any from litellm.credential_list that are not in the all-up list
        rl  Nr  c                 S   s   g | ]}|j qS rd   )credential_namer  rd   rd   re   r  +  s    z2ProxyConfig.delete_credentials.<locals>.<listcomp>T)reverse)
r  rD  r  rD  rT  r  r^  r  sortedr  )r  r]  r  r  Zcombined_listZidx_to_deleterO  rR  rd   rd   re   delete_credentials  s   

zProxyConfig.delete_credentialsc              
      s   z"|j j I d H } fdd|D } |I d H  t| W d S  tyA } ztd	t
| g W  Y d }~S d }~ww )Nc                    s   g | ]}  |qS rd   )r\  r  r  rd   re   r  5  s    z/ProxyConfig.get_credentials.<locals>.<listcomp>zSlitellm.proxy_server.py::get_credentials() - Error getting credentials from DB - {})r~  Zlitellm_credentialstabler  ra  r   Zupsert_credentialsr\  rx   rU  rq   r  )r  rN  credentialsre  rd   r  re   get_credentials2  s&   

zProxyConfig.get_credentials)r  NrB  F)Zr\   r  r  __doc__r  r  r  r  r  r  r   r  r  r  r   r  r  r	   r   r  r  r  r  r  r  r  r  r  r  r  r  rT  rv   r  rL  rK  rH  rG  rs  ru  r  r{  r  r  r   r   r  r
   r  r  r  r  r  staticmethodr   r  r   r  r  r  r  r  r  r  r   rA   r  r  r  r  r  r   r  r  r  rC  r  r  r  r  r  r  r  r  r  r  r   r\  ra  rc  rd   rd   rd   re   r    sh   

('+
%
;
9#
    Z*
*/
; B1
J

"


2
-
HKN	

T
-

"
*?R
;j
k 0r  c                  K   s   dd l }|| tjd< d S )Nr   rk  )r  dumpsr  r  )r  r  rd   rd   re   save_worker_configH  s   rh  r?  c                    s  ddl m} |  tdd dkrt  | a|a|du rBdd l}ddl	m
}m}m} |j|jd |j|jd |j|jd |du rjdd l}ddl	m
}m}m} |j|jd |j|jd |j|jd n]|d	u r|d	u rtjd
d}|d ur| dkrdd l}ddl	m}m} |j|jd |j|jd n)| dkrdd l}ddl	m
}m}m} |j|jd |j|jd |j|jd di ti i}|rtjt|dI d H \aaa|r|a||t d< |r|a||t d< |r|tjd< |r||t d< |r
|a||t d< |r|a||t d< |r||t d< |du r,dt_d|d d< |du r:dt_d|d d< |	rF|	t_|	|d d< t rJ	 |
a!d S )Nr   )show_bannerZLITELLM_DONT_SHOW_FEEDBACK_BOXrg  r  T)verbose_loggerrx   ry   )levelFZLITELLM_LOGINFOrw   DEBUGZgeneralrn  r  r0  ZAZURE_API_VERSION
max_tokenstemperaturerequest_timeoutaliasdrop_paramsadd_function_to_promptr  )"Z!litellm.proxy.common_utils.bannerri  r  rS  r  rr   
user_model
user_debuglogginglitellm._loggingrj  rx   ry   setLevelrl  rm  r  r  r  r  r  rs  r  ru  user_headersuser_api_baseuser_temperatureuser_request_timeoutrT  rr  rs  r  experimentaluser_telemetry)r/  rq  r0  api_versionrS  Zdetailed_debugro  rn  rp  r  Z	telemetryrr  rs  r  save	use_queuer  ri  rv  rj  rx   ry   Zlitellm_log_settingZdynamic_configrd   rd   re   r  N  s   

r  c              	   c   sh    t d | D ])}t d| zdt|  dV  W q ty1   dt| dV  Y qw d S )Ninside generatorzreturned chunk: %sdata: rA  )rx   rS  r  rg  r  r\  )r  chunkrd   rd   re   data_generator  s   
r  r  request_datac           
      C  s  t d zkt  | 4 I d H J}tj|||dI d H }|2 z03 d H W }|jdd}z	d| dV  W q tyO } zdt| dV  W Y d }~qd }~ww 6 W d   I d H  n1 I d H saw   Y  d}d| dV  W d S  ty } zXt d	t| tj
|||d	I d H  t d
| d t|tr|t|}tt|d|t|ddt|ddt|ddd}td| i}	d|	 dV  W Y d }~d S d }~ww )Nr  )r  r  r  Tr  r  rA  [DONE]zTlitellm.proxy.proxy_server.async_assistants_data_generator(): Exception occured - {}r  Zoriginal_exceptionr  [1;31mAn error occurred: P

 Debug this by setting `--debug`, e.g. `litellm --model gpt-3.5-turbo --debug`r^   rU   Noner  r    r^   rU   r  r  r  )rx   rS  rB  rq  async_post_call_streaming_hookmodel_dump_jsonr\  r  rU  rq   post_call_failure_hookr  r  r>   r  r  rg  r  )
r  r  r  r  cre  done_message	error_msgproxy_exceptionerror_returnedrd   rd   re   async_assistants_data_generator  sb   
(





r  c                 C   s4   |  d}t|tr|S |  d}t|tr|S dS )a  
    Prefer the original client-requested model (pre-alias mapping) when available.

    Pre-call processing can rewrite `request_data["model"]` for aliasing/routing purposes.
    The OpenAI-compatible public `model` field should reflect what the client sent.
    Z_litellm_client_requested_modelr/  rg  )r  r  r  )r  Zrequested_modelrd   rd   re   )_get_client_requested_model_for_streaming  s
   


r  r  requested_model_from_clientmodel_mismatch_loggedc                 C   s   |r	t | ttfs| |fS t | tr| dnt| dd }|s0||kr0td|d|| d}t | tr=|| d< | |fS zt| d| W | |fS  tyo } ztj	d|d|t
| t|dd W Y d }~| |fS d }~ww )Nr/  zolitellm_call_id=%s: streaming chunk model mismatch - requested=%r downstream=%r. Overriding model to requested.litellm_call_idTzPlitellm_call_id=%s: failed to override chunk.model=%r on chunk_type=%s. error=%srw  )r  r   r  r  r  rx   rS  rE  r\  r  rU   r  )r  r  r  r  Zdownstream_modelre  rd   rd   re   _restamp_streaming_chunk_model  s<   
	r  c                 C  sb  t d zZzd }t|d}d}d}tj|| |d2 zp3 d H W }tj||||r+|nd dI d H }t|ttfrCt	j
|d}||7 }t||||d\}}t|trZ|jd	d	d
}nt|trh|drh|} n&z	d| dV  W q ty }	 zdt|	 dV  W Y d }	~	qd }	~	ww 6 |d ur|V  d}
d|
 dV  W nn ty }	 zat dt|	 tj||	|dI d H  t d|	 d t|	tr|	t|	trt|	}nt|	}tt|	d|t|	ddt|	ddt|	ddd}td| i}d| dV  W Y d }	~	nd }	~	ww W tjd	dB t| dr?z	|  I d H  W n! ty> }	 zt d|	 W Y d }	~	nd }	~	ww W d    d S W d    d S W d    d S 1 s[w   Y  d S tjd	d? t| drz	|  I d H  W n  ty }	 zt d|	 W Y d }	~	nd }	~	ww W d    w W d    w W d    w 1 sw   Y  w )Nr  )r  Frg  r  r  r  )r  r  r  Z
str_so_far)Zresponse_obj)r  r  r  r  T)r  exclude_unsetr  rA  r  zIlitellm.proxy.proxy_server.async_data_generator(): Exception occured - {}r  r  r  r^   rU   r  r  r  r  r  r  )shieldaclosez7async_data_generator: error closing response stream: %s) rx   rS  r  rq  Z'async_post_call_streaming_iterator_hookr  r  rJ   rK   rT  Zget_response_stringr  r   r  r  r  r\  rU  rq   r  r  r  r>   r  r  rg  r  anyioZCancelScoper  r  BaseException)r  r  r  error_messager  r  Z_str_so_farr  Zresponse_strre  r  r  r  r  rd   rd   re   async_data_generatorN  s   



$







&2 r  c                 C   s   t | ||dS )Nr  r  r  )r  r  rd   rd   re   select_data_generator  s
   r  r/  c                 C   sf   |  di }|  di  dd }zd|v s| dr | dd }t|}|W S  ty2   i  Y S w )Nr  r  r/  ZazureZ
base_model)r  rT  get_model_infor\  )r/  r  Zmodel_to_lookuplitellm_model_inford   rd   re   get_litellm_model_info  s   
r  c                 C   s   t d| d  d S )Nz$Backing off... this was attempt # %stries)rx   rS  )r  rd   rd   re   
on_backoff  s   r  c                 C   sf   t | tot| dd d uot | jtod| jv  }tddu r"dS |r1tt	
dt| d |S )Nr^   z"Max parallel request limit reachedZ1disable_retry_on_max_parallel_request_limit_errorTgiveup)eventrU  )r  r>   r  r^   r  ru  r  rx   rS  r  rg  )re  resultrd   rd   re   r    s   

r  c                   @   sd  e Zd Zedee dedee fddZe	de
dee fddZedee d	eeef fd
dZede
dee defddZedefddZededededdfddZedd Zedd Zede
dededededefdd Zed!efd"d#Zed!ede
dedefd$d%Zed&ee dededee fd'd(Zed)d* Zed+d, ZdS )-r  rs  rq  rt  c                 C   s   t   |j||d dS )z*Initialize logging and alerting on startup)rs  rt  N)rZ  Zstartup_event)clsrs  rq  rt  rd   rd   re   r    s   	
z-ProxyStartupEvent._initialize_startup_loggingru  c                 C   sF   ddl m} | dd}t|tr||}|r|du r!tddS dS )z
        Validates that when use_redis_transaction_buffer is enabled,
        a Redis cache is properly configured in litellm_settings.
        r   )r   Zuse_redis_transaction_bufferFNa  `use_redis_transaction_buffer` is enabled in general_settings but no Redis cache is configured. This will cause spend updates to not be tracked. Add a Redis cache in litellm_settings:

litellm_settings:
  cache: true
  cache_params:
    type: redis
    url: os.environ/REDIS_URL
)litellm.secret_managers.mainr   r  r  r  r  )ru  rt  r   Z_use_redis_transaction_bufferrd   rd   re   r    s   	

z;ProxyStartupEvent._validate_redis_transaction_buffer_configrv  c                    s   ddl m} |dd}|r|ddstd dS td|du d	|  |j||d
I dH }|rBtd tj| dS t	d dS )z1Initialize MCP semantic tool filter if configuredr   r  r  Nr  FzKSemantic tool filter not configured or not enabled, skipping initializationz.Initializing semantic tool filter: llm_router=z	, config=r  z$Semantic tool filter hook registeredzASemantic tool filter hook was configured but failed to initialize)
r  r  r  rx   rS  r  rT  rX  rY  rc  )r  rs  rv  r  r  r  rd   rd   re   r    s6   
z2ProxyStartupEvent._initialize_semantic_tool_filterrN  rr  c                 C   sx   | dddur/|d  D ]\}}t|tr$|dr$t||d |< qtdi |d }nt }tj|||d dS )zInitialize JWT auth on startuplitellm_jwtauthNr  )rN  rr  r  rd   )	r  r  r  r  r  r   r8   rV  r  )r  ru  rN  rr  r  r  r  rd   rd   re   r  ;  s   
z&ProxyStartupEvent._initialize_jwt_authry  c                 C   sJ   t jdu r	tdttdd|dg i i dt jt jdt jt jdd dS )z Adds a global proxy budget to dbNzPbudget_duration not set on Proxy. budget_duration is required to use max_budget.userr   Zupdate_data)r  budget_duration)request_typer  r\  durationr  aliasesr  re  r  r  Z
query_typeZupdate_key_values)rT  r  r\  r  r  r   r  )r  ry  rd   rd   re   r  P  s,   
z)ProxyStartupEvent._add_proxy_budget_to_dbrz  r  Nc              
      sZ   zd |}t|||dI dH  W dS  ty, } ztd| W Y d}~dS d}~ww )zSWarm global spend cache once at startup to reduce impact of first wave of requests.rs  )r|  rr  rN  Nz;Global spend cache warm-up at startup skipped or failed: %s)rq   r   r\  rx   rS  )r  rz  rr  rN  r|  re  rd   rd   re   r  m  s   
z*ProxyStartupEvent._warm_global_spend_cachec                    sx   t jdu rdS t jdpg }|r8tdd |D r:ddlm} dd |D }||tttd	d
I dH  dS dS dS )z%Update the default team member budgetNteamsc                 s   s    | ]}t |tV  qd S rB  )r  r  r  r  rd   rd   re   r    s    zGProxyStartupEvent._update_default_team_member_budget.<locals>.<genexpr>r   )!update_default_team_member_budgetc                 S   r  r  )ZNewUserRequestTeamr  rd   rd   re   r    r  zHProxyStartupEvent._update_default_team_member_budget.<locals>.<listcomp>ra  )r  r  )	rT  Zdefault_internal_user_paramsr  r5  7litellm.proxy.ui_crud_endpoints.proxy_setting_endpointsr  rE   r   rC  )r  Z_teamsr  Zteams_pydantic_objrd   rd   re   r    s   
z4ProxyStartupEvent._update_default_team_member_budgetc              
      s   zSddl }ddlm} tjjjddidI dH }|rL|jrO|j}t|t	r+|
|nt|  fdd|D }|rRt| td	t|  W dS W dS W dS W dS  tym } ztd
| W Y d}~dS d}~ww )z
        Load persisted UI settings from the database and sync runtime flags
        into general_settings so they take effect immediately after startup.
        r   N)_RUNTIME_GENERAL_SETTINGS_FLAGSrb  ui_settingsr  c                    s   i | ]}| v r| | qS rd   rd   r:  r  rd   re   r    s
    zKProxyStartupEvent._sync_ui_settings_to_general_settings.<locals>.<dictcomp>z5Synced UI settings to general_settings on startup: %sz1UI settings sync on startup skipped or failed: %s)r  r  r  rN  r~  Zlitellm_uisettingsr	  r  r  r  r  r  ru  r=  rx   rR  r  r  r\  rS  )r  r  r  r  rawZflags_to_syncre  rd   r  re   r    s6   




z7ProxyStartupEvent._sync_ui_settings_to_general_settingsr{  r|  r}  c              
      s|  ddl m} ddlm} ttttdd| id| idda|t	
dtd||  }	|t	
dd	 }
|d
ddu rNt||d}tj|jd|	ddtd tjtd|
|t|gddtd |dddu ruddlm} t||t|d tdtp{tatdur|durz5|jjjddidI dH }|durt|jtr|jd}|du st|tr| dkrdat !d W n t"y } zt #dt| W Y d}~nd}~ww tdu r	tjt$j%dd||gddtd t$j%||dI dH  tjt$j&dd|gd dtd t$j&|d!I dH  | j't|||d"I dH  | j(td#I dH  |d$durt) }|d%}|rfdd&l*m+} z|,|}tj|j-||gd'dtd( t !d)|  W nB t.ye   t /d*|  Y n1w |d+d,}zt0|}tj|j-d|t	
dd- |gd'dtd W n t.y   t /d. Y nw t1durz&dd/l2m3} |||t1d0}tj|j4dt5t	
dd d1dtd t !d2 W n  t"y } zt #d3|  t #d4 W Y d}~nd}~ww t1dur.z&dd5l6m7} |||t1d0}tj|j8dt5t	
dd d6dtd t !d7 W n  t"y- } zt #d8|  t #d9 W Y d}~nd}~ww tj9dd: t !d;t  dS )<z%Initializes scheduled background jobsr   )AsyncIOExecutor)MemoryJobStore)Zcoalescer  Zmax_instancesrg   N)Zjob_defaultsZ	jobstoresZ	executorsr         Zdisable_reset_budgetF)rq  rN  r  Zreset_budget_jobT)r  rb  r  r  Zupdate_spend_jobr  r-  )_monitor_spend_logs_queue)rN  rX  rq  ZSTORE_MODEL_IN_DBr  ru  r  r=  r  z<store_model_in_db=True loaded from DB, overriding config/envz,Failed to check DB for store_model_in_db: %sZadd_deployment_jobrN  rq  Zget_credentials_jobr  )r  ru  rq  rN  r  r  r  r  r  r  z'Spend log cleanup scheduled with cron: r  r  r  rj   r  )CheckBatchCost)rq  rN  rs  check_batch_cost_jobz+Batch cost check job scheduled successfullyz%Failed to setup batch cost checking: zSChecking batch cost for LiteLLM Managed Files is an Enterprise Feature. Skipping...)CheckResponsesCostcheck_responses_cost_jobz/Responses cost check job scheduled successfullyz)Failed to setup responses cost checking: zWChecking responses cost for LiteLLM Managed Files is an Enterprise Feature. Skipping...)pausedzrAPScheduler started with memory leak prevention settings: removed jitter, increased intervals, misfire_grace_time=):Zapscheduler.executors.asyncior  Zapscheduler.jobstores.memoryr  ri   r~   r   r   r  rm   r  r  r  r   r  Zreset_budgetr   rX  litellm.proxy.utilsr  r  r  r   r=  r~  r  r  r  r  r  r  r  rx   rR  r\  rS  r  r  rc  _initialize_slack_alerting_jobs*_initialize_spend_tracking_background_jobsr   r  r  r  r  r  r  r   rs  Z6litellm_enterprise.proxy.common_utils.check_batch_costr  Zcheck_batch_costr,  Z:litellm_enterprise.proxy.common_utils.check_responses_costr  Zcheck_responses_coststart)r  ru  rN  r{  r|  r}  rq  r  r  Zbudget_intervalZbatch_writing_intervalZbudget_reset_jobr  Z_db_gs_recordZ_db_valre  r  r  r  r  r  r  r  r  r  r  rd   rd   re   r    s  	






	





z6ProxyStartupEvent.initialize_scheduled_background_jobsr  c              
      sH  ddl m} ddlm} ddlm} | I dH r"|j|dI dH  |j|dI dH  tj	du r<ddl
m} |j|d dd	lm}m} t|}td
|  |du rz-ddlm}	 tdurw|	t}
td| d |j|
jd|dd ntd W dS W dS  ty } ztd|  W Y d}~dS d}~ww td dS )a+  
        Initialize the spend tracking and other background jobs
        1. CloudZero Background Job
        2. Focus Background Job
        3. Prometheus Background Job
        4. Key Rotation Background Job

        Args:
            scheduler: The scheduler to add the background jobs to
        r   )CloudZeroLogger)FocusLogger)is_cloudzero_setupNr  Tr  )+LITELLM_KEY_ROTATION_CHECK_INTERVAL_SECONDSLITELLM_KEY_ROTATION_ENABLEDzkey_rotation_enabled: )KeyRotationManagerz,Key rotation background job scheduled every z, seconds (LITELLM_KEY_ROTATION_ENABLED=true)r  Zkey_rotation_job)r  rb  z4Key rotation enabled but prisma_client not availablez"Failed to setup key rotation job: zGKey rotation disabled (set LITELLM_KEY_ROTATION_ENABLED=true to enable))Z(litellm.integrations.cloudzero.cloudzeror  Z'litellm.integrations.focus.focus_loggerr  0litellm.proxy.spend_tracking.cloudzero_endpointsr  Zinit_cloudzero_background_jobZ init_focus_export_background_jobrT  Z$prometheus_initialize_budget_metricsrB  r  Z"initialize_budget_metrics_cron_joblitellm.constantsr  r  r   rx   rS  Z/litellm.proxy.common_utils.key_rotation_managerr  rN  r  Zprocess_rotationsrc  r\  )r  r  r  r  r  r  r  r  Zkey_rotation_enabledr  Zkey_rotation_managerre  rd   rd   re   r    sL   



z<ProxyStartupEvent._initialize_spend_tracking_background_jobsc                    s
  |dur}|j jdur|durtd |ddpd}t|dd }|d  dkr/td|j|j jd|t	
 td	td
d d |gddtd |j|j jddddd tdrd
dlm} |j|j jdtd
|dddd |j  I dH  dS dS dS dS dS )z<Initialize Slack alerting background jobs for spend reports.Nz3Alerting: Initializing Weekly/Monthly Spend Reportsspend_report_frequencyZ7dr  zBspend_report_frequency must be specified in days, e.g., '1d', '7d'r  
   r   i,  )r  Zweekly_spend_report_jobT)daysZnext_run_timer'  rb  r  r  cronri  Zmonthly_spend_report_job)dayrb  r  ZPROMETHEUS_URL)ZoneInfozAmerica/Los_AngelesZprometheus_fallback_stats_job)hourminuter   rb  r  )r  r_  rp   r  r  r  r  r  Zsend_weekly_spend_reportr   nowr   rm   r  r   Zsend_monthly_spend_reportr  rS  zoneinfor  Z#send_fallback_stats_from_prometheusr   )r  r  ru  rq  rN  r  r  r  rd   rd   re   r  "  s^   

	!z1ProxyStartupEvent._initialize_slack_alerting_jobsrp  c              
      sP  zd}|durzt ||d}W n ty } z|d}~ww z	| I dH  W n) tyQ } zdt|v s<dt|v rKtd td td |d}~ww t|dret|jd	re|j I dH  t	
|  t	
|  td
ddur| I dH  t|dr| I dH  |W S  ty } zt| W Y d}~dS d}~ww )zQ
        - Sets up prisma client
        - Adds necessary views to proxy
        N)rp  rq  ZP3018ZP3009z#CRITICAL: DATABASE MIGRATION FAILEDz$Your database is in a 'dirty' state.z<FIX: Run 'prisma migrate resolve --applied <migration_name>'r~  start_token_refresh_taskZ&DISABLE_PRISMA_HEALTH_CHECK_ON_STARTUPFTstart_db_health_watchdog_task)r   r\  connectr  rx   rS  r  r~  r  r  r  Zcheck_view_existsZ(_set_spend_logs_row_count_in_proxy_stater   Zhealth_checkr  r   Zhandle_db_exception)r  rp  rq  rr  rN  re  rd   rd   re   r  ]  sd   


z&ProxyStartupEvent._setup_prisma_clientc                 C   s^   ddl m}m} | rddl}|jddd | r-ddlm} | }|  t	d dS dS )	z
        Initialize dd tracer - if `USE_DDTRACE=true` in .env

        DD tracer is used to trace Python applications.
        Doc: https://docs.datadoghq.com/tracing/trace_collection/automatic_instrumentation/dd_libraries/python/
        r   )_should_use_dd_profiler_should_use_dd_tracerNTF)rv  openai)ProfilerzDatadog Profiler started......)
Z%litellm.litellm_core_utils.dd_tracingr  r  ddtraceZ	patch_allZddtrace.profilingr  r  rx   rS  )r  r  r  r  r  Zprofrd   rd   re   r    s   z!ProxyStartupEvent._init_dd_tracerc           	   	   C   s>  t ddstd dS zddl}td}|stdtd}|s'td	i }td
p2td}|r9||d< td}|||rD|ndd}|durgz
tt||d< W n tt	fyf   td|w |j
di | d| d| d| d}d|v r|d|d  7 }t| W dS  ty   td Y dS w )a  
        Optional continuous profiling via Grafana Pyroscope.

        Off by default. Enable with LITELLM_ENABLE_PYROSCOPE=true.
        Requires: pip install pyroscope-io (optional dependency).
        When enabled, PYROSCOPE_SERVER_ADDRESS and PYROSCOPE_APP_NAME are required (no defaults).
        Optional: PYROSCOPE_SAMPLE_RATE (parsed as integer) to set the sample rate.
        ZLITELLM_ENABLE_PYROSCOPEFzWLiteLLM: Pyroscope profiling is disabled (set LITELLM_ENABLE_PYROSCOPE=true to enable).Nr   ZPYROSCOPE_APP_NAMEzsLITELLM_ENABLE_PYROSCOPE is true but PYROSCOPE_APP_NAME is not set. Set PYROSCOPE_APP_NAME when enabling Pyroscope.ZPYROSCOPE_SERVER_ADDRESSzLITELLM_ENABLE_PYROSCOPE is true but PYROSCOPE_SERVER_ADDRESS is not set. Set PYROSCOPE_SERVER_ADDRESS when enabling Pyroscope.ZOTEL_ENVIRONMENT_NAMEZLITELLM_DEPLOYMENT_ENVIRONMENTenvironmentZPYROSCOPE_SAMPLE_RATE)app_nameserver_addressr  Zsample_ratez-PYROSCOPE_SAMPLE_RATE must be a number, got: z/LiteLLM: Pyroscope profiling started (app_name=z, server_address=zA). View CPU profiles at the Pyroscope UI and select application 'z'.z sample_rate=zLiteLLM: LITELLM_ENABLE_PYROSCOPE is set but the 'pyroscope-io' package is not installed. Pyroscope profiling will not run. Install with: pip install pyroscope-iord   )r   rx   rS  	pyroscoper  rS  r  r  rl  r  	configurerR  ImportErrorrc  )	r  r  r  r  r  env_nameZsample_rate_envZconfigure_kwargsmsgrd   rd   re   r    sf   






z!ProxyStartupEvent._init_pyroscope)r\   r  r  classmethodr   rv   r   r{   r  rf  r  r  r   r  r   r  r   rz   r  r  r  r  r  r  r  ri   r  r  r  r  r  rd   rd   rd   re   r    s    
(

"  !L:B
r  z
/v1/modelszmodel management)dependenciesr  z/modelsreturn_wildcard_routesinclude_model_access_groupsonly_model_access_groupsinclude_metadatafallback_typescopec                    s|  ddl m} ddlm}	m}
 |dur |dkr tdd| dd	}|dkr1|| tttd
I dH }|rt	du r<g }i }nt	
 }t	 }|rRtt|t|  }ddlm} |g g |dd	|pad	t	||pfd	|pid	d
}g }|D ]}|	|d|pxd	|t	d}|| qpt|ddS |
| t	tttt||pd	|pd	|pd	tdI dH }g }|D ]}|	|d|pd	|t	d}|| qt|ddS )a  
    Use `/model/info` - to get detailed model information, example - pricing, mode, etc.

    This is just for compatibility with openai projects like aider.

    Query Parameters:
    - include_metadata: Include additional metadata in the response with fallback information
    - fallback_type: Type of fallbacks to include ("general", "context_window", "content_policy")
                    Defaults to "general" when include_metadata=true
    - scope: Optional scope parameter. Currently only accepts "expand".
             When scope=expand is passed, proxy admins, team admins, and org admins
             will receive all proxy models as if they are a proxy admin.
    r   )r   )create_model_info_responseget_available_models_for_userNexpand  zIInvalid scope parameter. Only 'expand' is currently supported. Received: r@  Fr  rN  rr  rq  )r   )

key_modelsteam_modelsproxy_model_listrt  infer_model_from_keysr  rs  model_access_groupsr  r  r  rm  r  r  r  rs  r  )r  objectr  rs  ru  rt  rN  rq  r^  r  r  r  rr  )/litellm.proxy.management_endpoints.common_utilsr   r  r  r  r  rN  rr  rq  rs  get_model_namesget_model_access_groupsr  r  r  litellm.proxy.auth.model_checksr   r  r  ru  rt  )r  r  r^  r  r  r  r  r  r   r  r  Zshould_expand_scoper   r  r   
all_models
model_datar/  r  rd   rd   re   r    s   z/v1/models/{model_id}z/models/{model_id}rm  c           	         s   ddl m}m}m} ||tttttddddt	dI dH }|| |d tdu r-t
ddd	t| }|du r@t
d
d|  dd	tj|jjd\}}}}|| |ddtdS )ak  
    Retrieve information about a specific model accessible to your API key.

    Returns model details only if the model is available to your API key/team.
    Returns 404 if the model doesn't exist or is not accessible.

    Follows OpenAI API specification for individual model retrieval.
    https://platform.openai.com/docs/api-reference/models/retrieve
    r   )r  r  validate_model_accessNFr  )rm  Zavailable_modelsr  zRouter not initializedr@    zModel 'z#' not found in router configurationrw  r  )r  r  r  r  rs  ru  rt  rN  rq  rr  r  "get_deployment_by_model_group_namerT  get_llm_providerr  r/  )	rm  r  r  r  r  r
  r  r  r  rd   rd   re   r    s@   

r  z/v1/chat/completionszchat/completionsz/chat/completionsz&/engines/{model:path}/chat/completionsz1/openai/deployments/{model:path}/chat/completions   r  zSuccessful response)r  r  r  fastapi_responsec                    s~  t | dI dH }|dur\|ddu ri |d< t|dr)|jdur)|j|d d< t|dr:|jdur:|j|d d< t|drK|jdurK|j|d d	< t|d
r\|jdur\|j|d d
< t|d}zH|jd/i d| d|d|dddt	dt
dtdtdtd|dtdtdtdtdtdtI dH }t|trt|ddW S |W S  ty' } zq|j}t	j|||dI dH  t }	|j|	_|j|	jd  j_d!|	jd  _ |d"ddur|d" du rtj!j"|	dd#}
tj#|
|jd$|d%dd&}t|||d'}t$|d(d)d*W  Y d}~S tj%d d d d+}||	_&|	W  Y d}~S d}~w t'y } zt|j}t	j|||dI dH  t }	|j|	jd  j_|d"ddur|d" du rtj!j"|	dd#}
tj#|
|dd,d$|d%dd&}t|||d'}t$|d(t|d-r|j(nt)j*d*W  Y d}~S tj%d d d d+}||	_&|	W  Y d}~S d}~w t+y } z|j,||t	d.I dH d}~ww )0a  

    Follows the exact same API spec as `OpenAI's Chat API https://platform.openai.com/docs/api-reference/chat`

    ```bash
    curl -X POST http://localhost:4000/v1/chat/completions 
    -H "Content-Type: application/json" 
    -H "Authorization: Bearer sk-1234" 
    -d '{
        "model": "gpt-4o",
        "messages": [
            {
                "role": "user",
                "content": "Hello!"
            }
        ]
    }'
    ```

    r  Nmetadatar\  user_api_key_user_idr^  user_api_key_team_idorg_iduser_api_key_org_idagent_idr  r  r  r  
route_typeZacompletionrq  rs  ru  r  r  r/  rt  r{  r|  user_max_tokensrz  r  T)r  r  r   Zcontent_filterstreamZmodel_responseZconvert_to_deltacached_responselitellm_logging_obj)completion_streamr/  custom_llm_providerZlogging_objr  text/event-streamr  
media_typer  Zprompt_tokensZcompletion_tokenstotal_tokensrg  r  )re  r  rq  rd   )-r   r  r  r\  r^  r  r  r   base_process_llm_requestrq  rs  ru  r  r  rt  r{  r|  r  rz  r  r  r   r   r   r  r  rT  rJ   r/  r^   choicesr  Zfinish_reasonutilsModelResponseIteratorZCustomStreamWrapperr1  Usageusager   r  r'  HTTP_400_BAD_REQUESTr\  _handle_llm_api_exception)r  r  r/  r  r  base_llm_response_processorr  re  _data_chat_response	_iterator_streaming_responseselected_data_generator_usagerd   rd   re   chat_completion  s  4





	


 
 


	r6  z/v1/completionsZcompletionsz/completionsz!/engines/{model:path}/completionsz,/openai/deployments/{model:path}/completionsc                    s  i }zt | dI dH }|dur_|ddu ri |d< t|dr,|jdur,|j|d d< t|dr=|jdur=|j|d d< t|drN|jdurN|j|d d	< t|d
r_|jdur_|j|d d
< t|d}|jd5i d| d|d|dddt	dt
dtdtdtd|dtdtdtdtdtdtI dH W S  ty. } z|j}t	j|||dI dH  |dddur|d du rt }t|jd  d!|j |j|_tjd d d d"}	t|d#|	 tjj|dd$}
tj |
|jd%}t|||d&}t!|d'd(d)W  Y d}~S t" }|j|jd  _#|j|_tjd d d d"}	|	|_$|W  Y d}~S d}~w t%y } zz|j}t	j|||dI dH  |dddur|d du rt }tjd d d d"}	|	|_$|j|jd  j_&tjj|dd$}
tj |
|dd*d%}t|||d&}t!|d'i t|d+r|j'nt(j)d,W  Y d}~S t" }|j|jd  _#|W  Y d}~S d}~w t*y } z7t	j|||dI dH  t+,d--t.| t.| }t/t0|d.|t0|d/d0t0|d1d0t0|d2dt0|d+d3d4d}~ww )6a  
    Follows the exact same API spec as `OpenAI's Completions API https://platform.openai.com/docs/api-reference/completions`

    ```bash
    curl -X POST http://localhost:4000/v1/completions 
    -H "Content-Type: application/json" 
    -H "Authorization: Bearer sk-1234" 
    -d '{
        "model": "gpt-3.5-turbo-instruct",
        "prompt": "Once upon a time",
        "max_tokens": 50,
        "temperature": 0.7
    }'
    ```
    r  Nr  r\  r  r^  r  r  r  r  r  r  r  r  r  Zatext_completionrq  rs  ru  r  r  r/  rt  r{  r|  r  rz  r  r  r  Tr   textr%  r,  r  )r   r/  r  r"  r  r#  rg  r  )r$  r  r  z?litellm.proxy.proxy_server.completion(): Exception occured - {}r^   rU   r  r  r  r  r^   rU   r  Zopenai_coder  rd   )1r   r  r  r\  r^  r  r  r   r'  rq  rs  ru  r  r  rt  r{  r|  r  rz  r  r   r  r  rT  rJ   rE  r(  r^   r/  r+  r)  r*  ZTextCompletionStreamWrapperr1  rL   r7  r,  r   r  r  r'  r-  r\  rx   rU  rq   r  r>   r  )r  r  r/  r  r  r/  re  r0  Z_text_responser5  r2  r3  r4  	_responser1  r  rd   rd   re   
completion  sB  )





	
  







r:  z/v1/embeddings
embeddings)r  response_classr  z/embeddingsz /engines/{model:path}/embeddingsz+/openai/deployments/{model:path}/embeddingsc              
      sz  i }zt | dI dH }tdurtjng }d|v rt|d trt|d dkrt|d d trt|d d d trtdur|d|v rtj|d d}|dur|di p[i }|dd  t	j
v pqt fd	d
tD }|sg }	|d D ]}
|	t	jd|
d qz|	|d< |dur|ddu ri |d< t|dr|jdur|j|d d< t|dr|jdur|j|d d< t|dr|jdur|j|d d< t|dr|jdur|j|d d< t|d}|jd'i d| d|d|dddtdtdtdtdtd|d td!td"td#td$td%tI dH }|W S  t y< } zt|d}|j!||ttd&I dH d}~ww )(a  
    Follows the exact same API spec as `OpenAI's Embeddings API https://platform.openai.com/docs/api-reference/embeddings`

    ```bash
    curl -X POST http://localhost:4000/v1/embeddings 
    -H "Content-Type: application/json" 
    -H "Authorization: Bearer sk-1234" 
    -d '{
        "model": "text-embedding-ada-002",
        "input": "The quick brown fox jumps over the lazy dog"
    }'
    ```

r  Ninputr   r/  )Zmodel_group_namer  rg  c                 3   s    | ]}  |V  qd S rB  )r  )r  r  litellm_modelrd   re   r    s
    
zembeddings.<locals>.<genexpr>zgpt-3.5-turbo)r/  tokensr  r\  r  r^  r  r  r  r  r  r  r  r  r  Z
aembeddingrq  rs  ru  r  r  rt  r{  r|  r  rz  r  )re  r  rq  r  rd   )"r   rs  model_namesr  r  r  r  r  r  rT  Zopen_ai_embedding_modelsr  r!   r  decoder  r\  r^  r  r  r   r'  rq  ru  r  r  rt  r{  r|  r  rz  r  r\  r.  )r  r  r/  r  r  router_model_namesr  r  Zsupports_token_arraysZ
input_listir/  r  re  rd   r>  re   r;  O  s   0





	


z/v1/moderationsmoderationsz/moderationsc                    s  i }z|   I dH }t|}t|| t|ttdI dH }tddp)tp)|d|d< tr2t|d< t	j
||ddI dH }t  t|dttdI dH }|I dH }tt	j|d	d
dd t|di pfi }|ddpnd
}|ddpvd
}	|ddp~d
}
|jtj|||	|
tt|dd
||d |W S  ty } zRt	j|||dI dH  tdt| t|trtt|dt|t|ddt|ddt|dtj dt| }tt|d|t|ddt|ddt|dddd}~ww )a~  
    The moderations endpoint is a tool you can use to check whether content complies with an LLM Providers policies.
    Quick Start
    ```
    curl --location 'http://0.0.0.0:4000/moderations'     --header 'Content-Type: application/json'     --header 'Authorization: Bearer sk-1234'     --data '{"input": "Sample text goes here", "model": "text-moderation-stable"}'
    ```
    Nr  r  ru  r  r  r  moderation_modelr/  Z
moderationr  r  	call_typeZamoderationr  r  rs  rt  r  rg  r  r  r'  _hidden_paramsrm  r|  r0  allowed_model_regionr  rm  r|  r0  r  model_regionr  hidden_paramsr  z@litellm.proxy.proxy_server.moderations(): Exception occured - {}r^   rU   r  r  r  r  r  )!bodyorjsonr  r   ru  r  r  r  rt  rq  pre_call_hookrB  r   rs  r  r  update_request_statusr  r  r=  r   get_custom_headersr\  r  rx   rU  rq   r  r  r  r>   r'  r-  )r  r  r  r  rQ  llm_callr  rP  rm  r|  r0  re  r  rd   rd   re   rE    s   











r9  c                 C  s2   | j tdI d H }|2 z	3 d H W }|V  q6 d S )N)
chunk_size)Zaiter_bytesr   )r9  Z
_generatorr  rd   rd   re   _audio_speech_chunk_generatorY  s
   rX  z/v1/audio/speechZaudioz/audio/speechc                    s  i }z|   I dH }t|}t|| t|ttdI dH }|dddu r/|jdur/|j|d< t	r5t	|d< t
j||ddI dH }t|dtt	dI dH }|I dH }tt
j|dd	d
d t|di pei }|ddpmd	}|ddpud	}	|ddp}d	}
|ddpd	}|ddpd	}tj|||	|
t|t|dd	d|||d}d}|dd	}|r| }d|v rd|v sd|v rd}tt|||dW S  ty } zt
j|||dI dH  tdt| tt  |d}~ww )z`
    Same params as:

    https://platform.openai.com/docs/api-reference/audio/createSpeech
    NrF  r  r/  ZaspeechrH  rJ  r  rg  r  rK  rL  rm  r|  r0  r_  rM  )r  rm  r|  r0  r  r_  rO  Z!fastest_response_batch_completioncall_idr  rP  z
audio/mpeggeminiZttszpreview-ttsz	audio/wav)r$  r  r  zAlitellm.proxy.proxy_server.audio_speech(): Exception occured - {}) rQ  rR  r  r   ru  r  r  r  r\  rt  rq  rS  r   rs  r  r  rT  r  r   rU  r  r1  rX  r\  r  rx   r  rq   r  rS  rt  ru  )r  r  r  r  rQ  rV  r  rP  rm  r|  r0  r_  r  Zcustom_headersr$  request_modelZrequest_model_lowerre  rd   rd   re   audio_speeche  s   
	


r\  z/v1/audio/transcriptionsz/audio/transcriptions.rb   c                    s  i }zt | I dH }dd | D }t|| t|ttdI dH }|dddu r4|jdur4|j|d< tddpAtpA|dd|d< trJt|d< t	durQt	j
ng }|jdu ratdtjd	d
dt|||d | I dH }t|}|j|_||d
< z2ztj||ddI dH }t|dt	tdI dH }	|	I dH }
W n ty } z|d}~ww W |  n|  w ttj|dddd t|
di pi }|ddpd}|ddpd}|ddpd}|ddpd}|ddpd}|di pi }|jtj d(||||t|t|dd|||d
| |
W S  ty} } zYtj!|||dI dH  t"#d$t%| t&|t'rWtt|dt%|j(t|d d!t|d"d!t|d#tjd$t%| }tt|d|t|d d!t|d"d!t|d%dt|d#d&d'd}~ww ))zq
    Same params as:

    https://platform.openai.com/docs/api-reference/audio/createTranscription?lang=curl
    Nc                 S   s   i | ]\}}|d kr||qS )rb   rd   r  rd   rd   re   r        z(audio_transcriptions.<locals>.<dictcomp>rF  r  rG  r/  z.File name is None. Please check your file namebad_requestrb   )r^   r  rU   r  )r  rb   rC  ZtranscriptionrH  ZatranscriptionrJ  r  rg  r  rK  rL  rm  r|  r0  r_  additional_headersrM  )
r  rm  r|  r0  r  r_  rO  rY  r  rP  r  zHlitellm.proxy.proxy_server.audio_transcription(): Exception occured - {}r^   rU   r  r  r  r  r  r  r8  rd   ))r   r  r   ru  r  r  r  r\  rt  rs  rA  r`   r>   r'  r-  r   readioBytesIOr  rq  rS  r   r\  rW  r  r  rT  r  r  r=  r   rU  r  rx   rU  rq   r  r  r  rA  )r  r  rb   r  r  Z	form_datarC  Zfile_contentZfile_objectrV  r  re  rP  rm  r|  r0  r_  r  r_  r  rd   rd   re   audio_transcriptions  s   	












rc  z/vertex_ai/livezGOptional model name, used to determine Vertex region for global models.)r  zCOverride the Vertex AI project id used for the upstream connection.z;Override the Vertex AI region (for example, 'us-central1').	websocketvertex_projectvertex_locationc                    s   t | ||||dI dH S )z
    Vertex AI Live API WebSocket Pass-through Endpoint

    This endpoint delegates to the WebSocket function defined in llm_passthrough_endpoints.py
    rd  r/  re  rf  r  Nr   rg  rd   rd   re   #vertex_ai_live_passthrough_endpoint{  s   rh  )maxsizeintentc                 C   s(   d| fg}|dur| d|f t|S )z
    Build a hashable representation of the realtime query params so we can cache
    the repetitive model/intent combinations.
    r/  Nrj  )r  tuple)r/  rj  paramsrd   rd   re   _realtime_query_params_template  s   
rm  z	/realtimez'The intent of the websocket connection.zAComma-separated list of guardrail names to apply to this request.r  c                    s>  dd | j dpddD }i }|r|d |d< | jdi |I d H  tttt |} | |d}|rDd	d |dD |d
< t| j	dpLg }	t
 }
|	|
d< t|
d}| j|_ fdd}||_t|d}z|j|t|tttttttt ddI d H \}}W nA ty } z5td z| t ddt!|ddI d H  W n	 ty   Y nw | j"dddI d H  W Y d }~d S d }~ww z||d< t#|dt$tdI d H }|I d H  W d S  t%j&j'y } ztd | j"|j(ddI d H  W Y d }~d S d }~w ty   td | j"dddI d H  Y d S w )Nc                 S      g | ]
}|  r|  qS rd   r  )r  prd   rd   re   r    s    z/realtime_websocket_endpoint.<locals>.<listcomp>zsec-websocket-protocolrg  rh  r   Zsubprotocol)r/  rd  r  c                 S   rn  rd   ro  )r  grd   rd   re   r        r  r  )r  c                      s
   t  S rB  rH   rd   rw  rd   re   return_body  s   z0realtime_websocket_endpoint.<locals>.return_bodyr  Z
_arealtime)r  ru  r  r  rq  r  rt  r{  r|  r  rz  r/  r  zRealtime pre-call errorr  Zguardrail_error)rU   r^   )rU   r  i  zPre-call error)r  reasonr  rJ  zInvalid status codezInternal server errorrd   ))r  r  r  acceptr   r
  r  rm  r  r  rX   r  r!  r  _urlrQ  r   Z common_processing_pre_call_logicru  r  rq  r  rt  r{  r|  r  rz  r\  rx   rU  Z	send_textr  rg  r  rW  r   rs  
websockets
exceptionsZInvalidStatusCoder  )rd  r/  rj  r  r  Zrequested_protocolsZaccept_kwargsr  r  Zheaders_listr  r  rs  r/  r  re  rV  rd   rw  re   realtime_websocket_endpoint  s   




$
ry  z/v1/assistantsZ
assistantsz/assistantsc                    s  i }zs|   I dH  t|| t|ttdI dH }tdu r&tddtjj	idtj
di |I dH }ttj|dddd	 t|d
i pFi }|ddpNd}|ddpVd}|ddp^d}|jtj||||tt|dd||d |W S  ty }	 z_tj||	|dI dH  tdt|	 tt  t|	trtt|	dt|	j t|	ddt|	ddt|	dt!j"dt|	 }
tt|	d|
t|	ddt|	ddt|	ddt|	dddd}	~	ww )z
    Returns a list of assistants.

    API Reference docs - https://platform.openai.com/docs/api-reference/assistants/listAssistants
    NrF  r  r  r@  r  rg  r  rK  rL  rm  r|  r0  rM  rN  r  zClitellm.proxy.proxy_server.get_assistants(): Exception occured - {}r^   rU   r  r  r  r  r  r8  rd   )#rQ  r   ru  r  r  rs  r  r)   no_llm_routerr  Zaget_assistantsr  r  rq  rT  r  r  r  r=  r   rU  r\  r  rx   r  rq   r  rS  rt  ru  r  r>   rA  r'  r-  r  r  r  r  r  rP  rm  r|  r0  re  r  rd   rd   re   get_assistants+  s   










r|  c                    s  i }zx|   I dH }t|}t|| t|ttdI dH }tdu r+tddt	j
jidtjdi |I dH }ttj|dddd	 t|d
i pKi }|ddpSd}|ddp[d}|ddpcd}	|jtj||||	tt|dd||d |W S  ty }
 z^tj||
|dI dH  tdt|
 tt  t |
trt!t|
dt|
j"t|
ddt|
ddt|
dt#j$dt|
 }t!t|
d|t|
ddt|
ddt|
dt|
dddd}
~
ww )z~
    Create assistant

    API Reference docs - https://platform.openai.com/docs/api-reference/assistants/createAssistant
    NrF  r  r  r@  r  rg  r  rK  rL  rm  r|  r0  rM  rN  r  zElitellm.proxy.proxy_server.create_assistant(): Exception occured - {}r^   rU   r  r  r  r  r  rd   )%rQ  rR  r  r   ru  r  r  rs  r  r)   rz  r  Zacreate_assistantsr  r  rq  rT  r  r  r  r=  r   rU  r\  r  rx   r  rq   r  rS  rt  ru  r  r>   rA  r'  r-  )r  r  r  r  rQ  r  rP  rm  r|  r0  re  r  rd   rd   re   create_assistant  s   









r}  z"/v1/assistants/{assistant_id:path}z/assistants/{assistant_id:path}assistant_idc                      i }znt || t|ttdI dH }tdu rtddtjjidtj	dd|i|I dH }t
tj|ddd	d
 t|di pAi }|ddpId}|ddpQd}|ddpYd}	|jtj||||	tt|dd||d |W S  ty }
 z^tj||
|dI dH  tdt|
 tt  t|
trtt|
dt|
jt|
ddt|
ddt|
dt j!dt|
 }tt|
d|t|
ddt|
ddt|
dt|
dddd}
~
ww )z~
    Delete assistant

    API Reference docs - https://platform.openai.com/docs/api-reference/assistants/createAssistant
    rF  Nr  r  r@  r~  r  rg  r  rK  rL  rm  r|  r0  rM  rN  r  zElitellm.proxy.proxy_server.delete_assistant(): Exception occured - {}r^   rU   r  r  r  r  r  rd   )"r   ru  r  r  rs  r  r)   rz  r  Zadelete_assistantr  r  rq  rT  r  r  r  r=  r   rU  r\  r  rx   r  rq   r  rS  rt  ru  r  r>   rA  r'  r-  )r  r~  r  r  r  r  rP  rm  r|  r0  re  r  rd   rd   re   delete_assistant  s   








r  z/v1/threadsz/threadsc                    s  i }zs|   I dH  t|| t|ttdI dH }tdu r&tddtjj	idtj
di |I dH }ttj|dddd	 t|d
i pFi }|ddpNd}|ddpVd}|ddp^d}|jtj||||tt|dd||d |W S  ty }	 z^tj||	|dI dH  tdt|	 tt  t|	trtt|	dt|	j t|	ddt|	ddt|	dt!j"dt|	 }
tt|	d|
t|	ddt|	ddt|	dt|	dddd}	~	ww )zs
    Create a thread.

    API Reference - https://platform.openai.com/docs/api-reference/threads/createThread
    NrF  r  r  r@  r  rg  r  rK  rL  rm  r|  r0  rM  rN  r  zClitellm.proxy.proxy_server.create_threads(): Exception occured - {}r^   rU   r  r  r  r  r  rd   )#rQ  r   ru  r  r  rs  r  r)   rz  r  Zacreate_threadr  r  rq  rT  r  r  r  r=  r   rU  r\  r  rx   r  rq   r  rS  rt  ru  r  r>   rA  r'  r-  r{  rd   rd   re   create_threadsP  s   








r  z/v1/threads/{thread_id}z/threads/{thread_id}	thread_idc                    r  )zs
    Retrieves a thread.

    API Reference - https://platform.openai.com/docs/api-reference/threads/getThread
    rF  Nr  r  r@  r  r  rg  r  rK  rL  rm  r|  r0  rM  rN  r  z?litellm.proxy.proxy_server.get_thread(): Exception occured - {}r^   rU   r  r  r  r  r  rd   )"r   ru  r  r  rs  r  r)   rz  r  Zaget_threadr  r  rq  rT  r  r  r  r=  r   rU  r\  r  rx   r  rq   r  rS  rt  ru  r  r>   rA  r'  r-  r  r  r  r  r  r  rP  rm  r|  r0  re  r  rd   rd   re   
get_thread     








r  z /v1/threads/{thread_id}/messagesz/threads/{thread_id}/messagesc                    s  i }zz|   I dH }t|}t|| t|ttdI dH }tdu r+tddt	j
jidtjdd|i|I dH }ttj|ddd	d
 t|di pMi }|ddpUd}|ddp]d}	|ddped}
|jtj|||	|
tt|dd||d |W S  ty } z^tj|||dI dH  tdt| tt  t |trt!t|dt|j"t|ddt|ddt|dt#j$dt| }t!t|d|t|ddt|ddt|dt|dddd}~ww )zv
    Create a message.

    API Reference - https://platform.openai.com/docs/api-reference/messages/createMessage
    NrF  r  r  r@  r  r  rg  r  rK  rL  rm  r|  r0  rM  rN  r  zAlitellm.proxy.proxy_server.add_messages(): Exception occured - {}r^   rU   r  r  r  r  r  rd   )%rQ  rR  r  r   ru  r  r  rs  r  r)   rz  r  Za_add_messager  r  rq  rT  r  r  r  r=  r   rU  r\  r  rx   r  rq   r  rS  rt  ru  r  r>   rA  r'  r-  r  r  r  r  r  rQ  r  rP  rm  r|  r0  re  r  rd   rd   re   add_messages   s   









r  c                    r  )z
    Returns a list of messages for a given thread.

    API Reference - https://platform.openai.com/docs/api-reference/messages/listMessages
    rF  Nr  r  r@  r  r  rg  r  rK  rL  rm  r|  r0  rM  rN  r  zAlitellm.proxy.proxy_server.get_messages(): Exception occured - {}r^   rU   r  r  r  r  r  rd   )"r   ru  r  r  rs  r  r)   rz  r  Zaget_messagesr  r  rq  rT  r  r  r  r=  r   rU  r\  r  rx   r  rq   r  rS  rt  ru  r  r>   rA  r'  r-  r  rd   rd   re   get_messagess   r  r  z/v1/threads/{thread_id}/runsz/threads/{thread_id}/runsc                    s  i }z|   I dH }t|}t|| t|ttdI dH }tdu r+tddt	j
jidtjdd|i|I dH }d|v rR|d du rRtt|||d	d
i dI dH W S ttj|dddd t|di pgi }|ddpod}|ddpwd}	|ddpd}
|jtj|||	|
tt|dd||d |W S  ty } z^tj|||dI dH  tdt| tt !  t"|trt#t|dt|j$t|ddt|ddt|dt%j&dt| }t#t|d|t|ddt|ddt|dt|dddd}~ww ) zi
    Create a run.

    API Reference: https://platform.openai.com/docs/api-reference/runs/createRun
    NrF  r  r  r@  r  r  Tr  r"  )	generatorr$  r  r  rg  r  rK  rL  rm  r|  r0  rM  rN  r  z?litellm.proxy.proxy_server.run_thread(): Exception occured - {}r^   rU   r  r  r  r  r  rd   )'rQ  rR  r  r   ru  r  r  rs  r  r)   rz  r  Zarun_threadr   r  r  r  rq  rT  r  r  r  r=  r   rU  r\  r  rx   r  rq   r  rS  rt  ru  r  r>   rA  r'  r-  r  rd   rd   re   
run_thread   s   









r  )BaseTokenCounterr  model_to_usec                 C   s  | du rdS ddl m} | di dd}d}d}zL||| di d| di d| di d	d
\}}}}ddlm} ddlm}	 ||}
|
ra|	j||
d}|durd| ||fW S W dS W dS  t	y   |
dsxd| v rddlm} | }| ||f Y S Y dS w )z
    Auto-route to the correct provider's token counter based on model/deployment.
    Uses the existing get_provider_model_info infrastructure with switch-case pattern.
    Nr   )r  r  r/  rg  r!  r0  api_key)r/  r!  r0  r  )LlmProviders)ProviderConfigManager)r/  r  z
anthropic/Z	anthropic)AnthropicModelInfo)NNN)Z1litellm.litellm_core_utils.get_llm_provider_logicr  r  r?  r  rZ  r  Zget_provider_model_infoZget_token_counterr\  r  r  Z#litellm.llms.anthropic.common_utilsr  )r  r  r  Z
full_modelr/  r!  Zdynamic_api_keyr0  r  r  Zllm_provider_enumZprovider_model_infor  Zanthropic_model_inford   rd   re   _get_provider_token_counterK!  sN   
r  z/utils/token_counterz	llm utils)r  r  response_modelcall_endpointc              	      sB  ddl m} | j}| j}| j}| j}| j}|du r(|du r(|du r(tdddd}d}	d}
tdurNztj	| j
i dI dH }W n tyM   td Y nw |duru|d	i d
}	|di }
t|d	i  d|	v ru|	ddd }	|	py| j
}d}d}|du r|durt||\}}}|dur|}|dur|j|ddu r|j|pd|||| j
||dI dH }|dur|jdu rt jdu rt|jpddd
|jpddtd|j d|j d n|dur|S t jdu rtddd
ddd}|
durttt |
dd}t jj||d}t|d }|||||d}t || j
||d S )!z
    Args:
        request: TokenCountRequest
        call_endpoint: bool - When set to "True" it will call the token counting endpoint - e.g Anthropic or Google AI Studio Token Counting APIs.

    Returns:
        TokenCountResponse
    r   )token_counterNr  z/prompt or messages or contents must be providedr@  )r/  Zrequest_kwargszVlitellm.proxy.proxy_server.token_counter(): Exception occured while getting deploymentr  r/  r  r  ri  Tr!  rg  )r  rh   contentsr  r[  r  systemzToken counting failedZtoken_counting_errorr  r  z Provider token counting failed (z): z". Falling back to local tokenizer.z?Token counting is disabled and no provider API result availableZtoken_counting_disabledi  custom_tokenizer)r/  r  rU   )r/  r7  rh   r  )r&  r[  Z
model_usedZtokenizer_type)!rT  r  rF  rh   r  r  r  r  rs  Zasync_get_available_deploymentr/  r\  rx   rU  r  rO   r  r  Zshould_use_token_counting_apiZcount_tokensr  Zdisable_token_counterr>   r  r  rc  r   r   r  r)  Z_select_tokenizerr  rM   )r  r  r  rF  rh   r  r  r  r  rP  r  r  Zprovider_counterr!  _modelr  r  Z_tokenizer_usedZtokenizer_usedr&  rd   rd   re   r  !  s   




r  z/utils/supported_openai_params)r  r  c              	      sP   zt j| d\} }}}dt j| |diW S  ty'   tddd| idw )a*  
    Returns supported openai params for a given litellm model name

    e.g. `gpt-4` vs `gpt-3.5-turbo`

    Example curl:
    ```
    curl -X GET --location 'http://localhost:4000/utils/supported_openai_params?model=gpt-3.5-turbo-16k'         --header 'Authorization: Bearer sk-1234'
    ```
    rw  supported_openai_paramsr/  r!  r  r  zCould not map model={}r@  )rT  r  Zget_supported_openai_paramsr\  r  rq   )r/  r!  r  rd   rd   re   r  "  s   r  z/utils/transform_requestc                    s   ddl m} || j| jdS )Nr   )return_raw_request)endpointr(  )rZ  r  rI  request_body)r  r  rd   rd   re   transform_request1"  s   r  r  c                    s   |du rt ddtjjidg }| D ]-}|di dd}|du r$q|jjjd|idI dH }|dur@|j|j	kr@|
| q|S )	
    Check if model is in db

    Check if db model is 'created_by' == user_api_key_dict.user_id

    Only return models that match
    Nr  r  r@  r  rb  rm  r  )r  r)   db_not_connected_errorr  r  r~  r  r	  rq  r\  r  )r  r  rN  filtered_modelsr/  rb  rn  rd   rd   re   _check_if_model_is_user_added="  s&   

r  user_rowc                 C   sH   g }| D ]}| di  dd}|dur!||jv r!|tt| q|S )zm
    Check if model is a team model

    Check if user is a member of the team that the model belongs to
    r  r^  N)r  r  r  r   r   )r  r  Zuser_team_modelsr/  Zmodel_team_idrd   rd   re   _check_if_model_is_team_model\"  s   	
r  r
  c                    s   |du rt ddtjjidt| ||dI dH } |jrHz|jjjd|jidI dH }W n t	y;   t ddd	idw | t
| pCg |d
7 } t| d}|S )r  Nr  r  r@  )r  r  rN  r\  r  r  zUser not found)r  r  )r  )r  r)   r  r  r  r\  r~  litellm_usertabler	  r\  r  rM  r   )r
  rs  r  rN  r  unique_modelsrd   rd   re   non_admin_all_modelsp"  s2   


r  team_db_objects_typedc                 C   s  i }| D ]}t |jdkstjj|jv rX| }|durW|D ]8}|di dd}|du r/q|di dd}d}|du rBd}n||jv rId}|rV||t	 
|j qq|jD ],}	|j|	|jd}
|
dur|
D ]}|di dd}|dur||t	 
|j qkq[q|S )	z'
    Add team models to all models
    r   Nr  rb  r^  FTr.  r^  )r  r  r@   all_proxy_modelsr  rM  r  r^  r  r  add)r  rs  r  team_objectr  r/  rm  team_model_idcan_add_modelr.  _modelsrd   rd   re   _add_team_models_to_all_models"  sB   

r  
user_teamsc           	         s   g }| dkr|j j I dH }dd |D }n|j jjdd| iidI dH }dd |D }t||d	}i }| D ]
\}}t|||< q:|S )
z
    Get all models across all teams user is in.

    1. Get all teams user is in
    2. Get all models across all teams
    3. Return {"model_id": ["team_id1", "team_id2"]}
    r   Nc                 S      g | ]}t d i | qS r  r9   r  r  team_db_objectrd   rd   re   r  "      z'get_all_team_models.<locals>.<listcomp>r^  r  r  c                 S   r  r  r  r  rd   rd   re   r  "  r  )r  rs  )r~  litellm_teamtabler  r  r  r  )	r  rN  rs  r  Zteam_db_objectsr  Zreturned_team_modelsrm  team_idsrd   rd   re   get_all_team_models"  s*   
r  user_db_objectc                 C   sX   g }| j D ]$}|j|d}|dur)|D ]}|di dd}|dur(|| qq|S )z7
    Get all models that user has direct access to
    r.  Nr  rb  )r  rM  r  r  )r  rs  direct_access_modelsr/  Zdeploymentsr  rm  rd   rd   re   get_direct_access_models"  s   

r  c                    sf  d}g }| j tjkrd}|jdd}n+| jdur?|jjjd| jidI dH }|dur?tdi |	 }|j
p8g }t||d}|durt|||dI dH }|D ]=}	|	d	i d
d}
|	d	i dd}|
durd}|dur~||
g }|r}||v r}d}nd}|r||
g |	d	 d< qO|D ]}	|	d	i d
d}
|
dur|
|v rd|	d	 d< qdd |D }|S )z5
    Get all models across all teams user is in.
    Nr   T)Zexclude_team_modelsr\  r  )r  rs  )r  rN  rs  r  rb  r^  Faccess_via_team_idsdirect_accessc                 S   s8   g | ]}| d i  dds| d i  dg r|qS )r  r  Fr  r  )r  r  rd   rd   re   r  D#  s    z9get_all_team_and_direct_access_models.<locals>.<listcomp>rd   )	user_roler;   PROXY_ADMINrz  r\  r~  r  r	  r:   r  r  r  r  r  )r  rN  rs  r
  r  r  r  Zuser_objectr  r  rm  Zteam_only_model_idZcan_use_modelr  rd   rd   re   %get_all_team_and_direct_access_models	#  sd   


r  rS  c                 C   sH  |  di }|du r%d}|dur|j| i ddpd}nd}t|}|| d< t| d	}|i krN|  d
i }| dd}ztj|d	}W n tyM   i }Y nw |i kr|  d
i }| dd}|r|d}	t|	dkro|	d }ztj||	d d}W n ty   i }Y nw |	 D ]\}
}|
|vr|||
< q|| d< t
| dhd} | S )a  
    Enrich a model dictionary with litellm model info (pricing, context window, etc.)
    and remove sensitive information.

    Args:
        model: Model dictionary to enrich
        debug: Whether to include debug information like openai_client
        llm_router: Optional router instance for debug info

    Returns:
        Enriched model dictionary with sensitive info removed
    r  Tr  Nasync)r  r(  Zclient_typeZllm_router_is_Noneopenai_clientrw  r  r/  r  r   r  r  litellm_credential_name)excluded_keys)r  Z_get_clientr  r  rT  r  r\  r  r  r  r   )r/  rS  rs  r  Z_openai_clientr  r  r  r?  split_modelr  r  rd   rd   re   $_enrich_model_info_with_litellm_dataM#  sT   


r  searchpagesizer  sort_byc              
      s  |r|  s| dfS |     fdd| D }g }t }	|D ]"}
|
di }|dd}|d}|r>|r>|	| q!||
 q!t|}t|	}|| }g }d}|| }|durzvd	 d
di}|	rpddt|	ii|d< |jj	j
|dI dH }|| }|r|dkr|jj	j||dI dH }|D ]}||g}|r|| qn-||k rt|| |}|dkr|jj	j||dI dH }|D ]}||g}|r|| qW n  ty } ztdt|  |}W Y d}~nd}~ww |}|| }||fS )aC  
    Apply search filter to models, querying database for additional matching models.

    Args:
        all_models: List of models to filter
        search: Search term (case-insensitive)
        page: Current page number
        size: Page size
        prisma_client: Prisma client for database queries
        proxy_config: Proxy config for decrypting models
        sort_by: Optional sort field - if provided, fetch all matching models instead of paginating at DB level

    Returns:
        Tuple of (filtered_models, total_count). total_count is None if not searching.
    Nc                    s$   g | ]} | d d v r|qS )r.  rg  )r  r  r  search_lowerrd   re   r  #  s    z2_apply_search_filter_to_models.<locals>.<listcomp>r  rn  Frb  r   r.  Zinsensitive)containsmodenotr  rm  r  )r  Ztakez,Error querying database models with search: )r  r  r  r  r  r  r  r  r~  r  countr  r  r  r  r\  rx   rU  r  )r
  r  r  r  rN  r  r  Zfiltered_router_modelsZfiltered_config_modelsZdb_model_ids_in_routerr  r  Zis_db_modelrm  Zconfig_models_countZdb_models_in_router_countZrouter_models_countrv  Zdb_models_total_countZmodels_needed_for_pageZdb_where_conditionsearch_total_countZdb_models_rawrn  decrypted_modelsZmodels_to_fetchre  r  rd   r  re   _apply_search_filter_to_models#  s   






r  dtc              	   C   s   | du rdS t | trBz*| dr| ddn| }t|}|jdu r-|jtjd}|W S |	tj}|W S  t
tfyA   Y dS w t | trY| jdu rS| jtjdS | 	tjS dS )a  
    Normalize a datetime value to a timezone-aware UTC datetime for sorting.

    This function handles:
    - None values: returns None
    - String values: parses ISO format strings and converts to UTC-aware datetime
    - Datetime objects: converts naive datetimes to UTC-aware, and aware datetimes to UTC

    Args:
        dt: Datetime value (None, str, or datetime object)

    Returns:
        UTC-aware datetime object, or None if input is None or cannot be parsed
    NZz+00:00tzinfo)r  r  r!  r  r   r(  r  r   utc
astimezoner  r  )r  Zdt_strZ	parsed_dtrd   rd   re   _normalize_datetime_for_sorting$  s&   




r  asc
sort_orderc              
      s   rdvr| S |  dk dtttf dtf fdd}z
t| | d}|W S  tyI } ztd d	t|  | W  Y d
}~S d
}~ww )a  
    Sort models by the specified field and order.

    Args:
        all_models: List of models to sort
        sort_by: Field to sort by (model_name, created_at, updated_at, costs, status)
        sort_order: Sort order (asc or desc)

    Returns:
        Sorted list of models
    )r.  ro  rp  costsr'  descr/  r  c           	         s$  |  di }dkr|  dd S dkr7| d}t|}|d u r5 s-tjjtjdS tjjtjdS |S dkr\| d}t|}|d u rZ sRtjjtjdS tjjtjdS |S dkr| dd	pgd	}| d
d	pod	}|| }|d	kr s~t	dS t	dS |S dkr| dd}|S d S )Nr  r.  rg  ro  r  rp  r  Zinput_cost_per_tokenr   Zoutput_cost_per_tokenrd  z-infr'  rn  F)
r  r  r  r   maxr  r   r  r  rl  )	r/  r  ro  Znormalized_dtrp  Z
input_costZoutput_costZ
total_costrn  r_  r  rd   re   get_sort_keyc$  sD   

z"_sort_models.<locals>.get_sort_key)rc  r_  zError sorting models by rZ   N)r  r   r  r   r`  r\  rx   rU  )r
  r  r  r  Zsorted_modelsre  rd   r  re   _sort_modelsH$  s    -r  total_countc                 C   s|   |du rt | }|d | }|dkr| |  nd}| |||  }td| d| d| d| d| 
 |||||d	S )
aD  
    Paginate models and return response dictionary.

    Args:
        all_models: List of all models
        page: Current page number
        size: Page size
        total_count: Total count (if None, uses len(all_models))
        search: Search term (for logging)

    Returns:
        Paginated response dictionary
    Nri  r   zPagination: skip=z, take=z, total_count=z, total_pages=z	, search=r  r  Zcurrent_pagetotal_pagesr  )r  rx   rS  )r
  r  r  r  r  skipr  Zpaginated_modelsrd   rd   re   _paginate_models_response$  s    r  c              
      s  z(|j jjd|idI dH }|du rtd| d g W S tdi | }W n! tyJ } ztd| dt	|  g W  Y d}~S d}~ww t
 }t|jdks\tjj|jv r|rb| ng }|dur|D ]1}	|	d	i d
d}
|
du r{qj|	d	i dd}d}|du rd}n||krd}|r||
 qjn-|jD ])}|r|j||dng }|dur|D ]}	|	d	i d
d}
|
dur||
 qqz+|jrtjj|jvr|j jjdd|jiidI dH }|D ]}|j}
|
r||
 qW n  ty } ztd| dt	|  W Y d}~nd}~ww g }| D ]B}|d	i }|d
d}
|ddr6|| q|dg }t|trN||v rN|| q|
r[|
|v r[|| q|S )a  
    Filter models by team ID. Returns models where:
    - direct_access is True, OR
    - team_id is in access_via_team_ids

    Also searches config and database for models accessible to the team.

    Args:
        all_models: List of models to filter
        team_id: Team ID to filter by
        prisma_client: Prisma client for database queries
        llm_router: Router instance for config queries

    Returns:
        Filtered list of models
    r^  r  NzTeam z not found in databasezError fetching team rZ   r   r  rb  FTr  r.  r  z(Error querying database models for team r  r  rd   )r~  r  r	  rx   rc  r9   r  r\  rU  r  r  r  r  r@   r  r  rM  r  r  r  r  rm  rS  r  r  r  )r
  r^  rN  rs  r  r  re  Zteam_accessible_model_idsr  r/  rm  r  r  r.  r  rv  rn  r  r  r  r  rd   rd   re   _filter_models_by_team_id$  s   






r  c              
      s  d}|dur|j | d}|rt|}|du rUz|jjjd| idI dH }|r4||g}|r4|d }W n tyT } zt	d|  dt
|  W Y d}~nd}~ww |duru|duru| ru|  }	|dd	}
|	|
 vrud}|dur||gng }t|}||fS )
z<Find a model by its ID and optionally filter by search term.Nry  rm  r  r   z$Error querying database for modelId rZ   r.  rg  )r  r  r  r~  r  r	  r  r\  rx   rU  r  r  r  r  r  )rm  r  rs  rN  r  Zfound_modelrn  r  re  r  r.  r
  r  rd   rd   re   _find_model_by_id9%  s>   
r  z/v2/model/infozv2 - returns models available to the user based on their API key permissions. Shows model info from config.yaml (except api key and api base). Filter to just user-added models with ?user_models_only=true)r  r  r  r/  z!Specify the model name (optional)z%Only return models added by this userz.Return all models across all teams user is in.ri  zPage number)r  ge2   z	Page sizez3Search model names (case-insensitive partial match)z,Search for a specific model by its unique IDzaFilter models by team ID. Returns models with direct_access=True or teamId in access_via_team_idszLField to sort by. Options: model_name, created_at, updated_at, costs, statuszSort order. Options: asc, descuser_models_onlyinclude_team_modelsmodelIdteamIdsortBy	sortOrderc              	      s  t du st jsg d|d|dS tdu rtddtjjidt I dH  |dur8t	||t ttdI dH \}}n.t
t j}tdurG|tg7 } durT fdd	|D }t||pYd
||tt|
dI dH \}}|rst|t | tdI dH }|rt| tt |dI dH }t|D ]\}}t||dur|ndt d||< q|	dur|	 rt||	 tt dI dH }t|}|durt|}|
r|r| dvrtdd| ddt||
|pdd}td| t|| dI dH }t|}t|||||dS )zQ
    BETA ENDPOINT. Might change unexpectedly. Use `/v1/model/info` for now.
    Nr   r  r  r  r@  )rm  r  rs  rN  r  c                    s   g | ]
}|d   kr|qS r  rd   r  rw  rd   re   r  %  rr  z!model_info_v2.<locals>.<listcomp>rg  )r
  r  r  r  rN  r  r  )r
  rs  r  rN  )r  rN  rs  r
  F)r/  rS  rs  )r
  r^  rN  rs  )r  r  r  zInvalid sortOrder: z. Must be 'asc' or 'desc'r  )r
  r  r  all_models: %s)r  r  )r
  r  r  r  r  )rs  r  rN  r  r)   r  r  r  r  r  r  r  rt  r  r  r  rD  r  r  r  r  r  r  rx   rS  r   r  )r  r/  r  r  rS  r  r  r  r  r  r  r  r
  r  rD  r  rd   rw  re   model_info_v2h%  s   .
	

	
r  z/model/streaming_metricsz1View time to first token for models in spend logs)r  r  r/  r  _selected_model_group	startTimeendTimec                    s  t d u rttjjddtjd|pt t	dd }|p t }|
 |
 k}|r.d}nd}t }t j||||I d H }i }|d ur|D ]U}	|	d }
|	d	 }|	d
 }d}|rh|	d }|}||vrgi ||< n|	d }|}|	d
 }||vrzi ||< t|}d|
v rt|
}d|v r|dd }|| ||| |< qG	 g }tt| dd d}|D ]}dt|i}||  D ]\}}|||< q|| q|t|dS d S )Ninternal_errorr  r     r  a  
            SELECT
                api_base,
                model_group,
                model,
                "startTime",
                request_id,
                EXTRACT(epoch FROM ("completionStartTime" - "startTime")) AS time_to_first_token
            FROM
                "LiteLLM_SpendLogs"
            WHERE
                "model_group" = $1 AND "cache_hit" != 'True'
                AND "completionStartTime" IS NOT NULL
                AND "completionStartTime" != "endTime"
                AND DATE("startTime") = DATE($2::timestamp)
            GROUP BY
                api_base,
                model_group,
                model,
                request_id
            ORDER BY
                time_to_first_token DESC;
        a  
            SELECT
                api_base,
                model_group,
                model,
                DATE_TRUNC('day', "startTime")::DATE AS day,
                AVG(EXTRACT(epoch FROM ("completionStartTime" - "startTime"))) AS time_to_first_token
            FROM
                "LiteLLM_SpendLogs"
            WHERE
                "startTime" BETWEEN $2::timestamp AND $3::timestamp
                AND "model_group" = $1 AND "cache_hit" != 'True'
                AND "completionStartTime" IS NOT NULL
                AND "completionStartTime" != "endTime"
            GROUP BY
                api_base,
                model_group,
                model,
                day
            ORDER BY
                time_to_first_token DESC;
        r0  r/  time_to_first_tokenrg  Z
request_idr  https:///openai/r   c                 S      | d S Nr   rd   r  rd   rd   re   <lambda>&      z)model_streaming_metrics.<locals>.<lambda>rb  dater  Zall_api_bases)rN  r>   r)   r  r  r'  r  r   r  r   r  r  r~  	query_rawr  r  r  r  r`  r  r  r  )r  r  r  r  Zis_same_day	sql_query_all_api_basesdb_response_daily_entriesr  	_api_baser  r  Z
unique_keyZ_request_id_day_combined_model_namer  r  r  	model_keylatencyrd   rd   re   model_streaming_metrics&  sn   



r  z/model/metricsz>View number of requests & avg latency per model on config.yamlz	gpt-4-32kr  customerc                    s  t d u rtdddtjd|pt ttd }|pt }|d u s'|dkr)d}|d u s1|dkr3d}d}t }t j	
||||||I d H }i }	|d ur|D ]D}
|
d	 }|
d
 }|
d }|
d }||	vrhi |	|< t|}|d urxd|v rxt|}|d urd|v r|dd }|| ||	| |< qN	 g }tt|	 dd d}	|	D ]}dt|i}|	|  D ]\}}|||< q|| q|t|dS d S )N Prisma Client is not initializedr  r  r  r  	undefinednulla  
        SELECT
            api_base,
            model_group,
            model,
            DATE_TRUNC('day', "startTime")::DATE AS day,
            AVG(EXTRACT(epoch FROM ("endTime" - "startTime")) / NULLIF("completion_tokens", 0)) AS avg_latency_per_token
        FROM
            "LiteLLM_SpendLogs"
        WHERE
            "startTime" >= $2::timestamp AND "startTime" <= $3::timestamp
            AND "model_group" = $1 AND "cache_hit" != 'True'
            AND (
                CASE
                    WHEN $4 != 'null' THEN "api_key" = $4
                    ELSE TRUE
                END
            )
            AND (
                CASE
                    WHEN $5 != 'null' THEN "end_user" = $5
                    ELSE TRUE
                END
            )
        GROUP BY
            api_base,
            model_group,
            model,
            day
        HAVING
            SUM(completion_tokens) > 0
        ORDER BY
            avg_latency_per_token DESC;
    r0  r/  r  Zavg_latency_per_tokenr  r  r   c                 S   r   r  rd   r  rd   rd   re   r  &  r  zmodel_metrics.<locals>.<lambda>rb  r  r  )rN  r>   r'  r  r   r  r   r   r  r~  r  r  r  r  r  r`  r  r  r  )r  r  r  r  r  r  r  r	  r
  r  r  r  r  r  Z_avg_latency_per_tokenr  r  r  r  r  r  rd   rd   re   model_metrics&  s^   "



r  z/model/metrics/slow_responsesz/View number of hanging requests per model_groupc              	      s   t d u rtdddtjd|d u s|dkrd}|d u s |dkr"d}|p,t ttd }|p2t }tj	j
p8t}t|}d}t j|||||||I d H }|d urm|D ]}	|	d	p\d
}
d|
v rh|
dd }
|
|	d	< qT|S )Nr  r  r  r  r  r  r  a  
SELECT
    api_base,
    COUNT(*) AS total_count,
    SUM(CASE
        WHEN ("endTime" - "startTime") >= (INTERVAL '1 SECOND' * CAST($1 AS INTEGER)) THEN 1
        ELSE 0
    END) AS slow_count
FROM
    "LiteLLM_SpendLogs"
WHERE
    "model_group" = $2
    AND "cache_hit" != 'True'
    AND "startTime" >= $3::timestamp
    AND "startTime" <= $4::timestamp
    AND (
        CASE
            WHEN $5 != 'null' THEN "api_key" = $5
            ELSE TRUE
        END
    )
    AND (
        CASE
            WHEN $6 != 'null' THEN "end_user" = $6
            ELSE TRUE
        END
    )
GROUP BY
    api_base
ORDER BY
    slow_count DESC;
    r0  rg  r  r   )rN  r>   r'  r  r   r  r   r   rq  r  r`  r    r  r~  r  r  r  )r  r  r  r  r  r  r`  r  r
  rowr  rd   rd   re   model_metrics_slow_responses	'  sF   !


r  z/model/metrics/exceptionsz7View number of failed requests per model on config.yamlc                    s   t d u rtdddtjd|pt ttd }|pt }|d u s'|dkr)d}	 d}t j	|||||I d H }g }t
 }		 |d urw|D ]1}
|
d	d
}|
dd}|
di }||d}|| || | D ]	\}}|	| qlqE|t|	dS )Nr  r  r  r  r  r  r  a?  
        WITH cte AS (
            SELECT
                CASE WHEN api_base = '' THEN litellm_model_name ELSE CONCAT(litellm_model_name, '-', api_base) END AS combined_model_api_base,
                exception_type,
                COUNT(*) AS num_rate_limit_exceptions
            FROM "LiteLLM_ErrorLogs"
            WHERE
                "startTime" >= $1::timestamp
                AND "endTime" <= $2::timestamp
                AND model_group = $3
            GROUP BY combined_model_api_base, exception_type
        )
        SELECT
            combined_model_api_base,
            COUNT(*) AS total_exceptions,
            json_object_agg(exception_type, num_rate_limit_exceptions) AS exception_counts
        FROM cte
        GROUP BY combined_model_api_base
        ORDER BY total_exceptions DESC
        LIMIT 200;
    Zcombined_model_api_baserg  total_exceptionsr   exception_counts)r/  r  )r  exception_types)rN  r>   r'  r  r   r  r   r   r~  r  r  r  r=  r  r  r  r  )r  r  r  r  r  r  r  r
  r  r  r  r/  r  r  Zcurr_rowr  r  rd   rd   re   model_metrics_exceptionsc'  sD   




r  c                 C   s  |  di }t| d}|i kr/|  di }| dd }ztj|d}W n ty.   i }Y nw |i kre|  di }| dd }|d}t|dkrN|d }ztj||d d}W n tyd   i }Y nw | D ]\}}||vru|||< qi|| d< t| d	hd
} | S )Nr  rw  r  r/  r  r   r  r  r  Zdeployment_dictr  )	r  r  rT  r  r\  r  r  r  r   )r/  r  r  r  r?  r  r  r  rd   rd   re   _get_proxy_model_info'  s@   


r  z/model/infoz/v1/model/infolitellm_model_idc              	      s  t dur5ztttjt d}W n ty   i }Y nw tdtt d|d}| }t	|dhd}d|iS t
du rAtdd	d
idtdu rMtdd	did|durutj|d}|du rgtdd	d| didt|jddd}d|giS g }tt}tdu rg }nt }t }t| ||d}	t| j||d}
t|	|
|t tddtd}t|dkrg }|D ]}tj|d}|dur|| qt
durt|}ng }|D ]}t|d}qtd| d|iS )a  
    Provides more info about each model in /models, including config.yaml descriptions (except api key and api base)

    Parameters:
        litellm_model_id: Optional[str] = None (this is the value of `x-litellm-model-id` returned in response headers)

        - When litellm_model_id is passed, it will return the info for that specific model
        - When litellm_model_id is not passed, it will return the info for all models

    Returns:
        Returns a dictionary containing information about each model.

    Example Response:
    ```json
    {
        "data": [
                    {
                        "model_name": "fake-openai-endpoint",
                        "litellm_params": {
                            "api_base": "https://exampleopenaiendpoint-production.up.railway.app/",
                            "model": "openai/fake"
                        },
                        "model_info": {
                            "id": "112f74fab24a7a5245d2ced3536dd8f5f9192c57ee6e332af0f0512e08bed5af",
                            "db_model": false
                        }
                    }
                ]
    }

    ```
    Nrw  r   r~  r  r  r  r  r  zLLM Model List not loaded in. Make sure you passed models in your config.yaml or on the LiteLLM Admin UI. - https://docs.litellm.ai/docs/proxy/configsr@  zLLM Router is not loaded in. Make sure you passed models in your config.yaml or on the LiteLLM Admin UI. - https://docs.litellm.ai/docs/proxy/configs)rm  r  zModel id = z not found on litellm proxyTr  )r  r   r  )r  r   r  r  F)r  r  r   rt  r  rs  r   r  r  ) rt  r   r   rT  r  r\  r   r   r  r   r  r  rs  Zget_deploymentr  rs   r  r  r  r   r   r  r   ru  r  r  rM  r  r  r  rx   rS  )r  r  r  Z_deployment_infoZ_deployment_info_dictZdeployment_infor
  r  r   r  r  all_models_strZ_relevant_modelsr/  Zrouter_modelsZin_place_modelrd   rd   re   model_info_v1'  s   0


	
r!  r   rx  c           	      C   s   g }g }|D ]}||vr| | q|D ]-}|d ur||krq| j|d}|d ur6| tdi |  qt|g d}| | qtjd urU|D ]}|jtjv rTd|_qI|S )N)rx  )rx  	providersTrd   )r  Zget_model_group_infor  r  rT  Zpublic_model_groupsrx  Zis_public_model_group)	rs  r   rx  model_groupsr  r/  Z_model_group_infomodel_group_infoZmgrd   rd   re   _get_model_group_infov(  s.   

r%  z/model_group/infoc                    sv   t du stdu st sdg iS ddlm} || tttttddddtdI dH }t	t||d}t
|| dI dH }d|iS )	a  
    Get information about all the deployments on litellm proxy, including config.yaml descriptions (except api key and api base)

    - /model_group/info returns all model groups. End users of proxy should use /model_group/info since those models will be used for /chat/completions, /embeddings, etc.
    - /model_group/info?model_group=rerank-english-v3.0 returns all model groups for a specific model group (`model_name` in config.yaml)



    Example Request (All Models):
    ```shell
    curl -X 'GET'     'http://localhost:4000/model_group/info'     -H 'accept: application/json'     -H 'x-api-key: sk-1234'
    ```

    Example Request (Specific Model Group):
    ```shell
    curl -X 'GET'     'http://localhost:4000/model_group/info?model_group=rerank-english-v3.0'     -H 'accept: application/json'     -H 'Authorization: Bearer sk-1234'
    ```

    Example Request (Specific Wildcard Model Group): (e.g. `model_name: openai/*` on config.yaml)
    ```shell
    curl -X 'GET'     'http://localhost:4000/model_group/info?model_group=openai/tts-1'
    -H 'accept: application/json'     -H 'Authorization: Bearersk-1234'
    ```

    Learn how to use and set wildcard models [here](https://docs.litellm.ai/docs/wildcard_routing)

    Example Response:
    ```json
        {
            "data": [
                {
                "model_group": "rerank-english-v3.0",
                "providers": [
                    "cohere"
                ],
                "max_input_tokens": null,
                "max_output_tokens": null,
                "input_cost_per_token": 0.0,
                "output_cost_per_token": 0.0,
                "mode": null,
                "tpm": null,
                "rpm": null,
                "supports_parallel_function_calling": false,
                "supports_vision": false,
                "supports_function_calling": false,
                "supported_openai_params": [
                    "stream",
                    "temperature",
                    "max_tokens",
                    "logit_bias",
                    "top_p",
                    "frequency_penalty",
                    "presence_penalty",
                    "stop",
                    "n",
                    "extra_headers"
                ]
                },
                {
                "model_group": "gpt-3.5-turbo",
                "providers": [
                    "openai"
                ],
                "max_input_tokens": 16385.0,
                "max_output_tokens": 4096.0,
                "input_cost_per_token": 1.5e-06,
                "output_cost_per_token": 2e-06,
                "mode": "chat",
                "tpm": null,
                "rpm": null,
                "supports_parallel_function_calling": false,
                "supports_vision": false,
                "supports_function_calling": true,
                "supported_openai_params": [
                    "frequency_penalty",
                    "logit_bias",
                    "logprobs",
                    "top_logprobs",
                    "max_tokens",
                    "max_completion_tokens",
                    "n",
                    "presence_penalty",
                    "seed",
                    "stop",
                    "stream",
                    "stream_options",
                    "temperature",
                    "top_p",
                    "tools",
                    "tool_choice",
                    "function_call",
                    "functions",
                    "max_retries",
                    "extra_headers",
                    "parallel_tool_calls",
                    "response_format"
                ]
                },
                {
                "model_group": "llava-hf",
                "providers": [
                    "openai"
                ],
                "max_input_tokens": null,
                "max_output_tokens": null,
                "input_cost_per_token": 0.0,
                "output_cost_per_token": 0.0,
                "mode": null,
                "tpm": null,
                "rpm": null,
                "supports_parallel_function_calling": false,
                "supports_vision": true,
                "supports_function_calling": false,
                "supported_openai_params": [
                    "frequency_penalty",
                    "logit_bias",
                    "logprobs",
                    "top_logprobs",
                    "max_tokens",
                    "max_completion_tokens",
                    "n",
                    "presence_penalty",
                    "seed",
                    "stop",
                    "stream",
                    "stream_options",
                    "temperature",
                    "top_p",
                    "tools",
                    "tool_choice",
                    "function_call",
                    "functions",
                    "max_retries",
                    "extra_headers",
                    "parallel_tool_calls",
                    "response_format"
                ]
                }
            ]
            }
    ```
    Nr  r   )r  Fr  )rs  r   rx  )r#  r  )r  rs  r  r  ru  rt  rN  rq  rr  r%  r   )r  rx  r  r   r#  rd   rd   re   r$  (  s4    #r$  z/model/settingszMReturns provider name, description, and required parameters for each providerc                     s0   g } t jD ]}| t|t j|dd q| S )a?  
    Used by UI to generate 'model add' page
    {
        field_name=field_name,
        field_type=allowed_args[field_name]["type"], # string/int
        field_description=field_info.description or "", # human-friendly description
        field_value=general_settings.get(field_name, None), # example value
    }
    r  )r  fields)rT  Zprovider_listr  ZProviderInfoZget_provider_fields)Zreturned_listr  rd   rd   re   model_settingsZ)  s   

r'  z/alerting/settingszFReturn the configurable alerting param, description, and current valuer_  c              
      s  	 t d u rtddtjjid| jtjkr%tdddtj	j| jidt j
jjddidI d H }|d urL|jd urLt|j}|di }|d	}ni }d }d
did
did
did
did
did
did
did
did
did	}tj}|j }g }d}	td	rttd	 trdtd	 v rd}	td|d d
 d|	|d urdndd dd}
||
 tj D ]5\}}||v rd }||v rd}nd}t||| d
 |jpd||d ||j|dkrdndd}
||
 q|S )Nr  r  r@  {}, your role={}r  ru  r  rc  r_  rU   BooleanInteger)	slack_alertingZdaily_report_frequencyZreport_check_intervalZbudget_alert_ttlZoutage_alert_ttlregion_outage_alert_ttlZminor_outage_alert_thresholdZmajor_outage_alert_thresholdZmax_outage_alert_list_sizeFre  Tr+  zhEnable slack alerting for monitoring proxy in production: llm outages, budgets, spend tracking failures.)
field_name
field_typefield_descriptionfield_valuestored_in_dbfield_default_valueZpremium_fieldrg  r,  )rN  r  r)   r  r  r  r;   r  rq   not_allowed_accessr~  r  r  r  r  r  rq  r  rc  r  ru  r  r  r.   r  r  model_fieldsr  r  rg   )r  r  db_general_settings_dictZalerting_args_dictZalerting_valuesallowed_argsZ_slack_alertingZ_slack_alerting_args_dict
return_valZis_slack_enabled_response_objr-  
field_info_stored_in_dbrd   rd   re   alerting_settings{)  s   	




	


r;  z/queue/chat/completionsr}  )r  r  r/  c                    s  	 i }z|   I d H }t| j| jt|  t|d|d< td| t	dd p5t
p5|p5|	dd |d< |	dd d u rJ|jd urJ|j|d< d|vrRi |d< |j|d d< |j|d d	< t|  }|d
d  ||d d< t|dd |d d< |j|d d< t|dd |d d< t|dd |d d< t|dd |d d< t| j|d d< trt|d< trt|d< trt|d< trt|d< td u rtddtjjidtjd-i |I d H }d|v r|d du rtt|||dd d!W S |jd"t|d# i |W S  tyS } zGtj |||d$I d H  t!|tr5t"t|d%d&t| d't#j$t|d(d)t|d*t%j&d+t!|t"r=|t"d,t| t#j$t|d(d)t%j&d+d }~ww ).N)r  rV   r  rQ  Zproxy_server_requestzreceiving data: %sZcompletion_modelr/  r  r  Zuser_api_keyZuser_api_key_metadataauthorizationr  rf  Zuser_api_key_aliasr  r^  r  Zobject_permission_idZ!user_api_key_object_permission_idZteam_object_permission_idZ&user_api_key_team_object_permission_idr  ro  rp  rn  r0  r  r  r@  r  Tr  r"  r$  zx-litellm-prioritypriorityr  rA  Authentication Error(r@  r  r  r  r  Authentication Error, rd   )'r  r  r  rV   r   r  rx   rS  ru  r  rt  r\  r  r  r  r  r{  r|  r  rz  rs  r  r)   rz  r  Zschedule_acompletionr1  r  r  r=  r\  rq  r  r  r>   r=   
auth_errorr'  r-  )r  r  r/  r  r  _headersr  re  rd   rd   re   async_queue_request)  s   



	


rC  )r  r/  c                    s   ddl m} tt| j}td}|dr|d7 }n|d7 }|dur4ddlm	} |t
d	d
ddS ddlm	} |t
d	d
ddS )z
    Create Proxy API Keys using Google Workspace SSO. Requires setting PROXY_BASE_URL in .env
    PROXY_BASE_URL should be the your deployed proxy endpoint, e.g. PROXY_BASE_URL="https://litellm-production-7002.up.railway.app/"
    Example:
    r   )ui_linkZUI_USERNAMEr  zsso/callbackz/sso/callbackN)HTMLResponseF)Zshow_deprecation_bannerr  r  r  )Zlitellm.proxy.proxy_serverrD  r   r  base_urlr  rS  r!  fastapi.responsesrE  r   )r  rD  redirect_urlZui_usernamerE  rd   rd   re   fallback_loginc*  s    




rJ  z/loginc                    s   ddl m}m} ddlm} |  I d H }t|d}t|d}|||tt	dI d H }||t
td}dd l}	|	jtt|tttdd	}
|t| j}|d
rY|d7 }n|d7 }|d7 }t|dd}|jd|
d |S )Nr   authenticate_usercreate_ui_token_objectr   usernamer  rO  r  rC  rN  login_resultru  r9  HS256	algorithmr  ui//ui/?login=successi/  )r  r  r[  rc  r  )litellm.proxy.auth.login_utilsrL  rM  r  r   formr  r  rC  rN  ru  r9  jwtencoder   r  rG  r!  r0  
set_cookie)r  rL  rM  r   r[  rO  r  rR  returned_ui_token_objectr\  	jwt_tokenlitellm_dashboard_uiZredirect_responserd   rd   re   login*  s>   

rb  z	/v2/loginc                    s|  ddl m}m} ddlm} ze|  I d H }t|d}t|d}|||tt	dI d H }||t
td}dd l}	|	jtt|tttdd	}
|t| j}|d
rZ|d7 }n|d7 }|d7 }td|itjd}|jd|
d |W S  ty } z=tdt| t|tr|t|trtt|dt|tjt|ddt|dtj dt| }t|tjdtj dd }~ww )Nr   rK  rN  rO  r  rP  rQ  rS  rT  r  rV  rW  rX  rI  rF  r[  rY  z>litellm.proxy.proxy_server.login_v2(): Exception occurred - {}rA  r  r  r  r  )!rZ  rL  rM  r  r   r  r  r  rC  rN  ru  r9  r\  r]  r   r  rG  r!  r.  r'  ZHTTP_200_OKr^  r\  rx   rU  rq   r  r>   r  r  r=   rA  r  )r  rL  rM  r   rQ  rO  r  rR  r_  r\  r`  ra  Zjson_responsere  r  rd   rd   re   login_v2*  sv   





rc  z/onboarding/get_tokeninvite_linkc                    s  ddl m} tdu rtdtjdtjdtdu r#t	ddt
jjid	tjjjd
| idI dH }|du r<t	dddid	tj  }|j }||k rTt	dddid	|jdu rat	dddid	tjjjd|jidI dH }|du r{t	dddid	|j}td#ddi|jttjg i i d|jdd	I dH }|d }	tt|j}
|
 dr|
d7 }
n|
d7 }
ddl!}t" }||j|	|j|jdt#t$%dd|t& d	}|j't(t)|tdd }|
d!*||7 }
|
||d"S )$z
    - Get the invite link
    - Validate it's still 'valid'
    - Invalidate the link (prevents abuse)
    - Get user from db
    - Pass in user_email if set
    r   )ReturnedUITokenObjectNzMaster Key not set for Proxy. Please set Master Key to use Admin UI. Set `LITELLM_MASTER_KEY` in .env or set general_settings:master_key in config.yaml.  https://docs.litellm.ai/docs/proxy/virtual_keys. If set, use `--detailed_debug` to debug issue.rC  r  r  r  r@  rb  r    %Invitation link does not exist in db.Invitation link has expired.T&Invitation link has already been used.r\  User does not exist in db.r  rc  zlitellm-dashboard)	r  r  Zkey_max_budgetr  r  r  re  r\  r^  r[  r  zui/onboardingz/ui/onboardingZusername_passwordZlitellm_key_header_nameAuthorization)	r\  rc  
user_emailr  Zlogin_methodr9  Zauth_header_name(disabled_non_admin_personal_key_creationr  rS  rT  z?token={}&user_email={})Z	login_urlr[  rl  rd   )+Zlitellm.types.proxy.ui_ssore  rC  r>   r=   rA  r'  r  rN  r  r)   r  r  r~  litellm_invitationlinkr	  rT  r)  get_utc_datetimer  
expires_atis_acceptedr  r\  rl  r   r  r$   Zmax_ui_session_budgetr   r  rG  r!  r\  r   r9  ru  r  r   r]  r   r  rq   )rd  r  re  
invite_objutc_now_dateexpires_at_dateuser_objrl  r  rc  ra  r\  rm  r_  r`  rd   rd   re   
onboarding*  s   





rv  z/onboarding/claim_tokenr  c                    sB  t du rtddtjjidt jjjd| jidI dH }|du r)tdddidt	j
  }|j }||k rAtddd	id|jd
u rNtdddid|j| jkrbtddd| j|jidt| jd}t jjjd|jid|idI dH }|du rtdddidt	j
 }t jjjd| ji||d
|jddI dH  |S )a&  
    Special route. Allows UI link share user to update their password.

    - Get the invite link
    - Validate it's still 'valid'
    - Check if user within initial session (prevents abuse)
    - Get user from db
    - Update user password

    This route can only update user password.
    Nr  r  r@  rb  r  rf  rg  rh  Tri  zwInvalid invitation link. The user id submitted does not match the user id this link is attached to. Got={}, Expected={}ra  r\  r  r%  rj  )accepted_atrp  rq  rr  )rN  r  r)   r  r  r~  rn  r	  Zinvitation_linkrT  r)  ro  r  rp  rq  r\  rq   r   r  r  r=  )r  rr  rs  rt  Zhash_passwordru  r0  rd   rd   re   claim_onboarding_linkq+  sd   


	

rx  z/get_logo_urlc                  C   s   t dd} d| iS )z)Get the current logo URL from environmentUI_LOGO_PATHrg  Zlogo_url)r  rS  )	logo_pathrd   rd   re   get_logo_url+  s   r{  z
/get_imagec               
      s  t jt jt} t j| d}t dd dk}|r dn| }t d|}t j|sbzt j	|dd t
d	|  W n" ttfya } zt
d
| d| d | }W Y d}~nd}~ww || krmt j|dn|}|| kr{t j|s{|}t |t jr|n| }t j|d}t d|}	t
d|	 |	|kr|	dst j|	rt|	ddS t
d|	 d |}	t j|rt|ddS |	dr=zMddlm}
 ddlm} |
|jddid}||	I dH }|jdkrt|d}||j W d   n	1 sw   Y  t|ddW S t|ddW S  ty< } zt
d|	 d|  t|ddW  Y d}~S d}~ww t|	ddS )zGet logo to show on admin UIzlogo.jpgr  rg  r  z/var/lib/litellm/assetsZLITELLM_ASSETS_PATHTr  zCreated assets directory at z"Cannot create assets directory at rZ   z@. Logo caching may not work. Using current directory for assets.Nzcached_logo.jpgry  zReading logo from path: %szhttp://r  z
image/jpegr=  zUI_LOGO_PATH 'z.' does not exist, falling back to default logor   get_async_httpx_clienthttpxSpecialProvidertimeout      @Zllm_providerrl  r  wbzError downloading logo from )r  rW   r  r  __file__r  rS  r  r   r  rx   rS  r  r  rc  accessW_OKr  r-  &litellm.llms.custom_httpx.http_handlerr~  litellm.types.llms.custom_httpr  UIr  r  r  r]   r  r\  )r+  Zdefault_site_logois_non_rootZdefault_assets_dirZ
assets_dirre  Zdefault_logo	cache_dir
cache_pathrz  r~  r  async_clientr  frd   rd   re   	get_image+  sr   

r  z/get_faviconc            
   
      s  ddl m}  tjtjt}tj|ddd}tdd}|s4tj	|r.t
|dd	S td
dd|drzLddlm} ddlm} ||jddid}||I dH }|jdkrk|jdd}| |j|dW S td||j tj	|rt
|dd	W S td
dd ty     ty }	 ztd||	 tj	|rt
|dd	W  Y d}	~	S td
ddd}	~	ww tj	|rt
|dd	S tj	|rt
|dd	S td
dd)z$Get custom favicon for the admin UI.r   r"  r  r  zfavicon.icoZLITELLM_FAVICON_URLrg  zimage/x-iconr=  r  zDefault favicon not foundr@  r|  r}  r  r  r  r  Nr  content-type)r  r$  z*Failed to fetch favicon from %s: status %szFavicon not foundz%Error downloading favicon from %s: %s)rH  r"  r  rW   r  r  r  r  rS  r   r-  r  r  r  r~  r  r  r  r  r  r  r  rx   rc  r\  rS  )
r"  r+  Zdefault_faviconZfavicon_urlr~  r  r  r  content_typere  rd   rd   re   get_favicon,  s`   

r  z/invitation/newzInvite Links)r  r  r  r/  c              
      s   z_ddl m} tdu rtddtjjid|jtj	kp&t
|tttdI dH }|s8tdddtjj|jid|jtj	krUt| j|tttd	I dH }|sUtddd
id|| |dI dH }|W S  typ } zt|d}~ww )%  
    Allow admin to create invite links, to onboard new users to Admin UI.

    ```
    curl -X POST 'http://localhost:4000/invitation/new'         -H 'Content-Type: application/json'         -d '{
            "user_id": "1234" // 👈 id of user in 'LiteLLM_UserTable'
        }'
    ```
    r   )create_invitation_for_userNr  r  r@  r  r(  )Ztarget_user_idr  rN  rr  rq  zGYou can only create invitations for users in your organization or team.)r  r  )Z0litellm.proxy.management_helpers.user_invitationr  rN  r  r)   r  r  r  r;   r  r   rr  rq  rq   r3  r   r\  r\  r   )r  r  r  Z
has_accessZ
can_inviter  re  rd   rd   re   new_invitation[,  s`   

	r  z/invitation/infoinvitation_idc                    s~   t du rtddtjjid|jtjkr$tdddtj	j|jidt j
jjd| idI dH }|du r=tdddid|S )	r  Nr  r  r@  r(  rb  r  -Invitation id does not exist in the database.)rN  r  r)   r  r  r  r;   r  rq   r3  r~  rn  r	  )r  r  r  rd   rd   re   invitation_info,  s0   

r  z/invitation/updatec                    s   t du rtddtjjid|jdu r tddd|jidtj	 }t j
jjd| ji| j| j|||jdd	I dH }|du rItddd
id|S )uV  
    Update when invitation is accepted

    ```
    curl -X POST 'http://localhost:4000/invitation/update'         -H 'Content-Type: application/json'         -d '{
            "invitation_id": "1234" // 👈 id of invitation in 'LiteLLM_InvitationTable'
            "is_accepted": True // when invitation is accepted
        }'
    ```
    Nr  r  r@  r  z'Unable to identify user id. Received={}rb  )rb  rq  rw  rp  rr  r%  r  )rN  r  r)   r  r  r\  rq   rT  r)  ro  r~  rn  r=  r  rq  )r  r  r0  r  rd   rd   re   invitation_update,  s<   


	r  z/invitation/deletec                    s   t du rtddtjjid|jtjk}t|t t	t
dI dH }|s3|s3tdddtjj|jid|r_|s_t jjjd| jidI dH }|du rQtddd	id|j|jkr_td
ddidt jjjd| jidI dH }|du rytddd	id|S )u  
    Delete invitation link

    ```
    curl -X POST 'http://localhost:4000/invitation/delete'         -H 'Content-Type: application/json'         -d '{
            "invitation_id": "1234" // 👈 id of invitation in 'LiteLLM_InvitationTable'
        }'
    ```
    Nr  r  r@  r  r(  rb  r  r    z=Organization admins can only delete invitations they created.)rN  r  r)   r  r  r  r;   r  r   rr  rq  rq   r3  r~  rn  r	  r  rq  r\  delete)r  r  Zis_proxy_adminZis_other_adminZ
invitationr  rd   rd   re   invitation_delete-  s\   
r  z/config/updatezconfig.yamlconfig_infoc                    s,  z9ddl }	 tdu rtdtdurtdddid| jdd	}t|}| D ]\}}|d
krItjj	j
d|i||dd|iddI dH  q+t I dH }td| | jdur|di  | jjdd	}|d }| D ]*\}}|dkrd|vrddgi}nt|d trd|d vr|d d |||< qq||d< | jdur|di  | j}| D ]\}}t|d}	|	||< q|d }
| D ]
\}}|| |
|< q| jdur$|di  | j}i ||d |d< d|v r$d|d v r$t|d d tr$t|d tr$t|d }|d d | }tt|}||d d< tj|dI dH  tjttdI dH  ddiW S  ty } zMtdt| tt !  t|trwt"t#|ddt| d t$j%t#|d!d"t#|d#t&j'd$t|t"r|t"d%t| t$j%t#|d!d"t&j'd$d}~ww )&z
    For Admin UI - allows admin to update config via UI

    Currently supports modifying General Settings + LiteLLM settings
    r   NzNo DB ConnectedTr  r  CSet `'STORE_MODEL_IN_DB='True'` in your env to enable this feature.r@  r  r  r  r"  r  r#  r%  zLoaded config: %sru  rb  r_  re  r  r  rv  rY  r  r  r^   zConfig updated successfullyzBlitellm.proxy.proxy_server.update_config(): Exception occured - {}rA  r?  r@  r  r  r  r  r@  )(r  rN  r\  r=  r  r  Zjsonify_objectr  r~  r  r/  r  r  rx   rS  ru  r  r  r  r  r  r  r   rv  rF   r  r  r  rq  r  rq   r  rt  ru  r>   r  r=   rA  r'  r-  )r  r  Zupdated_settingsr  r  r  Zupdated_general_settingsZ_existing_settingsZ_updated_environment_variablesr  Z_existing_env_variablesZupdated_litellm_settingsZ$updated_success_callbacks_normalizedZcombined_success_callbackre  rd   rd   re   update_confign-  s   











r  z/config/field/updatec              
      s.  	 t du rtddtjjid|jtjkr tddtjjid| j	t
jvr2tddd| j	idzt
di | j	| ji W n tyT   tdddt| jidw t jjjddid	I dH }|du sk|jdu rni }nt|j}| j|| j	< t jjjddidt|d
dt|iddI dH }|S )z=
    Update a specific field in litellm general settings
    Nr  r  r@  Invalid field={} passed in.z)Invalid type of field value={} passed in.r  ru  r  r"  r  r#  r%  rd   )rN  r  r)   r  r  r  r;   r  r3  r-  r-   r4  rq   r0  r\  rU   r~  r  r  r  r  r/  r  rg  r  r  r  ru  r  rd   rd   re   update_config_general_settings	.  sT   


r  z/config/field/infor-  c                    s   	 t d u rtddtjjid|jtjkr tddtjjid| t	j
vr0tddd| idt jjjddidI d H }|d u sF|jd u rQtddd| idt|j}| |v rbt| ||  d	S tddd| id)
Nr  r  r@  r  r  ru  r  zField name={} not in DB)r-  r0  )rN  r  r)   r  r  r  r;   r  r3  r-   r4  rq   r~  r  r  r  r  r+   )r-  r  r  ru  rd   rd   re   get_config_general_settingsW.  sD   



r  z/config/listr  c                    sT  	 t du rtddtjjid|jtjkr%tdddtj	j|jidt j
jjddidI dH }|durA|jdurAt|j}ni }d	d
id	d
id	d
id	d
id	did	did	did	did	did	did	did	did}g }tj D ]\}}||v r'|| d	 }|dkr|dkrtg}	ng }	|	D ]W}
dd |
j D }d}|
j D ]\}}t|dr|jdur|j|| _|d7 }qd}||v rd}n|tv rd}t||| d	 |jpdt|d||j|d}|| qqqd}d}||v rd}n|tv rd}t|d}|du r||v r|| }t||| d	 |jpd|||j|d}|| qq|S )z
    List the available fields + current values for a given type of setting (currently just 'general_settings'user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),)
    Nr  r  r@  r(  r  ru  r  rU   r*  ZPydanticModelr)  Stringr	   )r  r  Zmax_request_size_mbZmax_response_size_mbr)  r=  r  r  Zmcp_internal_ip_rangesZmcp_trusted_proxy_rangesZalways_include_stream_usageZ!forward_client_headers_to_llm_apir)  c              
   S   s,   g | ]\}}t ||jd t|dddqS )rg  N)r-  r.  r/  r2  r1  )r1   r\   ru  r  )r  	sub_fieldZsub_field_typerd   rd   re   r  .  s    
z#get_config_list.<locals>.<listcomp>r   r  ri  TFrg  )r-  r.  r/  r0  r1  r2  nested_fields)rN  r  r)   r  r  r  r;   r  rq   r3  r~  r  r  r  r  r-   r4  r  r<   __annotations__r  r  r/  ru  r.   r  rg   r  )r  r  r  r5  r6  r7  r-  r9  Ztyped_dict_typeZpydantic_class_listZpydantic_classr  rO  r  Zsub_field_infor:  r8  Z_field_valuerd   rd   re   get_config_list.  s   





	-


	r  z/config/field/deletec                    s  	 t du rtddtjjid|jtjkr%tdddtj	j|jid| j
tjvr7tddd| j
idt jjjddid	I dH }|du sM|jdu rYtddd
| j
idt|j}|| j
d t jjjddidt|ddt|iddI dH }|S )z|
    Delete the db value of this field in litellm general settings. Resets it to it's initial default value on litellm.
    Nr  r  r@  r(  r  r  ru  r  zField name={} not in configr"  r  r#  r%  )rN  r  r)   r  r  r  r;   r  rq   r3  r-  r-   r4  r~  r  r  r  r  r  r/  r  rg  r  rd   rd   re   delete_config_general_settings)/  sL   


r  z/config/callback/deletec              
      st  t du rtddtjjid|jtjkr$tdddtj	j|jidt
dur0tdddidzWt I dH }| j }|d	i }|d
g }||vrYtddd| did|| ||d	i d
< tj|dI dH  tjt tdI dH  d| ||t  dW S  ty     ty } ztdt|  tt  tdt| t j!dt"j#dd}~ww )z>
    Delete specific logging callback from configuration.
    Nr  r  r@  r(  Tr  r  rv  rY  r  z
Callback 'z#' not found in active configurationr  r  zSuccessfully deleted callback: )r^   Zremoved_callbackZremaining_callbacksZ
deleted_atzClitellm.proxy.proxy_server.delete_callback(): Exception occurred - zError deleting callback: callback_namer  )$rN  r  r)   r  r  r  r;   r  rq   r3  r=  r  r  r  r  r  remover  r  r  rq  r   r  r.  r\  rx   r  r  rS  rt  ru  r>   r=   internal_server_errorr'  r  )r  r  r  r  rv  r  re  rd   rd   re   delete_callbackq/  sz   






r  z/get/config/callbacks)r  r/  r  c                     s  zddl } t }t I dH }|di }|di }|di }|dg }|dg }|dg }d	d
 }	|	|}|	|}|	|}g }
	 |D ]}|
t|d| qI|D ]}|
t|d| qW|D ]}|
t|d| qe|dg }g }d|v rdg}i }|D ]!}||d}|du rtdd}|||< qt	||d}|||< qt
jj}t
j }t
jj}|d|||d g d}i }|D ]}||d}|du rd||< qt	||d}|||< q|d|d tdu ri }nt }d|
|||dW S  tyO } zFtdt| t|tr1tt|ddt| dtjt|ddt|dtjdt|tr9|tdt| tjt|ddtjdd}~ww ) z~
    For Admin UI - allows admin to view config via UI
    # return the callbacks and the env variables for the callback

    r   Nrv  ru  r  rY  r  r
  c                 S   s    t | tr| gS | d u rg S | S rB  )r  r  )rN  rd   rd   re   normalize_callback/  s
   
z&get_config.<locals>.normalize_callbackr  r  Zsuccess_and_failurer_  re  ZSLACK_WEBHOOK_URLr[  )r  	variablesZactive_alertsZalerts_to_webhook)Z	SMTP_HOST	SMTP_PORTZSMTP_USERNAMEZSMTP_PASSWORDZSMTP_SENDER_EMAILZTEST_EMAIL_ADDRESSZEMAIL_LOGO_URLZEMAIL_SUPPORT_CONTACTemail)r  r  )r'  r
  Zalertsr  Zavailable_callbacksz?litellm.proxy.proxy_server.get_config(): Exception occured - {}rA  r?  r@  r  r  r  r  r@  )r  ZAllCallbacksr  r  r  r  rG   r  rS  r   rq  r  ra  Z_all_possible_alert_typesrb  rs  Zget_settingsr\  rx   rU  rq   r  r  r  r>   r  r=   rA  r'  r-  )r  Zall_available_callbacksr  r  r  r  Z_success_callbacksZ_failure_callbacksZ_success_and_failure_callbacksr  Z_data_to_return	_callbackZ	_alertingZalerting_dataZ_slack_varsZ_slack_env_varsZ_varZenv_variabler  Z_decrypted_valueZ_alerting_typesZ_all_alert_typesZ_alerts_to_webhookZ_email_varsZ_email_env_varsZ_router_settingsre  rd   rd   re   r  /  s   



	





r  z/config/yamlc                    s
   ddiS )a  
    This is a mock endpoint, to show what you can set in config.yaml details in the Swagger UI.

    Parameters:

    The config.yaml object has the following attributes:
    - **model_list**: *Optional[List[ModelParams]]* - A list of supported models on the server, along with model-specific configurations. ModelParams includes "model_name" (name of the model), "litellm_params" (litellm-specific parameters for the model), and "model_info" (additional info about the model such as id, mode, cost per token, etc).

    - **litellm_settings**: *Optional[dict]*: Settings for the litellm module. You can specify multiple properties like "drop_params", "set_verbose", "api_base", "cache".

    - **general_settings**: *Optional[ConfigGeneralSettings]*: General settings for the server like "completion_model" (default model for chat completion calls), "use_azure_key_vault" (option to load keys from azure key vault), "master_key" (key required for all calls to proxy), and others.

    Please, refer to each class's description for a better understanding of the specific attributes within them.

    Note: This is a mock endpoint primarily meant for demonstration purposes, and does not actually provide or change any configurations.
    ZhelloZworldrd   )r  rd   rd   re   config_yaml_endpointz0  s   r  z/reload/model_cost_mapc           	   
      sn  | j tjkrtdd| j  dztdu rtdddddlm} tj}||d	}|t_	t
  tj|d
 t }| atjjjddidI dH }d}|rX|jrX|jd}tjjjddidtdddddt|ddiddI dH  |r~t|nd}td|  d| dd|| dW S  ty } ztdt|  tddt| dd}~ww )z
    ADMIN ONLY / MASTER KEY Only Endpoint

    Manually reload the model cost map from the remote source.
    This will fetch fresh pricing data from the model_prices_and_context_window.json file.
    r  2Access denied. Admin role required. Current role: r@  Nr  !Database connection not availabler   r  r0  r   r  r  r  r  Tr!  r"  r  r#  r%  zCModel cost map reloaded successfully in current pod. Models count: z"Price data reloaded successfully! z models updated.r  )r^   r'  models_count	timestampz!Failed to reload model cost map: )r  r;   r  r  rN  r*  r  rT  r+  r,  rN   r-  r   r&  r.  r'  r~  r  r	  r  r  r/  r&   r  rx   rR  r\  rU  r  )	r  r  r+  r5  r0  Zexisting_configZexisting_intervalr  re  rd   rd   re   reload_model_cost_map0  sf   



r  z/schedule/model_cost_map_reloadhoursc              
         |j tjkrtdd|j  d| dkrtdddzCtdu r&tdd	dtjjjd
didt| ddddt| ddiddI dH  t	
d|  d d|  dd| t  dW S  ty } zt	dt|  tddt| dd}~ww )z
    ADMIN ONLY / MASTER KEY Only Endpoint

    Schedule periodic reload of the model cost map.
    This will create a background job that reloads the model cost map every specified hours.
    r  r  r@  r   r  Hours must be greater than 0Nr  r  r  r  Fr!  r"  r  r#  r%  z*Model cost map reload scheduled for every  hoursr  r^   r'  r  r  z*Failed to schedule model cost map reload: r  r;   r  r  rN  r~  r  r/  r&   rx   rR  r   r&  r.  r\  rU  r  r  r  re  rd   rd   re   schedule_model_cost_map_reload0  X   



r  c              
         | j tjkrtdd| j  dz'tdu rtdddtjjjddid	I dH  t	d
 d
dt
  dW S  tyY } ztdt|  tddt| dd}~ww )zp
    ADMIN ONLY / MASTER KEY Only Endpoint

    Cancel the scheduled periodic reload of the model cost map.
    r  r  r@  Nr  r  r  r  r  z(Model cost map reload schedule cancelledr  r^   r'  r  z(Failed to cancel model cost map reload: r  r;   r  r  rN  r~  r  r  rx   rR  r   r&  r.  r\  rU  r  r  re  rd   rd   re   cancel_model_cost_map_reload01  s8   


r  z&/schedule/model_cost_map_reload/statusc           
   
        | j tjkrtdd| j  dztdt  tdu r+td dddddW S tjj	j
d	d
idI dH }|du sA|jdu rNtd dddddW S |j}|d}|du rgtd dddddW S t }d}tdurztt}|| }| d }||k r|t|d  }W n ty }	 ztd|	  W Y d}	~	nd}	~	ww d|t|dW S  ty }	 ztdt|	  tddt|	 dd}	~	ww )zo
    ADMIN ONLY / MASTER KEY Only Endpoint

    Get the status of the scheduled model cost map reload job.
    r  r  r@  z4Checking model cost map reload status. Last reload: N/No database connection, returning not scheduledFZ	scheduledr  Zlast_runnext_runr  r  r  z,No model cost map reload configuration foundr  /No interval configured, returning not scheduledr8  r  r  Tz,Failed to get model cost map reload status: r  )r  r;   r  r  rx   rR  r'  rN  r~  r  r	  r  r  r   r&  r(  r)  r   r.  r\  rc  rU  r  
r  r  r  r  r0  r  r2  r3  r4  re  rd   rd   re    get_model_cost_map_reload_statusa1  s   





r  z/model/cost_map/sourcec              
      s   | j tjkrtdd| j  dzddlm} | }tjr#ttjnd}i |d|iW S  t	yN } zt
dt|  tddt| dd	}~ww )
a  
    ADMIN ONLY / MASTER KEY Only Endpoint

    Returns information about where the current model cost/pricing data was loaded from.

    Response fields:
    - source: "local" (bundled backup) or "remote" (fetched from URL)
    - url: the remote URL that was attempted (null when env-forced local)
    - is_env_forced: true if LITELLM_LOCAL_MODEL_COST_MAP=True forced local usage
    - fallback_reason: human-readable reason why remote failed (null on success)
    - model_count: number of models in the currently loaded cost map
    r  r  r@  r   )get_model_cost_map_source_infomodel_countz*Failed to get model cost map source info: r  N)r  r;   r  r  r*  r  rT  r,  r  r\  rx   rU  r  )r  r  Zsource_infor  re  rd   rd   re   get_model_cost_map_source1  s2   
r  z/reload/anthropic_beta_headersc              
      sR  | j tjkrtdd| j  dzvtdu rtdddddlm} | }t }|	 a
tjjjd	d
idI dH }d}|rG|jrG|jd}tjjjd	d
id
tdddddt|ddiddI dH  tdd | D }td|  d| dd||	 dW S  ty } ztdt|  tddt| dd}~ww )z
    ADMIN ONLY / MASTER KEY Only Endpoint

    Manually reload the Anthropic beta headers configuration from the remote source.
    This will fetch fresh configuration from the anthropic_beta_headers_config.json file.
    r  r  r@  Nr  r  r   r7  r  r6  r  r  Tr!  r"  r  r#  r%  c                 s   s    | ]	}|d vrdV  qdS ))r9  r  ri  Nrd   r:  rd   rd   re   r  12  s    z0reload_anthropic_beta_headers.<locals>.<genexpr>zOAnthropic beta headers config reloaded successfully in current pod. Providers: z<Anthropic beta headers configuration reloaded successfully! z providers updated.r  )r^   r'  Zproviders_countr  z)Failed to reload anthropic beta headers: )r  r;   r  r  rN  r<  r8  r   r&  r.  r;  r~  r  r	  r  r  r/  r&   r=  r  rx   rR  r\  rU  r  )r  r8  r  r0  Zexisting_beta_configZexisting_beta_intervalr>  re  rd   rd   re   reload_anthropic_beta_headers1  sf   


r  z'/schedule/anthropic_beta_headers_reloadc              
      r  )z
    ADMIN ONLY / MASTER KEY Only Endpoint

    Schedule periodic reload of the Anthropic beta headers configuration.
    This will create a background job that reloads the configuration every specified hours.
    r  r  r@  r   r  r  Nr  r  r  r6  Fr!  r"  r  r#  r%  z2Anthropic beta headers reload scheduled for every r  r  r  z2Failed to schedule anthropic beta headers reload: r  r  rd   rd   re   &schedule_anthropic_beta_headers_reloadG2  r  r  c              
      r  )z
    ADMIN ONLY / MASTER KEY Only Endpoint

    Cancel the scheduled periodic reload of the Anthropic beta headers configuration.
    r  r  r@  Nr  r  r  r6  r  z0Anthropic beta headers reload schedule cancelledr  r  z0Failed to cancel anthropic beta headers reload: r  r  rd   rd   re   $cancel_anthropic_beta_headers_reload2  s:   


r  z./schedule/anthropic_beta_headers_reload/statusc           
   
      r  )zw
    ADMIN ONLY / MASTER KEY Only Endpoint

    Get the status of the scheduled Anthropic beta headers reload job.
    r  r  r@  z<Checking anthropic beta headers reload status. Last reload: Nr  Fr  r  r6  r  z4No anthropic beta headers reload configuration foundr  r  r8  r  r  Tz4Failed to get anthropic beta headers reload status: r  )r  r;   r  r  rx   rR  r;  rN  r~  r  r	  r  r  r   r&  r(  r)  r   r.  r\  rc  rU  r  r  rd   rd   re   (get_anthropic_beta_headers_reload_status2  s   



r  )r  c                    s   dS )NzLiteLLM: RUNNINGrd   r  rd   rd   re   home$3  s   r  z/routesc                     sv   ddl m}  g }tjD ]*}t|dd}|dur#|| j||d qt|dr6t|dr6|| j|d qd	|iS )
zD
    Get a list of available routes in the FastAPI application.
    r   )	GetRoutesr  N)r  endpoint_router   rW   )r  r  )	Z%litellm.proxy.common_utils.get_routesr  r   r  r  r  Zget_app_routesr  Zget_routes_for_mounted_app)r  r  r  r  rd   rd   re   
get_routes)3  s    
r  z/{mcp_server_name}/mcp)GETrT   PUTDELETEPATCHOPTIONSHEAD)methodsmcp_server_namec              
      sN  ztddl m} ddlm} ddlm} ||}|j| |d}|du r.tdd|  d	d
t	|j
}d|  |d< ddlm} dd dg  fdd}	|||j|	dI dH  ddlm}
 dd D }|
 ||dddW S  ty } z|d}~w ty } ztd|  dt|  tddt| d
d}~ww )z5Handle dynamic MCP server routes like /github_mcp/mcpr   rQ  )IPAddressUtils)MCPAuth)	client_ipNr  zMCP server 'z' not foundr@  z/mcp/rW   )handle_streamable_http_mcpF    r  c                    sN   | d dkrd| d |  dg d S | d dkr% |  dd7  d S d S )	NrU   zhttp.response.startTr'  r  zhttp.response.bodyrQ  r  r  )r^   Zresponse_bodyresponse_headersZresponse_startedZresponse_statusrd   re   custom_send3  s   z&dynamic_mcp_route.<locals>.custom_send)receivesendr  c                 S   s   i | ]\}}|  |  qS rd   )rB  )r  r  r  rd   rd   re   r  3  r]  z%dynamic_mcp_route.<locals>.<dictcomp>r  zapplication/json)r  r  r  r$  z%Error handling dynamic MCP route for rZ   r  zInternal server error: )rW  rR  Z#litellm.proxy.auth.ip_address_utilsr  Zlitellm.types.mcpr  Zget_mcp_client_ipZget_mcp_server_by_namer  r  r  -litellm.proxy._experimental.mcp_server.serverr  r  Zstarlette.responsesr"  r  r\  rx   r  r  )r  r  rR  r  r  r  Z
mcp_serverr  r  r  r"  Zheaders_dictre  rd   r  re   dynamic_mcp_route3  sT   



r  )rW   r   )NNrd  rB  )NNNNFFNNr?  NFTTNFFN)FN)r  (;  r  r  enumr  r  ra  r  rm   Zsecretsr  r  r  r  rB  rt  warningsr   r   r   typingr   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r  rw  Zwebsockets.exceptionsZpydanticr   r   Zlitellm._uuidr   r  r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   Z*litellm.litellm_core_utils.litellm_loggingr%   Z*litellm.litellm_core_utils.safe_json_dumpsr&   Zlitellm.proxy._typesr'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   Z)litellm.proxy.common_utils.callback_utilsrF   rG   Z)litellm.proxy.common_utils.realtime_utilsrI   r?  rJ   rK   rL   rM   rZ  rN   rO   ra  rP   Zopentelemetry.tracerQ   _SpanZ"litellm.integrations.opentelemetryrR   rX   r  r  rf   filterwarningsUserWarningrh   r  rW   insertr  rv  backoffZfastapirR  r  Zapscheduler.schedulers.asynciori   r  re  ro   rr   collectionsrs   
contextlibrt   	functoolsru   rT  rv   rw  rx   ry   r<  rz   r{   Z#litellm.caching.redis_cluster_cacher|   r}   r~   r   r   r   r   r   r   r   r   r   r   r   r   Zlitellm.exceptionsr   Z%litellm.integrations.custom_guardrailr   Z"litellm.integrations.custom_loggerr   Z1litellm.integrations.SlackAlerting.slack_alertingr   Z'litellm.litellm_core_utils.core_helpersr   r   Z.litellm.litellm_core_utils.credential_accessorr   r   ZLiteLLMLoggingObjZ0litellm.litellm_core_utils.sensitive_data_maskerr   r  r   r   Z&litellm.llms.vertex_ai.vertex_llm_baser   Z;litellm.proxy._experimental.mcp_server.byok_oauth_endpointsr   Zmcp_byok_oauth_routerZ=litellm.proxy._experimental.mcp_server.discoverable_endpointsZ!mcp_discoverable_endpoints_routerZ5litellm.proxy._experimental.mcp_server.rest_endpointsZmcp_rest_endpoints_routerr  r   Zmcp_appZ4litellm.proxy._experimental.mcp_server.tool_registryr   Z+litellm.proxy.agent_endpoints.a2a_endpointsZ
a2a_routerrV  r   Z'litellm.proxy.agent_endpoints.endpointsZagent_endpoints_routerZ0litellm.proxy.agent_endpoints.model_list_helpersr   r   Z5litellm.proxy.analytics_endpoints.analytics_endpointsZanalytics_routerZ7litellm.proxy.anthropic_endpoints.claude_code_endpointsr   Z+litellm.proxy.anthropic_endpoints.endpointsZanthropic_routerZ2litellm.proxy.anthropic_endpoints.skills_endpointsZanthropic_skills_routerZlitellm.proxy.auth.auth_checksr   r   r   Zlitellm.proxy.auth.auth_utilsr   Zlitellm.proxy.auth.handle_jwtr   Z"litellm.proxy.auth.litellm_licenser   r	  r   r   r   r   r   Z$litellm.proxy.auth.user_api_key_authr   r   r   Z)litellm.proxy.batches_endpoints.endpointsZbatches_routerZlitellm.proxy.caching_routesZcaching_routerZ'litellm.proxy.common_request_processingr   r   r   Z&litellm.proxy.common_utils.debug_utilsr   Zdebugging_endpoints_routerZ0litellm.proxy.common_utils.encrypt_decrypt_utilsr   r   Z.litellm.proxy.common_utils.html_forms.ui_loginr   Z-litellm.proxy.common_utils.http_parsing_utilsr   r   r   r   Z,litellm.proxy.common_utils.load_config_utilsr   r   Z0litellm.proxy.common_utils.openai_endpoint_utilsr   Z&litellm.proxy.common_utils.proxy_stater   Z+litellm.proxy.common_utils.reset_budget_jobr   Z(litellm.proxy.common_utils.swagger_utilsr   Z+litellm.proxy.container_endpoints.endpointsZcontainer_routerZ,litellm.proxy.credential_endpoints.endpointsZcredential_routerr  r   Z"litellm.proxy.db.exception_handlerr   Z!litellm.proxy.discovery_endpointsr   Z-litellm.proxy.fine_tuning_endpoints.endpointsZfine_tuning_routerr   Z(litellm.proxy.google_endpoints.endpointsZgoogle_routerZ,litellm.proxy.guardrails.guardrail_endpointsZguardrails_routerZ(litellm.proxy.guardrails.init_guardrailsr   r   Zlitellm.proxy.health_checkr   r  Zhealth_routerZ,litellm.proxy.hooks.model_max_budget_limiterr   Z.litellm.proxy.hooks.prompt_injection_detectionr   Z-litellm.proxy.hooks.proxy_track_cost_callbackr   Z'litellm.proxy.image_endpoints.endpointsZimage_routerZ$litellm.proxy.litellm_pre_call_utilsr   Z9litellm.proxy.management_endpoints.access_group_endpointsZaccess_group_routerZ>litellm.proxy.management_endpoints.budget_management_endpointsZbudget_management_routerr  Zcache_settings_routerZ@litellm.proxy.management_endpoints.callback_management_endpointsZ$callback_management_endpoints_routerr  Zconfig_override_routerr  r   r   Z7litellm.proxy.management_endpoints.compliance_endpointsZcompliance_routerZ9litellm.proxy.management_endpoints.cost_tracking_settingsZcost_tracking_settings_routerZ5litellm.proxy.management_endpoints.customer_endpointsZcustomer_routerZ@litellm.proxy.management_endpoints.fallback_management_endpointsZfallback_management_routerZ:litellm.proxy.management_endpoints.internal_user_endpointsZinternal_user_routerr   Z<litellm.proxy.management_endpoints.jwt_key_mapping_endpointsZjwt_key_mapping_routerZ;litellm.proxy.management_endpoints.key_management_endpointsr   r   r   Zkey_management_routerZ;litellm.proxy.management_endpoints.mcp_management_endpointsZmcp_management_routerZJlitellm.proxy.management_endpoints.model_access_group_management_endpointsZ$model_access_group_management_routerZ=litellm.proxy.management_endpoints.model_management_endpointsr   r   r   Zmodel_management_routerZ9litellm.proxy.management_endpoints.organization_endpointsZorganization_routerZ3litellm.proxy.management_endpoints.policy_endpointsZpolicy_routerZ4litellm.proxy.management_endpoints.project_endpointsZproject_routerZ<litellm.proxy.management_endpoints.router_settings_endpointsZrouter_settings_routerZ/litellm.proxy.management_endpoints.scim.scim_v2r   Z;litellm.proxy.management_endpoints.tag_management_endpointsZtag_management_routerZ:litellm.proxy.management_endpoints.team_callback_endpointsZteam_callback_routerZ1litellm.proxy.management_endpoints.team_endpointsZteam_routerr   r   Z<litellm.proxy.management_endpoints.tool_management_endpointsZtool_management_routerZ)litellm.proxy.management_endpoints.ui_ssor   Zui_sso_routerZ2litellm.proxy.management_endpoints.usage_endpointsZusage_ai_routerZAlitellm.proxy.management_endpoints.user_agent_analytics_endpointsZuser_agent_analytics_routerZ+litellm.proxy.management_helpers.audit_logsr   Z6litellm.proxy.middleware.in_flight_requests_middlewarer   Z3litellm.proxy.middleware.prometheus_auth_middlewarer   Z%litellm.proxy.ocr_endpoints.endpointsZ
ocr_routerZ.litellm.proxy.openai_evals_endpoints.endpointsZevals_routerZ4litellm.proxy.openai_files_endpoints.files_endpointsZopenai_files_routerr   Z>litellm.proxy.pass_through_endpoints.llm_passthrough_endpointsr   Zllm_passthrough_routerr   rZ  r   Zpass_through_routerZ,litellm.proxy.policy_engine.policy_endpointsZpolicy_crud_routerZ4litellm.proxy.policy_engine.policy_resolve_endpointsZpolicy_resolve_routerrB  Zprompts_routerZlitellm.proxy.public_endpointsZpublic_endpoints_routerZ%litellm.proxy.rag_endpoints.endpointsZ
rag_routerZ(litellm.proxy.rerank_endpoints.endpointsZrerank_routerZ.litellm.proxy.response_api_endpoints.endpointsZresponse_routerZlitellm.proxy.route_llm_requestr   Z(litellm.proxy.search_endpoints.endpointsZsearch_routerZ5litellm.proxy.search_endpoints.search_tool_managementZsearch_tool_management_routerr  Zcloudzero_routerZ7litellm.proxy.spend_tracking.spend_management_endpointsZspend_management_routerZ1litellm.proxy.spend_tracking.spend_tracking_utilsr   Zlitellm.proxy.types_utils.utilsr   r  Zui_crud_endpoints_routerr  r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   Z.litellm.proxy.vector_store_endpoints.endpointsZvector_store_routerZ9litellm.proxy.vector_store_endpoints.management_endpointsZvector_store_management_routerZ4litellm.proxy.vector_store_files_endpoints.endpointsZvector_store_files_routerZ4litellm.proxy.vertex_ai_endpoints.langfuse_endpointsZlangfuse_routerZ'litellm.proxy.video_endpoints.endpointsZvideo_routerZlitellm.routerr   r   r   r   Zlitellm.schedulerr   r   Z*litellm.secret_managers.aws_secret_managerr   Z"litellm.secret_managers.google_kmsr   r  r   r   r   r   Z)litellm.types.integrations.slack_alertingr  Zlitellm.types.llms.anthropicr  r  r  r  Zlitellm.types.llms.openair  ZClitellm.types.proxy.management_endpoints.model_management_endpointsr  Z/litellm.types.proxy.management_endpoints.ui_ssor  r	  Zlitellm.types.realtimer
  r@  r  r  rs  r  r  r  Zlitellm.types.schedulerr  Z"litellm.types.secret_managers.mainr  r  r  r  ZModelMapInfor  r  r  Zlitellm._versionr  r\  Zsuppress_debug_infor  r  r  r  r  r  r  r  r   r!  r"  r#  r$  r%  r&  r'  Zfastapi.encodersr(  Zfastapi.middleware.corsr)  Zfastapi.openapi.docsr+  Zfastapi.openapi.utilsr,  rH  r-  r.  r/  r0  r1  Zfastapi.routingr2  Zfastapi.securityr3  Zfastapi.security.api_keyr4  Zfastapi.staticfilesr5  Zlitellm.types.agentsr6  Zenterprise_routerZlitellm.proxy.enterpriseproxyZ
enterpriseZ*litellm_enterprise.proxy.enterprise_routesZ_enterprise_routerZ%litellm_enterprise.proxy.proxy_serverr7  r8  r  r  r  r9  r  Zairgapped_license_datar:  rS  r;  Zproxy_stater  r=  r  r>  r?  rl  rD  Zfallback_login_linkZmodel_hub_linkZ
ui_messageZ	chat_linkZcustom_swagger_message_titleZ_descriptionrO  r]  rf  r  Z#vertex_live_passthrough_vertex_baser  r  r  ZopenapiEnumr  Zexception_handlerr  Zoriginsr  r  r+  r  Zpackaged_ui_pathr  Zlitellm_asset_prefixr  r  r	  rk  r  r  r  Zdefault_runtime_ui_pathZruntime_ui_pathr  Zshould_use_runtime_pathZis_pre_restructuredZhas_contentrR  rc  r  r  r  is_writabler  rootdirsr#  r`   r$  r!  r  r  r`  r  r  Zmodified_contentr]   UnicodeDecodeErrorr  r  r,  r&  rU  Zadd_middlewarer-  r  r.  r  r1  rz  rt  ru  r  r|  r{  r~  Zuser_configry  rD  Zlocal_loggingr}  rs  r  ru  r  r2  Zlog_filer  rC  r3  rE  rN  r  r  r  rr  Zmodel_max_budget_limiterrX  rY  rt  r6  r7  r9  rF  rG  rH  rI  rJ  rK  r  rL  rM  r  r:  r  r  r;  ry  rz  r<  r{  r|  r,  r}  rI  r-  rV  r  r=  r>  rq  Zasync_resultZcelery_app_connZ	celery_fnr  r'  r;  rX  rF  rL  rN  rW  rZ  r  r  r  r  r  r  r  r  r  r  rh  r  r  r  r  r  r  r  r  r  r  r  r  r  postr6  r:  r;  rE  bytesrX  r\  rc  rd  rh  rm  ry  r|  r}  r  r  r  r  r  r  r  Z litellm.llms.base_llm.base_utilsr  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r!  r%  r$  r'  r;  rC  rJ  rb  rc  rv  rx  r{  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  Zinclude_routerZ	api_router  rd   rd   rd   re   <module>   s@  
 @D!@ ""***"
2
	







 [


I

/




(
	
 



(
. 

  D" -                      
w
9/g
       

?



	 #

 9



	y

	m

m


 

%
z

X

X

	W

W

	U

	Y

	U

	l9
" 


--,E

L -P
(y/
 $
}
l
S
Q+

 "
 >

g
	t /ErOV;
J
-
	6
	J
 
H
	7
 
B
W
 '

O
A
+
Z
.
L
A
,
^0E