Ë
    tPêj]  ã                  ór  — U d Z ddlmZ ddlZddlZddlZddlZddl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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 ddlm Z  ddl!m"Z" ddl#m$Z$m%Z% ddl&m'Z'm(Z( erddl)m*Z*  ei «      Z+de,d<   dZ-de,d<   dZ.de,d<    ej^                  d«      Z0de,d<   dZ1de,d<   dZ2de,d<   dZ3de,d <   e3d!fZ4de,d"<   d#Z5de,d$<    e6e3d!d%h«      Z7de,d&<    e6h d'£«      Z8de,d(<    e6e'jr                  e'jt                  e'jv                  e'jx                  e'jz                  h«      Z>de,d)<   d*e'jr                  fd+e'jt                  fd,e'jv                  ffZ?de,d-<    ed.d.¬/«       G d0„ d1«      «       Z@ ed.d.¬/«       G d2„ d3«      «       ZA ed.d.¬/«       G d4„ d5«      «       ZBe@eAz  eBz  ZCd6e,d7<    ed.d.¬/«       G d8„ d9«      «       ZD ed.d.¬/«       G d:„ d;«      «       ZE ed.d.¬/«       G d<„ d=«      «       ZFeEeFz  ZGd6e,d><   eCeDz  eFz  ZHd6e,d?<    ed.d.¬/«       G d@„ dA«      «       ZI ed.d.¬/«       G dB„ dC«      «       ZJdYdD„ZKdZdE„ZLd[dF„ZMd\dG„ZNd]dH„ZOd^dI„ZPd_dJ„ZQd`dK„ZRdadL„ZSdbdM„ZTdcdN„ZUdddO„ZVdedP„ZWdfdQ„ZX	 	 	 	 	 	 	 	 	 	 dgdR„ZY	 	 	 	 	 	 	 	 	 	 dhdS„ZZdidT„Z[djdU„Z\	 	 	 	 	 	 	 	 	 	 dkdV„Z]dldW„Z^dmdX„Z_y)na  
Run the configured pre-call guardrails over every record of a batch input file.

Runs after ``batch_file_validation.check_batch_file_upload``, so every line here is already known
to parse as a JSON object carrying ``custom_id``, ``method``, ``url`` and ``body``.
é    )ÚannotationsN)ÚIteratorÚMapping)Ú	dataclass)ÚMappingProxyType)ÚTYPE_CHECKINGÚBinaryIOÚFinalÚNoReturnÚ	TypeAlias)Úurlsplit©ÚHTTPException)Úassert_never)ÚGuardrailRaisedException)Úis_guardrail_intervention)Úget_call_types_for_route)ÚUserAPIKeyAuth)ÚBatchGuardrailRecordÚBatchGuardrailReport)Ú	CallTypesÚCallTypesLiteral)ÚProxyLoggingzFinal[Mapping[str, object]]ÚEMPTY_MAPPINGé    r
   Ú_SCAN_WINDOWi   Ú_REWRITE_SPOOL_BYTESz[\x00-\x1f\x7f]Ú_CONTROL_CHARACTERSé€   Ú_CUSTOM_ID_LOG_LIMITé2   Ú_SUMMARY_LIMITÚlitellm_metadataÚ_SCAN_METADATA_KEYÚmetadataÚ_SCAN_METADATA_BAGSÚsensitive_data_routing_appliedÚ_ROUTE_APPLIED_KEYÚ
guardrailsÚ_INJECTED_KEYS>   ÚtagsÚheadersr)   Ú_guardrail_pipelinesÚuser_api_key_metadataÚuser_api_key_team_metadataÚ_pipeline_managed_guardrailsÚ_SCAN_METADATA_KEYSÚ_SCANNABLE_CALL_TYPESÚmessagesÚpromptÚinputÚ_BODY_SHAPE_CALL_TYPEST)ÚfrozenÚslotsc                  ó   — e Zd ZU ded<   y)ÚUnparseableRecordÚintÚline_numberN©Ú__name__Ú
__module__Ú__qualname__Ú__annotations__© ó    úz/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/openai_files_endpoints/batch_guardrails.pyr:   r:   ^   s   … àÔrC   r:   c                  ó,   — e Zd ZU ded<   ded<   ded<   y)ÚUnscannableRecordr;   r<   ú
str | NoneÚ	custom_idÚurlNr=   rB   rC   rD   rF   rF   c   s   … àÓØÓØ	„OrC   rF   c                  ó,   — e Zd ZU ded<   ded<   ded<   y)ÚUnroutableRecordr;   r<   rG   rH   Ú	guardrailNr=   rB   rC   rD   rK   rK   j   s   … àÓØÓØÔrC   rK   r   ÚBatchScanFailurec                  ó0   — e Zd ZU dZded<   ded<   ded<   y)	Ú
_Redactionz\A rewritten record on its way to the scan spool, held only for the window it was scanned in.r;   r<   rG   rH   ÚstrÚtextN)r>   r?   r@   Ú__doc__rA   rB   rC   rD   rO   rO   t   s   … áfàÓØÓØ
„IrC   rO   c                  ó6   — e Zd ZU ded<   ded<   ded<   ded<   y)ÚRecordRedactedr;   r<   rG   rH   ÚoffsetÚlengthNr=   rB   rC   rD   rT   rT   }   s   … àÓØÓØƒKØƒKØnrC   rT   c                  ó0   — e Zd ZU ded<   ded<   dZded<   y)ÚRecordDroppedr;   r<   rG   rH   NrL   )r>   r?   r@   rA   rL   rB   rC   rD   rX   rX   †   s   … àÓØÓØ €IˆzÔ rC   rX   Ú_RecordChangeÚ_ScanOutcomec                  óT   — e Zd ZU dZded<   ded<   ded<   	 edd„«       Zdd	„Zdd
„Zy)ÚBatchScanResultzUWhat the scan decided, per record. Empty changes means the upload proceeds untouched.ztuple[_RecordChange, ...]Úchangesr;   Úscanned_recordsr	   Ú
redactionsc                óT   — | j                   t        d„ | j                  D «       «      z
  S )Nc              3  óB   K  — | ]  }t        |t        «      sŒd –— Œ y­w©é   N)Ú
isinstancerX   ©Ú.0Úchanges     rD   ú	<genexpr>z4BatchScanResult.submitted_records.<locals>.<genexpr>œ   s   è ø€ Ò)l°Ì*ÐU[Ô]jÕJk¬!Ñ)lùs   ‚˜)r^   Úsumr]   ©Úselfs    rD   Úsubmitted_recordsz!BatchScanResult.submitted_recordsš   s"   € à×#Ñ#¤cÑ)l¸$¿,¹,Ô)lÓ&lÑlÐlrC   c                óª   — dj                  d„ | j                  dt         D «       «      }t        | j                  «      t        z
  }|dk  r|S |› d|› d�S )z^Compact per-record outcome for the server-side log line, capped so one upload cannot flood it.z, c           	   3  óŽ   K  — | ]=  }d |j                   › t        |j                  «      › dt        |t        «      rdnd› �–— Œ? y­w)zline ú ÚredactedÚdroppedN)r<   Ú	_describerH   rd   rT   re   s     rD   rh   z*BatchScanResult.summary.<locals>.<genexpr>    sN   è ø€ ò !
ð ð �F×&Ñ&Ð'¬	°&×2BÑ2BÓ(CÐ'DÀAÜ'¨´Ô?‰zÀYÐOôQñ!
ùs   ‚AANr   z, and z more)Újoinr]   r"   Úlen)rk   ÚshownÚ	remainings      rD   ÚsummaryzBatchScanResult.summaryž   s]   € à—y‘yñ !
ð Ÿ,™, ¬Ð7ô!
ó 
ˆô
 ˜tŸ|™|Ó,¬~Ñ=ˆ	Ø! QšˆuÐL¨u¨g°V¸I¸;ÀeÐ,LÐLrC   c                ód   — t        | j                  t        d„ | j                  D «       «      ¬«      S )Nc           
   3  ó¾   K  — | ]U  }t        |j                  |j                  t        |t        «      rd ndt        |t
        «      r|j                  nd¬«      –— ŒW y­w)rp   rq   N)ÚlinerH   ÚactionrL   )r   r<   rH   rd   rT   rX   rL   re   s     rD   rh   z)BatchScanResult.report.<locals>.<genexpr>«   sZ   è ø€ ò #ð ô %Ø×+Ñ+Ø$×.Ñ.Ü)3°F¼NÔ)K™:ÐQZÜ2<¸VÄ]Ô2S˜f×.Ò.ÐY]÷	ð ñ#ùs   ‚AA)rl   Úmodified_records)r   rl   Útupler]   rj   s    rD   ÚreportzBatchScanResult.report¨   s3   € Ü#Ø"×4Ñ4Ü"ñ #ð #Ÿl™lô#ó ô
ð 	
rC   N)Úreturnr;   )r   rP   )r   r   )	r>   r?   r@   rR   rA   Úpropertyrl   rw   r~   rB   rC   rD   r\   r\   ‘   s9   … á_à&Ó&ØÓØÓØ`àòmó ðmóMô
rC   r\   c                  ó"   — e Zd ZU ded<   ded<   y)Ú_ParsedRecordr;   r<   úMapping[str, object]ÚpayloadNr=   rB   rC   rD   r‚   r‚   ·   s   … àÓØ!Ô!rC   r‚   c                ó    — t        dd| i¬«      S )Ni�  Úerror)Ústatus_codeÚdetailr   )Úmessages    rD   Ú	_rejectedrŠ   ½   s   € Ü S°'¸7Ð1CÔDÐDrC   c                ó  — | xt         d˜ x�\  } t        d|› d�«      ‚ xt        d˜ x�'\  }}} t        d|› t        |«      › d|xs d› d	�«      ‚ t        d
˜ x�&\  }}}t        d|› t        |«      › d|xs d› d�«      ‚ 	 t        | «       y)zLMap a scan failure onto the 400 contract the files endpoint already returns.©r<   NzThe 'body' of batch input line z8 is not an object, so guardrails cannot be applied to it©r<   rH   rI   zBatch input line z	 targets zno urlz— and its body has no messages, prompt or input, so guardrails cannot read it. Give the record a chat, completion, embedding, responses or messages body©r<   rH   rL   z$ was routed to a different model by za guardrailz|, and every record of a batch file goes to one provider, so the file cannot be submitted. Send that record outside the batch)r:   rŠ   rF   rr   rK   r   )Úfailurer<   rH   rI   rL   s        rD   Úraise_publicr�   Á   sÑ   € à
Ø7Ô×7ÜØ1°+°Ð>vÐwóð ð 8ð VÔ×UÑUÜØ# K =´¸9Ó1EÐ0FÀiÐPSÒP_ÐW_ÐO`ð a\ð \óð ð Vô ×`Ð`ÜØ# K =´¸9Ó1EÐ0FÐFjØÒ- Ð.ð /SðSóð ð að Ü˜Õ!rC   c                 ó   — t        d«      ‚)z>Every record was blocked, so there is no batch left to create.zcEvery record in the batch input file was blocked by a guardrail, so there is nothing left to submit)rŠ   rB   rC   rD   Úraise_nothing_to_submitr’   Ø   s   € ä
Ømóð rC   c                ój   — t        | t        «      r| j                  S | j                  �yt	        | «      S )a  
    Whether the guardrail judged the record, as opposed to failing to judge it.

    Stricter than ``is_guardrail_intervention``, which answers a different question and counts
    every ``GuardrailRaisedException`` as a block. Several integrations raise that same exception
    for an unreachable backend or an unparseable response, and only when the operator configured
    the guardrail to fail closed, so treating it as a block would turn "refuse this request" into
    "drop this record and submit the rest", which is the silent loss of enforcement this whole
    path exists to prevent. A guardrail that does not say it blocked content aborts the upload.

    Guardrails that report a technical failure as an ``HTTPException`` carrying a block status
    are caught by ``__cause__``: raising ``from`` the underlying error is a deliberate statement
    that something else caused this, which a verdict on content never is. Implicit context is
    left alone, since a block raised inside an unrelated ``except`` would read as a failure.
    F)rd   r   Úblocked_contentÚ	__cause__r   )Úexcs    rD   Ú_is_content_blockr—   ß   s3   € ô  �#Ô/Ô0Ø×"Ñ"Ð"Ø
‡}�}Ð ØÜ$ SÓ)Ð)rC   c                óÈ   — t        | dd«      }t        |t        «      r|S t        | dd«      }t        |t        «      r|j	                  d«      nd}t        |t        «      r|S dS )zIThe guardrail that raised, from whichever place it recorded its own name.Úguardrail_nameNrˆ   )Úgetattrrd   rP   ÚdictÚget)r–   Únamedrˆ   Úenricheds       rD   Ú_naming_guardrailrŸ   ö   s]   € ä˜3Ð 0°$Ó7€EÜ�%œÔØˆÜ˜C ¨4Ó0€FÜ6@ÀÌÔ6N�f—j‘jÐ!1Ô2ÐTX€HÜ! (¬CÔ0ˆ8Ð:°dÐ:rC   c                óN   — | syt         j                  d| «      d t         }d|› d�S )NÚ ro   z (custom_id ú))r   Úsubr    )rH   Úsafes     rD   rr   rr      s2   € ÙØÜ%×)Ñ)¨#¨yÓ9Ð:OÔ;OÐP€DØ˜$˜˜qÐ!Ð!rC   c              #  ód   K  — t        | d¬«      D ]  \  }}|j                  «       sŒ||f–— Œ y­w)aÎ  
    Yield every non-blank line with its 1-based number, so both passes number records alike.

    Bytes, not text. The upload validation immediately before this parses each line as bytes,
    where the json module sniffs the encoding itself and accepts a leading byte order mark or a
    lone surrogate. Decoding to `str` first is stricter than that, so a file written by any of
    the editors that emit a BOM would pass validation and then fail the scan.
    rc   )ÚstartN)Ú	enumerateÚstrip©Úsourcer<   Úraw_lines      rD   Ú_iter_linesr¬     s8   è ø€ ô "+¨6¸Ô!;ò (Ñˆ�XØ�>‰>ÕØ˜xÐ'Ó'ñ(ùs   ‚$0§	0c              #  óv   K  — t        | «      D ]'  \  }}t        |t        j                  |«      ¬«      –— Œ) y­w)zMYield one record per line, relying on the upload validation that already ran.)r<   r„   N)r¬   r‚   ÚjsonÚloadsr©   s      rD   Ú_iter_recordsr°     s7   è ø€ ä!,¨VÓ!4ò SÑˆ�XÜ¨¼T¿Z¹ZÈÓ=QÔRÓRñSùs   ‚79c                óð   — 	 t        | «      j                  j                  d«      d   j                  d«      }t        |«      }|€yt        d„ |D «       d«      }|€dS |j                  S # t        $ r Y yw xY w)ab  
    Resolve the route a record names, tolerating how callers actually write it.

    An absolute url has to reduce to its path or nothing matches, and a record naming
    ``/v1/responses`` in full would fall through to its body, where ``input`` reads as an
    embedding and the record gets scanned as the wrong call type rather than the right one.
    ú?r   ú/Nc              3  ó2   K  — | ]  }|t         v sŒ|–— Œ y ­w©N)r2   )rf   Úcs     rD   rh   z&_call_type_from_url.<locals>.<genexpr>-  s   è ø€ ÒQ 1°aÔ;PÒ6PœQÑQùs   ‚�)r   ÚpathÚsplitÚrstripÚ
ValueErrorr   ÚnextÚvalue)rI   r·   Ú
call_typesÚ	scannables       rD   Ú_call_type_from_urlr¿     sƒ   € ðÜ˜s“m×(Ñ(×.Ñ.¨sÓ3°AÑ6×=Ñ=¸cÓBˆô 1°Ó6€JØÐØÜÑQ¨
ÔQÐSWÓX€IØÐ$ˆ4Ð9¨)¯/©/Ð9øô ò ñ ð	ús   ‚6A) Á)	A5Á4A5c                óV   ‡ — t        ˆ fd„t        D «       d «      }|€d S |j                  S )Nc              3  ó2   •K  — | ]  \  }}|‰v sŒ|–— Œ y ­wrµ   rB   )rf   ÚfieldÚ	call_typeÚbodys      €rD   rh   z'_call_type_from_body.<locals>.<genexpr>2  s   øè ø€ ÒcÑ'7 u¨iÐUZÐ^bÒUbœÑcùs   ƒ�)r»   r6   r¼   )rÄ   Úshapes   ` rD   Ú_call_type_from_bodyrÆ   1  s*   ø€ ÜÓcÔ;QÔcÐeiÓj€EØ�=ˆ4Ð1 e§k¡kÐ1rC   c                ó^   — t        | t        «      r| rt        | «      nd}|�|S t        |«      S )aH  
    Resolve how to scan a record: its url when we recognize one, otherwise its body shape.

    An unrecognized url falls through to the body rather than rejecting, because a record we can
    still read is a record we can still scan, and the provider transformers treat an unknown url
    as chat rather than as an error.
    N)rd   rP   r¿   rÆ   )rI   rÄ   Úfrom_urls      rD   Ú_scannable_call_typerÉ   6  s3   € ô 3=¸SÄ#Ô2FÉ3Ô)¨#Ô.ÐTX€HØÐ+ˆ8ÐKÔ1EÀdÓ1KÐKrC   c                óì   — | j                  d«      }t        |t        «      r!|j                  dd«      j	                  d«      S t        |t
        t        f«      rt        |t        «      st        |«      S dS )zñ
    The record's identifier, rendered as text.

    The batch spec asks for a string, but callers do send numbers, and reporting those as null
    would leave the one field a caller reconciles on empty for exactly the records it needs.
    rH   úutf-8ÚreplaceN)rœ   rd   rP   ÚencodeÚdecoder;   ÚfloatÚbool)r„   rH   s     rD   Ú_custom_id_ofrÑ   B  sd   € ð —{‘{ ;Ó/€IÜ�)œSÔ!ð ×Ñ ¨Ó3×:Ñ:¸7ÓCÐCÜ'¨	´C¼°<Ô@ÌÐT]Ô_cÔIdŒ3ˆy‹>ÐnÐjnÐnrC   c                ód   ‡ — t        j                  t        ˆ fd„t        |«      D «       «      «      S )a  
    Order-insensitive projection, so a guardrail re-serializing a dict does not read as a change.

    An absent key projects to ``null`` while a key holding ``None`` projects to the string
    ``"null"``, so adding or dropping a null-valued key still reads as a change.
    c              3  ól   •K  — | ]+  }||‰v rt        j                  ‰|   d t        ¬«      ndf–— Œ- y­w)T)Ú	sort_keysÚdefaultN)r®   ÚdumpsrP   )rf   ÚkeyrÄ   s     €rD   rh   z_fingerprint.<locals>.<genexpr>Y  s5   øè ø€ ò 
ØcfˆSÈÈtÉ”$—*‘*˜T #™Y°$ÄÕDÐY]Ô^ñ
ùs   ƒ14)r®   rÖ   r}   Úsorted)rÄ   Úkeyss   ` rD   Ú_fingerprintrÚ   Q  s1   ø€ ô �:‰:Üó 
ÜjpÐquÓjvô
ó 	
óð rC   c                óz   — t        | j                  «       D ��ci c]  \  }}|t        v sŒ||“Œ c}}«      S c c}}w )zÿ
    Narrow the request metadata to the keys guardrail dispatch reads.

    Passing the whole thing through would carry values that cannot be copied, such as the parent
    OTel span, and would hand every record proxy state it has no business seeing.
    )r   Úitemsr1   )Úrequest_metadatar×   r¼   s      rD   Úbuild_scan_metadatarÞ   _  s;   € ô Ø&6×&<Ñ&<Ó&>×]™
˜˜UÀ#ÔI\ÒB\ˆˆe‰Ó]óð ùÛ]s   ™7
ª7
c           	   ƒ  ó<  K  — | j                   j                  d«      }t        |t        «      st	        | j
                  ¬«      S t        | j                   «      }| j                   j                  d«      }t        ||«      }|€/t        | j
                  |t        |t        «      r|¬«      S d ¬«      S t        j                  |«      }t        t        D �	ci c]  }	|	|v sŒ|	||	   “Œ c}	«      }
t        D ]  }|j                  |d «       Œ t        D ]#  }t        j                  t        |«      «      ||<   Œ% 	 |j!                  |||d¬«      ƒ d {  –—† }|j                  d«      }t        |t        «      r<|j                  t*        «      r't-        | j
                  ||j                  d	«      ¬«      S t/        |«      t/        |«      z  t        z
  }t1        ||«      t1        ||«      k(  ry t        D ]  }|j                  |d «       Œ |j3                  |
«       t5        | j
                  |t7        j8                  i | j                   ¥d|i¥«      ¬
«      S c c}	w 7 �Œ# t"        $ r7}t%        |«      r&t'        | j
                  |t)        |«      ¬«      cY d }~S ‚ d }~ww xY w­w)NrÄ   rŒ   rI   r�   T)Úuser_api_key_dictÚdatarÃ   Úguardrails_onlyrŽ   r%   Ú sensitive_data_routing_guardrail)r<   rH   rQ   )r„   rœ   rd   r›   r:   r<   rÑ   rÉ   rF   rP   ÚcopyÚdeepcopyr   r*   Úpopr&   Úpre_call_hookÚ	Exceptionr—   rX   rŸ   r(   rK   Ú	frozensetrÚ   ÚupdaterO   r®   rÖ   )ÚrecordÚscan_metadatarà   Úproxy_logging_objrÄ   rH   rI   rÃ   Ú
scan_inputr×   Úown_injectedÚinjectedÚscannedr–   ÚreroutedÚcompareds                   rD   Ú_scan_recordrô   k  sm  è ø€ ð —.‘.×$Ñ$ VÓ,€DÜ�dœDÔ!Ü ¨V×-?Ñ-?Ô@Ð@ä$ V§^¡^Ó4€IØ—‘×#Ñ# EÓ*€CÜ+¨C°Ó6€IØÐÜ Ø×*Ñ*ØÜ! #¤sÔ+�ô
ð 	
ð 26ô
ð 	
ô ,0¯=©=¸Ó+>€JÜ*ÄnÖ+d¸sÐX[Ð_cÒXc¨C°°c±©NÒ+dÓe€LÜ"ò 'ˆØ�‰�x Õ&ð'ô (ò BˆÜ#Ÿ}™}¬T°-Ó-@ÓAˆ
�8ÒðBðð &7×%DÑ%DØ/ØØØ ð	 &Eó &
÷  
ˆð —k‘k *Ó-€HÜ�(œDÔ! h§l¡lÔ3EÔ&FÜØ×*Ñ*ØØ—l‘lÐ#EÓFô
ð 	
ô ! “¬°7Ó);Ñ;¼~ÑM€HÜ�G˜XÓ&¬,°t¸XÓ*FÒFØÜ"ò $ˆØ�‰�H˜dÕ#ð$à‡N�N�<Ô ÜØ×&Ñ&ØÜ�Z‰ZÐ;˜6Ÿ>™>Ð;¨6°7Ñ;Ó<ôð ùòO ,eð 
úô ò Ü˜SÔ!Ü ¨V×-?Ñ-?È9Ô`qÐruÓ`vÔwÕwØûðüsb   ‚CJÃ	IÃIÃ%AJÄ6I ÅIÅI ÅDJÉI É	JÉ"+JÊJÊJÊJÊJÊJc              ƒ  óœ   ‡‡‡K  — t        j                  ˆˆˆfd„| D «       ddiŽƒ d{  –—† }t        d„ t        | |«      D «       «      S 7 Œ ­w)zV``return_exceptions=True`` so one record raising never leaves its siblings unobserved.c              3  ó:   •K  — | ]  }t        |‰‰‰«      –— Œ y ­wrµ   )rô   )rf   rë   rí   rì   rà   s     €€€rD   rh   z_scan_window.<locals>.<genexpr>¶  s   øè ø€ Ò	iÐX^Œ,�v˜}Ð.?ÐAR×
SÑ	iùs   ƒÚreturn_exceptionsTNc              3  óD   K  — | ]  \  }}|€Œ	|j                   |f–— Œ y ­wrµ   rŒ   )rf   rë   Úoutcomes      rD   rh   z_scan_window.<locals>.<genexpr>¹  s%   è ø€ Òs±?°6¸7Ð_fÑ_r�&×$Ñ$ gÔ.Ñsùs   ‚
 � )ÚasyncioÚgatherr}   Úzip)Úwindowrì   rà   rí   Úoutcomess    ``` rD   Ú_scan_windowrÿ   ®  sM   úè ø€ ô $ŸN™NÝ	iÐbhÔ	iðàñ÷ €Hô ÑsÄcÈ&ÐRZÓF[ÔsÓsÐsð	ús   …$A©A
ª!Ac                óö   — |j                   j                  d«      }| j                  dd«       | j                  «       }| j	                  |«       t        |j                  |j                  |t        |«      ¬«      S )z[Park the rewritten record on disk so only its location is carried for the rest of the scan.rË   r   é   )r<   rH   rU   rV   )	rQ   rÍ   ÚseekÚtellÚwriterT   r<   rH   rt   )r_   Ú	redactionÚencodedrU   s       rD   Ú_spoolr  ¼  sg   € à—^‘^×*Ñ*¨7Ó3€GØ‡O�O�A�qÔØ—O‘OÓ%€FØ×Ñ�WÔÜØ×)Ñ)Ø×%Ñ%ØÜ�7‹|ô	ð rC   c                óP   — t        d„ | D «       «      }t        |xs | d„ ¬«      d   S )zVA guardrail that blocked outranks a record we merely refused; then earliest line wins.c              3  óH   K  — | ]  }t        |d    t        «      sŒ|–— Œ y­wrb   )rd   ÚBaseException)rf   Úproblems     rD   rh   z_worst.<locals>.<genexpr>Ì  s   è ø€ Òc g¼ZÈÐPQÉ
ÔTaÕ=bœ'Ñcùs   ‚"›"c                ó   — | d   S )Nr   rB   )r  s    rD   ú<lambda>z_worst.<locals>.<lambda>Í  s
   € °w¸q±z€ rC   ©r×   rc   )r}   Úmin)ÚproblemsÚraiseds     rD   Ú_worstr  Ê  s*   € äÑc°ÔcÓc€FÜˆvÒ!˜Ñ'AÔBÀ1ÑEÐErC   c           	   ƒ  óÂ  ‡‡‡‡‡	‡
‡‡K  — t        |«      Š
g Šg Šg Šg Št        j                  t        ¬«      Š	dˆˆˆˆ	ˆ
ˆˆˆfd„}	 t	        | «      D ]9  }‰j                  |«       t        ‰«      t        k\  sŒ' |«       ƒ d{  –—†  ‰sŒ9 n ‰s |«       ƒ d{  –—†  | j                  d«       ‰r8‰	j                  «        t        t        ‰«      «      }t        |t        «      r|‚|S ‰s‰	j                  «        t        t        t        ‰d„ ¬«      «      t!        ‰«      ‰	¬«      S 7 Œ¤7 Œ�# t        $ r ‰	j                  «        ‚ w xY w# | j                  d«       w xY w­w)	aÏ  
    Stream a batch input file and run the pre-call guardrail chain against every record.

    A record a guardrail rewrites is kept in its rewritten form and a record it blocks is dropped,
    which is what the online path does per request. Both are returned for reporting. A guardrail
    exception that is not a block is re-raised untouched so its status code survives, since dropping
    a record that was never inspected is worse than refusing the file.
    ©Úmax_sizec               “  ó|  •K  — ‰	r³‰j                  t        ‰	«      «       t        t        ‰	«      ‰‰‰«      ƒ d {  –—† D ]f  \  } }t	        |t
        «      r‰j                  t        ‰|«      «       Œ2t	        |t        «      r‰j                  |«       ŒT‰j                  | |f«       Œh ‰	j                  «        y y 7 Œ­wrµ   )	Úappendrt   rÿ   r}   rd   rO   r  rX   Úclear)
r<   rù   r]   r  rí   r_   rì   rñ   rà   rý   s
     €€€€€€€€rD   Údrainz$scan_batch_input_file.<locals>.drainè  s¢   øè ø€ ÙØ�N‰Nœ3˜v›;Ô'Ü.:Ü�f“˜}Ð.?ÐARó/÷ )ò <Ñ$�˜Wô ˜g¤zÔ2Ø—N‘N¤6¨*°gÓ#>Õ?Ü ¬Ô7Ø—N‘N 7Õ+à—O‘O [°'Ð$:Õ;ð<ð �L‰L�Nð ð)ús   ƒ7B<ºB:»B B<Nr   c                ó   — | j                   S rµ   rŒ   )rg   s    rD   r  z'scan_batch_input_file.<locals>.<lambda>  s   € ¸×9KÑ9K€ rC   r  )r]   r^   r_   )r   ÚNone)rÞ   ÚtempfileÚSpooledTemporaryFiler   r°   r  rt   r   r
  Úcloser  r  r}   rd   r\   rØ   ri   )Úfile_sourcerÝ   rà   rí   r  ÚitemÚworstr]   r  r_   rì   rñ   rý   s     ``   @@@@@@rD   Úscan_batch_input_filer"  Ð  sC  ÿè ø€ ô /Ð/?Ó@€MØJL€HØ*,€GØ)+€FØ "€GÜ ×5Ñ5Ü%ô€J÷ô ðÜ! +Ó.ò 	ˆDØ�M‰M˜$ÔÜ�6‹{œlÓ*Ù“g—�ÚÙð	ñ Ù“'�MˆMð
 	×Ñ˜ÔáØ×ÑÔÜœe H›oÓ.ˆÜ�eœ]Ô+ØˆKØˆÙØ×ÑÔÜÜ”f˜WÑ*KÔLÓMÜ˜G›Øôð ð' øð ùÜò Ø×ÑÔØðûð 	×Ñ˜ÕüsZ   Š;EÁ1D+ Á8
D+ ÂD'ÂD+ Â
D+ ÂD)ÂD+ ÂB	EÄ'D+ Ä)D+ Ä+EÅE	 Å	EÅEc                ón   — | j                  |j                  «       | j                  |j                  «      S rµ   )r  rU   ÚreadrV   )r_   rg   s     rD   Ú_read_spooledr%    s%   € Ø‡O�O�F—M‘MÔ"Ø�?‰?˜6Ÿ=™=Ó)Ð)rC   c           	     ó†  — t        |j                  D �ci c]   }t        |t        «      sŒ|j                  |“Œ" c}«      }t        d„ |j                  D «       «      }t        j                  t        ¬«      }d}	 t        | «      D ]^  \  }}||v rŒ|j                  |«      }|€|j                  d«      nt        |j                  |«      }	|j                  |rd|	z   n|	«       d}Œ` 	 | j#                  d«       |j#                  d«       |S c c}w # t        $ r |j!                  «        ‚ w xY w# | j#                  d«       w xY w)a   
    Re-emit the file with redacted records rewritten and dropped records left out.

    Untouched records are copied through as written rather than re-serialized, so enabling the
    feature does not reformat records no guardrail objected to. Blank lines between records are
    not carried over, since they are not records. Rewritten records are read back from the scan's
    spool rather than from memory, so a file whose records are mostly rewritten does not put a
    second copy of itself on the heap.
    c              3  óV   K  — | ]!  }t        |t        «      sŒ|j                  –— Œ# y ­wrµ   )rd   rX   r<   re   s     rD   rh   z+rewrite_batch_input_file.<locals>.<genexpr>&  s"   è ø€ Òt°fÔR\Ð]cÔerÕRs˜v×1Õ1Ñtùs   ‚)˜)r  Fó   
Tr   )r   r]   rd   rT   r<   ré   r  r  r   r¬   rœ   r¹   r%  r_   r  r
  r  r  )
r  Úresultrg   rp   rq   ÚoutputÚ	wrote_anyr<   r«   rz   s
             rD   Úrewrite_batch_input_filer,    s+  € ô 'Ø28·.±.Ög¨ÄJÈvÔWeÕDfˆ×	Ñ	˜VÑ	#Ògó€Hô ÑtÀÇÁÔtÓt€Gä×1Ñ1Ü%ô€Fð €IðÜ%0°Ó%=ò 	Ñ!ˆK˜Ø˜gÑ%ØØ—\‘\ +Ó.ˆFØ-3¨^�8—?‘? 5Ô)ÄÈv×O`ÑO`ÐbhÓAiˆDØ�L‰L©˜ š¸Ô=Ø‰Iñ	ð 	×Ñ˜ÔØ
‡K�K�„NØ€Mùò- 	høô  ò Ø�‰ŒØðûð 	×Ñ˜Õús#   ”D
ªD
Á9A,D ÄD*Ä*D- Ä-E )r‰   rP   r   r   )r�   rM   r   r   )r   r   )r–   r
  r   rÐ   )r–   r
  r   rG   )rH   rG   r   rP   )rª   r	   r   zIterator[tuple[int, bytes]])rª   r	   r   zIterator[_ParsedRecord])rI   rP   r   úCallTypesLiteral | None)rÄ   rƒ   r   r-  )rI   ÚobjectrÄ   rƒ   r   r-  )r„   rƒ   r   rG   )rÄ   rƒ   rÙ   zfrozenset[str]r   rP   )rÝ   rƒ   r   rƒ   )
rë   r‚   rì   rƒ   rà   r   rí   r   r   z_ScanOutcome | None)
rý   ztuple[_ParsedRecord, ...]rì   rƒ   rà   r   rí   r   r   z4tuple[tuple[int, _ScanOutcome | BaseException], ...])r_   r	   r  rO   r   rT   )r  z8tuple[tuple[int, BatchScanFailure | BaseException], ...]r   z BatchScanFailure | BaseException)
r  r	   rÝ   rƒ   rà   r   rí   r   r   z"BatchScanFailure | BatchScanResult)r_   r	   rg   rT   r   Úbytes)r  r	   r)  r\   r   r	   )`rR   Ú
__future__r   rú   rä   r®   Úrer  Úcollections.abcr   r   Údataclassesr   Útypesr   Útypingr   r	   r
   r   r   Úurllib.parser   Úfastapir   Útyping_extensionsr   Úlitellm.exceptionsr   Ú%litellm.integrations.custom_guardrailr   Ú2litellm.litellm_core_utils.api_route_to_call_typesr   Úlitellm.proxy._typesr   Úlitellm.types.llms.openair   r   Úlitellm.types.utilsr   r   Úlitellm.proxy.utilsr   r   rA   r   r   Úcompiler   r    r"   r$   r&   r(   ré   r*   r1   ÚacompletionÚatext_completionÚ
aembeddingÚ
aresponsesÚanthropic_messagesr2   r6   r:   rF   rK   rM   rO   rT   rX   rY   rZ   r\   r‚   rŠ   r�   r’   r—   rŸ   rr   r¬   r°   r¿   rÆ   rÉ   rÑ   rÚ   rÞ   rô   rÿ   r  r  r"  r%  r,  rB   rC   rD   ú<module>rF     sÎ  ðòõ #ã Û Û Û 	Û ß -Ý !Ý "ß FÕ FÝ !å !Ý *å 7Ý KÝ WÝ /ß Pß ;áÝ0á-=¸bÓ-A€Ð*Ó Aà€ˆeÓ ð *Ð �eÓ )ð (˜RŸZ™ZÐ(:Ó;Ð �UÓ ;Ø!Ð �eÓ !Ø€�Ó à.Ð �EÓ .Ø0°*Ð=Ð �UÓ =ð =Ð �EÓ <ñ "Ð#5°zÀ<Ð"PÓQ€�Ó Qñ 'òó
Ð �Uó 
ñ  )à×ÑØ×"Ñ"Ø×ÑØ×ÑØ×$Ñ$ðó Ð �uó ð �×&Ñ&Ð'Øˆy×)Ñ)Ð*Øˆi×"Ñ"Ð#ð!Ð ˜ó ñ �$˜dÔ#÷ð ó $ðñ �$˜dÔ#÷ð ó $ðñ �$˜dÔ#÷ð ó $ðð 0Ð2CÑCÐFVÑVÐ �)Ó Vñ �$˜dÔ#÷ð ó $ðñ �$˜dÔ#÷oð oó $ðoñ �$˜dÔ#÷!ð !ó $ð!ð *¨MÑ9€ˆyÓ 9Ø*¨ZÑ7¸-ÑG€ˆiÓ Gñ �$˜dÔ#÷"
ð "
ó $ð"
ñJ �$˜dÔ#÷"ð "ó $ð"ó
Eó"ó.ó*ó.;ó"ó(óSó:ó,2ó
	Lóoóó	ð@Øð@à'ð@ð &ð@ð $ð	@ð
 ó@ðFtØ%ðtà'ðtð &ðtð $ð	tð
 :ótóóFðAàðAð +ðAð &ð	Að
 $ðAð (óAóH*ô
!rC   