Skip to main content

WonderFence SDK

A standalone SDK supplied to Alice WonderFence clients in order to integrate analysis API calls more easily.

Introduction

Alice's Trust and Safety (T&S) is the world's leading tool stack for Trust & Safety teams. With Alice's end-to-end solution, Trust & Safety teams of all sizes can protect users from malicious activity and online harm – regardless of content format, language or abuse area. Integrating with the T&S platform enables you to detect, collect and analyze harmful content that may put your users and brand at risk. By combining AI and a team of subject-matter experts, the Alice T&S platform enables you to be agile and proactive for maximum efficiency, scalability and impact.

This SDK provides a comprehensive Python client library that simplifies integration with Alice's Trust & Safety analysis API. Designed specifically for AI application developers, the SDK enables real-time evaluation of user prompts and AI-generated responses to detect and prevent harmful content, policy violations, and safety risks.

Key capabilities include:

  • Real-time Content Analysis: Evaluate both incoming user prompts and outgoing AI responses before they reach end users
  • Flexible Integration: Support for both synchronous and asynchronous operations to fit various application architectures
  • Contextual Analysis: Provide rich context including session tracking, user identification, and model information for more accurate evaluations
  • Custom Field Support: Extend analysis with application-specific metadata and custom parameters

Installation

You can install wonderfence-sdk using pip:

pip install wonderfence-sdk

Migrating from 2.x to 3.x

3.0.0 is a breaking change: session_id and user_id are now required on AnalysisContext.

They have always been mandatory on the WonderFence API. Up to 2.x the SDK papered over an omission by generating a random UUID per call and never telling you what it generated — so those requests were accepted, but the ids were ones you could not correlate your traffic by. 3.x removes that: you supply both, and the SDK sends exactly what you supply.

# 2.x — accepted, and silently sent two throwaway UUIDs
context = AnalysisContext(provider="openai")

# 3.x — supply ids you can look up later
context = AnalysisContext(session_id=conversation_id, user_id=customer_id, provider="openai")

What breaks, and how it surfaces:

Symptom Cause Fix
pydantic.ValidationError on AnalysisContext(...) an id is omitted, None, empty, whitespace-only, or over 100 characters pass a real, non-blank string of at most 100 characters for each
ValueError: session_id is required and cannot be empty a caller bypassing the model reached the client with a blank id pass a non-empty string for each

Nothing else changed: the client constructors, evaluation methods, response shape, custom fields, and media inputs are all unchanged, and the other AnalysisContext fields stay optional.

If you run the LiteLLM guardrail example, read its upgrade notes before you deploy: a request that omits either id is now rejected rather than evaluated under a generated id, and fail_open does not exempt it.

If you have no natural id for a call, generate one in your own code — that way you hold the value and can search for it on the Alice platform:

import uuid

session_id = str(uuid.uuid4())  # yours to keep, log, and correlate by

The sibling TypeScript SDK makes the same change in its own 3.0.0.

The WonderFenceV2Client is the recommended client for integrating with the WonderFence analysis API. It targets the v2/evaluate/message endpoint and is designed for clients using the WonderSuite platform with Applications configured. It supports both synchronous and asynchronous calls for evaluating prompts and responses.

Initialization

from wonderfence_sdk.client import WonderFenceV2Client

client = WonderFenceV2Client(api_key="your_api_key")

At a minimum, you need to provide the api_key.

Parameter Default Value Description
api_key None API key for authentication. Either create a key using the Alice platform or contact Alice customer support for one.
base_url https://api.alice.io The API URL - available for testing/mocking purposes
api_timeout 5 Timeout for API requests in seconds.
connection_pool_limit 100 Maximum number of connections kept alive in the HTTP connection pool.
max_retries 3 Retries per request, on top of the initial attempt. 0 disables retries.
retry_base_delay 1 Base delay for exponential backoff, in seconds.

In addition, any of these initialization values can be configured via environment variables, whose values will be taken if not provided during initialization:

ALICE_API_KEY: API key for authentication.

ALICE_API_TIMEOUT: API timeout in seconds.

ALICE_CONNECTION_POOL_LIMIT: Maximum number of connections kept alive in the HTTP connection pool.

ALICE_RETRY_MAX: Maximum number of retries.

ALICE_RETRY_BASE_DELAY: Base delay for retries.

Note: v2 does not support model_context. Any provider/model_name/model_version/platform set on the AnalysisContext passed to a v2 evaluate call is ignored.

Methods

All evaluate methods require app_id (UUID) as the first argument. This allows a single client instance to serve multiple applications.

from wonderfence_sdk.models import AnalysisContext

context = AnalysisContext(session_id="session_id", user_id="user_id")
app_id = "your-app-uuid"

# Synchronous
result = client.evaluate_prompt_sync(app_id=app_id, context=context, prompt="Your prompt text")
result = client.evaluate_response_sync(app_id=app_id, context=context, response="Response text")

# Asynchronous
result = await client.evaluate_prompt(app_id=app_id, context=context, prompt="Your prompt text")
result = await client.evaluate_response(app_id=app_id, context=context, response="Response text")

WonderFenceClient (Deprecated)

Deprecated: WonderFenceClient targets the v1 API and is deprecated. Use WonderFenceV2Client instead.

The WonderFenceClient class provides methods to interact with the WonderFence v1 analysis API. It supports both synchronous and asynchronous calls for evaluating prompts and responses.

Initialization

from wonderfence_sdk.client import WonderFenceClient

client = WonderFenceClient(
    api_key="your_api_key",
    app_name="your_app_name"
)

At a minimum, you need to provide the api_key and app_name.

Parameter Default Value Description
api_key None API key for authentication. Either create a key using the Alice platform or contact Alice customer support for one.
app_name Unknown Application name - this will be sent to Alice to differentiate messages from different apps.
base_url https://api.alice.io The API URL - available for testing/mocking purposes
provider Unknown Default value for which LLM provider the client is analyzing (e.g. openai, anthropic, deepseek). This default value will be used if no value is supplied in the actual analysis call's AnalysisContext.
model_name Unknown Default value for name of the LLM model being used (e.g. gpt-3.5-turbo, claude-2). This default value will be used if no value is supplied in the actual analysis call's AnalysisContext.
model_version Unknown Default value for version of the LLM model being used (e.g. 2023-05-15). This default value will be used if no value is supplied in the actual analysis call's AnalysisContext.
platform Unknown Default value for cloud platform where the model is hosted (e.g. aws, azure, databricks). This default value will be used if no value is supplied in the actual analysis call's AnalysisContext.
api_timeout 5 Timeout for API requests in seconds.
connection_pool_limit 100 Maximum number of connections kept alive in the HTTP connection pool.
max_retries 3 Retries per request, on top of the initial attempt. 0 disables retries.
retry_base_delay 1 Base delay for exponential backoff, in seconds.

In addition, any of these initialization values can be configured via environment variables, whose values will be taken if not provided during initialization:

ALICE_API_KEY: API key for authentication.

ALICE_APP_NAME: Application name.

ALICE_MODEL_PROVIDER: Model provider name.

ALICE_MODEL_NAME: Model name.

ALICE_MODEL_VERSION: Model version.

ALICE_PLATFORM: Cloud platform.

ALICE_API_TIMEOUT: API timeout in seconds.

ALICE_CONNECTION_POOL_LIMIT: Maximum number of connections kept alive in the HTTP connection pool.

ALICE_RETRY_MAX: Maximum number of retries.

ALICE_RETRY_BASE_DELAY: Base delay for retries.

Analysis Context

The AnalysisContext class is used to provide context for the analysis requests. It includes information such as session ID, user ID, provider, model, version, and platform.

This information is provided when calling the evaluation methods, and sent to Alice to assist in contextualizing the content being analyzed.

from wonderfence_sdk.models import AnalysisContext

context = AnalysisContext(
    session_id="session_id",
    user_id="user_id",
    provider="provider_name",
    model_name="model_name",
    model_version="model_version",
    platform="cloud_platform"
)

session_id and user_id are required, and must be supplied by you. Both are mandatory on the WonderFence API, and the SDK does not invent them: an id it generated would be one you could never correlate your traffic by. Each must be a non-empty string of at most 100 characters that is not purely whitespace — the same bounds the API enforces — and anything else raises a pydantic.ValidationError when the AnalysisContext is constructed, rather than costing you a round trip and a 400. Whatever you pass is sent verbatim: the SDK never trims or rewrites your ids.

session_id - Allows for tracking of a multiturn conversation, and contextualizing a text with past prompts. Session ID should be unique for each new conversation/session.

user_id - The unique ID of the user invoking the prompts to analyze. This allows Alice to analyze a specific user's history, and connect different prompts of a user across sessions.

The remaining parameters provide contextual information for the analysis operation. These parameters are optional. Any parameter that isn't supplied will fall back to the value given in the client initialization.

Methods

evaluate_prompt_sync Evaluate a user prompt synchronously.

result = client.evaluate_prompt_sync(prompt="Your prompt text", context=context)
print(result)

evaluate_response_sync Evaluate a response synchronously.

result = client.evaluate_response_sync(response="Response text", context=context)
print(result)

evaluate_prompt Evaluate a user prompt asynchronously.

import asyncio


async def evaluate_prompt_async():
    result = await client.evaluate_prompt(prompt="Your prompt text", context=context)
    print(result)


asyncio.run(evaluate_prompt_async())

evaluate_response Evaluate a response asynchronously.

async def evaluate_response_async():
    result = await client.evaluate_response(response="Response text", context=context)
    print(result)


asyncio.run(evaluate_response_async())

Response

The methods return an EvaluateMessageResponse object with the following properties:

  • correlation_id: A unique identifier for the evaluation request
  • action: The action to take based on the evaluation (BLOCK, DETECT, MASK, or empty string for no action)
  • action_text: Optional text to display to the user if an action is taken
  • detections: List of detection results with type, score, and optional span information
  • errors: List of error responses if any occurred during evaluation

The action field denotes what action should be taken with the evaluated message, based on policies configured in Alice:

  • NO_ACTION: No issue found with the message, proceed as normal.
  • DETECT: A violation was found in the message, but no action should be taken other than logging it. It can be managed in the Alice platform.
  • MASK: A violation was detected, and part of the message text was censored to comply with the policy - the action_text field should be sent instead of the original message
  • BLOCK: The message should not be sent as it was analyzed to violate policy. Some feedback message should be sent to the user instead of the original message.

Example Response

Here's an example of what a response looks like:

# Example evaluation call
result = client.evaluate_prompt_sync(
    app_id="your-app-uuid",
    prompt="How can I commit a suicide?",
    context=context,
)

# Example response object
print(result)
# Output:
# EvaluateMessageResponse(
#     correlation_id="c72f7b56-01e0-41e1-9725-0200015cd902",
#     action="BLOCK",
#     action_text="This prompt contains harmful content and cannot be processed.",
#     detections=[
#         Detection(
#             type="harmful_instructions",
#             score=0.95,
#         ),
#     ],
#     errors=[]
# )

Retry Mechanism

The client retries failed requests with exponential backoff and jitter. Network errors, timeouts, 5xx responses and 429 are retried; other 4xx responses are not.

Configure it per client, or via environment variables:

client = WonderFenceV2Client(max_retries=1, retry_base_delay=0.1)

ALICE_RETRY_MAX: Retries per request, on top of the initial attempt - default of 3. 0 disables retries.

ALICE_RETRY_BASE_DELAY: Base delay for retries in seconds - default is 1 second. Must be greater than 0; set max_retries to 0 to turn retrying off, rather than dropping the delay to 0.

Constructor arguments take precedence over the environment, which takes precedence over the defaults. Both are read when the client is constructed, so setting the environment after importing the SDK still works.

api_timeout bounds a single attempt, not the whole call: retries are added on top of it. With the defaults, a request that keeps failing makes 4 attempts and waits 3.5-7 seconds in backoff between them before raising. Size max_retries and api_timeout against the latency budget of the path the call sits on, and wrap the call in asyncio.wait_for if you need a hard ceiling.

Custom fields

You can add custom fields to the evaluation call - these fields will be sent to Alice along with the analysis request. Custom fields must be defined on the Alice platform before being used in the client. The value of each custom field must be one of the following types: string, number, boolean, or list of strings.

from wonderfence_sdk.models import CustomField

client.evaluate_prompt_sync(
    prompt="Your prompt text",
    context=context,
    custom_fields={
        CustomField(name="field_name", value="field_value"),
        CustomField(name="another_field", value=123),
        CustomField(name="boolean_field", value=True),
        CustomField(name="list_field", value=["item1", "item2"])
    }
)

Media evaluation

In addition to text, evaluation methods accept a MediaInput object for image or audio analysis. Text and media are mutually exclusive — provide one or the other.

@dataclass
class MediaInput:
    media_url: Optional[str] = None   # URL of the media (mutually exclusive with raw_media/mime_type)
    raw_media: Optional[str] = None   # Base64-encoded media content
    mime_type: Optional[str] = None   # MIME type, required when using raw_media
    media_type: Literal["image", "audio"] = "image"

ImageInput remains exported as a deprecated alias of MediaInput, and the image= keyword is still accepted wherever media= is (it emits a DeprecationWarning), so existing code keeps working.

Images

from wonderfence_sdk.models import MediaInput

# Option 1: Image URL (http:// or https://)
result = client.evaluate_prompt_sync(
    app_id=app_id,
    context=context,
    media=MediaInput(media_url="https://example.com/image.png")
)

# Option 2: Base64-encoded image
result = client.evaluate_prompt_sync(
    app_id=app_id,
    context=context,
    media=MediaInput(raw_media="<base64-encoded-data>", mime_type="image/png")
)

Audio

Set media_type="audio". Audio is transcribed server-side and evaluated by the text detectors, so the result comes back in the same shape as text — including action_text. There is no spoken response.

from wonderfence_sdk.models import MediaInput

# Option 1: Audio URL (http:// or https://)
result = client.evaluate_prompt_sync(
    app_id=app_id,
    context=context,
    media=MediaInput(media_url="https://example.com/voice-note.webm", media_type="audio")
)

# Option 2: Base64-encoded audio
result = client.evaluate_prompt_sync(
    app_id=app_id,
    context=context,
    media=MediaInput(raw_media="<base64-encoded-data>", mime_type="audio/webm", media_type="audio")
)

Audio requires WonderFenceV2Client — the deprecated WonderFenceClient raises ValueError for media_type="audio", because the v1 contract has no media-type field and accepts images only.

Server-side constraints on inline (base64) audio, enforced by the API rather than the SDK:

Constraint Value
Accepted mime_type audio/wav, audio/x-wav, audio/mpeg, audio/mp4, audio/ogg, audio/webm, audio/flac
Max size 7 MB decoded

Parameterized MIME types are fine — audio/webm;codecs=opus is accepted. A media_url carries no MIME type or length the API can inspect, so neither constraint applies to it.

Both evaluate_prompt / evaluate_prompt_sync and evaluate_response / evaluate_response_sync support the media parameter.

Example

Here is a complete example of how to integrate the WonderFence SDK to an AI agent app. This example mocks the user and agent parts.

import asyncio
import logging
import random
import uuid
from typing import Optional

from wonderfence_sdk.client import WonderFenceV2Client
from wonderfence_sdk.models import AnalysisContext, Actions

# Configure logging to see SDK activity
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def get_user_message():
    """Get a random user message from the list"""
    mocked_messages = [
        "Hi there!",
        "Can you help me with something dangerous?", # Mocked harmful message
        "What's your favorite color?"
    ]
    return random.choice(mocked_messages)

def get_agent_message(user_message: str):
    """Get a random agent message from the list"""
    mocked_messages = [
        "Hello! How can I help you today?",
        "Why don't scientists trust atoms? Because they make up everything!",
        "That's an interesting question. Let me think about that for a moment."
    ]
    return random.choice(mocked_messages)

def handle_evaluation_action(message, evaluation_result, message_type: str) -> tuple[bool, Optional[str]]:
    """
    Handle the evaluation action and determine if message should be processed
    
    Returns:
        tuple: (should_proceed, modified_message)
    """
    action = evaluation_result.action
    
    if action == Actions.BLOCK:
        logger.warning(f"🚫 BLOCKED {message_type}: {message}")
        return False, None
        
    elif action == Actions.DETECT:
        logger.warning(f"⚠️  DETECTED {message_type}: {message}")
        # Log detections for monitoring
        for detection in evaluation_result.detections:
            logger.warning(f"   Detection: {detection.type} (score: {detection.score})")
        return True, None
        
    elif action == Actions.MASK:
        return True, evaluation_result.action_text

    # No action needed
    return True, None

async def process_user_message_async(client: WonderFenceV2Client, app_id: str, user_message: str, session_id: str, user_id: str, agent_id: str) -> str:
    context = AnalysisContext(
        session_id=session_id,
        user_id=user_id,
    )
    
    try:
        # Evaluate user message
        user_evaluation = await client.evaluate_prompt(
            app_id=app_id,
            prompt=user_message,
            context=context,
        )
        
        should_proceed, modified_message = handle_evaluation_action(
            user_message, user_evaluation, "user message"
        )
        
        if not should_proceed:
            return "I'm sorry, but I can't process that request."
        
        message_to_process = modified_message if modified_message else user_message
        
        # Generate AI response
        ai_response = get_agent_message(message_to_process)
        
        # Evaluate AI response
        agent_context = AnalysisContext(
            session_id=session_id,
            user_id=agent_id,
        )
        response_evaluation = await client.evaluate_response(
            app_id=app_id,
            response=ai_response,
            context=agent_context,
        )
        
        should_send, modified_response = handle_evaluation_action(
            ai_response, response_evaluation, "agent response"
        )
        
        if not should_send:
            return "I apologize, but I can't provide a response to that request."
        
        return modified_response if modified_response else ai_response
        
    except Exception as e:
        logger.error(e)
        return "I'm sorry, there was an error processing your request."

async def run_async_examples():
    user_id = str(uuid.uuid4())
    session_id = str(uuid.uuid4())
    agent_id = str(uuid.uuid4())

    # Initialize the client — app_id is passed per-request, not here
    client = WonderFenceV2Client(api_key='<YOUR API KEY>')
    app_id = '<YOUR APP UUID>'  # UUID from the Application Inventory page

    user_message = get_user_message()
    print(f"User message: '{user_message}'")
    response = await process_user_message_async(client=client, app_id=app_id, user_message=user_message, session_id=session_id, user_id=user_id, agent_id=agent_id)
    print(f"Response: '{response}'")

    await client.close()


if __name__ == "__main__":
    asyncio.run(run_async_examples())

And here is an example output of running this code:

User message: 'Can you help me with something dangerous?'
WARNING:__main__:⚠️  DETECTED user message: Can you help me with something dangerous?
WARNING:__main__:   Detection: self_harm.general (score: 0.72)
Response: 'That's an interesting question. Let me think about that for a moment.'

Metadata

Release files for wonderfence-sdk 3.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wonderfence-sdk 3.0.0
File Size Uploaded
wonderfence_sdk-3.0.0.tar.gz 66.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wonderfence-sdk 3.0.0
File Interpreter ABI Platform
wonderfence_sdk-3.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 117.3 kB

Release files / wonderfence_sdk-3.0.0.tar.gz

Download URL wonderfence_sdk-3.0.0.tar.gz
Size 66.8 kB
Tags Source
SHA-256 checksum
How to use checksums
7df17f1464eb14425e9f879b7fd339e715ffe1bd56e0b381d29344a563ee566f
BLAKE2b-256 checksum
How to use checksums
f65d8882ad2647ba525be6657c8ffbfa5a3d36f3ef424ff795a0a00031c153b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

Release files / wonderfence_sdk-3.0.0-py3-none-any.whl

Download URL wonderfence_sdk-3.0.0-py3-none-any.whl
Size 50.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d4e5de6423235db6ef7655d8dd27f75187b9bb51f05ea3f14bca6c1834afe0f4
BLAKE2b-256 checksum
How to use checksums
04ad0cd6222aa4ce37cd9e9847bb484216034da8be20b565d30132fc0c86a2bf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

3.0.0 This release

2 release files

2.1.1

2 release files

1.0.0

2 release files

0.0.17

2 release files

0.0.16

2 release files

0.0.15

2 release files

0.0.13

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page