Ë
    tPêjy/  ã            	       ó    — d Z ddlZddlmZmZ ddlmZmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZmZ  G d	„ d
«      Z	 ddededee   dz  defd„Zy)z>
Response Polling Handler for Background Responses with Cache
é    N)ÚdatetimeÚtimezone)ÚAnyÚFinal)Úverbose_proxy_logger)Úuuid4)Ú
RedisCache)ÚResponsesAPIResponseÚResponsesAPIStatusc            +       óÎ  — e Zd ZdZdZdZd'dedz  defd„Ze	de
fd	„«       Ze	d
e
defd„«       Ze	de
de
fd„«       Zde
dee
ef   defd„Z	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d(de
dedz  dedz  dedz  dedz  dedz  dedz  dedz  dedz  de
dz  de
dz  dedz  dedz  dedz  de
dz  dedz  de
dz  d edz  d!e
dz  d"edz  ddf*d#„Zde
dee
ef   dz  fd$„Zde
defd%„Zde
defd&„Zy))ÚResponsePollingHandlerz0Handles polling-based responses with Redis cachezlitellm:polling:response:Úlitellm_poll_NÚredis_cacheÚttlc                 ó    — || _         || _        y ©N)r   r   )Úselfr   r   s      ús/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/response_polling/polling_handler.pyÚ__init__zResponsePollingHandler.__init__   s   € Ø&ˆÔØˆ�ó    Úreturnc                 ó2   — | j                   › t        «       › �S )z4Generate a unique UUID for polling with clear prefix)ÚPOLLING_ID_PREFIXr   )Úclss    r   Úgenerate_polling_idz*ResponsePollingHandler.generate_polling_id   s   € ð ×'Ñ'Ð(¬«¨	Ð2Ð2r   Úresponse_idc                 ó8   — |j                  | j                  «      S )z&Check if a response_id is a polling ID)Ú
startswithr   )r   r   s     r   Úis_polling_idz$ResponsePollingHandler.is_polling_id   s   € ð ×%Ñ% c×&;Ñ&;Ó<Ð<r   Ú
polling_idc                 ó"   — | j                   › |› �S )z$Get Redis cache key for a polling ID)ÚCACHE_KEY_PREFIX)r   r    s     r   Úget_cache_keyz$ResponsePollingHandler.get_cache_key#   s   € ð ×&Ñ&Ð'¨
 |Ð4Ð4r   Úrequest_datac              ƒ   óÂ  K  — t        t        j                  t        j                  «      j                  «       «      }t        |dd|g |j                  di «      d¬«      }| j                  |«      }| j                  r_| j                  j                  ||j                  «       | j                  ¬«      ƒ d{  –—†  t        j                  d|| j                  «       |S 7 Œ'­w)a‘  
        Create initial state in Redis for a polling request

        Uses OpenAI ResponsesAPIResponse object:
        https://platform.openai.com/docs/api-reference/responses/object

        Args:
            polling_id: Unique identifier for this polling request
            request_data: Original request data

        Returns:
            ResponsesAPIResponse object following OpenAI spec
        ÚresponseÚqueuedÚmetadataN)ÚidÚobjectÚstatusÚ
created_atÚoutputr(   Úusage©ÚkeyÚvaluer   z1Created initial polling state for %s with TTL=%ss)Úintr   Únowr   ÚutcÚ	timestampr
   Úgetr#   r   Úasync_set_cacheÚmodel_dump_jsonr   r   Údebug)r   r    r$   Úcreated_timestampr&   Ú	cache_keys         r   Úcreate_initial_statez+ResponsePollingHandler.create_initial_state(   sÒ   è ø€ ô$ $'¤x§|¡|´H·L±LÓ'A×'KÑ'KÓ'MÓ#NÐô /ØØØØ(ØØ!×%Ñ% j°"Ó5Øô
ˆð  ×-Ñ-¨jÓ9ˆ	à×Òà×"Ñ"×2Ñ2ØØ×.Ñ.Ó0Ø—H‘Hð 3ó ÷ ð ô
 !×&Ñ&Ð'ZÐ\fÐhl×hpÑhpÔqàˆðús   ‚B3CÂ5CÂ6(Cr+   r.   ÚerrorÚincomplete_detailsÚ	reasoningÚtool_choiceÚtoolsr-   ÚmodelÚinstructionsÚtemperatureÚtop_pÚmax_output_tokensÚprevious_response_idÚtextÚ
truncationÚparallel_tool_callsÚuserÚstorec              ƒ   óú  K  — | j                   sy| j                  |«      }| j                   j                  |«      ƒ d{  –—† }|st        j                  d|«       yt        j                  |«      }|r||d<   |	�|	|d<   |r||d<   |r
d|d<   ||d<   |r||d<   |�||d	<   |�||d
<   |�||d<   |
�|
|d<   |�||d<   |�||d<   |�||d<   |�||d<   |�||d<   |�||d<   |�||d<   |�||d<   |�||d<   |�||d<   | j                   j                  |t        j                  |«      | j                  ¬«      ƒ d{  –—†  t        |j                  dg «      «      }t        j                  d||d   |«       y7 �Œ77 Œ>­w)a  
        Update the polling state in Redis

        Uses OpenAI Response object format with native status types:
        https://platform.openai.com/docs/api-reference/responses/object

        Args:
            polling_id: Unique identifier for this polling request
            status: OpenAI ResponsesAPIStatus value
            usage: Usage information
            error: Error dict (automatically sets status to "failed")
            incomplete_details: Details for incomplete responses
            reasoning: Reasoning configuration from response.completed
            tool_choice: Tool choice configuration from response.completed
            tools: Tools list from response.completed
            output: Full output list to replace current output
            model: Model identifier
            instructions: System instructions
            temperature: Sampling temperature
            top_p: Nucleus sampling parameter
            max_output_tokens: Maximum output tokens
            previous_response_id: ID of previous response in conversation
            text: Text configuration
            truncation: Truncation setting
            parallel_tool_calls: Whether parallel tool calls are enabled
            user: User identifier
            store: Whether to store the response
        Nz(No cached state found for polling_id: %sr+   r-   r.   Úfailedr=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   rJ   rK   rL   r/   z8Updated polling state for %s: status=%s, output_items=%s)r   r#   Úasync_get_cacher   ÚwarningÚjsonÚloadsr7   Údumpsr   Úlenr6   r9   )r   r    r+   r.   r=   r>   r?   r@   rA   r-   rB   rC   rD   rE   rF   rG   rH   rI   rJ   rK   rL   r;   Úcached_stateÚstateÚoutput_counts                            r   Úupdate_statez#ResponsePollingHandler.update_stateT   s  è ø€ ðh ×ÒØà×-Ñ-¨jÓ9ˆ	ð %)×$4Ñ$4×$DÑ$DÀYÓ$O×OˆÙÜ ×(Ñ(Ð)SÐU_Ô`Øô —z‘z ,Ó/ˆñ Ø$ˆE�(‰Oð ÐØ$ˆE�(‰Oñ Ø"ˆE�'‰Nñ Ø&ˆE�(‰OØ"ˆE�'‰Nñ Ø*<ˆEÐ&Ñ'ð Ð Ø!*ˆE�+ÑØÐ"Ø#.ˆE�-Ñ ØÐØ"ˆE�'‰Nð ÐØ"ˆE�'‰NØÐ#Ø$0ˆE�.Ñ!ØÐ"Ø#.ˆE�-Ñ ØÐØ"ˆE�'‰NØÐ(Ø):ˆEÐ%Ñ&ØÐ+Ø,@ˆEÐ(Ñ)ØÐØ ˆE�&‰MØÐ!Ø",ˆE�,ÑØÐ*Ø+>ˆEÐ'Ñ(ØÐØ ˆE�&‰MØÐØ"ˆE�'‰Nð ×Ñ×.Ñ.ØÜ—*‘*˜UÓ#Ø—‘ð /ó 
÷ 	
ð 	
ô " %§)¡)¨H°bÓ"9Ó:ˆÜ×"Ñ"ØFÈ
ÐTYÐZbÑTcÐeqõ	
ðK Pùð|	
ús#   ‚=E;¿E6Á C:E;Ä:E9Ä;<E;Å9E;c              ƒ   óÀ   K  — | j                   sy| j                  |«      }| j                   j                  |«      ƒ d{  –—† }|rt        j                  |«      S y7 Œ­w)z$Get current polling state from RedisN)r   r#   rO   rQ   rR   )r   r    r;   rU   s       r   Ú	get_statez ResponsePollingHandler.get_state×   sV   è ø€ à×ÒØà×-Ñ-¨jÓ9ˆ	Ø$(×$4Ñ$4×$DÑ$DÀYÓ$O×OˆáÜ—:‘:˜lÓ+Ð+àð Pús   ‚=A¿AÁ Ac              ƒ   óF   K  — | j                  |d¬«      ƒ d{  –—†  y7 Œ­w)zp
        Cancel a polling request

        Following OpenAI Response object format for cancelled status
        Ú	cancelled)r    r+   NT)rX   )r   r    s     r   Úcancel_pollingz%ResponsePollingHandler.cancel_pollingä   s5   è ø€ ð ×ÑØ!Øð  ó 
÷ 	
ð 	
ð ð		
ús   ‚!™š!c              ƒ   ó’   K  — | j                   sy| j                  |«      }| j                   j                  |«      ƒ d{  –—†  y7 Œ­w)z#Delete a polling request from cacheFNT)r   r#   Úasync_delete_cache)r   r    r;   s      r   Údelete_pollingz%ResponsePollingHandler.delete_pollingð   sD   è ø€ à×ÒØà×-Ñ-¨jÓ9ˆ	à×Ñ×1Ñ1°)Ó<×<Ð<Øð 	=ús   ‚=A¿AÁ A)Ni  )NNNNNNNNNNNNNNNNNNN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r"   r   r	   r2   r   ÚclassmethodÚstrr   Úboolr   r#   Údictr   r
   r<   r   ÚlistÚfloatrX   rZ   r]   r`   © r   r   r   r      sl  „ Ù:à2ÐØ'Ðñ J°Ñ$5ð À3ó ð ð3 Cò 3ó ð3ð ð=¨ð =°ò =ó ð=ð ð5 sð 5¨sò 5ó ð5ð*àð*ð ˜3 ˜8‘nð*ð 
ó	*ð^ -1Ø!Ø!Ø*.Ø!%Ø"&Ø!Ø"à Ø#'Ø$(Ø"Ø(,Ø+/Ø Ø!%Ø+/ØØ!ñ-A
àðA
ð # TÑ)ðA
ð �d‰{ð	A
ð
 �d‰{ðA
ð ! 4™KðA
ð ˜$‘;ðA
ð ˜4‘ZðA
ð �d‰{ðA
ð �t‘ðA
ð �T‰zðA
ð ˜D‘jðA
ð ˜T‘\ðA
ð �t‰|ðA
ð   ™:ð!A
ð" " D™jð#A
ð$ �T‰kð%A
ð& ˜$‘Jð'A
ð( " D™[ð)A
ð* �D‰jð+A
ð, �d‰{ð-A
ð. 
ó/A
ðF¨#ð °$°s¸C°x±.À4Ñ2Gó ð
¨sð 
°tó 
ð¨sð °tô r   r   Úbackground_moderB   Únative_background_moder   c                 óZ  — | r|r|sy|r||v rt        j                  d|«       y|dk(  ryt        |t        «      rÄd|v r|j	                  d«      d   }||v ryy|�¤	 |j
                  j                  |g «      }|D ]€  }|j                  |   }	|	j                  di «      }
|
j                  d	«      }|s*|
j                  d
d«      }d|v r|j	                  d«      d   }|sŒd||v sŒit        j                  d||«        y 	 yy# t        $ r!}t        j                  d||«       Y d}~yd}~ww xY w)a�  
    Determine if polling via cache should be used for a request.

    Args:
        background_mode: Whether background=true was set in the request
        polling_via_cache_enabled: Config value - False, "all", or list of providers
        redis_cache: Redis cache instance (required for polling)
        model: Model name from the request (e.g., "gpt-5" or "openai/gpt-4o")
        llm_router: LiteLLM router instance for looking up model deployments
        native_background_mode: List of model names that should use native provider
            background mode instead of polling via cache

    Returns:
        True if polling should be used, False otherwise
    FzFModel %s is in native_background_mode list, skipping polling via cacheÚallTú/r   NÚlitellm_paramsÚcustom_llm_providerrB   Ú z)Polling enabled for model=%s, provider=%sz+Could not resolve provider for model %s: %s)	r   r9   Ú
isinstanceri   ÚsplitÚ model_name_to_deployment_indicesr6   Ú
model_listÚ	Exception)rl   Úpolling_via_cache_enabledr   rB   Ú
llm_routerrm   ÚproviderÚindicesÚidxÚdeployment_dictrq   Údep_providerÚ	dep_modelÚes                 r   Úshould_use_polling_for_requestr‚   û   sn  € ñ0 Ñ 9¹kØñ  %Ð+AÑ"AÜ×"Ñ"Ð#kÐmrÔsØð ! EÒ)Øô Ð+¬TÔ2à�%‰<Ø#Ÿk™k¨#Ó.¨qÑ1ˆHØÐ4Ñ4Øð4 ð1 Ð#ðdà!+×!LÑ!L×!PÑ!PÐQVÐXZÓ![�Ø"ò $�CØ&0×&;Ñ&;¸CÑ&@�OØ%4×%8Ñ%8Ð9IÈ2Ó%N�Nð $2×#5Ñ#5Ð6KÓ#L�Lñ (Ø$2×$6Ñ$6°wÀÓ$C˜	Ø )Ñ+Ø+4¯?©?¸3Ó+?ÀÑ+B˜Lò $¨Ð8QÒ(QÜ,×2Ñ2Ð3^Ð`eÐgsÔtÙ#ñ!$ñ( øô ò dÜ$×*Ñ*Ð+XÐZ_Ðab×cÐcàûðdús+   ÁBD  ÃD  Ã#D  Ã<D  Ä 	D*Ä	D%Ä%D*r   )rd   rQ   r   r   Útypingr   r   Úlitellm._loggingr   Úlitellm._uuidr   Úlitellm.caching.redis_cacher	   Úlitellm.types.llms.openair
   r   r   rg   rf   ri   r‚   rk   r   r   ú<module>rˆ      sl   ðñó ß 'ß å 1Ý Ý 2ß N÷iñ iðd 04ñDØðDð ð	Dð ! ™I¨Ñ,ðDð 
ôDr   