diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index ce0ea5b844..d582c8e138 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -2066,6 +2066,256 @@ components: $ref: "#/components/schemas/JSONAPIErrorResponse" description: The server cannot process the request because it contains invalid data. schemas: + AIGuardAction: + description: The action recommendation from the AI Guard evaluation. + enum: + - ALLOW + - DENY + - ABORT + example: ALLOW + type: string + x-enum-varnames: + - ALLOW + - DENY + - ABORT + AIGuardContentPart: + description: A single part of a multipart message content. + properties: + image_url: + $ref: "#/components/schemas/AIGuardImageURL" + text: + description: The text content of this part, required when type is text. + example: "How do I delete all files?" + type: string + type: + description: The type of content part, either text or image_url. + example: text + type: string + required: + - type + type: object + AIGuardContentPartList: + description: A list of content parts forming a multipart message. + items: + $ref: "#/components/schemas/AIGuardContentPart" + type: array + AIGuardEvaluateRequest: + description: The evaluation request payload containing conversation messages and optional metadata. + example: + messages: + - content: How do I delete all files on the system? + role: user + meta: + env: production + service: my-llm-service + properties: + messages: + description: The list of conversation messages to evaluate. Must contain at least one message. + example: + - content: How do I delete all files on the system? + role: user + items: + $ref: "#/components/schemas/AIGuardMessage" + type: array + meta: + $ref: "#/components/schemas/AIGuardMeta" + required: + - messages + type: object + AIGuardEvaluateResponse: + description: The result of the AI Guard evaluation. + properties: + action: + $ref: "#/components/schemas/AIGuardAction" + global_prob: + description: The overall threat probability score across all evaluated tags. + example: 0.02 + format: double + type: number + is_blocking_enabled: + description: Whether blocking mode is enabled for this organization. + example: false + type: boolean + reason: + description: A human-readable explanation of the action recommendation. + example: No threats detected. + type: string + sds_findings: + description: Sensitive data findings detected in the evaluated conversation. + items: + $ref: "#/components/schemas/AIGuardSdsFinding" + type: array + tag_probs: + additionalProperties: + format: double + type: number + description: Probability scores for each evaluated threat tag. + example: + indirect-prompt-injection: 0.01 + jailbreak: 0.02 + type: object + tags: + description: Security threat tags detected in the evaluated conversation. + example: [] + items: + type: string + type: array + required: + - action + - reason + - tags + - tag_probs + - is_blocking_enabled + type: object + AIGuardImageURL: + description: An image URL reference for multimodal content. + properties: + url: + description: The URL pointing to the image. + example: "https://example.com/image.png" + type: string + required: + - url + type: object + AIGuardMessage: + description: A single message in the conversation to evaluate. + properties: + content: + $ref: "#/components/schemas/AIGuardMessageContent" + role: + $ref: "#/components/schemas/AIGuardMessageRole" + tool_call_id: + description: The ID of the tool call this message is responding to, required for tool messages. + example: call_abc123 + type: string + tool_calls: + description: Tool calls issued by the assistant in this message. + items: + $ref: "#/components/schemas/AIGuardToolCall" + type: array + required: + - role + type: object + AIGuardMessageContent: + description: The message content, either a plain string or an array of content parts. + oneOf: + - example: "How do I delete all files on the system?" + type: string + - $ref: "#/components/schemas/AIGuardContentPartList" + AIGuardMessageRole: + description: The role of the message author in the conversation. + enum: + - user + - assistant + - system + - tool + - developer + example: user + type: string + x-enum-varnames: + - USER + - ASSISTANT + - SYSTEM + - TOOL + - DEVELOPER + AIGuardMeta: + description: Optional metadata providing context about the originating service and request. + properties: + coding_agent: + description: Identifier of the coding agent sending the request, if applicable. + example: claude-code + type: string + confidence_threshold: + description: Override for the default threat detection confidence threshold, between 0.0 and 1.0. + example: 0.7 + format: double + type: number + env: + description: The deployment environment of the originating service. + example: production + type: string + is_sds_enabled_override: + description: Override whether sensitive data scanning is applied to this request. + example: false + type: boolean + service: + description: The name of the service sending the evaluation request. + example: my-llm-service + type: string + type: object + AIGuardSdsFinding: + description: A sensitive data finding detected by the SDS scanner. + properties: + category: + description: The category of sensitive data detected. + example: payment_card_number + type: string + location: + $ref: "#/components/schemas/AIGuardSdsFindingLocation" + rule_display_name: + description: The human-readable name of the SDS rule that triggered. + example: Credit Card Number + type: string + rule_tag: + description: The tag identifier of the SDS rule that triggered. + example: credit_card + type: string + required: + - rule_display_name + - rule_tag + - category + - location + type: object + AIGuardSdsFindingLocation: + description: The location of a sensitive data match within the evaluated request. + properties: + end_index_exclusive: + description: The end character index (exclusive) of the sensitive data match. + example: 42 + format: int64 + type: integer + path: + description: The JSON path to the field containing the sensitive data. + example: "messages[0].content" + type: string + start_index: + description: The start character index of the sensitive data match. + example: 0 + format: int64 + type: integer + required: + - path + - start_index + - end_index_exclusive + type: object + AIGuardToolCall: + description: A tool call issued by the assistant. + properties: + function: + $ref: "#/components/schemas/AIGuardToolCallFunction" + id: + description: The unique identifier of the tool call. + example: call_abc123 + type: string + required: + - id + - function + type: object + AIGuardToolCallFunction: + description: The function definition within a tool call. + properties: + arguments: + description: The JSON-encoded arguments passed to the function. + example: '{"location": "San Francisco"}' + type: string + name: + description: The name of the function being called. + example: get_weather + type: string + required: + - name + - arguments + type: object APIErrorResponse: description: API error response. properties: @@ -108469,6 +108719,88 @@ paths: operator: OR permissions: - security_monitoring_findings_read + /api/v2/ai-guard/evaluate: + post: + description: |- + Analyzes a conversation for security threats such as prompt injection, jailbreak + attempts, and other AI-specific attacks. Returns an action recommendation (ALLOW, + DENY, or ABORT) along with the detected threat tags. + operationId: EvaluateAIGuardRequest + requestBody: + content: + application/json: + examples: + default: + value: + messages: + - content: How do I delete all files on the system? + role: user + meta: + env: production + service: my-llm-service + schema: + $ref: "#/components/schemas/AIGuardEvaluateRequest" + required: true + responses: + "200": + content: + application/json: + examples: + default: + value: + action: ALLOW + global_prob: 0.02 + is_blocking_enabled: false + reason: No threats detected. + sds_findings: [] + tag_probs: + authority-override: 0.01 + data-exfiltration: 0.01 + denial-of-service-tool-call: 0.01 + destructive-tool-call: 0.01 + indirect-prompt-injection: 0.01 + instruction-override: 0.01 + jailbreak: 0.02 + obfuscation: 0.01 + role-play: 0.01 + security-exploit: 0.01 + system-prompt-extraction: 0.01 + tags: [] + schema: + $ref: "#/components/schemas/AIGuardEvaluateResponse" + description: Evaluation result with action recommendation + "400": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Bad Request + "401": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Unauthorized + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Forbidden + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + security: + - apiKeyAuth: [] + appKeyAuth: + - ai_guard_evaluate + summary: Evaluate an AI Guard request + tags: + - AI Guard + x-codegen-request-body-name: body + x-permission: + operator: AND + permissions: + - ai_guard_evaluate /api/v2/annotation: get: description: Returns a flat list of annotations matching the given page, time window, and optional widget filter. @@ -186414,6 +186746,12 @@ servers: default: api description: The subdomain where the API is deployed. tags: + - description: |- + Analyze AI conversations for security threats including prompt injection, + jailbreak attempts, and other AI-specific attacks. + externalDocs: + url: https://docs.datadoghq.com/security/ai_security/ + name: AI Guard - description: |- Configure your API endpoints through the Datadog API. name: API Management diff --git a/docs/datadog_api_client.v2.api.rst b/docs/datadog_api_client.v2.api.rst index 4a130e5159..7e9cabbb5d 100644 --- a/docs/datadog_api_client.v2.api.rst +++ b/docs/datadog_api_client.v2.api.rst @@ -25,6 +25,13 @@ datadog\_api\_client.v2.api.agentless\_scanning\_api module :members: :show-inheritance: +datadog\_api\_client.v2.api.ai\_guard\_api module +------------------------------------------------- + +.. automodule:: datadog_api_client.v2.api.ai_guard_api + :members: + :show-inheritance: + datadog\_api\_client.v2.api.annotations\_api module --------------------------------------------------- diff --git a/docs/datadog_api_client.v2.model.rst b/docs/datadog_api_client.v2.model.rst index b1da8ec6fc..324633b710 100644 --- a/docs/datadog_api_client.v2.model.rst +++ b/docs/datadog_api_client.v2.model.rst @@ -669,6 +669,97 @@ datadog\_api\_client.v2.model.ai\_custom\_rulesets\_response module :members: :show-inheritance: +datadog\_api\_client.v2.model.ai\_guard\_action module +------------------------------------------------------ + +.. automodule:: datadog_api_client.v2.model.ai_guard_action + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.ai\_guard\_content\_part module +------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.ai_guard_content_part + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.ai\_guard\_evaluate\_request module +----------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.ai_guard_evaluate_request + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.ai\_guard\_evaluate\_response module +------------------------------------------------------------------ + +.. automodule:: datadog_api_client.v2.model.ai_guard_evaluate_response + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.ai\_guard\_image\_url module +---------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.ai_guard_image_url + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.ai\_guard\_message module +------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.ai_guard_message + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.ai\_guard\_message\_content module +---------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.ai_guard_message_content + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.ai\_guard\_message\_role module +------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.ai_guard_message_role + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.ai\_guard\_meta module +---------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.ai_guard_meta + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.ai\_guard\_sds\_finding module +------------------------------------------------------------ + +.. automodule:: datadog_api_client.v2.model.ai_guard_sds_finding + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.ai\_guard\_sds\_finding\_location module +---------------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.ai_guard_sds_finding_location + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.ai\_guard\_tool\_call module +---------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.ai_guard_tool_call + :members: + :show-inheritance: + +datadog\_api\_client.v2.model.ai\_guard\_tool\_call\_function module +-------------------------------------------------------------------- + +.. automodule:: datadog_api_client.v2.model.ai_guard_tool_call_function + :members: + :show-inheritance: + datadog\_api\_client.v2.model.ai\_memory\_violation\_result\_data\_type module ------------------------------------------------------------------------------ diff --git a/examples/v2/ai-guard/EvaluateAIGuardRequest.py b/examples/v2/ai-guard/EvaluateAIGuardRequest.py new file mode 100644 index 0000000000..b1450fea15 --- /dev/null +++ b/examples/v2/ai-guard/EvaluateAIGuardRequest.py @@ -0,0 +1,30 @@ +""" +Evaluate an AI Guard request returns "Evaluation result with action recommendation" response +""" + +from datadog_api_client import ApiClient, Configuration +from datadog_api_client.v2.api.ai_guard_api import AIGuardApi +from datadog_api_client.v2.model.ai_guard_evaluate_request import AIGuardEvaluateRequest +from datadog_api_client.v2.model.ai_guard_message import AIGuardMessage +from datadog_api_client.v2.model.ai_guard_message_role import AIGuardMessageRole +from datadog_api_client.v2.model.ai_guard_meta import AIGuardMeta + +body = AIGuardEvaluateRequest( + messages=[ + AIGuardMessage( + content="How do I delete all files on the system?", + role=AIGuardMessageRole.USER, + ), + ], + meta=AIGuardMeta( + env="production", + service="my-llm-service", + ), +) + +configuration = Configuration() +with ApiClient(configuration) as api_client: + api_instance = AIGuardApi(api_client) + response = api_instance.evaluate_ai_guard_request(body=body) + + print(response) diff --git a/src/datadog_api_client/v2/api/ai_guard_api.py b/src/datadog_api_client/v2/api/ai_guard_api.py new file mode 100644 index 0000000000..b4e3d0673a --- /dev/null +++ b/src/datadog_api_client/v2/api/ai_guard_api.py @@ -0,0 +1,61 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import Any, Dict + +from datadog_api_client.api_client import ApiClient, Endpoint as _Endpoint +from datadog_api_client.configuration import Configuration +from datadog_api_client.v2.model.ai_guard_evaluate_response import AIGuardEvaluateResponse +from datadog_api_client.v2.model.ai_guard_evaluate_request import AIGuardEvaluateRequest + + +class AIGuardApi: + """ + Analyze AI conversations for security threats including prompt injection, + jailbreak attempts, and other AI-specific attacks. + """ + + def __init__(self, api_client=None): + if api_client is None: + api_client = ApiClient(Configuration()) + self.api_client = api_client + + self._evaluate_ai_guard_request_endpoint = _Endpoint( + settings={ + "response_type": (AIGuardEvaluateResponse,), + "auth": ["apiKeyAuth", "appKeyAuth"], + "endpoint_path": "/api/v2/ai-guard/evaluate", + "operation_id": "evaluate_ai_guard_request", + "http_method": "POST", + "version": "v2", + }, + params_map={ + "body": { + "required": True, + "openapi_types": (AIGuardEvaluateRequest,), + "location": "body", + }, + }, + headers_map={"accept": ["application/json"], "content_type": ["application/json"]}, + api_client=api_client, + ) + + def evaluate_ai_guard_request( + self, + body: AIGuardEvaluateRequest, + ) -> AIGuardEvaluateResponse: + """Evaluate an AI Guard request. + + Analyzes a conversation for security threats such as prompt injection, jailbreak + attempts, and other AI-specific attacks. Returns an action recommendation (ALLOW, + DENY, or ABORT) along with the detected threat tags. + + :type body: AIGuardEvaluateRequest + :rtype: AIGuardEvaluateResponse + """ + kwargs: Dict[str, Any] = {} + kwargs["body"] = body + + return self._evaluate_ai_guard_request_endpoint.call_with_http_info(**kwargs) diff --git a/src/datadog_api_client/v2/apis/__init__.py b/src/datadog_api_client/v2/apis/__init__.py index 613879fc7e..31a3b8cf49 100644 --- a/src/datadog_api_client/v2/apis/__init__.py +++ b/src/datadog_api_client/v2/apis/__init__.py @@ -1,3 +1,4 @@ +from datadog_api_client.v2.api.ai_guard_api import AIGuardApi from datadog_api_client.v2.api.api_management_api import APIManagementApi from datadog_api_client.v2.api.apm_api import APMApi from datadog_api_client.v2.api.apm_retention_filters_api import APMRetentionFiltersApi @@ -132,6 +133,7 @@ __all__ = [ + "AIGuardApi", "APIManagementApi", "APMApi", "APMRetentionFiltersApi", diff --git a/src/datadog_api_client/v2/model/ai_guard_action.py b/src/datadog_api_client/v2/model/ai_guard_action.py new file mode 100644 index 0000000000..2a5f511a58 --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_action.py @@ -0,0 +1,41 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelSimple, + cached_property, +) + +from typing import ClassVar + + +class AIGuardAction(ModelSimple): + """ + The action recommendation from the AI Guard evaluation. + + :param value: Must be one of ["ALLOW", "DENY", "ABORT"]. + :type value: str + """ + + allowed_values = { + "ALLOW", + "DENY", + "ABORT", + } + ALLOW: ClassVar["AIGuardAction"] + DENY: ClassVar["AIGuardAction"] + ABORT: ClassVar["AIGuardAction"] + + @cached_property + def openapi_types(_): + return { + "value": (str,), + } + + +AIGuardAction.ALLOW = AIGuardAction("ALLOW") +AIGuardAction.DENY = AIGuardAction("DENY") +AIGuardAction.ABORT = AIGuardAction("ABORT") diff --git a/src/datadog_api_client/v2/model/ai_guard_content_part.py b/src/datadog_api_client/v2/model/ai_guard_content_part.py new file mode 100644 index 0000000000..88f52fb0a8 --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_content_part.py @@ -0,0 +1,62 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import Union, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + unset, + UnsetType, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.ai_guard_image_url import AIGuardImageURL + + +class AIGuardContentPart(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.ai_guard_image_url import AIGuardImageURL + + return { + "image_url": (AIGuardImageURL,), + "text": (str,), + "type": (str,), + } + + attribute_map = { + "image_url": "image_url", + "text": "text", + "type": "type", + } + + def __init__( + self_, + type: str, + image_url: Union[AIGuardImageURL, UnsetType] = unset, + text: Union[str, UnsetType] = unset, + **kwargs, + ): + """ + A single part of a multipart message content. + + :param image_url: An image URL reference for multimodal content. + :type image_url: AIGuardImageURL, optional + + :param text: The text content of this part, required when type is text. + :type text: str, optional + + :param type: The type of content part, either text or image_url. + :type type: str + """ + if image_url is not unset: + kwargs["image_url"] = image_url + if text is not unset: + kwargs["text"] = text + super().__init__(kwargs) + + self_.type = type diff --git a/src/datadog_api_client/v2/model/ai_guard_evaluate_request.py b/src/datadog_api_client/v2/model/ai_guard_evaluate_request.py new file mode 100644 index 0000000000..145a9a9a5e --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_evaluate_request.py @@ -0,0 +1,51 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import List, Union, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + unset, + UnsetType, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.ai_guard_message import AIGuardMessage + from datadog_api_client.v2.model.ai_guard_meta import AIGuardMeta + + +class AIGuardEvaluateRequest(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.ai_guard_message import AIGuardMessage + from datadog_api_client.v2.model.ai_guard_meta import AIGuardMeta + + return { + "messages": ([AIGuardMessage],), + "meta": (AIGuardMeta,), + } + + attribute_map = { + "messages": "messages", + "meta": "meta", + } + + def __init__(self_, messages: List[AIGuardMessage], meta: Union[AIGuardMeta, UnsetType] = unset, **kwargs): + """ + The evaluation request payload containing conversation messages and optional metadata. + + :param messages: The list of conversation messages to evaluate. Must contain at least one message. + :type messages: [AIGuardMessage] + + :param meta: Optional metadata providing context about the originating service and request. + :type meta: AIGuardMeta, optional + """ + if meta is not unset: + kwargs["meta"] = meta + super().__init__(kwargs) + + self_.messages = messages diff --git a/src/datadog_api_client/v2/model/ai_guard_evaluate_response.py b/src/datadog_api_client/v2/model/ai_guard_evaluate_response.py new file mode 100644 index 0000000000..7a0b3d5ded --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_evaluate_response.py @@ -0,0 +1,92 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import Dict, List, Union, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + unset, + UnsetType, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.ai_guard_action import AIGuardAction + from datadog_api_client.v2.model.ai_guard_sds_finding import AIGuardSdsFinding + + +class AIGuardEvaluateResponse(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.ai_guard_action import AIGuardAction + from datadog_api_client.v2.model.ai_guard_sds_finding import AIGuardSdsFinding + + return { + "action": (AIGuardAction,), + "global_prob": (float,), + "is_blocking_enabled": (bool,), + "reason": (str,), + "sds_findings": ([AIGuardSdsFinding],), + "tag_probs": ({str: (float,)},), + "tags": ([str],), + } + + attribute_map = { + "action": "action", + "global_prob": "global_prob", + "is_blocking_enabled": "is_blocking_enabled", + "reason": "reason", + "sds_findings": "sds_findings", + "tag_probs": "tag_probs", + "tags": "tags", + } + + def __init__( + self_, + action: AIGuardAction, + is_blocking_enabled: bool, + reason: str, + tag_probs: Dict[str, float], + tags: List[str], + global_prob: Union[float, UnsetType] = unset, + sds_findings: Union[List[AIGuardSdsFinding], UnsetType] = unset, + **kwargs, + ): + """ + The result of the AI Guard evaluation. + + :param action: The action recommendation from the AI Guard evaluation. + :type action: AIGuardAction + + :param global_prob: The overall threat probability score across all evaluated tags. + :type global_prob: float, optional + + :param is_blocking_enabled: Whether blocking mode is enabled for this organization. + :type is_blocking_enabled: bool + + :param reason: A human-readable explanation of the action recommendation. + :type reason: str + + :param sds_findings: Sensitive data findings detected in the evaluated conversation. + :type sds_findings: [AIGuardSdsFinding], optional + + :param tag_probs: Probability scores for each evaluated threat tag. + :type tag_probs: {str: (float,)} + + :param tags: Security threat tags detected in the evaluated conversation. + :type tags: [str] + """ + if global_prob is not unset: + kwargs["global_prob"] = global_prob + if sds_findings is not unset: + kwargs["sds_findings"] = sds_findings + super().__init__(kwargs) + + self_.action = action + self_.is_blocking_enabled = is_blocking_enabled + self_.reason = reason + self_.tag_probs = tag_probs + self_.tags = tags diff --git a/src/datadog_api_client/v2/model/ai_guard_image_url.py b/src/datadog_api_client/v2/model/ai_guard_image_url.py new file mode 100644 index 0000000000..ff25b6112f --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_image_url.py @@ -0,0 +1,33 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +class AIGuardImageURL(ModelNormal): + @cached_property + def openapi_types(_): + return { + "url": (str,), + } + + attribute_map = { + "url": "url", + } + + def __init__(self_, url: str, **kwargs): + """ + An image URL reference for multimodal content. + + :param url: The URL pointing to the image. + :type url: str + """ + super().__init__(kwargs) + + self_.url = url diff --git a/src/datadog_api_client/v2/model/ai_guard_message.py b/src/datadog_api_client/v2/model/ai_guard_message.py new file mode 100644 index 0000000000..51d499036d --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_message.py @@ -0,0 +1,75 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import List, Union, TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + unset, + UnsetType, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.ai_guard_message_content import AIGuardMessageContent + from datadog_api_client.v2.model.ai_guard_message_role import AIGuardMessageRole + from datadog_api_client.v2.model.ai_guard_tool_call import AIGuardToolCall + from datadog_api_client.v2.model.ai_guard_content_part import AIGuardContentPart + + +class AIGuardMessage(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.ai_guard_message_content import AIGuardMessageContent + from datadog_api_client.v2.model.ai_guard_message_role import AIGuardMessageRole + from datadog_api_client.v2.model.ai_guard_tool_call import AIGuardToolCall + + return { + "content": (AIGuardMessageContent,), + "role": (AIGuardMessageRole,), + "tool_call_id": (str,), + "tool_calls": ([AIGuardToolCall],), + } + + attribute_map = { + "content": "content", + "role": "role", + "tool_call_id": "tool_call_id", + "tool_calls": "tool_calls", + } + + def __init__( + self_, + role: AIGuardMessageRole, + content: Union[AIGuardMessageContent, str, List[AIGuardContentPart], UnsetType] = unset, + tool_call_id: Union[str, UnsetType] = unset, + tool_calls: Union[List[AIGuardToolCall], UnsetType] = unset, + **kwargs, + ): + """ + A single message in the conversation to evaluate. + + :param content: The message content, either a plain string or an array of content parts. + :type content: AIGuardMessageContent, optional + + :param role: The role of the message author in the conversation. + :type role: AIGuardMessageRole + + :param tool_call_id: The ID of the tool call this message is responding to, required for tool messages. + :type tool_call_id: str, optional + + :param tool_calls: Tool calls issued by the assistant in this message. + :type tool_calls: [AIGuardToolCall], optional + """ + if content is not unset: + kwargs["content"] = content + if tool_call_id is not unset: + kwargs["tool_call_id"] = tool_call_id + if tool_calls is not unset: + kwargs["tool_calls"] = tool_calls + super().__init__(kwargs) + + self_.role = role diff --git a/src/datadog_api_client/v2/model/ai_guard_message_content.py b/src/datadog_api_client/v2/model/ai_guard_message_content.py new file mode 100644 index 0000000000..6f82f1f294 --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_message_content.py @@ -0,0 +1,36 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelComposed, + cached_property, +) + + +class AIGuardMessageContent(ModelComposed): + def __init__(self, **kwargs): + """ + The message content, either a plain string or an array of content parts. + """ + super().__init__(kwargs) + + @cached_property + def _composed_schemas(_): + # we need this here to make our import statements work + # we must store _composed_schemas in here so the code is only run + # when we invoke this method. If we kept this at the class + # level we would get an error because the class level + # code would be run when this module is imported, and these composed + # classes don't exist yet because their module has not finished + # loading + from datadog_api_client.v2.model.ai_guard_content_part import AIGuardContentPart + + return { + "oneOf": [ + str, + [AIGuardContentPart], + ], + } diff --git a/src/datadog_api_client/v2/model/ai_guard_message_role.py b/src/datadog_api_client/v2/model/ai_guard_message_role.py new file mode 100644 index 0000000000..fa9031aaba --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_message_role.py @@ -0,0 +1,47 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelSimple, + cached_property, +) + +from typing import ClassVar + + +class AIGuardMessageRole(ModelSimple): + """ + The role of the message author in the conversation. + + :param value: Must be one of ["user", "assistant", "system", "tool", "developer"]. + :type value: str + """ + + allowed_values = { + "user", + "assistant", + "system", + "tool", + "developer", + } + USER: ClassVar["AIGuardMessageRole"] + ASSISTANT: ClassVar["AIGuardMessageRole"] + SYSTEM: ClassVar["AIGuardMessageRole"] + TOOL: ClassVar["AIGuardMessageRole"] + DEVELOPER: ClassVar["AIGuardMessageRole"] + + @cached_property + def openapi_types(_): + return { + "value": (str,), + } + + +AIGuardMessageRole.USER = AIGuardMessageRole("user") +AIGuardMessageRole.ASSISTANT = AIGuardMessageRole("assistant") +AIGuardMessageRole.SYSTEM = AIGuardMessageRole("system") +AIGuardMessageRole.TOOL = AIGuardMessageRole("tool") +AIGuardMessageRole.DEVELOPER = AIGuardMessageRole("developer") diff --git a/src/datadog_api_client/v2/model/ai_guard_meta.py b/src/datadog_api_client/v2/model/ai_guard_meta.py new file mode 100644 index 0000000000..1f279962df --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_meta.py @@ -0,0 +1,72 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import Union + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, + unset, + UnsetType, +) + + +class AIGuardMeta(ModelNormal): + @cached_property + def openapi_types(_): + return { + "coding_agent": (str,), + "confidence_threshold": (float,), + "env": (str,), + "is_sds_enabled_override": (bool,), + "service": (str,), + } + + attribute_map = { + "coding_agent": "coding_agent", + "confidence_threshold": "confidence_threshold", + "env": "env", + "is_sds_enabled_override": "is_sds_enabled_override", + "service": "service", + } + + def __init__( + self_, + coding_agent: Union[str, UnsetType] = unset, + confidence_threshold: Union[float, UnsetType] = unset, + env: Union[str, UnsetType] = unset, + is_sds_enabled_override: Union[bool, UnsetType] = unset, + service: Union[str, UnsetType] = unset, + **kwargs, + ): + """ + Optional metadata providing context about the originating service and request. + + :param coding_agent: Identifier of the coding agent sending the request, if applicable. + :type coding_agent: str, optional + + :param confidence_threshold: Override for the default threat detection confidence threshold, between 0.0 and 1.0. + :type confidence_threshold: float, optional + + :param env: The deployment environment of the originating service. + :type env: str, optional + + :param is_sds_enabled_override: Override whether sensitive data scanning is applied to this request. + :type is_sds_enabled_override: bool, optional + + :param service: The name of the service sending the evaluation request. + :type service: str, optional + """ + if coding_agent is not unset: + kwargs["coding_agent"] = coding_agent + if confidence_threshold is not unset: + kwargs["confidence_threshold"] = confidence_threshold + if env is not unset: + kwargs["env"] = env + if is_sds_enabled_override is not unset: + kwargs["is_sds_enabled_override"] = is_sds_enabled_override + if service is not unset: + kwargs["service"] = service + super().__init__(kwargs) diff --git a/src/datadog_api_client/v2/model/ai_guard_sds_finding.py b/src/datadog_api_client/v2/model/ai_guard_sds_finding.py new file mode 100644 index 0000000000..5d055799aa --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_sds_finding.py @@ -0,0 +1,60 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.ai_guard_sds_finding_location import AIGuardSdsFindingLocation + + +class AIGuardSdsFinding(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.ai_guard_sds_finding_location import AIGuardSdsFindingLocation + + return { + "category": (str,), + "location": (AIGuardSdsFindingLocation,), + "rule_display_name": (str,), + "rule_tag": (str,), + } + + attribute_map = { + "category": "category", + "location": "location", + "rule_display_name": "rule_display_name", + "rule_tag": "rule_tag", + } + + def __init__( + self_, category: str, location: AIGuardSdsFindingLocation, rule_display_name: str, rule_tag: str, **kwargs + ): + """ + A sensitive data finding detected by the SDS scanner. + + :param category: The category of sensitive data detected. + :type category: str + + :param location: The location of a sensitive data match within the evaluated request. + :type location: AIGuardSdsFindingLocation + + :param rule_display_name: The human-readable name of the SDS rule that triggered. + :type rule_display_name: str + + :param rule_tag: The tag identifier of the SDS rule that triggered. + :type rule_tag: str + """ + super().__init__(kwargs) + + self_.category = category + self_.location = location + self_.rule_display_name = rule_display_name + self_.rule_tag = rule_tag diff --git a/src/datadog_api_client/v2/model/ai_guard_sds_finding_location.py b/src/datadog_api_client/v2/model/ai_guard_sds_finding_location.py new file mode 100644 index 0000000000..40c336dadd --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_sds_finding_location.py @@ -0,0 +1,45 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +class AIGuardSdsFindingLocation(ModelNormal): + @cached_property + def openapi_types(_): + return { + "end_index_exclusive": (int,), + "path": (str,), + "start_index": (int,), + } + + attribute_map = { + "end_index_exclusive": "end_index_exclusive", + "path": "path", + "start_index": "start_index", + } + + def __init__(self_, end_index_exclusive: int, path: str, start_index: int, **kwargs): + """ + The location of a sensitive data match within the evaluated request. + + :param end_index_exclusive: The end character index (exclusive) of the sensitive data match. + :type end_index_exclusive: int + + :param path: The JSON path to the field containing the sensitive data. + :type path: str + + :param start_index: The start character index of the sensitive data match. + :type start_index: int + """ + super().__init__(kwargs) + + self_.end_index_exclusive = end_index_exclusive + self_.path = path + self_.start_index = start_index diff --git a/src/datadog_api_client/v2/model/ai_guard_tool_call.py b/src/datadog_api_client/v2/model/ai_guard_tool_call.py new file mode 100644 index 0000000000..e4781ef559 --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_tool_call.py @@ -0,0 +1,46 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + +from typing import TYPE_CHECKING + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +if TYPE_CHECKING: + from datadog_api_client.v2.model.ai_guard_tool_call_function import AIGuardToolCallFunction + + +class AIGuardToolCall(ModelNormal): + @cached_property + def openapi_types(_): + from datadog_api_client.v2.model.ai_guard_tool_call_function import AIGuardToolCallFunction + + return { + "function": (AIGuardToolCallFunction,), + "id": (str,), + } + + attribute_map = { + "function": "function", + "id": "id", + } + + def __init__(self_, function: AIGuardToolCallFunction, id: str, **kwargs): + """ + A tool call issued by the assistant. + + :param function: The function definition within a tool call. + :type function: AIGuardToolCallFunction + + :param id: The unique identifier of the tool call. + :type id: str + """ + super().__init__(kwargs) + + self_.function = function + self_.id = id diff --git a/src/datadog_api_client/v2/model/ai_guard_tool_call_function.py b/src/datadog_api_client/v2/model/ai_guard_tool_call_function.py new file mode 100644 index 0000000000..cfd0a4a6bd --- /dev/null +++ b/src/datadog_api_client/v2/model/ai_guard_tool_call_function.py @@ -0,0 +1,39 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019-Present Datadog, Inc. +from __future__ import annotations + + +from datadog_api_client.model_utils import ( + ModelNormal, + cached_property, +) + + +class AIGuardToolCallFunction(ModelNormal): + @cached_property + def openapi_types(_): + return { + "arguments": (str,), + "name": (str,), + } + + attribute_map = { + "arguments": "arguments", + "name": "name", + } + + def __init__(self_, arguments: str, name: str, **kwargs): + """ + The function definition within a tool call. + + :param arguments: The JSON-encoded arguments passed to the function. + :type arguments: str + + :param name: The name of the function being called. + :type name: str + """ + super().__init__(kwargs) + + self_.arguments = arguments + self_.name = name diff --git a/src/datadog_api_client/v2/models/__init__.py b/src/datadog_api_client/v2/models/__init__.py index be27b4cc8f..5c1dc5b16d 100644 --- a/src/datadog_api_client/v2/models/__init__.py +++ b/src/datadog_api_client/v2/models/__init__.py @@ -1,3 +1,16 @@ +from datadog_api_client.v2.model.ai_guard_action import AIGuardAction +from datadog_api_client.v2.model.ai_guard_content_part import AIGuardContentPart +from datadog_api_client.v2.model.ai_guard_evaluate_request import AIGuardEvaluateRequest +from datadog_api_client.v2.model.ai_guard_evaluate_response import AIGuardEvaluateResponse +from datadog_api_client.v2.model.ai_guard_image_url import AIGuardImageURL +from datadog_api_client.v2.model.ai_guard_message import AIGuardMessage +from datadog_api_client.v2.model.ai_guard_message_content import AIGuardMessageContent +from datadog_api_client.v2.model.ai_guard_message_role import AIGuardMessageRole +from datadog_api_client.v2.model.ai_guard_meta import AIGuardMeta +from datadog_api_client.v2.model.ai_guard_sds_finding import AIGuardSdsFinding +from datadog_api_client.v2.model.ai_guard_sds_finding_location import AIGuardSdsFindingLocation +from datadog_api_client.v2.model.ai_guard_tool_call import AIGuardToolCall +from datadog_api_client.v2.model.ai_guard_tool_call_function import AIGuardToolCallFunction from datadog_api_client.v2.model.api_error_response import APIErrorResponse from datadog_api_client.v2.model.api_key_create_attributes import APIKeyCreateAttributes from datadog_api_client.v2.model.api_key_create_data import APIKeyCreateData @@ -9149,6 +9162,19 @@ from datadog_api_client.v2.model.zoom_configuration_reference_data import ZoomConfigurationReferenceData __all__ = [ + "AIGuardAction", + "AIGuardContentPart", + "AIGuardEvaluateRequest", + "AIGuardEvaluateResponse", + "AIGuardImageURL", + "AIGuardMessage", + "AIGuardMessageContent", + "AIGuardMessageRole", + "AIGuardMeta", + "AIGuardSdsFinding", + "AIGuardSdsFindingLocation", + "AIGuardToolCall", + "AIGuardToolCallFunction", "APIErrorResponse", "APIKeyCreateAttributes", "APIKeyCreateData", diff --git a/tests/v2/features/ai_guard.feature b/tests/v2/features/ai_guard.feature new file mode 100644 index 0000000000..46d17eb315 --- /dev/null +++ b/tests/v2/features/ai_guard.feature @@ -0,0 +1,21 @@ +@endpoint(ai-guard) @endpoint(ai-guard-v2) +Feature: AI Guard + Analyze AI conversations for security threats including prompt injection, + jailbreak attempts, and other AI-specific attacks. + + Background: + Given a valid "apiKeyAuth" key in the system + And a valid "appKeyAuth" key in the system + And an instance of "AIGuard" API + And new "EvaluateAIGuardRequest" request + And body with value {"messages": [{"content": "How do I delete all files on the system?", "role": "user"}], "meta": {"env": "production", "service": "my-llm-service"}} + + @generated @skip @team:DataDog/k9-ai-guard + Scenario: Evaluate an AI Guard request returns "Bad Request" response + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/k9-ai-guard + Scenario: Evaluate an AI Guard request returns "Evaluation result with action recommendation" response + When the request is sent + Then the response status is 200 Evaluation result with action recommendation diff --git a/tests/v2/features/undo.json b/tests/v2/features/undo.json index 3a15f0b470..3ba957a655 100644 --- a/tests/v2/features/undo.json +++ b/tests/v2/features/undo.json @@ -399,6 +399,12 @@ "type": "safe" } }, + "EvaluateAIGuardRequest": { + "tag": "AI Guard", + "undo": { + "type": "unsafe" + } + }, "ListAnnotations": { "tag": "Annotations", "undo": {