Ë
    tPêj+  ã                   óø  — U d Z ddlmZmZmZ ddlmZmZ  eh d£«      Z	eee
      ed<   de
defd„Z eh d	£«      Zeee
      ed
<    eddh«      Zeee
      ed<   dee
ef   de
dz  fd„Zdedee
   fd„Zdedeee
ef      fd„Zdee
ef   deee
ef      fd„Zdee
ef   dee
   fd„Zdee
ef   dee
ge
f   defd„Zdee
ef   deee
ef      ddfd„Zdee
ef   defd„Zdee
ef   deee
e
f      fd„Zy)up  
Shared helpers for guardrail hooks: extract text from a request body
regardless of whether it uses Chat Completions ``messages``, Responses-API
``input``, or multimodal list-format ``content`` parts.

Hooks that only check ``data["messages"]`` for string content silently
skip the other shapes â€” these helpers normalise that so every hook sees
every text fragment.
é    )ÚCallableÚIteratorÚMapping)ÚAnyÚFinal>   Ú
aresponsesÚ
completionÚacompletionÚTEXT_CONTENT_CALL_TYPESÚ	call_typeÚreturnc                 ó   — | t         v S )z€Return True if ``call_type`` carries free-form text that text
    guardrails should inspect (Chat Completions or Responses API).)r   )r   s    úl/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/guardrails/_content_utils.pyÚis_text_content_call_typer      s   € ð Ô/Ð/Ð/ó    >   ÚtextÚ
input_textÚoutput_textÚsummary_textÚreasoning_textÚTEXT_PART_TYPESÚfunction_call_outputÚcustom_tool_call_outputÚ_OUTPUT_ITEM_TYPESÚpartNc                 óp   — t        | t        «      sy| j                  d«      }t        |t        «      r|r|S y)zGReturn non-empty plaintext from any content part that carries ``text``.Nr   )Ú
isinstanceÚdictÚgetÚstr)r   r   s     r   Ú
_part_textr!   /   s1   € ä�dœDÔ!ØØ�8‰8�FÓ€DÜ�$œÔ¡ØˆØr   Úcontentc              #   óà   K  — t        | t        «      r| r| –— yyt        | t        «      rB| D ]<  }t        |t        «      r|r|–— Œt        |t        «      sŒ+t	        |«      }|€Œ9|–— Œ> yy­w)u‡   Yield text fragments from a ``message.content`` value (string or
    multimodal list). Non-text parts (images, audio, â€¦) are skipped.N)r   r    Úlistr   r!   )r"   r   r   s      r   Ú_iter_text_parts_in_contentr%   9   sv   è ø€ ô �'œ3ÔÙØ‹Mð ä	�GœTÔ	"Øò 	ˆDÜ˜$¤Ô$ñ Ø’JØÜ˜d¤DÔ)ØÜ˜dÓ#ˆDØÑØ“
ñ	ð 
#ùs   ‚A#A.Á&A.Úinput_valuec                 óL  — t        | t        «      rd| dœgS t        | t        «      sg S g }| D �]s  }t        |t        «      r|j                  d|dœ«       Œ)t        |t        «      sŒ:t        |«      �)|j                  |j                  d«      xs d|gdœ«       Œn|j                  d«      dk(  ryd|v r*|j                  |j                  d«      xs d|d   dœ«       t        |j                  d«      t        «      sŒÐ|j                  |j                  d«      xs d|d   dœ«       Œûd|v r,|j                  |j                  d«      xs d|d   dœ«       �Œ+|j                  d«      t        v s�ŒDd	|v s�ŒJ|j                  |j                  d«      xs d
|d	   dœ«       �Œv |S )zHCoerce a Responses-API ``data["input"]`` value into chat-style messages.Úuser©Úroler"   r*   ÚtypeÚ	reasoningr"   Ú	assistantÚsummaryÚoutputÚtool)r   r    r$   Úappendr   r!   r   r   )r&   ÚmessagesÚitems      r   Ú_coerce_input_to_messagesr4   N   sˆ  € ä�+œsÔ#Ø¨KÑ8Ð9Ð9Ü�k¤4Ô(Øˆ	Ø,.€HØó aˆÜ�dœCÔ Ø�O‰O V¸Ñ=Õ>Ü˜œdÕ#Ü˜$ÓÐ+Ø—‘¨¯©°&Ó)9Ò)C¸VÐQUÐPVÑ WÕXØ—‘˜&Ó! [Ò0Ø Ñ$Ø—O‘Oà$(§H¡H¨VÓ$4Ò$C¸Ø'+¨I¡ñôô ˜dŸh™h yÓ1´4Õ8Ø—O‘Oà$(§H¡H¨VÓ$4Ò$C¸Ø'+¨I¡ñõð ˜dÑ"Ø—‘¨¯©°&Ó)9Ò)C¸VÐPTÐU^ÑP_Ñ `ÖaØ—‘˜&Ó!Ô%7Ó7¸HÈÓ<LØ—‘¨¯©°&Ó)9Ò)C¸VÐPTÐU]ÑP^Ñ _Ö`ð1að2 €Or   Údatac              #   ó®   K  — | j                  d«      }t        |t        «      r
|E d{  –—†  t        | j                  d«      «      E d{  –—†  y7 Œ'7 Œ­w)zBYield every message-like dict, walking ``messages`` AND ``input``.r2   NÚinput)r   r   r$   r4   )r5   r2   s     r   Ú_iter_inspection_messagesr8   q   sG   è ø€ à—h‘h˜zÓ*€HÜ�(œDÔ!Ø×ÐÜ(¨¯©°'Ó):Ó;×;Ñ;ð 	øØ;ús!   ‚'A©Aª!AÁAÁAÁAc              #   ó–   K  — t        | «      D ]5  }t        |t        «      sŒt        |j	                  d«      «      E d{  –—†  Œ7 y7 Œ­w)u½   Yield every text fragment from ``messages`` AND ``input``.

    Walks every role (user, assistant, system, â€¦) â€” guardrails inspect
    the entire conversation, not just user turns.
    r"   N)r8   r   r   r%   r   )r5   Úmessages     r   Úiter_message_textr;   y   sH   è ø€ ô -¨TÓ2ò GˆÜ˜'¤4Ô(ØÜ.¨w¯{©{¸9Ó/EÓF×FÑFñGð 	Gús   ‚=A	¿AÁ A	Úvisitc                 ó\  ‡‡— dŠdt         dt         fˆˆfd„}| j                  d«      }t        |t        «      r+|D ]&  }t        |t        «      sŒd|v sŒ ||d   «      |d<   Œ( | j                  d«      }t        |t
        «      r|r‰dz  Š ‰|«      | d<   ‰S t        |t        «      �rt        |«      D ]ò  \  }}t        |t
        «      r|sŒ‰dz  Š ‰|«      ||<   Œ*t        |t        «      sŒ;t        |«      �‰dz  Ši |¥d ‰|d   «      i¥||<   Œ`|j                  d	«      d
k(  rAd|v r ||d   «      |d<   t        |j                  d«      t        «      sŒ¦ ||d   «      |d<   Œµd|v r ||d   «      |d<   ŒÈ|j                  d	«      t        v sŒàd|v sŒå ||d   «      |d<   Œô ‰S ‰S )zÚRewrite every text fragment in place via ``visit``.

    Mutates ``data["messages"]`` and ``data["input"]``. Returns the number
    of fragments visited so callers can short-circuit when nothing was
    inspected.
    r   r"   r   c           	      ó‚  •— t        | t        «      r| r‰dz  Š ‰| «      S | S t        | t        «      rŒg }| D ]ƒ  }t        |t        «      r|r‰dz  Š|j                   ‰|«      «       Œ2t        |t        «      r1t        |«      �&‰dz  Š|j                  i |¥d ‰|d   «      i¥«       Œs|j                  |«       Œ… |S | S )Né   r   )r   r    r$   r1   r   r!   )r"   Ú	new_partsr   r<   Úvisiteds      €€r   Ú_rewrite_contentz(walk_user_text.<locals>._rewrite_contentŽ   sÉ   ø€ ä�gœsÔ#ÙØ˜1‘�Ù˜W“~Ð%ØˆNÜ�gœtÔ$Ø*,ˆIØò +�Ü˜d¤CÔ(©TØ˜q‘L�GØ×$Ñ$¡U¨4£[Õ1Ü ¤dÔ+´
¸4Ó0@Ð0LØ˜q‘L�GØ×$Ñ$Ð%J¨Ð%J¨f±e¸DÀ¹LÓ6IÑ%JÕKà×$Ñ$ TÕ*ð+ð ÐØˆr   r2   r7   r?   r   r+   r,   r.   r/   )	r   r   r   r$   r   r    Ú	enumerater!   r   )	r5   r<   rB   r2   r:   r&   Úidxr3   rA   s	    `      @r   Úwalk_user_textrE   …   sÌ  ù€ ð €Gð¤#ð ¬#ö ð* —h‘h˜zÓ*€HÜ�(œDÔ!Øò 	JˆGÜ˜'¤4Õ(¨Y¸'Ò-AÙ%5°g¸iÑ6HÓ%I�˜	Ò"ð	Jð Ÿ™ 'Ó*€KÜ�+œsÔ#ÙØ�q‰LˆGÙ! +Ó.ˆD�‰MØˆÜ�+œtÕ$Ü" ;Ó/ò 	F‰IˆC�Ü˜$¤Ô$ÚØ˜q‘L�GÙ',¨T£{�K Ò$Ü˜D¤$Õ'Ü˜dÓ#Ð/Ø˜q‘L�GØ'L¨$Ð'L°¹¸dÀ6¹lÓ8KÑ'L�K Ò$Ø—X‘X˜fÓ%¨Ò4Ø  DÑ(Ù*:¸4À	¹?Ó*K˜˜Y™Ü! $§(¡(¨9Ó"5´tÕ<Ù*:¸4À	¹?Ó*K˜˜YšØ $Ñ&Ù&6°t¸I±Ó&G�D˜’OØ—X‘X˜fÓ%Ô);Ò;ÀÈDÒ@PÙ%5°d¸8±nÓ%E�D˜’Nð#	Fð$ ˆà€Nr   Úredacted_messagesc                 ó  — d| v r|| d<   t        | j                  d«      t        «      rXg }|D ]<  }t        |t        «      sŒ|j	                  t        |j                  d«      «      «       Œ> dj                  |«      | d<   yy)aè  Write redacted messages back to whichever field(s) the caller used.

    Mask/anonymize paths take a synthesised messages list (from
    :func:`build_inspection_messages`), get a redacted version back from a
    third-party guardrail, and need to rewrite the request body. Writing
    only to ``data["messages"]`` leaves the Responses-API ``data["input"]``
    field untouched, so the unredacted text still reaches the LLM.

    This helper updates both fields when both are present.
    r2   r7   r"   ú
N)r   r   r    r   Úextendr%   Újoin)r5   rF   Ú
text_partsÚmsgs       r   Úapply_redacted_messages_backrM   Ç   s‚   € ð �TÑØ,ˆˆZÑÜ�$—(‘(˜7Ó#¤SÔ)Ø')ˆ
Ø$ò 	OˆCÜ˜c¤4Ô(ØØ×ÑÔ9¸#¿'¹'À)Ó:LÓMÕNð	Oð Ÿ	™	 *Ó-ˆˆWŠð *r   c                 ó$  — | j                  d«      }t        |t        «      rK|D ]F  }t        |t        «      sŒt        |j                  d«      t        «      rŒ4|j                  d«      €ŒF y | j                  d«      }|�t        |t        «      syy)aV  Return True if any inspected content is not a plain string.

    Used by hooks whose mask/redact path operates on string offsets and
    therefore cannot preserve multimodal non-text parts. Such hooks should
    degrade to block-on-detect when this returns True so image/audio parts
    are not silently stripped during in-place masking.
    r2   r"   Tr7   F)r   r   r$   r   r    )r5   r2   r:   r&   s       r   Úhas_non_string_contentrO   Ý   s   € ð —h‘h˜zÓ*€HÜ�(œDÔ!Øò 	 ˆGÜ˜'¤4Õ(´¸G¿K¹KÈ	Ó<RÔTWÕ1XØ—;‘;˜yÓ)Ñ5Ùð	 ð Ÿ™ 'Ó*€KØÐ¤z°+¼sÔ'CØØr   c                 óø   — g }t        | «      D ]i  }t        |t        «      sŒdj                  t	        |j                  d«      «      «      }|sŒ@|j                  dd«      xs d}|j                  ||dœ«       Œk |S )uë  Synthesize a chat-style messages list for posting to a guardrail API.

    Each returned message has a plain-string ``content`` â€” multimodal text
    parts are joined with newlines and Responses-API ``input`` is lifted
    into synthetic messages. Messages with no inspectable text are dropped.

    Hooks that POST ``{"messages": [...]}`` to an external service should
    call this instead of ``data.get("messages", [])`` so the Responses API
    and multimodal content are covered.
    rH   r"   r*   r(   r)   )r8   r   r   rJ   r%   r   r1   )r5   Ú	flattenedr:   r   r*   s        r   Úbuild_inspection_messagesrR   ñ   s}   € ð .0€IÜ,¨TÓ2ò :ˆÜ˜'¤4Ô(ØØ�y‰yÔ4°W·[±[ÀÓ5KÓLÓMˆÙØØ�{‰{˜6 6Ó*Ò4¨fˆØ×Ñ $°4Ñ8Õ9ð:ð Ðr   )Ú__doc__Úcollections.abcr   r   r   Útypingr   r   Ú	frozensetr   r    Ú__annotations__Úboolr   r   r   Úobjectr!   r%   r$   r   r4   r8   r;   ÚintrE   rM   rO   rR   © r   r   ú<module>r\      sË  ðò÷ 8Ñ 7ß ñ 2;Ò;fÓ1gÐ ˜˜y¨™~Ñ.Ó gð0¨ð 0°ó 0ñ *3ÚKó*€��y ‘~Ñ&ó ñ -6Ð7MÐOhÐ6iÓ,jÐ �E˜) C™.Ñ)Ó jð�W˜S &˜[Ñ)ð ¨c°D©jó ð¨ð °¸#±ó ð* ¨3ð  °4¸¸SÀ#¸X¹Ñ3Gó  ðF< D¨¨c¨¡Nð <°xÀÀSÈ#ÀXÁÑ7Oó <ð	G˜D  c ™Nð 	G¨x¸©}ó 	Gð?˜˜c 3˜h™ð ?°¸#¸À¸Ñ0Dð ?Èó ?ðD. t¨C°¨H¡~ð .È$ÈtÐTWÐY\ÐT\É~ÑJ^ð .Ðcgó .ð,  c¨3 h¡ð °Dó ð( D¨¨c¨¡Nð °t¸DÀÀcÀ¹NÑ7Kô r   