Ë
    tPêj¥  ã                   ó®   — U d Z ddlZddl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r	dd	lmZ eZneZd
Zeed<   dZeed<    G d„ de«      Zy)a¼  
Sensitive Data Routing Hook for LiteLLM Proxy.

When a guardrail detects sensitive data and is configured with on_sensitive_data='route',
this hook manages:
1. Storing the routing decision (session_id -> model) in cache
2. Checking incoming requests for existing routing overrides
3. Applying sticky routing so all subsequent requests in a session go to the same model

Works across multiple proxy instances via DualCache (in-memory + Redis).
é    N)ÚTYPE_CHECKINGÚAnyÚFinal)Úverbose_proxy_logger)Ú	DualCache)Ú get_session_id_from_request_data)ÚCustomLogger)ÚUserAPIKeyAuth)ÚInternalUsageCacheÚsensitive_routeÚSENSITIVE_ROUTING_CACHE_PREFIXi  ÚDEFAULT_SENSITIVE_ROUTING_TTLc                   óÌ   — e Zd ZdZdefd„Zdededefd„Zede	d	z  defd
„«       Z
dede	d	z  ded	z  fd„Z	 	 ddedede	d	z  ded	z  dd	f
d„Zde	dedededeez  ez  d	z  f
d„Zy	)Ú"_PROXY_SensitiveDataRoutingHandlera  
    Pre-call hook that checks for existing sensitive data routing overrides
    and applies them to incoming requests.

    This hook runs early in the pre-call chain and modifies the request's
    model field if a routing override exists for the session.
    Úinternal_usage_cachec                 ót   — || _         t        t        j                  dt	        t
        «      «      «      | _        y )NÚLITELLM_SENSITIVE_ROUTING_TTL)r   ÚintÚosÚgetenvÚstrr   Úttl)Úselfr   s     úo/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/hooks/sensitive_data_routing.pyÚ__init__z+_PROXY_SensitiveDataRoutingHandler.__init__+   s.   € Ø$8ˆÔ!ÜÜ�I‰IØ/ÜÔ1Ó2óó
ˆ�ó    Ú
session_idÚtenantÚreturnc                 ó"   — dt         › d|› d|› d�S )Nú{ú:z}:model)r   )r   r   r   s      r   Ú_make_cache_keyz2_PROXY_SensitiveDataRoutingHandler._make_cache_key4   s   € ØÔ2Ð3°1°V°H¸A¸j¸\ÈÐRÐRr   Úuser_api_key_dictNc                 óò   — | €y| j                   r| j                   S d| j                  fd| j                  fd| j                  ffD ��cg c]  \  }}|r|› d|› �‘Œ }}}|rdj	                  |«      S dS c c}}w )a‚  
        Identify the authenticated principal the routing override belongs to.

        API-key auth is scoped by the hashed key. JWT (and other keyless) auth
        has no api_key, so fall back to a stable identity claim. Without this,
        every keyless caller would share the ``default`` namespace and could read
        or overwrite another principal's session routing.
        ÚdefaultÚuserÚteamÚorgr"   ú|)Úapi_keyÚuser_idÚteam_idÚorg_idÚjoin)r$   ÚlabelÚvalueÚ	principals       r   Ú_resolve_tenantz2_PROXY_SensitiveDataRoutingHandler._resolve_tenant7   s¡   € ð Ð$ØØ×$Ò$Ø$×,Ñ,Ð,ð Ð*×2Ñ2Ð3ØÐ*×2Ñ2Ð3ØÐ)×0Ñ0Ð1ð!÷
á��uñ
 ð ˆg�Q�u�gÒð
ˆ	ñ 
ñ '0ˆs�x‰x˜	Ó"Ð>°YÐ>ùó
s   ÁA3c              ƒ   óÜ  K  — | j                  || j                  |«      «      }| j                  j                  j                  �·	 | j                  j                  j                  j                  |¬«      ƒ d{  –—† }|�{t        |«      }| j                  j                  j                  j                  |¬«      ƒ d{  –—† }| j                  j                  |||�|n| j                  dd¬«      ƒ d{  –—†  |S 	 | j                  j                  |dd¬«      ƒ d{  –—† }|�t        |«      S y7 Œ¶7 Œs7 Œ?# t        $ r)}t        j                  dt        |«      «       Y d}~Œgd}~ww xY w7 ŒM­w)z7Get the model this session should be routed to, if any.N)ÚkeyT©r5   r1   r   Úlitellm_parent_otel_spanÚ
local_onlyzLSensitiveDataRoutingHandler: Redis GET failed, falling back to in-memory: %s)r5   r7   r8   )r#   r3   r   Ú
dual_cacheÚredis_cacheÚasync_get_cacher   Úasync_get_ttlÚasync_set_cacher   Ú	Exceptionr   Úwarning)r   r   r$   Ú	cache_keyÚresultÚrouted_modelÚremaining_ttlÚes           r   Ú_get_routed_modelz4_PROXY_SensitiveDataRoutingHandler._get_routed_modelP   su  è ø€ à×/Ñ/°
¸D×<PÑ<PÐQbÓ<cÓdˆ	à×$Ñ$×/Ñ/×;Ñ;ÐGðØ#×8Ñ8×CÑC×OÑO×_Ñ_ÐdmÐ_Ón×n�ØÐ%Ü*-¨f«+�LØ*.×*CÑ*C×*NÑ*N×*ZÑ*Z×*hÑ*hÐmvÐ*hÓ*w×$w�MØ×3Ñ3×CÑCØ%Ø*Ø-:Ð-F™MÈDÏHÉHØ15Ø#'ð Dó ÷ ð ð (Ð'ð &ð" ×0Ñ0×@Ñ@ØØ%)Øð Aó 
÷ 
ˆð
 ÐÜ�v“;ÐØð3 oøð %xøðùô ò Ü$×,Ñ,ØbÜ˜“F÷ñ ûðúð
úss   ‚AE,Á3D5 Á8D/Á9AD5 Â=D1Â>5D5 Ã3D3Ã4D5 Ã9#E,ÄE*ÄE,Ä/D5 Ä1D5 Ä3D5 Ä5	E'Ä>E"ÅE,Å"E'Å'E,ÚmodelÚguardrail_namec              ƒ   ó4  K  — | j                  || j                  |«      «      }t        j                  d|||| j                  «       | j
                  j                  j                  �E	 | j
                  j                  j                  j                  ||| j                  ¬«      ƒ d{  –—†  | j
                  j                  ||| j                  dd¬«      ƒ d{  –—†  y7 Œ7# t        $ r)}t        j                  dt        |«      «       Y d}~Œbd}~ww xY w7 Œ<­w)a   
        Store a routing override for a session.

        Called by guardrails when they detect sensitive data and want to
        route the session to a specific model. The override is scoped to the
        requesting principal so sessions from different tenants cannot collide.
        z_SensitiveDataRoutingHandler: Setting session routing session_id=%s model=%s guardrail=%s ttl=%sN)r5   r1   r   zLSensitiveDataRoutingHandler: Redis SET failed, falling back to in-memory: %sTr6   )r#   r3   r   Úinfor   r   r9   r:   r=   r>   r?   r   )r   r   rF   r$   rG   r@   rD   s          r   Úset_session_routingz6_PROXY_SensitiveDataRoutingHandler.set_session_routingq   s  è ø€ ð  ×/Ñ/°
¸D×<PÑ<PÐQbÓ<cÓdˆ	ä×!Ñ!ØmØØØØ�H‰Hô	
ð ×$Ñ$×/Ñ/×;Ñ;ÐGð
Ø×/Ñ/×:Ñ:×FÑF×VÑVØ!ØØŸ™ð Wó ÷ ð ð ×'Ñ'×7Ñ7ØØØ—‘Ø%)Øð 8ó 
÷ 	
ñ 	
ðùô
 ò Ü$×,Ñ,ØbÜ˜“F÷ñ ûðúð	
úsN   ‚A%DÁ(?C! Â'CÂ(C! Â,-DÃDÃDÃC! Ã!	DÃ*DÄ	DÄDÄDÚcacheÚdataÚ	call_typec              ƒ   ó  K  — t        |«      }|€y| j                  ||«      ƒ d{  –—† }|€y|j                  d«      }||k(  ryt        j                  d|||«       ||d<   |j                  d«      xs i }d|d<   ||d<   ||d<   |S 7 Œa­w)z†
        Before each LLM call, check if this session has a routing override.
        If so, modify the request's model field.
        NrF   znSensitiveDataRoutingHandler: Applying session routing override session_id=%s original_model=%s routed_model=%sÚmetadataTÚsensitive_data_routing_appliedÚ%sensitive_data_routing_original_model)r   rE   Úgetr   rI   )	r   r$   rK   rL   rM   r   rB   Úoriginal_modelrO   s	            r   Úasync_pre_call_hookz6_PROXY_SensitiveDataRoutingHandler.async_pre_call_hookž   s¸   è ø€ ô =¸TÓBˆ
ØÐØà$(×$:Ñ$:¸:ÐGXÓ$Y×YˆØÐØà $§¡¨Ó 1ˆØ˜\Ò)Øä×!Ñ!ð>àØØô	
ð %ˆˆW‰àŸ(™( :Ó.Ò4°"ˆØ59ˆÐ1Ñ2Ø<JˆÐ8Ñ9Ø#ˆˆZÑàˆð/ Zús   ‚$B
¦B§A"B
)NN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r#   Ústaticmethodr
   r3   rE   rJ   r   Údictr>   rT   © r   r   r   r   "   s  „ ñð
Ð-?ó 
ðS¨#ð S°sð S¸só Sð ð?¨>¸DÑ+@ð ?ÀSò ?ó ð?ð0°#ð È.Ð[_ÑJ_ð ÐdgÐjnÑdnó ðJ 48Ø%)ñ+
àð+
ð ð+
ð *¨DÑ0ð	+
ð
 ˜d™
ð+
ð 
ó+
ðZ&à)ð&ð ð&ð ð	&ð
 ð&ð 
�S‰˜4Ñ	 $Ñ	&ô&r   r   )rX   r   Útypingr   r   r   Úlitellm._loggingr   Úlitellm.caching.cachingr   Ú%litellm.integrations.custom_guardrailr   Ú"litellm.integrations.custom_loggerr	   Úlitellm.proxy._typesr
   Úlitellm.proxy.utilsr   Ú_InternalUsageCacher   Ú__annotations__r   r   r[   r   r   ú<module>re      s\   ðò
ó 
ß ,Ñ ,å 1Ý -Ý RÝ ;Ý /áÝMà,ÑàÐð ):Ð  Ó 9Ø'+Ð ˜uÓ +ôb¨õ br   