Ë
    uPêjµF  ã                   óŠ   — d Z ddlZddlmZmZmZmZ ddlmZ ddl	m
Z
 ddlmZ erddlmZ ddlmZ dd	lmZ  G d
„ de
«      Zy)a£  
A2A Protocol Handler for Unified Guardrails

This module provides guardrail translation support for A2A (Agent-to-Agent) Protocol.
It handles both JSON-RPC 2.0 input requests and output responses, extracting text
from message parts and applying guardrails.

A2A Protocol Format:
- Input: JSON-RPC 2.0 with params.message.parts containing text parts
- Output: JSON-RPC 2.0 with result containing message/artifact parts
é    N)ÚTYPE_CHECKINGÚAnyÚFinalÚOptional)Úverbose_proxy_logger)ÚBaseTranslation)ÚGenericGuardrailAPIInputs)ÚCustomGuardrail)ÚLogging)ÚUserAPIKeyAuthc                   ó
  — e Zd ZdZ	 ddeddded   defd	„Z	 	 	 d d
eddded   ded   dedz  defd„Z	 	 	 d de	e   ddded   ded   dedz  de	e   fd„Z
de	e   dee	eeef   dz     e	eeeeef   f      f   fd„Zde	eeeeef   f      deee	e   f   fd„Zdeeef   de	e   de	eeedf   ef      ddfd„Zde	eeef      deedf   de	e   de	eeedf   ef      ddf
d„Zdeeez  ef   deedf   dededdf
d„Zy)!ÚA2AGuardrailHandleraÀ  
    Handler for processing A2A Protocol messages with guardrails.

    This class provides methods to:
    1. Process input messages (pre-call hook) - extracts text from A2A message parts
    2. Process output responses (post-call hook) - extracts text from A2A response parts

    A2A Message Format:
    - Input: params.message.parts[].text (where kind == "text")
    - Output: result.message.parts[].text or result.artifacts[].parts[].text
    NÚdataÚguardrail_to_applyr
   Úlitellm_logging_objÚLiteLLMLoggingObjÚreturnc              ƒ   óÆ  K  — |j                  di «      }|j                  di «      }|j                  dg «      }|st        j                  d«       |S g }g }t        |«      D ]Q  \  }	}
|
j                  d«      dk(  sŒ|
j                  dd«      }|sŒ0|j	                  |«       |j	                  |	«       ŒS |r�t        |¬«      }|g|d	<   |j                  d
«      }|r||d
<   |j                  ||d|¬«      ƒ d{  –—† }|j                  dg «      }|r5t        |«      t        |«      k(  rt        |«      D ]  \  }}	||   ||	   d<   Œ t        j                  d|«       |S 7 Œe­w)aª  
        Process A2A input messages by applying guardrails to text content.

        Extracts text from A2A message parts and applies guardrails.

        Args:
            data: The A2A JSON-RPC 2.0 request data
            guardrail_to_apply: The guardrail instance to apply
            litellm_logging_obj: Optional logging object

        Returns:
            Modified data with guardrails applied to text content
        ÚparamsÚmessageÚpartsz,A2A: No parts in message, skipping guardrailÚkindÚtextÚ ©ÚtextsÚstructured_messagesÚmodelÚrequest©ÚinputsÚrequest_dataÚ
input_typeÚlogging_objNr   z A2A: Processed input message: %s)Úgetr   ÚdebugÚ	enumerateÚappendr	   Úapply_guardrailÚlen)Úselfr   r   r   r   r   r   Útexts_to_checkÚtext_part_indicesÚpart_idxÚpartr   r!   r   Úguardrailed_inputsÚguardrailed_textsÚtask_idxs                    úx/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/llms/a2a/chat/guardrail_translation/handler.pyÚprocess_input_messagesz*A2AGuardrailHandler.process_input_messages'   s�  è ø€ ð( Ÿ™ ¨2Ó.ˆØŸ™ I¨rÓ2ˆØ—{‘{ 7¨BÓ/ˆáÜ ×&Ñ&Ð'UÔVØˆKà+-ˆØ.0Ðô (¨Ó.ò 	7‰NˆH�dØ�x‰x˜Ó 6Ó)Ø—x‘x ¨Ó+�ÚØ"×)Ñ)¨$Ô/Ø%×,Ñ,¨XÕ6ð	7ñ Ü5¸NÔKˆFð .5¨IˆFÐ(Ñ)ð  Ÿ8™8 GÓ,ˆEÙØ"'��w‘à.@×.PÑ.PØØ!Ø$Ø/ð	 /Qó /÷ )Ðð (:×'=Ñ'=¸gÀrÓ'JÐñ !¤SÐ):Ó%;¼sÐCTÓ?UÒ%UÜ*3Ð4EÓ*Fò JÑ&�H˜hØ.?ÀÑ.I�E˜(‘O FÒ+ðJô 	×"Ñ"Ð#EÀwÔOàˆð!)ús    ‚A9E!Á<E!ÂA(E!Ã9EÃ:A&E!ÚresponseÚuser_api_key_dictr   r"   c              ƒ   ó6  K  — t        |d«      r|j                  «       }d}n6t        |t        «      r|}d}n!t	        j
                  dt        |«      «       |S |j                  di «      }|rt        |t        «      st	        j                  d«       |S g }	g }
| j                  ||	|
¬«       |	st	        j                  d«       |S |€d
|i}n	d
|vr||d
<   d|vr| j                  |«      }|r||d<   t        |	¬«      }|j                  ||d
|¬«      ƒ d	{  –—† }|j                  dg «      }|rEt        |«      t        |
«      k(  r.t        |
«      D ]   \  }\  }}| j                  |||||   ¬«       Œ" t	        j                  d«       |r||d<   |S ||d<   |S 7 Œ‚­w)a.  
        Process A2A output response by applying guardrails to text content.

        Handles multiple A2A response formats:
        - Direct message: {"result": {"kind": "message", "parts": [...]}}
        - Nested message: {"result": {"message": {"parts": [...]}}}
        - Task with artifacts: {"result": {"kind": "task", "artifacts": [{"parts": [...]}]}}
        - Task with status message: {"result": {"kind": "task", "status": {"message": {"parts": [...]}}}}

        Args:
            response: A2A JSON-RPC 2.0 response dict or object
            guardrail_to_apply: The guardrail instance to apply
            litellm_logging_obj: Optional logging object
            user_api_key_dict: User API key metadata

        Returns:
            Modified response with guardrails applied to text content
        Ú
model_dumpTFz1A2A: Unknown response type %s, skipping guardrailÚresultz.A2A: No result in response, skipping guardrail©r9   r,   Útask_mappingsz A2A: No text content in responseNr5   Úlitellm_metadatar   r    r   ©r9   Úpathr.   r   zA2A: Processed output response)Úhasattrr8   Ú
isinstanceÚdictr   ÚwarningÚtyper%   r&   Ú_extract_texts_from_resultÚ'transform_user_api_key_dict_to_metadatar	   r)   r*   r'   Ú_apply_text_to_path)r+   r5   r   r   r6   r"   Úresponse_dictÚis_pydanticr9   r,   r;   Úuser_metadatar!   r0   r1   r2   r>   r.   s                     r3   Úprocess_output_responsez+A2AGuardrailHandler.process_output_responsel   s÷  è ø€ ô6 �8˜\Ô*Ø$×/Ñ/Ó1ˆMØ‰KÜ˜¤$Ô'Ø$ˆMØ‰Kä ×(Ñ(Ð)\Ô^bÐckÓ^lÔmØˆOà%×)Ñ)¨(°BÓ7ˆÙœZ¨´Ô5Ü ×&Ñ&Ð'WÔXØˆOð ,.ˆð CEˆð 	×'Ñ'ØØ)Ø'ð 	(ô 	
ñ Ü ×&Ñ&Ð'IÔJØˆOð
 ÐØ&¨Ð6‰Là Ñ-Ø+8�˜ZÑ(ð  \Ñ1Ø#'×#OÑ#OÐPaÓ#bˆMÙØ3@�Ð/Ñ0ä1¸ÔGˆà*<×*LÑ*LØØ%Ø!Ø+ð	 +Mó +
÷ %
Ðð $6×#9Ñ#9¸'À2Ó#FÐñ ¤Ð%6Ó!7¼3¸}Ó;MÒ!MÜ.7¸Ó.Fò Ñ*�Ñ*˜4 Ø×(Ñ(Ø!ØØ%Ø*¨8Ñ4ð	 )õ ðô 	×"Ñ"Ð#CÔDñ ð '-ˆM˜(Ñ#ØˆOà!'ˆH�XÑØˆOð;%
ús   ‚DFÄFÄBFÚresponses_so_farc              ƒ   ó:  K  — | j                  |«      \  }}|s|S | j                  |«      \  }}	|s|S |€d|i}n	d|vr||d<   d|vr| j                  |«      }
|
r|
|d<   t        |g¬«      }|j	                  ||d|¬«      ƒ d{  –—† }|j                  dg «      }|s|S |d   }|	r|	d   nd}|D ]œ  \  }}|j                  d	i «      }t        |t        «      sŒ)g }g }| j                  |||¬
«       |sŒD||k(  r5t        |«      D ]&  \  }\  }}|dk(  r|nd}| j                  ||||¬«       Œ( Œ~|D ]  \  }}| j                  |||d¬«       Œ Œž t        |«      D ]:  \  }}t        |t        «      sŒ||   €Œt        j                  ||   «      dz   ||<   Œ< |S 7 �Œ­w)aa  
        Process A2A streaming output by applying guardrails to accumulated text.

        responses_so_far can be a list of JSON-RPC 2.0 objects (dict or NDJSON str), e.g.:
        - task with history, status-update, artifact-update (with result.artifact.parts),
        - then status-update (final). Text is extracted from result.artifact.parts,
        result.message.parts, result.parts, etc., concatenated in order, guardrailed once,
        then the combined guardrailed text is written into the first chunk that had text
        and all other text parts in other chunks are cleared (in-place).
        NrK   r<   r   r5   r    r   r   r9   r:   r   r=   ú
)Ú_parse_streaming_responsesÚ _collect_text_from_parsed_chunksrE   r	   r)   r%   r@   rA   rD   r'   rF   ÚstrÚjsonÚdumps)r+   rK   r   r   r6   r"   ÚparsedÚvalid_parsedÚcombined_textÚchunk_indices_with_textrI   r!   r0   r1   Úguardrailed_textÚfirst_chunk_with_textÚorig_iÚobjr9   Útexts_in_chunkÚmappingsr2   r>   r.   r   ÚiÚitems                              r3   Ú!process_output_streaming_responsez5A2AGuardrailHandler.process_output_streaming_response×   sF  è ø€ ð$  $×>Ñ>Ð?OÓPÑˆ�ÙØ#Ð#à15×1VÑ1VÐWcÓ1dÑ.ˆÐ.ÙØ#Ð#àÐØ.Ð0@ÐA‰Là!¨Ñ5Ø3C�Ð/Ñ0à \Ñ1Ø#'×#OÑ#OÐPaÓ#bˆMÙØ3@�Ð/Ñ0ä1¸¸ÔHˆØ*<×*LÑ*LØØ%Ø!Ø+ð	 +Mó +
÷ %
Ðð $6×#9Ñ#9¸'À2Ó#FÐÙ Ø#Ð#Ø"3°AÑ"6Ðñ RiÐ3JÈ1Ò3MÐnrÐà'ò 	‰KˆF�CØ—W‘W˜X rÓ*ˆFÜ˜f¤dÔ+ØØ(*ˆNØ:<ˆHØ×+Ñ+ØØ-Ø&ð ,ô ñ
 ØØÐ.Ò.ä2;¸HÓ2Eò Ñ.�HÑ.˜t XØ/7¸1ª}Ñ+À"�DØ×,Ñ,Ø%Ø!Ø!)Ø!ð	 -õ ñð '/ò ‘N�D˜(Ø×,Ñ,Ø%Ø!Ø!)Øð	 -õ ñð1	ôB !Ð!1Ó2ò 	C‰GˆAˆtÜ˜$¤Õ$¨°©Ñ)>Ü&*§j¡j°¸±Ó&;¸dÑ&BÐ  Ò#ð	Cð  Ððg%
ûs   ‚BFÂFÂC*FÅ0FÅ6#Fc                 ó¸  — dgt        |«      z  }t        |«      D ]s  \  }}t        |t        «      r|}n6t        |t        «      r%	 t        j                  |j                  «       «      }nŒOt        |j                  d«      t        «      sŒo|||<   Œu t        |«      D ��cg c]  \  }}|€Œ	||f‘Œ }}}||fS # t
        j                  t        f$ r Y Œ·w xY wc c}}w )zFParse JSON-RPC items, returning aligned parsed list and valid entries.Nr9   )r*   r'   r@   rA   rP   rQ   ÚloadsÚstripÚJSONDecodeErrorÚ	TypeErrorr%   )r+   rK   rS   r]   r^   rZ   rT   s          r3   rN   z.A2AGuardrailHandler._parse_streaming_responses2  sØ   € ð
 7;°V¼cÐBRÓ>SÑ5SˆÜ Ð!1Ó2ò 	 ‰GˆAˆtÜ˜$¤Ô%Ø‘Ü˜D¤#Ô&ðÜŸ*™* T§Z¡Z£\Ó2‘Cð Ü˜#Ÿ'™' (Ó+¬TÕ2Ø��q’	ð	 ô 7@ÀÓ6G×[©F¨A¨sÈ3É?  3šxÐ[ˆÑ[Ø�|Ð#Ð#øô ×,Ñ,¬iÐ8ò Ùðüó \s   Á#B7Â
CÂ*CÂ7CÃCrT   c                 óÂ   — ddl m} g }g }t        |«      D ]5  \  }\  }} ||«      }|sŒ|j                  |«       |j                  |«       Œ7 dj	                  |«      |fS )zECollect text from parsed chunks, returning combined text and indices.r   )Úextract_text_from_a2a_responser   )Úlitellm.llms.a2a.common_utilsrf   r'   r(   Újoin)	r+   rT   rf   Ú
text_partsrV   Ú_idxrY   rZ   Úts	            r3   rO   z4A2AGuardrailHandler._collect_text_from_parsed_chunksG  sp   € õ
 	Qà')ˆ
Ø46ÐÜ#,¨\Ó#:ò 	7ÑˆD‘-�6˜3Ù.¨sÓ3ˆAÚØ×!Ñ! !Ô$Ø'×.Ñ.¨vÕ6ð		7ð
 �w‰w�zÓ"Ð$;Ð;Ð;ó    r9   r,   r;   .c                 óà  — d|v r| j                  |d   d||¬«       |j                  d«      }|r,t        |t        «      rd|v r| j                  |d   d||¬«       |j                  d«      }|r,t        |t        «      rd|v r| j                  |d   d||¬«       |j                  di «      }t        |t        «      r?|j                  d«      }|r,t        |t        «      rd|v r| j                  |d   d	||¬«       |j                  d
g «      }|r_t        |t        «      rNt        |«      D ]?  \  }	}
t        |
t        «      sŒd|
v sŒ| j                  |
d   d
t        |	«      df||¬«       ŒA yyy)a¾  
        Extract text from all possible locations in an A2A result.

        Handles multiple response formats:
        1. Direct message with parts: {"parts": [...]}
        2. Nested message: {"message": {"parts": [...]}}
        3. Task with artifacts: {"artifacts": [{"parts": [...]}]}
        4. Task with status message: {"status": {"message": {"parts": [...]}}}
        5. Streaming artifact-update: {"artifact": {"parts": [...]}}
        r   )r   )r   r>   r,   r;   r   )r   r   Úartifact)rn   r   Ústatus)ro   r   r   Ú	artifactsN)Ú_extract_texts_from_partsr%   r@   rA   Úlistr'   rP   )r+   r9   r,   r;   r   rn   ro   Ústatus_messagerp   Úartifact_idxÚarts              r3   rD   z.A2AGuardrailHandler._extract_texts_from_resultW  sœ  € ð" �fÑØ×*Ñ*Ø˜W‘oØØ-Ø+ð	 +ô ð  Ÿ™ IÓ.ˆÙ”z '¬4Ô0°WÀÑ5GØ×*Ñ*Ø˜gÑ&Ø)Ø-Ø+ð	 +ô ð !Ÿ*™* ZÓ0ˆÙœ
 8¬TÔ2°wÀ(Ñ7JØ×*Ñ*Ø˜wÑ'Ø*Ø-Ø+ð	 +ô ð Ÿ
™
 8¨RÓ0ˆÜ�fœdÔ#Ø$*§J¡J¨yÓ$9ˆNÙ¤*¨^¼TÔ"BÀwÐR`ÑG`Ø×.Ñ.Ø(¨Ñ1Ø7Ø#1Ø"/ð	 /ô ð "Ÿ:™: k°2Ó6ˆ	Ùœ I¬tÔ4Ü%.¨yÓ%9ò Ñ!�˜cÜ˜c¤4Õ(¨W¸ª^Ø×2Ñ2Ø! '™lØ)¬3¨|Ó+<¸gÐFØ'5Ø&3ð	 3õ ñð 5ˆ9rl   r   r>   c                 óÆ   — t        |«      D ]S  \  }}|j                  d«      dk(  sŒ|j                  dd«      }|sŒ0|j                  |«       |j                  ||f«       ŒU y)z Extract text from message parts.r   r   r   N)r'   r%   r(   )r+   r   r>   r,   r;   r.   r/   r   s           r3   rq   z-A2AGuardrailHandler._extract_texts_from_partsœ  sa   € ô (¨Ó.ò 	;‰NˆH�dØ�x‰x˜Ó 6Ó)Ø—x‘x ¨Ó+�ÚØ"×)Ñ)¨$Ô/Ø!×(Ñ(¨$°Ð)9Õ:ñ	;rl   r.   r   c                 ón   — |}|D ]&  }|j                  «       r|t        |«         }Œ"||   }Œ( |||   d<   y)z@Apply guardrailed text back to the specified path in the result.r   N)ÚisdigitÚint)r+   r9   r>   r.   r   ÚcurrentÚkeys          r3   rF   z'A2AGuardrailHandler._apply_text_to_path«  sI   € ð ˆØò 	'ˆCØ�{‰{Œ}à!¤# c£(Ñ+‘à! #™,‘ð	'ð %)ˆ�Ñ˜&Ò!rl   )N)NNN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__rA   r   r   r4   rJ   rr   r_   ÚtuplerP   ry   rN   rO   rD   rq   rF   © rl   r3   r   r      sž  „ ñ
ð  >Bñ	CàðCð .ðCð &Ð&9Ñ:ð	Cð
 
óCðR >BØ8<Ø$(ñiàðið .ðið &Ð&9Ñ:ð	ið
 $Ð$4Ñ5ðið ˜T‘kðið 
óið^ >BØ8<Ø$(ñY à˜s™)ðY ð .ðY ð &Ð&9Ñ:ð	Y ð
 $Ð$4Ñ5ðY ð ˜T‘kðY ð 
ˆc‰óY ðv$à˜s™)ð$ð 
ˆt�D˜˜c˜‘N TÑ)Ñ*¨D°°s¸DÀÀcÀ¹NÐ7JÑ1KÑ,LÐLÑ	Mó$ð*<à˜5  d¨3°¨8¡nÐ!4Ñ5Ñ6ð<ð 
ˆs�D˜‘Iˆ~Ñ	ó<ð Cà�S˜#�X‘ðCð ˜S™	ðCð ˜E %¨¨S¨¡/°3Ð"6Ñ7Ñ8ð	Cð
 
óCðJ;à�D˜˜c˜‘NÑ#ð;ð �C˜�H‰oð;ð ˜S™	ð	;ð
 ˜E %¨¨S¨¡/°3Ð"6Ñ7Ñ8ð;ð 
ó;ð)à�S˜3‘Y �^Ñ$ð)ð �C˜�H‰oð)ð ð	)ð
 ð)ð 
ô)rl   r   )r   rQ   Útypingr   r   r   r   Úlitellm._loggingr   Ú<litellm.llms.base_llm.guardrail_translation.base_translationr   Úlitellm.types.utilsr	   Ú%litellm.integrations.custom_guardrailr
   Ú*litellm.litellm_core_utils.litellm_loggingr   r   Úlitellm.proxy._typesr   r   r�   rl   r3   ú<module>r‰      s8   ðñ
ó ß 6Ó 6å 1Ý XÝ 9áÝEÝWÝ3ôc)˜/õ c)rl   