Ë
    uPêjV:  ã                   óò   — U d Z ddlZddlmZmZ ddlZddlmZ ddl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 dd
lmZ ddlmZ ddlmZmZ ddlmZmZmZmZm Z  ddl!m"Z" dZ#ee$d<    G d„ de«      Z%y)a_  
Manus Files API implementation.

Manus has an OpenAI-compatible Files API with some differences:
- Uses API_KEY header instead of Authorization: Bearer
- File upload is a two-step process:
  1. Create file record to get upload URL
  2. Upload file content to the upload URL

Reference: https://open.manus.im/docs/openai-compatibility#file-management
é    N)ÚAnyÚFinal)ÚFileDeleted)Úverbose_logger)Úextract_file_data)Úencode_url_path_segment)ÚBaseLLMException)ÚBaseFilesConfigÚLiteLLMLoggingObj©ÚOpenAIError)Úget_secret_str)ÚTwoStepFileUploadConfigÚTwoStepFileUploadRequest)ÚCreateFileRequestÚFileContentRequestÚHttpxBinaryResponseContentÚ%OpenAICreateFileRequestOptionalParamsÚOpenAIFileObject)ÚLlmProviderszhttps://api.manus.imÚMANUS_API_BASEc                   ó´  — e Zd ZdZd„ Zedefd„«       Z	 	 d)dede	de
d	ed
ede	dz  de	dz  defd„Zde	de
e   fd„Zded	ede	dedef
d„Z	 d*de	dz  de	dz  de	d	ed
ededz  de	fd„Zde	dedeej&                  z  defd„Zde	ded	ed
edef
d„Zde	dz  dej2                  ded
edef
d„Zde	d	ed
edee	ef   fd„Zdej2                  ded
edefd„Zde	d	ed
edee	ef   fd„Z dej2                  ded
ede!fd „Z"d!e	dz  d	ed
edee	ef   fd"„Z#dej2                  ded
ede
e   fd#„Z$d$ee	e%f   defd%„Z&d&e'd	ed
edee	ef   fd'„Z(dej2                  ded
ede)fd(„Z*y)+ÚManusFilesConfiga*  
    Configuration for Manus Files API.

    Manus uses:
    - API_KEY header for authentication (not Authorization: Bearer)
    - Two-step file upload process
    - Content-Type: application/json for all requests

    Reference: https://open.manus.im/docs/openai-compatibility#file-management
    c                  ó   — y ©N© ©Úselfs    úl/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/llms/manus/files/transformation.pyÚ__init__zManusFilesConfig.__init__7   s   € Øó    Úreturnc                 ó"   — t         j                  S r   )r   ÚMANUSr   s    r   Úcustom_llm_providerz$ManusFilesConfig.custom_llm_provider:   s   € ä×!Ñ!Ð!r!   NÚheadersÚmodelÚmessagesÚoptional_paramsÚlitellm_paramsÚapi_keyÚapi_basec                 óŠ   — |xs t         j                  xs t        d«      }|st        d«      ‚|j	                  |ddœ«       |S )zá
        Validate environment and set up headers for Manus API.

        Manus uses API_KEY header instead of Authorization: Bearer.
        For file uploads, don't set Content-Type - httpx will set it for multipart.
        ÚMANUS_API_KEYú\Manus API key is required. Set MANUS_API_KEY environment variable or pass api_key parameter.úapplication/json©ÚAPI_KEYzContent-Type)Úlitellmr+   r   Ú
ValueErrorÚupdate)r   r&   r'   r(   r)   r*   r+   r,   s           r   Úvalidate_environmentz%ManusFilesConfig.validate_environment>   sO   € ð  ÒOœWŸ_™_ÒO´¸Ó0OˆáÜØnóð ð 	�‰à"Ø 2ñô	
ð ˆr!   c                 ó   — dgS )z†
        Return supported OpenAI file creation parameters for Manus.
        Manus supports the standard 'purpose' parameter.
        Úpurposer   )r   r'   s     r   Úget_supported_openai_paramsz,ManusFilesConfig.get_supported_openai_params_   s   € ð
 ˆ{Ðr!   Únon_default_paramsÚdrop_paramsc                 ó   — |S )z‡
        Map OpenAI parameters to Manus-specific parameters.
        Manus is OpenAI-compatible, so no special mapping needed.
        r   )r   r:   r)   r'   r;   s        r   Úmap_openai_paramsz"ManusFilesConfig.map_openai_paramsf   s
   € ð Ðr!   Ústreamc                 ó¬   — |xs% t         j                  xs t        d«      xs t        }|j	                  d«      }|j                  d«      r|› d�S |› d�S )z•
        Get the complete URL for Manus Files API endpoint.

        Returns:
            str: The full URL for the Manus /v1/files endpoint
        r   ú/z/v1z/filesz	/v1/files)r3   r,   r   r   ÚrstripÚendswith)r   r,   r+   r'   r)   r*   r>   s          r   Úget_complete_urlz!ManusFilesConfig.get_complete_urls   s_   € ð Òeœw×/Ñ/Òe´>ÐBRÓ3SÒeÔWeˆð —?‘? 3Ó'ˆð ×Ñ˜UÔ#Ø�Z˜vÐ&Ð&Ø�˜9Ð%Ð%r!   Úerror_messageÚstatus_codec                 ó   — t        |||¬«      S )z…
        Return the appropriate error class for Manus API errors.
        Uses OpenAIError since Manus is OpenAI-compatible.
        )rE   Úmessager&   r   )r   rD   rE   r&   s       r   Úget_error_classz ManusFilesConfig.get_error_classŒ   s   € ô Ø#Ø!Øô
ð 	
r!   Úcreate_file_datac           	      óê  — |j                  d«      }|€t        d«      ‚t        |«      }|d   xs  dt        t	        j                  «       «      › �}|d   }| j                  |j                  d«      |j                  d«      |||¬«      }	|j                  d«      xs t        j                  xs t        d	«      }
|
st        d
«      ‚t        t        d|	|
ddœd|i¬«      t        ddi |¬«      dd¬«      S )uQ  
        Transform OpenAI-style file creation request into Manus's two-step format.

        Manus API spec (https://open.manus.im/docs/openai-compatibility#file-management):
        1. POST /v1/files with JSON {"filename": "..."} â†’ returns {"id": "...", "upload_url": "..."}
        2. PUT to upload_url with raw file content
        ÚfilezFile data is requiredÚfilenameÚfile_Úcontentr,   r+   ©r,   r+   r'   r)   r*   r.   r/   ÚPOSTr0   r1   )ÚmethodÚurlr&   ÚdataÚPUTÚ ÚbodyÚ
upload_url)Úinitial_requestÚupload_requestÚupload_url_locationÚupload_url_key)Úgetr4   r   ÚintÚtimerC   r3   r+   r   r   r   )r   r'   rI   r)   r*   Ú	file_dataÚextracted_datarL   rN   r,   r+   s              r   Útransform_create_file_requestz.ManusFilesConfig.transform_create_file_requestœ   s!  € ð ,×/Ñ/°Ó7ˆ	ØÐÜÐ4Ó5Ð5ä 1°)Ó <ˆØ(¨Ñ4ÒR¸%ÄÄDÇIÁIÃKÓ@PÐ?QÐ8RˆØ'¨	Ñ2ˆð ×/Ñ/Ø#×'Ñ'¨
Ó3Ø"×&Ñ& yÓ1ØØ+Ø)ð 0ó 
ˆð (×+Ñ+¨IÓ6Òl¼'¿/¹/ÒlÌ^Ð\kÓMlˆáÜØnóð ô
 'Ü4ØØà&Ø$6ñð ! (Ð+ôô 4ØØØØô	ð !'Ø'ô#
ð 	
r!   Úraw_responseÚlogging_objc                 ó>  — 	 |j                  d«      }|r|}n0t        j                  d|j                  «       |j	                  «       }t        j                  d|«       |j                  dd«      }|rG	 t        t        j                  t        j                  |j                  dd«      dd	 d
«      «      «      }nt        t        j                  «       «      }t        |j                  dd«      |j                  dd«      ||j                  dd«      d|j                  dd«      d|j                  d«      ¬«      S # t        t        f$ r  t        t        j                  «       «      }Y Œ�w xY w# t        $ r)}	t        j                  d|	«       t        d|	› �«      ‚d}	~	ww xY w)a<  
        Transform Manus's file upload response into OpenAI-style FileObject.

        For two-step uploads, the handler stores the initial response in litellm_params.
        We need to return the file object from the initial POST, not the final PUT.

        Manus initial response format:
        {
            "id": "file-abc123xyz",
            "object": "file",
            "filename": "document.pdf",
            "status": "pending",
            "upload_url": "https://...",
            "upload_expires_at": "...",
            "created_at": "..."
        }
        Úinitial_file_responsezManus raw response text: %szManus file response: %sÚ
created_atrU   ÚZú+00:00Né   ú%Y-%m-%dT%H:%M:%SÚidÚbytesr   rL   rK   r8   Ú
assistantsÚuploadedÚstatus_details©rk   rl   rf   rL   Úobjectr8   Ústatusro   z%Error parsing Manus file response: %sz#Error parsing Manus file response: )r\   r   ÚdebugÚtextÚjsonr]   r^   ÚmktimeÚstrptimeÚreplacer4   Ú	TypeErrorr   Ú	ExceptionÚ	exception)
r   r'   rb   rc   r*   Úinitial_response_dataÚresponse_jsonÚcreated_at_strrf   Úes
             r   Útransform_create_file_responsez/ManusFilesConfig.transform_create_file_responseÙ   s†  € ð0*	Hà+9×+=Ñ+=Ð>UÓ+VÐ!Ù$Ø 5‘ô ×$Ñ$Ð%BÀL×DUÑDUÔVØ ,× 1Ñ 1Ó 3�ä× Ñ Ð!:¸MÔJð %2×$5Ñ$5°lÀBÓ$GˆNÙð2ä!$ÜŸ™Ü ŸM™MØ .× 6Ñ 6°s¸HÓ EÀcÀrÐ JØ 3óóó"‘Jô !¤§¡£Ó-�
ä#Ø ×$Ñ$ T¨2Ó.Ø#×'Ñ'¨°Ó3Ø%Ø&×*Ñ*¨:°rÓ:ØØ%×)Ñ)¨)°\ÓBØ!Ø,×0Ñ0Ð1AÓBô	ð 	øô #¤IÐ.ò 2Ü!$¤T§Y¡Y£[Ó!1’Jð2ûô ò 	HÜ×$Ñ$Ð%LÈaÔPÜÐBÀ1À#ÐFÓGÐGûð	Hús>   ‚A0E* Á3AD8 Â8A?E* Ä8,E'Å$E* Å&E'Å'E* Å*	FÅ3$FÆFÚfile_idc                 ó–   — | j                  |j                  d«      |j                  d«      d||¬«      }t        |d¬«      }|› d|› �i fS )z)Get URL and params for retrieving a file.r,   r+   rU   rO   r�   ©Ú
field_namer@   ©rC   r\   r   ©r   r�   r)   r*   r,   Úencoded_file_ids         r   Útransform_retrieve_file_requestz0ManusFilesConfig.transform_retrieve_file_request  óc   € ð ×/Ñ/Ø#×'Ñ'¨
Ó3Ø"×&Ñ& yÓ1ØØ+Ø)ð 0ó 
ˆô "9¸ÈYÔ!WˆØ�˜1˜_Ð-Ð.°Ð2Ð2r!   c                 ó,   — | j                  d|||¬«      S )z!Transform retrieve file response.N)r'   rb   rc   r*   )r€   ©r   rb   rc   r*   s       r   Ú transform_retrieve_file_responsez1ManusFilesConfig.transform_retrieve_file_response.  s(   € ð ×2Ñ2ØØ%Ø#Ø)ð	 3ó 
ð 	
r!   c                 ó–   — | j                  |j                  d«      |j                  d«      d||¬«      }t        |d¬«      }|› d|› �i fS )z'Get URL and params for deleting a file.r,   r+   rU   rO   r�   rƒ   r@   r…   r†   s         r   Útransform_delete_file_requestz.ManusFilesConfig.transform_delete_file_request<  r‰   r!   c                 ó8   — |j                  «       }t        di |¤ŽS )zTransform delete file response.r   )ru   r   )r   rb   rc   r*   r}   s        r   Útransform_delete_file_responsez/ManusFilesConfig.transform_delete_file_responseM  s    € ð  ,×0Ñ0Ó2ˆÜÑ+˜]Ñ+Ð+r!   r8   c                 ó„   — | j                  |j                  d«      |j                  d«      d||¬«      }i }|r||d<   ||fS )z%Get URL and params for listing files.r,   r+   rU   rO   r8   )rC   r\   )r   r8   r)   r*   r,   Úparamss         r   Útransform_list_files_requestz-ManusFilesConfig.transform_list_files_requestW  s]   € ð ×/Ñ/Ø#×'Ñ'¨
Ó3Ø"×&Ñ& yÓ1ØØ+Ø)ð 0ó 
ˆð ˆÙØ 'ˆF�9ÑØ˜ÐÐr!   c                 óŽ   — |j                  «       }|j                  dg «      }|D �cg c]  }| j                  |«      ‘Œ c}S c c}w )zTransform list files response.rS   )ru   r\   Ú_parse_file_dict)r   rb   rc   r*   r}   Ú
files_dataÚfs          r   Útransform_list_files_responsez.ManusFilesConfig.transform_list_files_responsej  sC   € ð  ,×0Ñ0Ó2ˆØ)×-Ñ-¨f°bÓ9ˆ
Ø2<Ö=¨Q�×%Ñ% aÕ(Ò=Ð=ùÒ=s   §AÚ	file_dictc                 ó:  — |j                  dd«      }|rG	 t        t        j                  t        j                  |j                  dd«      dd d«      «      «      }nt        t        j                  «       «      }t        |j                  dd«      |j                  d	d
«      ||j                  dd«      d|j                  dd«      |j                  dd«      |j                  d«      ¬«      S # t        t        f$ r  t        t        j                  «       «      }Y Œ w xY w)z(Parse a file dict into OpenAIFileObject.rf   rU   rg   rh   Nri   rj   rk   rl   r   rL   rK   r8   rm   rr   rn   ro   rp   )	r\   r]   r^   rv   rw   rx   r4   ry   r   )r   r™   r~   rf   s       r   r•   z!ManusFilesConfig._parse_file_dictu  sô   € à )§¡¨l¸BÓ ?ˆÙð
.Ü Ü—K‘KÜŸ™Ø*×2Ñ2°3¸ÓAÀ#À2ÐFØ/óóó‘
ô œTŸY™Y›[Ó)ˆJäØ�}‰}˜T 2Ó&Ø—-‘- ¨Ó+Ø!Ø—]‘] :¨rÓ2ØØ—M‘M )¨\Ó:Ø—=‘= ¨:Ó6Ø$Ÿ=™=Ð)9Ó:ô	
ð 		
øô ¤	Ð*ò .Ü ¤§¡£Ó-’
ð.ús   –AC+ Ã+,DÄDÚfile_content_requestc                 óº   — |j                  d«      }| j                  |j                  d«      |j                  d«      d||¬«      }t        |d¬«      }|› d|› d�i fS )	z/Get URL and params for retrieving file content.r�   r,   r+   rU   rO   rƒ   r@   z/content)r\   rC   r   )r   r›   r)   r*   r�   r,   r‡   s          r   Útransform_file_content_requestz/ManusFilesConfig.transform_file_content_request’  su   € ð .×1Ñ1°)Ó<ˆØ×/Ñ/Ø#×'Ñ'¨
Ó3Ø"×&Ñ& yÓ1ØØ+Ø)ð 0ó 
ˆô "9¸ÈYÔ!WˆØ�˜1˜_Ð-¨XÐ6¸Ð:Ð:r!   c                 ó   — t        |¬«      S )z Transform file content response.)Úresponse)r   r‹   s       r   Útransform_file_content_responsez0ManusFilesConfig.transform_file_content_response¤  s   € ô *°<Ô@Ð@r!   )NNr   )+Ú__name__Ú
__module__Ú__qualname__Ú__doc__r    Úpropertyr   r%   ÚdictÚstrÚlistr6   r   r9   Úboolr=   rC   r]   ÚhttpxÚHeadersr	   rH   r   r   ra   ÚResponser   r   r€   Útuplerˆ   rŒ   rŽ   r   r�   r“   r˜   r   r•   r   r�   r   r    r   r!   r   r   r   +   sž  „ ñ	òð ð" \ò "ó ð"ð #Ø#ñàðð ðð ð	ð
 ðð ðð �t‘ðð ˜‘*ðð 
óðB°ð ¸Ð>cÑ9dó ðà ðð ðð ð	ð
 ðð 
óð( #ñ&à˜‘*ð&ð �t‘ð&ð ð	&ð
 ð&ð ð&ð �t‘ð&ð 
ó&ð2
àð
ð ð
ð ˜Ÿ™Ñ%ð	
ð
 
ó
ð ;
àð;
ð ,ð;
ð ð	;
ð
 ð;
ð 
!ó;
ðzBHà�T‰zðBHð —n‘nðBHð 'ð	BHð
 ðBHð 
óBHðH3àð3ð ð3ð ð	3ð
 
ˆs�DˆyÑ	ó3ð"
à—n‘nð
ð 'ð
ð ð	
ð
 
ó
ð3àð3ð ð3ð ð	3ð
 
ˆs�DˆyÑ	ó3ð",à—n‘nð,ð 'ð,ð ð	,ð
 
ó,ð à�t‘ð ð ð ð ð	 ð
 
ˆs�DˆyÑ	ó ð&	>à—n‘nð	>ð 'ð	>ð ð		>ð
 
ÐÑ	ó	>ð
¨$¨s°C¨x©.ð 
Ð=Mó 
ð:;à0ð;ð ð;ð ð	;ð
 
ˆs�DˆyÑ	ó;ð$Aà—n‘nðAð 'ðAð ð	Að
 
$ôAr!   r   )&r¤   r^   Útypingr   r   rª   Úopenai.types.file_deletedr   r3   Úlitellm._loggingr   Ú8litellm.litellm_core_utils.prompt_templates.common_utilsr   Ú$litellm.litellm_core_utils.url_utilsr   Ú)litellm.llms.base_llm.chat.transformationr	   Ú*litellm.llms.base_llm.files.transformationr
   r   Ú litellm.llms.openai.common_utilsr   Úlitellm.secret_managers.mainr   Úlitellm.types.filesr   r   Úlitellm.types.llms.openair   r   r   r   r   Úlitellm.types.utilsr   r   Ú__annotations__r   r   r!   r   ú<module>r»      s`   ðò
ó ß ã Ý 1ã Ý +Ý VÝ HÝ F÷õ 9Ý 7ß Q÷õ õ -à.€�Ó .ô@A�õ @Ar!   