o
    i1                     @   s  d Z ddlmZ ddl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 ddlmZ ddlmZ ddlm  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# e$e%ZdZ&dZ'dZ(e&e'e(gZ)G dd deZ*G dd deZ+G dd deddZ,G d d! d!eddZ-G d"d# d#eddZ.G d$d% d%eZ/G d&d' d'eddZ0G d(d) d)eddZ1G d*d+ d+e2Z3G d,d- d-e2Z4G d.d/ d/Z5	d4d0ee6 d1e5fd2d3Z7dS )5z@AI Guard client for security evaluation of agentic AI workflows.    )deepcopyN)Any)Literal)Optional)	TypedDict)Union)config)AI_GUARD)_aiguard_manual_keep)core)	telemetry)ai_guard_config)TELEMETRY_NAMESPACE)MetricTagType)Response)get_connection)tracer)__version__ALLOWDENYABORTc                   @   s   e Zd ZU eed< eed< dS )Functionname	argumentsN__name__
__module____qualname__str__annotations__ r    r    W/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/appsec/ai_guard/_api_client.pyr   "      
 r   c                   @   s   e Zd ZU eed< eed< dS )ToolCallidfunctionN)r   r   r   r   r   r   r    r    r    r!   r#   '   r"   r#   c                   @      e Zd ZU eed< dS )ImageURLurlNr   r    r    r    r!   r'   ,      
 r'   F)totalc                   @   s.   e Zd ZU eed< ee ed< ee ed< dS )ContentParttypetext	image_urlN)r   r   r   r   r   r   r'   r    r    r    r!   r+   0   s   
 r+   c                   @   s>   e Zd ZU eed< eeee f ed< eed< ee ed< dS )Messagerolecontenttool_call_id
tool_callsN)	r   r   r   r   r   r   listr+   r#   r    r    r    r!   r/   6   s
   
 r/   c                   @   s.   e Zd ZU ed ed< eed< ee ed< dS )
Evaluation)r   r   r   actionreasontagsN)r   r   r   r   r   r   r4   r    r    r    r!   r5   =   s   
 r5   c                   @   r&   )OptionsblockN)r   r   r   boolr   r    r    r    r!   r9   C   r)   r9   c                   @   s.   e Zd ZU eed< eed< eed< eed< dS )ErrorstatustitlecodedetailNr   r    r    r    r!   r<   G   s
   
 r<   c                	       s<   e Zd ZdZd	dee dedeee  f fddZ	  Z
S )
AIGuardClientErrorz%Exception for AI Guard client errors.r   Nmessager=   errorsc                    s    || _ |pg | _t | d S N)r=   rC   super__init__)selfrB   r=   rC   	__class__r    r!   rF   Q   s   
zAIGuardClientError.__init__)r   N)r   r   r   __doc__r   r   intr4   r<   rF   __classcell__r    r    rH   r!   rA   N   s    0rA   c                	       s8   e Zd ZdZddededeee  f fddZ  ZS )	AIGuardAbortErrorz<Exception to abort current execution due to security policy.Nr6   r7   r8   c              	      s6   || _ || _|| _t d| d| d| d d S )NzAIGuardAbortError(action='z', reason='z	', tags='z'))r6   r7   r8   rE   rF   )rG   r6   r7   r8   rH   r    r!   rF   Z   s   $zAIGuardAbortError.__init__rD   )	r   r   r   rJ   r   r   r4   rF   rL   r    r    rH   r!   rM   W   s    ,rM   c                   @   s   e Zd ZdZdededefddZededd	fd
dZede	e
 de	e
 fddZede
defddZede
defddZede
de	e
 dee fddZedee dedefddZd de	e
 dee defddZdededefddZd	S )!AIGuardClientz=HTTP client for communicating with AI Guard security service.endpointapi_keyapp_keyc                 C   s:   || _ d||tddd| _tjtjd| _tjd | _	dS )zInitialize AI Guard client.

        Args:
            endpoint: AI Guard service endpoint URL
            api_key: Datadog API key
            app_key: Datadog application key
        zapplication/jsonSDKpython)zContent-Typez
DD-API-KEYzDD-APPLICATION-KEYzDD-AI-GUARD-VERSIONzDD-AI-GUARD-SOURCEzDD-AI-GUARD-LANGUAGE)serviceenvi  N)
	_endpointr   _headersr   rT   rU   _metar   _ai_guard_timeout_timeout)rG   rO   rP   rQ   r    r    r!   rF   d   s   zAIGuardClient.__init__r8   returnNc                 C   s   t jtjtjd|  d S )N   )r   telemetry_writeradd_count_metricr   APPSECr	   REQUESTS_METRIC)r8   r    r    r!   _add_request_to_telemetryx   s   z'AIGuardClient._add_request_to_telemetrymessagesc                    s   t j}t| |krtjtjtj	dd | | d  } t j
d dtdtf fddfdd	| D } rBtjtjtj	dd
 |S )Nr\   ))r,   rb   FrB   r[   c                    s   t | }|dd}t|tr!t|kr|d  |d< d |S t|trO|D ]&}t|trNd|v rN|dd}t|trNt|krN|d  |d< d q(|S )Nr1    Tr-   )r   get
isinstancer   lenr4   dict)rB   new_messager1   partr-   )content_truncatedmax_content_sizer    r!   truncate_message   s    
	
zAAIGuardClient._messages_for_meta_struct.<locals>.truncate_messagec                    s   g | ]} |qS r    r    ).0rB   )rl   r    r!   
<listcomp>   s    z;AIGuardClient._messages_for_meta_struct.<locals>.<listcomp>))r,   r1   )r   _ai_guard_max_messages_lengthrf   r   r]   r^   r   r_   r	   TRUNCATED_METRIC_ai_guard_max_content_sizer/   )rb   max_messages_lengthresultr    )rj   rk   rl   r!   _messages_for_meta_struct|   s   z'AIGuardClient._messages_for_meta_structrB   c                 C      |  d}t|ot|dkS )Nr3   r   rd   r;   rf   )rB   r3   r    r    r!   _has_tool_calls      
zAIGuardClient._has_tool_callsc                 C   ru   )Nr2   r   rv   )rB   r2   r    r    r!   _has_tool_call_id   rx   zAIGuardClient._has_tool_call_idc                 C   s   t | r| dg }dd |D }ddd |D S t | rZ| d}|s*d S t|D ]+}|dg }|D ] }d|v rX|d |krXd	|v rXd
|d	 v rX|d	 d
     S q8q.d S )Nr3   c                 S   s,   g | ]}d |v rd|d  v r|d  d qS )r%   r   r    )rm   	tool_callr    r    r!   rn      s
    
z0AIGuardClient._get_tool_name.<locals>.<listcomp>,c                 s   s    | ]}|r|V  qd S rD   r    )rm   r   r    r    r!   	<genexpr>   s    z/AIGuardClient._get_tool_name.<locals>.<genexpr>r2   r$   r%   r   )rN   rw   rd   joinry   reversed)rB   rb   r3   names	target_idmsgrz   r    r    r!   _get_tool_name   s*   


	zAIGuardClient._get_tool_nameoptionsremote_enabledc                 C   s   |r| sdS |  ddS )NFr:   )rd   )r   r   r    r    r!   _is_blocking_enabled   s   z"AIGuardClient._is_blocking_enabledc                 C   s  |rt |dkrtdttja}z@dd|| jdii}|d }| ||}|r;|tj	d |tj
| n|tj	d d	| |i}|tj| z| | j d
|}| p`i }	W n tyw }
 z	td|
 d|
d}
~
ww |jdkrz$|	d d }|d }|dd}|dg }|dg }|dd}W n" ty }
 ztj|	dddd }td| |jd|
d}
~
ww |tvrtd| dt |jd|tj| |r|d|i |r|tj| |r|d|i ntd|j |jd |	v r|	d  d!dd!| ||o|tk}| d|fd"|r%d#nd$fd%f t }|r6t | |rG|tj!d# t"|||d&t#|||d&W W  d   S  t"y^     tys   | d' t$j%d(|d)d*  w 1 sxw   Y  dS )+a  Evaluate if the list of messages are safe to execute.

        Args:
            messages: list of messages to evaluate
            options: Optional configuration with 'block' parameter (defaults to False)

        Returns:
            EvaluationResult containing action and reason

        Raises:
            AIGuardAbortError: If execution should be aborted and block is set to true
            AIGuardClientError: If evaluation request fails
        r   zMessages must not be emptydata
attributes)rb   metatoolpromptrb   z	/evaluatez+Unexpected error calling AI Guard service: )rB   N   r6   r7   r8   sds_findingsis_blocking_enabledF   )indenti  z6AI Guard service returned unexpected response format: )rB   r=   z0AI Guard service returned unrecognized action: 'z'. Expected )r=   attack_categoriessdsz&AI Guard service call failed, status: rC   )rB   r=   rC   r:   truefalse)errorr   )r6   r7   r8   ))r   r   z+AI Guard evaluation failed for messages: %sT)exc_info)&rf   
ValueErrorr   tracer	   RESOURCE_TYPErX   r   set_tag
TARGET_TAGTOOL_NAME_TAGrt   _set_struct_tagSTRUCT_execute_requestrV   get_json	ExceptionrA   r=   rd   jsondumpsACTIONS
ACTION_TAGupdate
REASON_TAGr   r   ra   r   get_root_spanr
   BLOCKED_TAGrM   r5   loggerdebug)rG   rb   r   spanpayloadlast	tool_namemeta_structresponsers   er   r6   r7   r8   r   blocking_enabledvalueshould_block	root_spanr    r    r!   evaluate   s   

H
zAIGuardClient.evaluater(   r   c                 C   sX   z&t || j}tj|ddtd}|d||| j | }t	|W |
  S |
  w )NT)ensure_asciiskipkeysdefaultPOST)r   rZ   r   r   r   requestrW   getresponser   from_http_responseclose)rG   r(   r   conn	json_bodyrespr    r    r!   r   1  s   
zAIGuardClient._execute_requestrD   )r   r   r   rJ   r   rF   staticmethodr   ra   r4   r/   rt   r;   rw   ry   r   r   r9   r   r5   r   r   r   r   r    r    r    r!   rN   a   s"    %  arN   rO   r[   c                 C   sd   t j}t j}|r
|std| stj} | s,t jddkr#dt j nt j}d| d} t| ||S )NzFAuthentication credentials required: provide DD_API_KEY and DD_APP_KEY.r\   zapp.zhttps://z/api/v2/ai-guard)	r   _dd_api_key_dd_app_keyr   r   _ai_guard_endpoint_dd_sitecountrN   )rO   rP   rQ   siter    r    r!   new_ai_guard_client<  s   "r   rD   )8rJ   copyr   r   typingr   r   r   r   r   ddtracer   ddtrace.appsec._constantsr	   ddtrace.appsec._trace_utilsr
   ddtrace.internalr   r   ddtrace.internal.loggerinternalr   ddloggerddtrace.internal.settings.asmr   ddtrace.internal.telemetryr   -ddtrace.internal.telemetry.metrics_namespacesr   ddtrace.internal.utils.httpr   r   ddtrace.tracer   ddtrace.versionr   
get_loggerr   r   r   r   r   r   r#   r'   r+   r/   r5   r9   r<   r   rA   rM   rN   r   r   r    r    r    r!   <module>   sX    

	
 ]