Ë
    tPêjÔ  ã                   ó˜  — U d dl Z d dlZd dlZd dlm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mZmZmZ d dlmZ d dlmZmZ d dlmZ d d	lmZ er$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$ d dlm%Z% dZ&ee'd<   dZ(ee'd<   de)dz  ddfd„Z*de+dz  ddfd„Z,e G d„ de«      «       Z-de+de+ed   z  fd„Z.de+de+fd„Z/de+dz  d e+dz  de+dz  fd!„Z0d"e+de1e+   fd#„Z2d$e+de+dz  fd%„Z3d$e+de+fd&„Z4dŠd$e+d'e+d(ed)   de+fd*„Z5d'e+ddfd+„Z6d,e+de+dz  fd-„Z7d,e+de+fd.„Z8d$e+de9fd/„Z:	 d‹d$e+d0e;dz  de<e+dz  e+dz  f   fd1„Z=	 dŒd2e+d3e+fd4„Z>d5ed6   d7d8d9e+de;dz  fd:„Z?d0e;d5ed6   d7d8d9e+ddf
d;„Z@d0e;d5d6d2e+dz  ddfd<„ZA	 	 d�d0e;d=e;d$e+dz  d>e9ddf
d?„ZB	 dŽd$e+d0e;d@e9de<e9e+dz  e+dz  e;dz  f   fdA„ZCh dB£ZDee'dC<   h dD£ZEee'dE<   h dF£ZFee'dG<   dHdIhZGee'dJ<   dKdKdLdMdIdNdOdPdQœZHee'dR<   dSe+de+fdT„ZId‹dUe+dVe+dz  de+fdW„ZJdUe+de9fdX„ZKdYe;dz  de+fdZ„ZLe G d[„ d\«      «       ZM	 	 	 d�d]d^d_e;dz  d`e+dz  dae+dz  deMf
db„ZNd‹dae+dz  de+fdc„ZO	 d‹d`e+dz  de1e+   fdd„ZPdee+de9fdf„ZQd]d^de1e+   fdg„ZR	 d‹dhe1e+   d'e+dz  ddfdi„ZSdje+dz  dkedl   d7d8dmeTdz  ddf
dn„ZUd]d^d_e;de+dz  fdo„ZVdpe+ed   z  dz  de<e+dqf   fdr„ZWdsdtdpe+ed   z  dz  de+dz  fdu„ZXdsdtde+dz  fdv„ZYd�dx„ZZd‘dy„Z[d‘dz„Z\d{e]e+   d|d}dee+e+f   fd~„Z^dsdtdee+e+f   ddfd€„Z_	 	 	 d�dwd�dpe+ed   z  dz  ddfd‚„Z`dƒe+dpe+ed   z  fd„„Zade9fd…„Zbdsdtde9fd†„Zc	 	 	 	 d’dƒe+dpe+ed   z  dwd�d‡e+dˆe9dz  f
d‰„Zdy)“é    N)ÚMapping)Ú	dataclassÚfield)ÚMappingProxyType)ÚTYPE_CHECKINGÚFinalÚLiteralÚOptionalÚProtocolÚcastÚget_argsÚruntime_checkable)ÚProxyException)ÚManagedFileRepositoryÚManagedObjectRepository)ÚOpenAIFilesPurpose)ÚSpecialEnums)ÚRequest)ÚLiteLLM_ManagedObjectTable©ÚUserAPIKeyAuth)ÚPrismaClient)ÚRouter©ÚLiteLLMBatchi'  ÚMAX_FILE_LIST_LIMITéô  Ú!FILE_LIST_CONTINUATION_CHUNK_SIZEÚlimitÚreturnc           	      óŽ   — | �d| cxk  r	t         k  ry ny| dk  rdnddt         › �df\  }}}t        d|› d|› d	| › d
�ddd|¬«      ‚)zHReject a ``limit`` outside the range OpenAI documents for GET /v1/files.Né   )zbelow minimumz>= 1Úinteger_below_min_valuezabove maximumz<= Úinteger_above_max_valuezInvalid 'limit': integer z value. Expected a value z
, but got z	 instead.Úinvalid_request_errorr   é�  )ÚmessageÚtypeÚparamÚcodeÚopenai_code)r   r   )r   ÚboundÚexpectedr+   s       úv/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/openai_files_endpoints/common_utils.pyÚvalidate_file_list_limitr/   )   s„   € à€}˜˜UÔ9Ô&9Ò9Øñ :Øð �1Š9ñ 	=à Ô%8Ð$9Ð:Ð<UÐVñ !€Eˆ8�[ô
 Ø+¨E¨7Ð2KÈHÈ:ÐU_Ð`eÐ_fÐfoÐpØ$ØØØôð ó    Úpurposec                 óX   — t        t        «      }| �| |v ryt        d| › d|› �ddd¬«      ‚)a  Reject a ``purpose`` filter no upload to this proxy could have stored.

    An unknown purpose matches no file, so filtering on it would report an
    empty page for what is really a bad request. Rejecting it keeps a managed
    listing consistent with the upload route, which refuses the same values
    against this same set. The provider-backed listings do not: they pass
    ``purpose`` upstream, so a purpose OpenAI accepts before it is added here
    is rejected on the managed path while still working on those.
    NzInvalid purpose: z. Must be one of: r%   r1   r&   )r'   r(   r)   r*   )r   r   r   )r1   Úvalid_purposess     r.   Úvalidate_file_list_purposer4   ;   sF   € ô %Ô%7Ó8€NØ€˜' ^Ñ3ØÜ
Ø# G 9Ð,>¸~Ð>NÐOØ$ØØô	ð r0   c                   ó4   — e Zd Zdedddefd„Zdedddefd„Zy)	ÚManagedResourceAccessCheckerÚunified_file_idÚuser_api_key_dictr   r    c              ƒ   ó   K  — y ­w©N© )Úselfr7   r8   s      r.   Úcan_user_call_unified_file_idz:ManagedResourceAccessChecker.can_user_call_unified_file_idR   ó   è ø€ ð ùó   ‚Úunified_object_idc              ƒ   ó   K  — y ­wr:   r;   )r<   r@   r8   s      r.   Úcan_user_call_unified_object_idz<ManagedResourceAccessChecker.can_user_call_unified_object_idX   r>   r?   N)Ú__name__Ú
__module__Ú__qualname__ÚstrÚboolr=   rB   r;   r0   r.   r6   r6   P   sD   „ ðàðð ,ðð 
ó	ðàðð ,ðð 
ô	r0   r6   Úb64_uidFc                 ó  — t        | t        «      sy| dt        | «       dz  z  z   }	 t        j                  |«      j                  «       }|j                  t        j                  j                  «      r|S y# t        $ r Y yw xY w)NFú=é   )Ú
isinstancerF   ÚlenÚbase64Úurlsafe_b64decodeÚdecodeÚ
startswithr   ÚLITELM_MANAGED_FILE_ID_PREFIXÚvalueÚ	Exception)rH   ÚpaddedÚdecodeds      r.   Ú"_is_base64_encoded_unified_file_idrW   _   s{   € ä�gœsÔ#Øà˜c¤c¨'£l ]°QÑ%6Ñ7Ñ7€FðÜ×1Ñ1°&Ó9×@Ñ@ÓBˆØ×Ñœl×HÑH×NÑNÔOØˆNàøÜò Ùðús   ¨AA7 Á7	BÂBc                 ó$   — t        | «      }|r|S | S r:   )rW   )rH   Úis_base64_unified_file_ids     r.   Úconvert_b64_uid_to_unified_uidrZ   p   s   € Ü'IÈ'Ó'RÐÙ Ø(Ð(àˆr0   Úunified_input_file_idÚfallback_model_namec                 ó\   — | s|S t        t        | «      «      }|rdj                  |«      S |S )Nú,)Úget_models_from_unified_file_idrZ   Újoin)r[   r\   Útarget_model_namess      r.   Ú&resolve_managed_output_file_model_namerb   x   s8   € ñ !Ø"Ð"Ü ?Ô@^Ð_tÓ@uÓ vÐÙØ�x‰xÐ*Ó+Ð+ØÐr0   r7   c                 ó   — 	 t        | t        «      sg S t        j                  d| «      }|r<|j	                  d«      j                  d«      D �cg c]  }|j                  «       ‘Œ c}S g S c c}w # t        $ r g cY S w xY w)a  
    Extract model names from unified file ID.

    Example:
    unified_file_id = "litellm_proxy:application/octet-stream;unified_id,c4843482-b176-4901-8292-7523fd0f2c6e;target_model_names,gpt-4o-mini,gemini-2.0-flash"
    returns: ["gpt-4o-mini", "gemini-2.0-flash"]
    ztarget_model_names,([^;]+)r"   r^   )rL   rF   ÚreÚsearchÚgroupÚsplitÚstriprT   )r7   ÚmatchÚmodels      r.   r_   r_   ƒ   ss   € ð
ä˜/¬3Ô/ØˆIÜ—y‘yÐ!>ÀÓPˆÙà/4¯{©{¸1«~×/CÑ/CÀCÓ/HÖI e�E—K‘K•MÒIÐIØˆ	ùò Jøäò ØŠ	ðús.   ‚A/ ”:A/ ÁA*Á%A/ Á(A/ Á*A/ Á/A=Á<A=Úfile_idc                 ó�   — 	 t        | t        «      sy| j                  d«      d   j                  d«      d   S # t        $ r Y yw xY w)z�
    Get the model_id from the file_id

    Expected format: litellm_proxy;model_id:{};llm_batch_id:{};llm_output_file_id:{}
    Nz	model_id:r"   ú;r   )rL   rF   rg   rT   ©rk   s    r.   Ú"get_model_id_from_unified_batch_idro   ˜   sJ   € ðä˜'¤3Ô'ØØ�}‰}˜[Ó)¨!Ñ,×2Ñ2°3Ó7¸Ñ:Ð:øÜò Ùðús   ‚9 “%9 ¹	AÁAc                 ó¸   — t        | t        «      syd| v r| j                  dd«      d   }n| j                  dd«      d   }t        j                  d|d¬«      d   S )	NÚ Úllm_batch_idzllm_batch_id:r"   zgeneric_response_id:z[;,])Úmaxsplitr   )rL   rF   rg   rd   )rk   Úbatch_ids     r.   Ú"get_batch_id_from_unified_batch_idru   ¨   s\   € ô �gœsÔ#ØØ˜Ñ Ø—=‘= °!Ó4°QÑ7‰à—=‘=Ð!7¸Ó;¸AÑ>ˆÜ�8‰8�G˜X°Ô2°1Ñ5Ð5r0   rj   Úid_type)ÚfileÚbatchc                 ó  — d| › d|› �}t        j                  |j                  «       «      }|j                  «       j	                  d«      }| j                  d«      rd}n| j                  d«      rd}n	|dk(  rdnd}|› |› �S )a°  
    Encode a file/batch ID with model routing information.

    Format: <prefix><base64(litellm:<original_id>;model,<model_name>)>
    The result preserves the original prefix (file-, batch_, etc.) for OpenAI compliance.

    Args:
        file_id: Original file/batch ID from the provider (e.g., "file-abc123", "batch_xyz")
        model: Model name from model_list (e.g., "gpt-4o-litellm")
        id_type: Type of ID being encoded. Used to determine the correct prefix when
                 the raw ID lacks a recognizable prefix (e.g., Vertex AI numeric IDs).
                 Defaults to "file" for backward compatibility.

    Returns:
        Encoded ID starting with appropriate prefix and containing routing information

    Examples:
        encode_file_id_with_model("file-abc123", "gpt-4o-litellm")
        -> "file-bGl0ZWxsbTpmaWxlLWFiYzEyMzttb2RlbCxncHQtNG8taWZvb2Q"

        encode_file_id_with_model("batch_abc123", "gpt-4o-test")
        -> "batch_bGl0ZWxsbTpiYXRjaF9hYmMxMjM7bW9kZWwsZ3B0LTRvLXRlc3Q"

        encode_file_id_with_model("3814889423749775360", "gemini-2.5-pro", id_type="batch")
        -> "batch_bGl0ZWxsbTozODE0ODg5NDIzNzQ5Nzc1MzYwO21vZGVsLGdlbWluaS0yLjUtcHJv"
    úlitellm:ú;model,rJ   Úbatch_úfile-rx   )rN   Úurlsafe_b64encodeÚencoderP   ÚrstriprQ   )rk   rj   rv   Úencoded_strÚencoded_bytesÚencoded_b64Úprefixs          r.   Úencode_file_id_with_modelr…   ´   s�   € ð6 $ G 9¨G°E°7Ð;€KÜ!×3Ñ3°K×4FÑ4FÓ4HÓI€MØ&×-Ñ-Ó/×6Ñ6°sÓ;€Kð
 ×Ñ˜(Ô#Ø‰Ø	×	Ñ	˜GÔ	$Ø‰à$¨Ò/‘°WˆàˆX�k�]Ð#Ð#r0   c                 óú   — | rt        | d«      r| j                  syt        | j                  |d¬«      | _        dD ]>  }t        | |«      sŒt        | |«      sŒt	        | |t        t        | |«      |¬«      «       Œ@ y)zFEncode all IDs in a batch response with model routing info (in-place).ÚidNrx   )rk   rj   rv   )Úoutput_file_idÚerror_file_idÚinput_file_id)rk   rj   )Úhasattrr‡   r…   ÚgetattrÚsetattr)Úresponserj   Úattrs      r.   Úencode_batch_response_idsr�   à   sn   € áœ7 8¨TÔ2¸(¿+º+ØÜ+°H·K±KÀuÐV]Ô^€H„KØDò ˆÜ�8˜TÕ"¤w¨x¸Õ'>ÜØØÜ)´'¸(ÀDÓ2IÐQVÔWõñr0   Ú
encoded_idc                 ó®  — 	 t        | t        «      sy| j                  d«      r| dd }n| j                  d«      r| dd }n| }|dt        |«       dz  z  z   }t	        j
                  |«      j                  «       }|j                  d«      r;d	|v r7t        j                  d
|«      }|r|j                  d«      j                  «       S y# t        $ r Y yw xY w)zw
    Extract model name from an encoded file/batch ID.
    Handles IDs that start with "file-" or "batch_" prefix.
    Nr}   é   r|   é   rJ   rK   rz   r{   z;model,([^;]+)r"   )rL   rF   rQ   rM   rN   rO   rP   rd   re   rf   rh   rT   ©r‘   Úb64_partrU   rV   ri   s        r.   Údecode_model_from_file_idr—   î   sÕ   € ð
Ü˜*¤cÔ*Øð × Ñ  Ô)Ø! ! "�~‰HØ×"Ñ" 8Ô,Ø! ! "�~‰Hà!ˆHà  3¬3¨x«=¨.¸1Ñ*<Ñ#=Ñ=ˆÜ×1Ñ1°&Ó9×@Ñ@ÓBˆØ×Ñ˜jÔ)¨i¸7Ñ.BÜŸ9™9Ð%6¸Ó@ˆEÙØ—{‘{ 1“~×+Ñ+Ó-Ð-àøÜò Ùðús   ‚C “B3C Ã	CÃCc                 óš  — 	 t        | t        «      s| S | j                  d«      r| dd }n| j                  d«      r| dd }n| }|dt        |«       dz  z  z   }t	        j
                  |«      j                  «       }|j                  d«      r-d	|v r)t        j                  d
|«      }|r|j                  d«      S | S # t        $ r | cY S w xY w)z…
    Extract the original provider file/batch ID from an encoded ID.
    Handles IDs that start with "file-" or "batch_" prefix.
    r}   r“   Nr|   r”   rJ   rK   rz   r{   zlitellm:([^;]+);model,r"   )rL   rF   rQ   rM   rN   rO   rP   rd   re   rf   rT   r•   s        r.   Úget_original_file_idr™     sÕ   € ð
Ü˜*¤cÔ*ØÐð × Ñ  Ô)Ø! ! "�~‰HØ×"Ñ" 8Ô,Ø! ! "�~‰Hà!ˆHà  3¬3¨x«=¨.¸1Ñ*<Ñ#=Ñ=ˆÜ×1Ñ1°&Ó9×@Ñ@ÓBˆà×Ñ˜jÔ)¨i¸7Ñ.BÜŸ9™9Ð%>ÀÓHˆEÙØ—{‘{ 1“~Ð%àÐøÜò ØÒðús   ‚B< ”B%B< Â:B< Â<C
Ã	C
c                 ó   — t        | «      duS )zJ
    Check if a file/batch ID has model routing information embedded.
    N)r—   rn   s    r.   Úis_model_embedded_idr›   )  s   € ô % WÓ-°TÐ9Ð9r0   Údatac                 ó¾   — |€i }t        | «      }|j                  d«      xs8 |j                  j                  d«      xs |j                  j                  d«      }||fS )a?  
    Extract model information from multiple sources in priority order:
    1. Embedded in file_id (highest priority)
    2. Request headers (x-litellm-model)
    3. Query parameters (?model=)
    4. Request body/data dict

    Args:
        file_id: File ID that may contain embedded model info
        request: FastAPI request object
        data: Optional request data dictionary

    Returns:
        Tuple of (model_from_id, model_from_param)
        - model_from_id: Model decoded from file ID (if embedded)
        - model_from_param: Model from header/query/body
    rj   úx-litellm-model)r—   ÚgetÚquery_paramsÚheaders)rk   Úrequestrœ   Úmodel_from_idÚmodel_from_params        r.   Úextract_model_from_sourcesr¥   5  se   € ð, €|Øˆô 5°WÓ=€Mð —x‘x Ó(Òw¨G×,@Ñ,@×,DÑ,DÀWÓ,MÒwÐQX×Q`ÑQ`×QdÑQdÐevÓQwÐàÐ*Ð*Ð*r0   Úmodel_idÚoperation_contextc                 óv   — ddl m} | € |dddi¬«      ‚| j                  |¬«      }|€ |ddd	|› d
�i¬«      ‚|S )a¼  
    Retrieve API credentials for a model from the LLM Router.

    Args:
        llm_router: LiteLLM Router instance
        model_id: Model name or deployment ID
        operation_context: Description for error messages (e.g., "file upload", "batch creation")

    Returns:
        Dictionary with credentials (api_key, api_base, custom_llm_provider, etc.)

    Raises:
        HTTPException: If router not initialized or model not found
    r   ©ÚHTTPExceptionr   Úerrorz7Router not initialized. Cannot use model-based routing.©Ústatus_codeÚdetail©r¦   r&   zModel 'z9' not found in model_list. Please check your config.yaml.)Úfastapirª   Ú(get_deployment_credentials_with_provider)Ú
llm_routerr¦   r§   rª   Úcredentialss        r.   Úget_credentials_for_modelr´   W  sl   € õ& &àÐÙØØÐVÐWô
ð 	
ð
 $×LÑLÐV^ÐLÓ_€KàÐÙØØ˜w x jÐ0iÐjÐkô
ð 	
ð
 Ðr0   r²   r   r8   r   Úcustom_llm_providerc                 ó  ‡ ‡‡‡— ‰ €yddl m} ddlm}m} |j
                  Š|j                  xs g }‰ j                  ‰¬«      }‰ j                  «       }|j                  xs g }	|j                  j                  |j                  j                  h}
t        |	«      xr t        |	«      |
z   }|r't        t         j#                   ||||¬«      «      «      nd}t%        |«      Šdt&        dz  d	t        fˆfd
„}dt&        d	t         dz  fˆˆ ˆfd„}‰�Œ‰ j(                  xs g D ]y  }|j+                  d«      xs i }|j+                  d«      ‰k7  rŒ-|j+                  d«      }|€ŒA ||j+                  d«      xs |j+                  d«      «      sŒl ||«      }|€Œw|c S  |j                  j                  |v }|rg n|}t-        t         j#                   |t-        |«      ||ddd‰ |d‰¬«
      «      «      }|D ]  } ||«      }|€Œ|c S  y)u…  
    Resolve upstream credentials for a provider-scoped file operation
    (e.g. GET /v1/files), which doesn't pin a model.

    Priority:
    1. The team's own (BYOK) deployment for this provider â€” a deployment whose
       ``model_info.team_id`` matches the caller's team. This keeps team-scoped
       listings on the team's own provider account/key instead of a shared
       global one.
    2. Fallback: any deployment the caller is granted access to for this
       provider, expanding wildcard routes and the all-proxy-models sentinel.

    Credential lookup is scoped to both the team's allowlist and the key's own
    model allowlist (``user_api_key_dict.models``), so neither a team nor a
    restricted key within a team can resolve a provider key for a deployment
    it isn't authorized to use. A key restricted to an explicit model list
    only narrows the team scope; sentinel-bearing keys (all-proxy-models /
    all-team-models) defer to the team scope instead of widening past it.
    Returns None when the router is unavailable or no authorized deployment
    matches, so the caller can fall back to default credential resolution.
    Nr   )ÚSpecialModelNames)Úget_complete_model_listÚget_key_models)Úteam_id)r8   Úproxy_model_listÚmodel_access_groupsr;   Úpublic_model_namer    c                 ó   •— ‰sy| d uxr | ‰v S )NTr;   )r½   Úkey_model_allowlist_sets    €r.   Ú_key_may_usez3get_team_provider_credentials.<locals>._key_may_use¸  s    ø€ Ù&ØØ ¨Ð,Ò]Ð1BÐF]Ð1]Ð]r0   r¦   c                 ó¸   •— ‰j                  | ‰¬«      }|�>|j                  d«      ‰k(  r*|j                  «       D ��ci c]  \  }}|dk7  sŒ||“Œ c}}S y c c}}w )N)r¦   rº   rµ   rj   )r±   rŸ   Úitems)r¦   r³   ÚkeyrS   rµ   r²   rº   s       €€€r.   Ú_provider_credentialsz<get_team_provider_credentials.<locals>._provider_credentials½  sc   ø€ Ø'×PÑPÐZbÐlsÐPÓtˆØÐ" {§¡Ð7LÓ'MÐQdÒ'dØ1<×1BÑ1BÓ1D×W¡: 3¨ÈÈwË�C˜‘JÓWÐWØùó Xs   ¾AÁAÚ
model_inforº   r‡   Úteam_public_model_nameÚ
model_nameFT)
Ú
key_modelsÚteam_modelsr»   Ú
user_modelÚinfer_model_from_keysÚreturn_wildcard_routesr²   r¼   Úinclude_model_access_groupsrº   )Úlitellm.proxy._typesr·   Úlitellm.proxy.auth.model_checksr¸   r¹   rº   rÉ   Úget_model_namesÚget_model_access_groupsÚmodelsÚall_proxy_modelsrS   Úall_team_modelsrG   ÚsetÚtupleÚdictÚfromkeysÚ	frozensetrF   Ú
model_listrŸ   Úlist)r²   r8   rµ   r·   r¸   r¹   rÉ   r»   r¼   Úraw_key_modelsÚsentinel_valuesÚkey_is_restrictedÚkey_model_allowlistrÀ   rÄ   Ú
deploymentrÅ   Údeployment_idr³   Úgrants_all_modelsÚeffective_team_modelsÚmodels_to_tryrÇ   r¿   rº   s   ` `                    @@r.   Úget_team_provider_credentialsrå   }  sG  û€ ð4 ÐØå6ßWà&×.Ñ.€GØ*×6Ñ6Ò<¸"€Kà(×8Ñ8ÀÐ8ÓIÐØ!+×!CÑ!CÓ!EÐà-×4Ñ4Ò:¸€Nà×*Ñ*×0Ñ0Ø×)Ñ)×/Ñ/ð€Oô  $ NÓ3Òc¼SÀÓ=PÐSbÑ=bÐ8cÐñ ô 	Ü�M‰MÙØ&7Ø%5Ø(;ôóô	
ð ð ô &/Ð/BÓ%CÐð^¬¨d©
ð ^´tõ ^ð
¬ð ´°t±÷ ð ÐØ$×/Ñ/Ò5°2ò 	#ˆJØ#Ÿ™¨Ó5Ò;¸ˆJØ�~‰~˜iÓ(¨GÒ3ØØ&ŸN™N¨4Ó0ˆMØÐ$ØÙ 
§¡Ð/GÓ HÒ hÈJÏNÉNÐ[gÓLhÔiØÙ/°Ó>ˆKØÑ&Ø"Ò"ð	#ð*  1×AÑA×GÑGÈ;ÐVÐÙ):¡2ÀÐäÜ�‰Ù#ÜÐ 3Ó4Ø1Ø!1ØØ&+Ø'+Ø%Ø$7Ø,0Øôó	
ó€Mð  $ò ˆ
Ù+¨JÓ7ˆØÑ"ØÒðð
 r0   c                 ó@   — t        |||¬«      }|€yt        | |¬«       y)a5  
    Resolve credentials for a provider-only request (no model pinned) via
    ``get_team_provider_credentials`` and merge them into ``data`` in-place.
    Leaves ``data`` untouched when no authorized deployment matches, so the
    caller falls back to environment-variable credentials exactly as before.
    )r²   r8   rµ   N)rœ   r³   )rå   Úprepare_data_with_credentials)rœ   r²   r8   rµ   r³   s        r.   Úapply_team_provider_credentialsrè   õ  s,   € ô 7ØØ+Ø/ô€Kð
 ÐØÜ! t¸ÖEr0   c                 ó‚   — |€y	 |j                  |¬«      }|€yt        t        |«      «      | d<   y# t        $ r Y yw xY w)aº  
    Attach the deployment's immutable server-side credential snapshot to a router-routed
    batch call (in-place).

    Cost accounting for a completed batch reads the batch's output file, and the Bedrock
    file config resolves its bucket only from this snapshot, never from a request param,
    because the bucket is what managed file ids are validated against. Without it that
    read fails and the batch's cost is never recorded.
    Nr¯   Ú#_litellm_internal_model_credentials)r±   rT   r   r×   )rœ   r²   r¦   r³   s       r.   Úadd_internal_model_credentialsrë     sZ   € ð ÐØðØ'×PÑPÐZbÐPÓcˆð ÐØÜ2BÄ4ÈÓCTÓ2U€DÐ	.Ò/øô	 ò Ùðús   …2 ²	>½>r³   Úinclude_internal_credentialsc                 óŒ   — | j                  |«       |rt        t        |«      «      | d<   | j                  dd«       |�|| d<   yy)a�  
    Update data dictionary with model credentials (in-place).

    Args:
        data: Data dictionary to update
        credentials: Credentials from router
        file_id: Optional original file_id to set (for decoded file IDs)
        include_internal_credentials: Preserve an immutable server-side snapshot
            for code paths that must distinguish proxy config from request params.
    rê   rµ   Nrk   )Úupdater   r×   Úpop)rœ   r³   rk   rì   s       r.   rç   rç   $  sK   € ð  	‡K�K�ÔÙ#Ü6FÄtÈKÓGXÓ6YˆÐ2Ñ3Ø‡H�HÐ" DÔ)àÐØ!ˆˆYŠð r0   Úcheck_file_id_encodingc                 ó    — t        | ||¬«      \  }}|r%|�#t        ||d|› d�¬«      }t        | «      }d|||fS |�t        ||d¬«      }d|d|fS y)	a÷  
    Orchestrate model-based credential routing for file operations.

    Args:
        file_id: File ID (may contain embedded model info)
        request: FastAPI request object
        llm_router: LiteLLM Router instance
        data: Request data dictionary
        check_file_id_encoding: Whether to check for embedded model in file_id

    Returns:
        Tuple of (should_use_model_routing, model_used, original_file_id, credentials)
        - should_use_model_routing: True if model-based routing should be used
        - model_used: The model name being used
        - original_file_id: Decoded file ID (if it was encoded)
        - credentials: Model credentials dict

    Raises:
        HTTPException: If router unavailable or model not found
    )rk   r¢   rœ   Nz)file operation (file created with model 'z'))r²   r¦   r§   Túfile operation)FNNN)r¥   r´   r™   )	rk   r¢   r²   rœ   rð   r£   r¤   r³   Úoriginal_file_ids	            r.   Úhandle_model_based_routingrô   =  s”   € ô6 'AØØØô'Ñ#€MÐ#ñ  -Ð";Ü/Ø!Ø"Ø IÈ-ÈÐXZÐ[ô
ˆô
 #7°wÓ"?ÐØ�]Ð$4°kÐAÐAð 
Ð	%Ü/Ø!Ø%Ø.ô
ˆð
 Ð% t¨[Ð8Ð8ð #r0   >   ú	image/pngú
image/jpegú
image/webpÚGEMINI_SUPPORTED_IMAGE_TYPES>	   ú	video/mp4ú	video/mpgú	video/wmvú
video/3gppú
video/mpegú
video/webmúvideo/x-flvúvideo/mpegpsúvideo/quicktimeÚGEMINI_SUPPORTED_VIDEO_TYPES>   ú	audio/aacú	audio/m4aú	audio/mp3ú	audio/pcmú
audio/flacú
audio/mpgaú
audio/opusú
audio/webmú	audio/mp4ú	audio/wavú
audio/mpegÚGEMINI_SUPPORTED_AUDIO_TYPESz
text/plainzapplication/pdfÚGEMINI_SUPPORTED_DOCUMENT_TYPESrö   rõ   r÷   r  r  r  )z.jpgz.jpegz.pngz.webpz.pdfz.mp3z.wavz.m4aÚEXTENSION_TO_MIME_TYPEÚfilenamec                 óÄ   — | sy| j                  «       }t        j                  «       D ]  \  }}|j                  |«      sŒ|c S  t	        j
                  | «      \  }}|�|S y)z´
    Detect content type from filename using extension.

    Uses Python's mimetypes module with custom overrides for common cases.
    Normalizes jpg to jpeg for consistency.
    úapplication/octet-stream)Úlowerr  rÂ   ÚendswithÚ	mimetypesÚ
guess_type)r  Úfilename_lowerÚextÚ	mime_typeÚmime_type_guessÚ_s         r.   Ú!detect_content_type_from_filenamer  ±  sn   € ñ Ø)ð %ŸN™NÓ,€NÜ0×6Ñ6Ó8ò ‰ˆˆYØ×"Ñ" 3Õ'ØÒðô
 #×-Ñ-¨hÓ7Ñ€O�QØÐ"ØÐà%r0   r  Úproviderc                 óª   — | j                  «       j                  «       }|r+d|j                  «       v sd|j                  «       v r|dk(  rd}|dk(  rd}|S )a)  
    Normalize MIME type for specific provider requirements.

    Currently handles:
    - Gemini: Normalizes image/jpg to image/jpeg

    Args:
        mime_type: Original MIME type
        provider: Provider name (e.g., "gemini", "vertex_ai")

    Returns:
        str: Normalized MIME type
    ÚgeminiÚ	vertex_aiz	image/jpgrö   )r  rh   )r  r  Ú
normalizeds      r.   Ú normalize_mime_type_for_providerr#  É  s\   € ð —‘Ó"×(Ñ(Ó*€Jñ �X §¡Ó!1Ñ1°[ÀHÇNÁNÓDTÑ5TØ˜Ò$Ø%ˆJð �[Ò Ø!ˆ
àÐr0   c                 óV   — t        | d¬«      }|t        t        z  t        z  t        z  v S )a¿  
    Check if a MIME type is supported by Gemini multimodal models.

    Supported categories:
    - Images: image/png, image/jpeg, image/webp
    - Video: 3gpp, wmv, webm, mp4, mpg, mpegps, mpeg, quicktime, x-flv
    - Audio: webm, wav, pcm, opus, mp4, mpga, mpeg, m4a, mp3, flac, aac
    - Documents: text/plain, application/pdf

    Args:
        mime_type: MIME type to check

    Returns:
        bool: True if supported, False otherwise
    r   )r  )r#  rø   r  r  r  )r  r"  s     r.   Úis_gemini_supported_mime_typer%  å  s:   € ô  9¸ÈXÔV€JØÜ$Ü
&ñ	'ä
&ñ	'ô *ñ	*ðð r0   Úfile_objectc                 óà   — | syt        | t        «      rddl}	 |j                  | «      } t        | t
        «      sy| j                  dd«      }|rt        |«      S y# |j                  $ r Y yw xY w)aœ  
    Determine content type from file object (from database or API response).

    Extracts filename from file object and uses detect_content_type_from_filename.
    Falls back to default if file object is invalid or filename not found.

    Args:
        file_object: File object dictionary (can be None)

    Returns:
        str: MIME type (defaults to "application/octet-stream" if cannot be determined)
    r  r   Nr  rq   )rL   rF   ÚjsonÚloadsÚJSONDecodeErrorr×   rŸ   r  )r&  r(  r  s      r.   Ú!get_content_type_from_file_objectr+  þ  sx   € ñ Ø)ô �+œsÔ#Ûð	.ØŸ*™* [Ó1ˆKô �k¤4Ô(Ø)ð "—o‘o j°"Ó5€HÙÜ0°Ó:Ð:à%øð ×#Ñ#ò 	.Ù-ð	.ús   ™A ÁA-Á,A-c                   ó\   — e Zd ZU dZdZeed<    ee¬«      Z	ee   ed<   dZ
edz  ed<   d„ Zy)	ÚFileCreationParamsa"  
    Structured parameters extracted from file creation requests.

    Attributes:
        target_storage: Storage backend name (e.g., "azure_storage", "default")
        target_model_names: List of model names for managed files
        model: Model parameter for multi-account routing
    ÚdefaultÚtarget_storage)Údefault_factoryra   Nrj   c                 óÖ   — | j                   €g | _         | j                  sd| _        | j                   D �cg c]#  }|j                  «       sŒ|j                  «       ‘Œ% c}| _         yc c}w )z7Normalize and validate parameters after initialization.Nr.  )ra   r/  rh   )r<   Únames     r.   Ú__post_init__z FileCreationParams.__post_init__6  sZ   € à×"Ñ"Ð*Ø&(ˆDÔ#ð ×"Ò"Ø"+ˆDÔð =A×<SÑ<SÖ"d°DÐW[×WaÑWaÕWc 4§:¡:¥<Ò"dˆÕùÒ"ds   µA&ÁA&)rC   rD   rE   Ú__doc__r/  rF   Ú__annotations__r   rÛ   ra   rj   r3  r;   r0   r.   r-  r-  '  s;   … ñð $€N�CÓ#Ù$)¸$Ô$?Ð˜˜S™	Ó?Ø€Eˆ3�‰:Óó
er0   r-  r¢   r   Úrequest_bodyÚtarget_model_names_formÚtarget_storage_formc              ƒ   óÖ   K  — ddl m} |€ || ¬«      ƒ d{  –—† xs i }t        |«      }t        |«      }|st	        | «      ƒ d{  –—† }t        | |«      }t        |||¬«      S 7 ŒM7 Œ ­w)a®  
    Extract file creation parameters from request.

    Args:
        request: FastAPI request object
        request_body: Optional pre-parsed request body
        target_model_names_form: target_model_names from form field (comma-separated string)
        target_storage_form: target_storage from form field (defaults to "default")

    Returns:
        FileCreationParams: Structured parameters extracted from the request
    r   )Ú_read_request_bodyN)r¢   )r/  ra   rj   )Ú-litellm.proxy.common_utils.http_parsing_utilsr:  Ú_extract_target_storage_simpleÚ"_extract_target_model_names_simpleÚ%_extract_target_model_names_from_formÚ_extract_model_paramr-  )r¢   r6  r7  r8  r:  r/  ra   rj   s           r.   Úextract_file_creation_paramsr@  C  s�   è ø€ õ$ QàÐÙ/¸Ô@×@ÒFÀBˆô ;Ð;NÓO€Nô <Ð<SÓTÐÙÜ#HÈÓ#Q×QÐô (¨°Ó>€EäØ%Ø-Øôð ð Aøð Rús!   ‚A)—A%˜.A)ÁA'ÁA)Á'A)c                 ó(   — | r| j                  «       S y)zÇ
    Extract target_storage parameter from form field.

    Args:
        target_storage_form: target_storage from form field

    Returns:
        str: Target storage backend name, or "default"
    r.  )rh   )r8  s    r.   r<  r<  l  s   € ñ Ø"×(Ñ(Ó*Ð*Ør0   c                 ó2  — | sg S t        | t        «      r>| j                  d«      D �cg c]#  }|j                  «       sŒ|j                  «       ‘Œ% c}S t        | t        «      r*| D �cg c]  }|sŒt        |«      j                  «       ‘Œ  c}S g S c c}w c c}w )z?
    Extract target_model_names parameter from form field.
    r^   )rL   rF   rg   rh   rÛ   )r7  r2  s     r.   r=  r=  {  sz   € ñ #Øˆ	ô Ð)¬3Ô/Ø)@×)FÑ)FÀsÓ)KÖ\ ÈtÏzÉzÍ|�—
‘
•Ò\Ð\Ü	Ð+¬TÔ	2Ø.EÖN dÊ”�D“	—‘Õ!ÒNÐNà€Iùò	 ]ùâNs   ¨B¾BÁ'BÁ/BrÃ   c                 óX   — | dk(  xs$ | j                  d«      xr | j                  d«      S )Nra   ztarget_model_names[ú])rQ   r  )rÃ   s    r.   Ú_is_target_model_names_keyrE  �  s/   € ØÐ&Ñ&Òg¨3¯>©>Ð:OÓ+PÒ+fÐUX×UaÑUaÐbeÓUfÐgr0   c              ƒ   ó^  K  — | j                  «       ƒ d{  –—† }g }|j                  «       D ]<  \  }}t        |«      sŒt        |t        «      sŒ#|j                  t        |«      «       Œ> t        «       }g }|D ],  }|sŒ||vsŒ|j                  |«       |j                  |«       Œ. |S 7 Œ”­w)aÚ  
    Collect target_model_names from the raw multipart form.

    Reads ``request.form()`` directly instead of the parsed request body, which is
    built via ``dict(form_data)`` and keeps only the last value for repeated keys.
    The OpenAI SDK sends a list ``extra_body`` as repeated ``target_model_names[]``
    fields, so reading the form preserves every value instead of truncating to one.
    Indexed keys like ``target_model_names[0]`` are handled the same way.
    N)
ÚformÚmulti_itemsrE  rL   rF   Úextendr=  rÕ   ÚaddÚappend)r¢   Ú	form_dataÚnamesrÃ   rS   ÚseenÚresultr2  s           r.   r>  r>  ‘  s¦   è ø€ ð %Ÿ\™\›^×+€Ià €EØ×+Ñ+Ó-ò D‰
ˆˆUÜ% cÕ*¬z¸%ÄÕ/EØ�L‰LÔ;¸EÓBÕCðDô “%€DØ!€FØò  ˆÚ�D Ò$Ø�H‰H�TŒNØ�M‰M˜$Õð ð €Mð ,ús&   ‚B-–B+—'B-¿B-Á/B-Â B-Â'B-ra   c                 óf   — ddl m} ddl}|j                  dury| s
 |dd¬«      ‚|r
 |dd¬«      ‚y)	a\  
    Enforce proxy-level managed files when litellm.require_managed_files is enabled.

    Raises:
        HTTPException: 400 if the upload would bypass the managed-files flow, i.e.
            target_model_names is missing or a model parameter routes the request
            through the direct provider path instead of the managed-files hook.
    r   r©   NTr&   zËtarget_model_names is required when require_managed_files is enabled in litellm_settings. Provide one or more model aliases via the target_model_names form field (e.g. target_model_names=my-model-alias).r¬   z®model is not allowed when require_managed_files is enabled in litellm_settings. Uploads must go through managed files using target_model_names instead of the model parameter.)r°   rª   ÚlitellmÚrequire_managed_files)ra   rj   rª   rQ  s       r.   Ú"validate_managed_files_requirementrS  «  sT   € õ &ãà×$Ñ$¨DÑ0ØáÙØðZô
ð 	
ñ ÙØðEô
ð 	
ð r0   Úresource_idÚresource_kind)rw   rx   zfine-tuning jobÚmanaged_files_objc           
   ƒ   óP  K  — ddl m} ddl}|j                  dury| syt	        | «      s |dd|› d|› d|› d	�¬
«      ‚t        |t        «      s
 |dd¬
«      ‚|dk(  r|j                  | |«      ƒ d{  –—† n|j                  | |«      ƒ d{  –—† }|ry |dd|› d�¬
«      ‚7 Œ/7 Œ­w)a‰  
    Enforce proxy-level managed resources on every route that accepts a provider-issued id
    when ``litellm.require_managed_files`` is enabled, and authenticate managed ids against
    the caller's stored ownership record.

    Ownership is only recorded for LiteLLM managed ids, so a raw provider id is forwarded to the
    provider under shared credentials without any tenant check; knowing another tenant's provider
    id would be enough to read, reuse, or destroy the object behind it.

    Raises:
        HTTPException: 400 for a raw id, 403 for an inaccessible managed id, or 500 when
            ownership validation is unavailable.
    r   r©   NTr&   zRaw provider zg ids cannot be used when require_managed_files is enabled in litellm_settings. Use the LiteLLM managed z id returned when the z was created.r¬   r   z5Managed resource ownership validation is unavailable.rw   i“  z0The caller does not have access to this managed z id.)	r°   rª   rQ  rR  rW   rL   r6   r=   rB   )rT  rU  r8   rV  rª   rQ  Ú
can_accesss          r.   Úvalidate_managed_id_requirementrY  Ó  sé   è ø€ õ& &ãà×$Ñ$¨DÑ0ØáØä-¨kÔ:ÙØà ˜ð /=Ø=J¸OÐKaØ �/ ð0ô
ð 	
ô Ð'Ô)EÔFÙØØJô
ð 	
ð ˜FÒ"ð  ×=Ñ=¸kÐK\Ó]×]Ð]à$×DÑDÀ[ÐRcÓd×dð ñ
 Øá
ØØAÀ-ÀÐPTÐUôð ð 	^øàdús$   ‚A0B&Á2B"Á3B&ÂB$ÂB&Â$B&c                 ó˜   — |j                  d«      xs8 | j                  j                  d«      xs | j                  j                  d«      S )z™
    Extract model parameter from request.

    Priority:
    1. request_body.model
    2. Query parameter (?model=)
    3. Header (x-litellm-model)
    rj   rž   )rŸ   r    r¡   )r¢   r6  s     r.   r?  r?    s@   € ð ×Ñ˜GÓ$Òs¨×(<Ñ(<×(@Ñ(@ÀÓ(IÒsÈWÏ_É_×M`ÑM`ÐarÓMsÐsr0   Úunified_batch_id.c           	      ó&  — t        | dd «      }t        |t        «      rt        |«      nd}t	        d„ t        |t        «      r|nd |xs d t        |t        «      r-|s+|j                  t        j                  j                  «      r|nd fD «       «      S )Nr‡   Fc              3   ó$   K  — | ]  }|r|–— Œ
 y ­wr:   r;   )Ú.0Ú	candidates     r.   ú	<genexpr>z6_batch_response_model_id_candidates.<locals>.<genexpr>'  s   è ø€ ò àñ ô 	ñùs   ‚)	rŒ   rL   rF   rW   rÖ   rQ   r   rR   rS   )rŽ   r[  Úresponse_idÚdecoded_response_ids       r.   Ú#_batch_response_model_id_candidatesrc    s–   € ô ! ¨4°Ó6€Kä;EÀkÔSVÔ;WÔ*¨;Ô7Ð]bð ô ñ ô !+Ð+;¼SÔ AÑÀtØÒ' 4ä˜+¤sÔ+Ù'Ø×&Ñ&¤|×'QÑ'Q×'WÑ'WÔXñ ð ð
ôó ð r0   rŽ   r   c                 óŽ   ‡— t        | dd «      xs i }|j                  d«      }|r|S t        ˆfd„t        | |«      D «       d «      S )NÚ_hidden_paramsr¦   c              3   ó<   •K  — | ]  }t        |«      xŠr‰–— Œ y ­wr:   )ro   )r^  r_  Úcandidate_model_ids     €r.   r`  z/_model_id_for_batch_response.<locals>.<genexpr>?  s*   øè ø€ ò 	
àÜ&HÈÓ&SÐSÐ"ÐSô ñ	
ùs   ƒ)rŒ   rŸ   Únextrc  )rŽ   r[  Úhidden_paramsr¦   rg  s       @r.   Ú_model_id_for_batch_responserj  6  sX   ø€ ô # 8Ð-=¸tÓDÒJÈ€MØ#×'Ñ'¨
Ó3€HÙØˆÜó	
ä@ÀÐK[Ó\ô	
ð
 	óð r0   c                 ó¸   — t        | dd «      xs i }|j                  d«      }t        t        |t        «      r|nt        | dd «      |j                  d«      ¬«      S )Nre  r7   rŠ   rÇ   )r[   r\   )rŒ   rŸ   rb   rL   rF   )rŽ   ri  r7   s      r.   Ú_model_name_for_batch_responserl  H  s]   € Ü" 8Ð-=¸tÓDÒJÈ€MØ*×.Ñ.Ð/@ÓA€OÜ1ä�o¤sÔ+ñ .ä�X˜°Ó5Ø)×-Ñ-¨lÓ;ô	ð r0   Údb_batch_objectc                 óª   — ddl m} t        | dd «      }t        |t        «      r|sy t        | dd «      } ||t        |t        «      r|¬«      S d ¬«      S )Nr   r   Ú
created_byrº   )Úuser_idrº   )rÎ   r   rŒ   rL   rF   )rm  r   ro  Úraw_team_ids       r.   Ú _batch_owner_auth_from_db_objectrr  S  sQ   € Ý3ä °¸tÓD€JÜ�j¤#Ô&©jØÜ  °)¸TÓB€KÙ *ÄZÐP[Ô]`ÔEa°kÔlÐlÐgkÔlÐlr0   c              ƒ   ó4  K  — t        | d«      rw| j                  rjt        | j                  «      sT|rQ	 t        |«      j                  j                  dd| j                  ii¬«      ƒ d{  –—† }|r|j                  | _        yyyyyy7 Œ# t        $ r Y yw xY w­w)zÈ
    If the batch response contains a raw provider input_file_id (not already a
    unified ID), look up the corresponding unified file ID from the managed file
    table and replace it in-place.
    rŠ   Úflat_model_file_idsÚhas©ÚwhereN)r‹   rŠ   rW   r   ÚtableÚ
find_firstr7   rT   )rŽ   Úprisma_clientÚmanaged_files      r.   Ú resolve_input_file_id_to_unifiedr|  ]  s¯   è ø€ ô 	�˜/Ô*Ø×"Ò"Ü2°8×3IÑ3IÔJÙð	Ü(=¸mÓ(L×(RÑ(R×(]Ñ(]Ø,¨u°h×6LÑ6LÐ.MÐNð )^ó )÷ #ˆLñ Ø)5×)EÑ)E�Õ&ð ð ð Kð #ð 	+ð#ùô
 ò 	Ùð	üs:   ‚0B³6B	 Á)BÁ*B	 ÂBÂB	 Â		BÂBÂBÂBc              ƒ   ó  K  — |sydD ]h  }t        | |d«      }|rt        |«      rŒ	 t        |«      j                  j	                  dd|ii¬«      ƒ d{  –—† }|rt        | ||j                  «       Œj y7 Œ # t        $ r Y Œyw xY w­w)zÚ
    If the batch response contains raw provider output_file_id or error_file_id
    (not already unified IDs), look up the corresponding unified file IDs from
    the managed file table and replace them in-place.
    N©rˆ   r‰   rt  ru  rv  )rŒ   rW   r   rx  ry  r�   r7   rT   )rŽ   rz  r�   Úraw_idr{  s        r.   Ú"resolve_output_file_ids_to_unifiedr€  s  s    è ø€ ñ ØØ3ò ˆÜ˜ 4¨Ó.ˆÙÔ;¸FÔCØð	Ü!6°}Ó!E×!KÑ!K×!VÑ!VØ,¨u°f¨oÐ>ð "Wó "÷ ˆLñ Ü˜ $¨×(DÑ(DÔEøñð
ùô
 ò 	Ùð	üs:   ‚$B§,A6ÁA4ÁA6Á1BÁ4A6Á6	BÁ?BÂBÂBÚraw_file_idsrz  zPrismaClient | Nonec           	   ƒ   ó"  K  — | r|st        i «      S t        |«      j                  j                  ddt	        | «      ii¬«      ƒ d {  –—† }t        |D ��ci c]$  }|j
                  D ]  }|| v r||j                  “Œ Œ& c}}«      S 7 Œ?c c}}w ­w)Nrt  ÚhasSomerv  )r   r   rx  Ú	find_manyÚsortedrt  r7   )r�  rz  Úmanaged_filesr{  r  s        r.   Úmap_raw_file_ids_to_unifiedr‡  ‰  s¯   è ø€ ñ ™}Ü Ó#Ð#Ü!6°}Ó!E×!KÑ!K×!UÑ!UØ$ y´&¸Ó2FÐ&GÐHð "Vó "÷ €Mô ð !.÷	
àØ&×:Ñ:ò	
ð Ø˜Ñ%ð �L×0Ñ0Ñ0ð	
Øó	
óð ðúó	
ùs$   ‚ABÁBÁBÁ)B	
Á?	BÂ	BÚunified_id_by_raw_idc                 ó¸   — dt        | dd «      fdt        | dd «      fdt        | dd «      ffD ]+  \  }}t        |t        «      sŒ||v sŒt        | |||   «       Œ- y )NrŠ   rˆ   r‰   )rŒ   rL   rF   r�   )rŽ   rˆ  Ú	file_attrr  s       r.   Úapply_unified_file_idsr‹  ›  st   € à	œ' (¨O¸TÓBÐCØ	œ7 8Ð-=¸tÓDÐEØ	œ' (¨O¸TÓBÐCðò GÑˆ	�6ô
 �fœcÕ" vÐ1EÒ'EÜ�H˜iÐ)=¸fÑ)EÕFñGr0   z!LiteLLM_ManagedObjectTable | Nonec           
   ƒ   ó*  K  — t        | |«      ƒ d{  –—†  t        | |«      ƒ d{  –—†  |€yt        | |«      }|syt        | «      }|�t	        |«      nd}	|	�|	n|}
|
€ydD ]}  }t        | |d«      }|rt        |«      rŒ	 |j                  |||¬«      }|j                  |dt        |
dd«      ||i|
¬«      ƒ d{  –—†  t        | ||«       |j                  d||«       Œ y7 ŒÐ7 Œ¾7 Œ+# t        $ r}|j                  d|||«       Y d}~Œ©d}~ww xY w­w)zFNormalize batch file IDs to managed unified IDs before DB persistence.Nr~  )rˆ   r¦   rÇ   Úparent_otel_span)rk   r&  Úlitellm_parent_otel_spanÚmodel_mappingsr8   z3Converted batch %s %r to managed ID before DB writez?Failed to convert batch %s=%r to managed ID before DB write: %s)r|  r€  rj  rl  rr  rŒ   rW   Úget_unified_output_file_idÚstore_unified_file_idr�   ÚdebugrT   Úwarning)rŽ   rV  rz  Úverbose_proxy_loggerr8   rm  r[  r¦   rÇ   Ú
owner_authÚeffective_authrŠ  Úraw_file_idÚnew_unified_file_idÚes                  r.   Ú&ensure_batch_response_managed_file_idsrš  ¥  si  è ø€ ô +¨8°]Ó
C×CÐCÜ
,¨X°}Ó
E×EÐEàÐ Øä2°8Ð=MÓN€HÙØä6°xÓ@€JàM\ÐMhÔ8¸ÔIÐnr€JØ*4Ð*@™JÐFW€NØÐØà8ò ˆ	Ü˜h¨	°4Ó8ˆÙÔ@ÀÔMØð	Ø"3×"NÑ"NØ*Ø!Ø%ð #Oó #Ðð
 $×9Ñ9Ø+Ø Ü)0°ÐASÐUYÓ)ZØ (¨+Ð6Ø"0ð :ó ÷ ð ô �H˜iÐ)<Ô=Ø ×&Ñ&Ð'\Ð^gÐitÕuñ%ð# DøØEøð4ùô ò 	Ø ×(Ñ(ØQÐS\Ð^iÐkl÷ñ ûð	üs\   ‚D’C#“D¦C%§ADÂ:C)Â;C'Â<$C)Ã DÃ%DÃ'C)Ã)	DÃ2DÄDÄDÄDrt   c              ƒ   ó  K  — ddl }ddlm} |�|sy	 |syt        |«      j                  j                  d| i¬«      ƒ d{  –—† }|r|j                  syt        d|j                  «      }t        |t        «      r|j                  |«      n|}	 |j                  |	«      }
| |
_        t        |
|||||¬«      ƒ d{  –—†  |j                  d	| |
j                  «       ||
fS 7 ŒŸ7 Œ'# t         $ r}|j#                  d
|«       Y d}~yd}~ww xY w­w)a6  
    Try to retrieve batch object from ManagedObjectTable for consistent state.

    Args:
        batch_id: The batch ID (may be unified/encoded)
        unified_batch_id: Result from _is_base64_encoded_unified_file_id()
        managed_files_obj: The managed_files proxy hook object
        prisma_client: Prisma database client
        verbose_proxy_logger: Logger instance

    Returns:
        Tuple of (db_batch_object, response_batch)
        - db_batch_object: Raw database object (or None)
        - response_batch: Parsed LiteLLMBatch object (or None)
    r   Nr   )NNr@   rv  zMapping[str, object] | str)rŽ   rV  rz  r”  rm  r[  z9Retrieved batch %s from ManagedObjectTable with status=%szNFailed to retrieve batch from ManagedObjectTable: %s, falling back to provider)r(  Úlitellm.types.utilsr   r   rx  ry  r&  r   rL   rF   r)  Úmodel_validater‡   rš  r’  ÚstatusrT   r“  )rt   r[  rV  rz  r”  r(  r   rm  r&  Ú
batch_datarŽ   r™  s               r.   Úget_batch_from_databaser   Ù  s6  è ø€ ó, å0àÐ Ñ(8Øð(ÙØä'>¸}Ó'M×'SÑ'S×'^Ñ'^Ø&¨Ð1ð (_ó (
÷ "
ˆñ  o×&AÒ&AØô "Ø(¨/×*EÑ*Eó
ˆô 8BÀ+ÌsÔ7S˜DŸJ™J {Ô3ÐYdˆ
Ø5˜,×5Ñ5°jÓAˆØˆŒô 5ØØ/Ø'Ø!5Ø+Ø-ô
÷ 	
ð 	
ð 	×"Ñ"ØGÈÐS[×SbÑSbô	
ð  Ð(Ð(ð="
øð"	
ùô ò Ø×$Ñ$Ø\Ð^_ô	
ô ûð	üsi   ‚D“C$ •D–*C$ Á C ÁC$ ÁDÁA&C$ Â:C"Â;$C$ ÃDÃ C$ Ã"C$ Ã$	D	Ã-DÃ?DÄD	Ä	Dc                  óÜ   — ddl m}  | sy	 ddlmc m} t        |dd«      }|€y|j                  d«      }|€yt        t        |dd«      dd«      }t        |d	d«      d
u S # t        $ r Y yw xY w)a	  
    Whether the CheckBatchCost poller will account for a managed batch's cost itself.

    False whenever the poller cannot be relied on: polling disabled by config, the job
    absent from the scheduler because the enterprise import failed, or the poller not
    yet having confirmed that the batch_processed column exists. That last condition
    matters because the poller needs the column both to find outstanding batches and to
    mark them accounted; without it the poller falls back to a query that excludes
    terminal statuses, so a batch the retrieve path has already marked complete becomes
    invisible to it. Defaulting to False until the poller confirms support keeps the
    retrieve path accounting in exactly the cases the poller would drop the batch.
    r   )ÚPROXY_BATCH_POLLING_ENABLEDFNÚ	schedulerÚcheck_batch_cost_jobÚfuncÚ__self__Ú!batch_processed_support_confirmedT)Úlitellm.constantsr¢  Úlitellm.proxy.proxy_serverÚproxyÚproxy_serverrŒ   Úget_jobrT   )r¢  Úproxy_server_moduler£  ÚjobÚpollers        r.   Úbatch_cost_poller_is_activer°  !  s‡   € õ >á&Øðß@Ð@äÐ/°¸dÓCˆ	ØÐØØ×ÑÐ 6Ó7ˆØˆ;ØÜœ  f¨dÓ3°ZÀÓFˆÜ�vÐBÀEÓJÈdÐRÐRøÜò Ùðús   ‹A ¤A ¸&A Á	A+Á*A+c                 óz   — | j                   �y| j                  }|€y|j                  dkD  xr |j                  dk(  S )a%  Whether a "completed" batch may be retired from cost recovery.

    ``batch_processed=True`` is the sole re-pickup gate for CheckBatchCost's
    cost-recovery poller, so setting it retires the batch permanently. A batch can
    reach ``status="completed"`` while ``output_file_id`` is still ``None`` (the
    provider response briefly lags before the output id populates). Retiring in that
    window loses the spend record forever. Retire only once we can prove there is
    nothing left to recover: the output file has actually arrived, or the provider
    reported a positive total with zero successful request lines, proving it
    enumerated the batch and none succeeded. A zero or unknown total means counts
    are unreported, so stay eligible and let the next poller pass revisit it. (#37713)
    TFr   )rˆ   Úrequest_countsÚtotalÚ	completed)rŽ   r²  s     r.   Ú_completed_batch_safe_to_retirerµ  A  sH   € ð ×ÑÐ*ØØ×,Ñ,€NØÐØØ×Ñ !Ñ#ÒE¨×(@Ñ(@ÀAÑ(EÐEr0   Ú	operationÚpoller_owns_accountingc
           	   ƒ   ó^  K  — ddl }
|�|sy	 |sy|�|n.t        |«      j                  j                  d| i¬«      ƒ d{  –—† }t	        |||||||¬«      ƒ d{  –—†  |r|j
                  |j
                  k(  ry|r)|j                  d| |j
                  |j
                  «       n|j                  d| |j
                  |«       |j
                  dk7  r|j
                  nd	}||j                  «       |
j                  j                  «       d
œ}|	€
t        «       n|	}|d	k(  r|st        |«      rd|d<   	 t        |«      j                  j                  d| i|¬«      ƒ d{  –—†  y7 �Œ$7 �Œ7 Œ# t        $ r�}t        |«      j                  «       }d|v rg|j!                  d«      �V|j#                  d|«       |j%                  dd«       t        |«      j                  j                  d| i|¬«      ƒ d{  –—†7   n‚ Y d}~yd}~ww xY w# t        $ r}|j'                  d|«       Y d}~yd}~ww xY w­w)a  
    Update batch status and object in ManagedObjectTable.

    Args:
        batch_id: The batch ID (unified/encoded)
        unified_batch_id: Result from _is_base64_encoded_unified_file_id()
        response: The batch response object with updated state
        managed_files_obj: The managed_files proxy hook object
        prisma_client: Prisma database client
        verbose_proxy_logger: Logger instance
        db_batch_object: Optional existing database object; fetched by unified_object_id when omitted
        operation: Description of operation ("update", "cancel", etc.)
        user_api_key_dict: Optional auth context for creating managed file IDs
        poller_owns_accounting: Whether the caller already decided that the cost poller
            owns this batch's accounting. Callers that suppress their own inline
            accounting must pass the same decision they acted on, because re-deciding
            here can observe a poller that became usable in between and leave the batch
            unmarked after it was already accounted for, billing it twice. Left None by
            callers that record no cost themselves.
    r   Nr@   rv  )rŽ   rV  rz  r”  r8   rm  r[  z&Updating batch %s status from %s to %sz'Updating batch %s status to %s after %sr´  Úcomplete)rž  r&  Ú
updated_atTÚbatch_processed)rw  rœ   z@batch_processed column not found, retrying update without it: %sz7Failed to update batch status in ManagedObjectTable: %s)Úlitellm.utilsr   rx  ry  rš  rž  ÚinfoÚmodel_dump_jsonÚutilsÚget_utc_datetimer°  rµ  rî   rT   rF   r  rŸ   r“  rï   r«   )rt   r[  rŽ   rV  rz  r”  rm  r¶  r8   r·  rQ  Úeffective_db_batch_objectÚ	db_statusÚupdate_dataÚpoller_ownsÚcol_errÚerr_strr™  s                     r.   Úupdate_batch_in_databaserÇ  V  so  è ø€ ó@ àÐ Ñ(8ØðDaÙØð Ð*ñ ä.¨}Ó=×CÑC×NÑNÐViÐksÐUtÐNÓu×uð 	"ô 5ØØ/Ø'Ø!5Ø/Ø5Ø-ô
÷ 	
ð 	
ñ %¨¯©Ð<U×<\Ñ<\Ò)\Øá$Ø ×%Ñ%Ø8¸(ÐD]×DdÑDdÐfn×fuÑfuõð !×%Ñ%Ð&OÐQYÐ[c×[jÑ[jÐluÔvð /7¯o©oÀÒ.L˜8Ÿ?š?ÐR\ˆ	ð  Ø#×3Ñ3Ó5Ø!Ÿ-™-×8Ñ8Ó:ñ1
ˆð ?UÐ>\Ô8Ô:ÐbxˆØ˜
Ò"©;Ô;ZÐ[cÔ;dØ-1ˆKÐ)Ñ*ð	Ü)¨-Ó8×>Ñ>×EÑEØ*¨HÐ5Ø ð Fó ÷ ñ ðS vùð	
ùðFùô ò 	ô ! ›\×/Ñ/Ó1ˆGØ  GÑ+°·±Ð@QÓ0RÐ0^Ø$×,Ñ,ØVÐX_ôð —‘Ð 1°4Ô8Ü-¨mÓ<×BÑB×IÑIØ.°Ð9Ø$ð Jó ÷ ò ð
 ôûð	ûô ò aØ×"Ñ"Ð#\Ð^_×`Ñ`ûðaüs°   ‚
H-�H �H-�.H ¾E"¿H ÁE%ÁH Á8H-Á9B7H Ä1+E* ÅE(ÅE* Å!H-Å"H Å%H Å(E* Å*	HÅ3A=G=Ç0G3Ç1G=Ç8H Ç<H-Ç=HÈH È	H*ÈH%È H-È%H*È*H-)rw   r:   )rò   )NF)T)NNN)rm  r   r    zUserAPIKeyAuth | None)r    N)Nrî   NN)erN   r  rd   Úcollections.abcr   Údataclassesr   r   Útypesr   Útypingr   r   r	   r
   r   r   r   r   rÎ   r   Ú'litellm.repositories.table_repositoriesr   r   Úlitellm.types.llms.openair   rœ  r   r°   r   Úprisma.modelsr   r   Úlitellm.proxy.utilsr   Úlitellm.routerr   r   r   r5  r   Úintr/   rF   r4   r6   rW   rZ   rb   rÛ   r_   ro   ru   r…   r�   r—   r™   rG   r›   r×   rÖ   r¥   r´   rå   rè   rë   rç   rô   rø   r  r  r  r  r  r#  r%  r+  r-  r@  r<  r=  rE  r>  rS  ÚobjectrY  r?  rc  rj  rl  rr  r|  r€  rÙ   r‡  r‹  rš  r   r°  rµ  rÇ  r;   r0   r.   ú<module>rÓ     s*  ðÜ Û Û 	Ý #ß (Ý "÷	÷ 	ó 	õ 0÷õ 9Ý ,áÝÝ8å3Ý0Ý%Ý0ð #Ð �UÓ "à+.Ð ! 5Ó .ð C¨$¡Jð °4ó ð$¨¨d©
ð °tó ð* ô 8ó ó ðð°ð ¸¸gÀe¹nÑ8Ló ð"¨Cð °Có ðØ ™:ðØ<?À$¹Jðàˆ4�Zóð°Sð ¸TÀ#¹Yó ð*°ð ¸¸d¹
ó ð 	6°ð 	6¸ó 	6ñ)$ sð )$°3ð )$ÀÈÑAYð )$Ðgjó )$ðX¨sð °tó ð¨#ð °#¸±*ó ð: Sð ¨Só ð<: #ð :¨$ó :ð ñ+Øð+ð �‰+ð+ð ˆ3�‰:�s˜T‘zÐ!Ñ"ó	+ðJ .ñ#àð#ð ó#ðLuØ˜Ñ"ðuà'ðuð ðuð 
ˆD�[ó	uðpFØ
ðFà˜Ñ"ðFð (ðFð ð	Fð
 
óFð,VØ
ðVàðVð �D‰jðVð 
ó	Vð8 Ø).ñ	"Ø
ð"àð"ð �4‰Zð"ð #'ð	"ð
 
ó"ð< $(ñ5#Øð5#ð ð	5#ð
 !ð5#ð ˆ4��t‘˜S 4™Z¨°©Ð4Ñ5ó5#ò|'Ð ˜eó ò
'Ð ˜eó 
ò'Ð ˜eó ð  Øð*Ð  ó ð ØØØØØØØñ	!Ð ˜ó 	ð&°ð &¸ó &ñ0°ð ¸sÀT¹zð ÐUXó ð8¨Sð °Tó ð2!&°4¸$±;ð !&À3ó !&ðR ÷eð eó ðeð: !%Ø*.Ø&*ñ	&Øð&à˜‘+ð&ð ! 4™Zð&ð ˜t™ð	&ð
 ó&ñR¸¸d¹
ð Ècó ð  +/ñØ  4™Zðà	ˆ#�Yóð$h Cð h¨Dó hð¸ð ÀtÈCÁyó ð8 ñ%
Ø˜S™	ð%
à�‰:ð%
ð 
ó%
ðP8Ø�t‘ð8àÐ=Ñ>ð8ð (ð8ð  ‘}ð	8ð
 
ó8ðv	t )ð 	t¸4ð 	tÀCÈ$ÁJó 	tð"à˜G E™NÑ*¨TÑ1ðð ˆ3�ˆ8�_óð.Øðà˜G E™NÑ*¨TÑ1ðð 	ˆ4�Zóð$¨^ð ÀÀdÁ
ó ómóó,ð,Ø˜C‘.ðØ1FðàˆS�#ˆXÑóð$G ^ð GÈ7ÐSVÐX[ÐS[ÑK\ð GÐaeó Gð Ø;?Ø48ñ1ð 9ð1ð ˜G E™NÑ*¨TÑ1ð1ð 
ó1ðhEØðEà˜G E™NÑ*óEðP Tó ð@F¨nð FÀó Fð8 <@ØØØ*.ñiaØðiaà˜G E™NÑ*ðiað 9ðiað ðiað ! 4™Kôiar0   