mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-06 08:16:43 +00:00
chore: rename GraySwan to Gray Swan (#15771)
This commit is contained in:
parent
d4aadda692
commit
39641e7e68
4 changed files with 38 additions and 38 deletions
|
|
@ -1,9 +1,9 @@
|
|||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# GraySwan Cygnal Guardrail
|
||||
# Gray Swan Cygnal Guardrail
|
||||
|
||||
Use [GraySwan Cygnal](https://docs.grayswan.ai/cygnal/monitor-requests) to continuously monitor conversations for policy violations, indirect prompt injection (IPI), jailbreak attempts, and other safety risks.
|
||||
Use [Gray Swan Cygnal](https://docs.grayswan.ai/cygnal/monitor-requests) to continuously monitor conversations for policy violations, indirect prompt injection (IPI), jailbreak attempts, and other safety risks.
|
||||
|
||||
Cygnal returns a `violation` score between `0` and `1` (higher means more likely to violate policy), plus metadata such as violated rule indices, mutation detection, and IPI flags. LiteLLM can automatically block or monitor requests based on this signal.
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ Cygnal returns a `violation` score between `0` and `1` (higher means more likely
|
|||
|
||||
### 1. Obtain Credentials
|
||||
|
||||
1. Create a GraySwan account and generate a Cygnal API key.
|
||||
1. Create a Gray Swan account and generate a Cygnal API key.
|
||||
2. Configure environment variables for the LiteLLM proxy host:
|
||||
|
||||
```bash
|
||||
|
|
@ -22,7 +22,7 @@ export GRAYSWAN_API_KEY="your-grayswan-key"
|
|||
|
||||
### 2. Configure `config.yaml`
|
||||
|
||||
Add a guardrail entry that references the GraySwan integration. Below is a balanced example that monitors both input and output but only blocks once the violation score reaches the configured threshold.
|
||||
Add a guardrail entry that references the Gray Swan integration. Below is a balanced example that monitors both input and output but only blocks once the violation score reaches the configured threshold.
|
||||
|
||||
```yaml
|
||||
model_list:
|
||||
|
|
@ -63,7 +63,7 @@ litellm --config config.yaml --port 4000
|
|||
|
||||
## Choosing Guardrail Modes
|
||||
|
||||
GraySwan can run during `pre_call`, `during_call`, and `post_call` stages. Combine modes based on your latency and coverage requirements.
|
||||
Gray Swan can run during `pre_call`, `during_call`, and `post_call` stages. Combine modes based on your latency and coverage requirements.
|
||||
|
||||
| Mode | When it Runs | Protects | Typical Use Case |
|
||||
|--------------|-------------------|-----------------------|------------------|
|
||||
|
|
@ -138,10 +138,10 @@ Provides the strongest enforcement by inspecting both prompts and responses.
|
|||
|
||||
| Parameter | Type | Description |
|
||||
|---------------------------------------|-----------------|-------------|
|
||||
| `api_key` | string | GraySwan Cygnal API key. Reads from `GRAYSWAN_API_KEY` if omitted. |
|
||||
| `api_key` | string | Gray Swan Cygnal API key. Reads from `GRAYSWAN_API_KEY` if omitted. |
|
||||
| `mode` | string or list | Guardrail stages (`pre_call`, `during_call`, `post_call`). |
|
||||
| `optional_params.on_flagged_action` | string | `monitor` (log only) or `block` (raise `HTTPException`). |
|
||||
| `.optional_params.violation_threshold`| number (0-1) | Scores at or above this value are considered violations. |
|
||||
| `optional_params.reasoning_mode` | string | `off`, `hybrid`, or `thinking`. Enables Cygnal’s reasoning capabilities. |
|
||||
| `optional_params.categories` | object | Map of custom category names to descriptions. |
|
||||
| `optional_params.policy_id` | string | GraySwan policy identifier. |
|
||||
| `optional_params.policy_id` | string | Gray Swan policy identifier. |
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""GraySwan Cygnal guardrail integration for LiteLLM."""
|
||||
"""Gray Swan Cygnal guardrail integration for LiteLLM."""
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ def initialize_guardrail(
|
|||
|
||||
guardrail_name = guardrail.get("guardrail_name")
|
||||
if not guardrail_name:
|
||||
raise ValueError("GraySwan guardrail requires a guardrail_name")
|
||||
raise ValueError("Gray Swan guardrail requires a guardrail_name")
|
||||
|
||||
optional_params = getattr(litellm_params, "optional_params", None)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""GraySwan Cygnal guardrail integration."""
|
||||
"""Gray Swan Cygnal guardrail integration."""
|
||||
|
||||
import os
|
||||
from typing import Any, Dict, Literal, Optional, Union
|
||||
|
|
@ -24,16 +24,16 @@ from litellm.types.utils import LLMResponseTypes
|
|||
|
||||
|
||||
class GraySwanGuardrailMissingSecrets(Exception):
|
||||
"""Raised when the GraySwan API key is missing."""
|
||||
"""Raised when the Gray Swan API key is missing."""
|
||||
|
||||
|
||||
class GraySwanGuardrailAPIError(Exception):
|
||||
"""Raised when the GraySwan API returns an error."""
|
||||
"""Raised when the Gray Swan API returns an error."""
|
||||
|
||||
|
||||
class GraySwanGuardrail(CustomGuardrail):
|
||||
"""
|
||||
Guardrail that calls GraySwan's Cygnal monitoring endpoint.
|
||||
Guardrail that calls Gray Swan's Cygnal monitoring endpoint.
|
||||
|
||||
see: https://docs.grayswan.ai/cygnal/monitor-requests
|
||||
"""
|
||||
|
|
@ -63,7 +63,7 @@ class GraySwanGuardrail(CustomGuardrail):
|
|||
api_key_value = api_key or os.getenv("GRAYSWAN_API_KEY")
|
||||
if not api_key_value:
|
||||
raise GraySwanGuardrailMissingSecrets(
|
||||
"GraySwan API key missing. Set `GRAYSWAN_API_KEY` or pass `api_key`."
|
||||
"Gray Swan API key missing. Set `GRAYSWAN_API_KEY` or pass `api_key`."
|
||||
)
|
||||
self.api_key: str = api_key_value
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ class GraySwanGuardrail(CustomGuardrail):
|
|||
else:
|
||||
if action:
|
||||
verbose_proxy_logger.warning(
|
||||
"GraySwan Guardrail: Unsupported on_flagged_action '%s', defaulting to '%s'.",
|
||||
"Gray Swan Guardrail: Unsupported on_flagged_action '%s', defaulting to '%s'.",
|
||||
action,
|
||||
self.DEFAULT_ON_FLAGGED_ACTION,
|
||||
)
|
||||
|
|
@ -131,11 +131,11 @@ class GraySwanGuardrail(CustomGuardrail):
|
|||
):
|
||||
return data
|
||||
|
||||
verbose_proxy_logger.debug("GraySwan Guardrail: pre-call hook triggered")
|
||||
verbose_proxy_logger.debug("Gray Swan Guardrail: pre-call hook triggered")
|
||||
|
||||
messages = data.get("messages")
|
||||
if not messages:
|
||||
verbose_proxy_logger.debug("GraySwan Guardrail: No messages in data")
|
||||
verbose_proxy_logger.debug("Gray Swan Guardrail: No messages in data")
|
||||
return data
|
||||
|
||||
dynamic_body = self.get_guardrail_dynamic_request_body_params(data) or {}
|
||||
|
|
@ -143,7 +143,7 @@ class GraySwanGuardrail(CustomGuardrail):
|
|||
payload = self._prepare_payload(messages, dynamic_body)
|
||||
if payload is None:
|
||||
verbose_proxy_logger.debug(
|
||||
"GraySwan Guardrail: no content to scan; skipping request"
|
||||
"Gray Swan Guardrail: no content to scan; skipping request"
|
||||
)
|
||||
return data
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ class GraySwanGuardrail(CustomGuardrail):
|
|||
|
||||
messages = data.get("messages")
|
||||
if not messages:
|
||||
verbose_proxy_logger.debug("GraySwan Guardrail: No messages in data")
|
||||
verbose_proxy_logger.debug("Gray Swan Guardrail: No messages in data")
|
||||
return data
|
||||
|
||||
dynamic_body = self.get_guardrail_dynamic_request_body_params(data) or {}
|
||||
|
|
@ -189,7 +189,7 @@ class GraySwanGuardrail(CustomGuardrail):
|
|||
payload = self._prepare_payload(messages, dynamic_body)
|
||||
if payload is None:
|
||||
verbose_proxy_logger.debug(
|
||||
"GraySwan Guardrail: no content to scan; skipping request"
|
||||
"Gray Swan Guardrail: no content to scan; skipping request"
|
||||
)
|
||||
return data
|
||||
|
||||
|
|
@ -227,7 +227,7 @@ class GraySwanGuardrail(CustomGuardrail):
|
|||
|
||||
if not response_messages:
|
||||
verbose_proxy_logger.debug(
|
||||
"GraySwan Guardrail: no response messages detected; skipping post-call scan"
|
||||
"Gray Swan Guardrail: no response messages detected; skipping post-call scan"
|
||||
)
|
||||
return response
|
||||
|
||||
|
|
@ -236,7 +236,7 @@ class GraySwanGuardrail(CustomGuardrail):
|
|||
payload = self._prepare_payload(response_messages, dynamic_body)
|
||||
if payload is None:
|
||||
verbose_proxy_logger.debug(
|
||||
"GraySwan Guardrail: no content to scan; skipping request"
|
||||
"Gray Swan Guardrail: no content to scan; skipping request"
|
||||
)
|
||||
return response
|
||||
|
||||
|
|
@ -263,13 +263,13 @@ class GraySwanGuardrail(CustomGuardrail):
|
|||
response.raise_for_status()
|
||||
result = response.json()
|
||||
verbose_proxy_logger.debug(
|
||||
"GraySwan Guardrail: monitor response %s", safe_dumps(result)
|
||||
"Gray Swan Guardrail: monitor response %s", safe_dumps(result)
|
||||
)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as exc: # pragma: no cover - depends on HTTP client behaviour
|
||||
verbose_proxy_logger.exception(
|
||||
"GraySwan Guardrail: API request failed: %s", exc
|
||||
"Gray Swan Guardrail: API request failed: %s", exc
|
||||
)
|
||||
raise GraySwanGuardrailAPIError(str(exc)) from exc
|
||||
|
||||
|
|
@ -315,14 +315,14 @@ class GraySwanGuardrail(CustomGuardrail):
|
|||
flagged = violation_score >= self.violation_threshold
|
||||
if not flagged:
|
||||
verbose_proxy_logger.debug(
|
||||
"GraySwan Guardrail: request passed (score=%s, rules=%s)",
|
||||
"Gray Swan Guardrail: request passed (score=%s, rules=%s)",
|
||||
violation_score,
|
||||
violated_rules,
|
||||
)
|
||||
return
|
||||
|
||||
verbose_proxy_logger.warning(
|
||||
"GraySwan Guardrail: violation score %.3f exceeds threshold %.3f",
|
||||
"Gray Swan Guardrail: violation score %.3f exceeds threshold %.3f",
|
||||
violation_score,
|
||||
self.violation_threshold,
|
||||
)
|
||||
|
|
@ -331,7 +331,7 @@ class GraySwanGuardrail(CustomGuardrail):
|
|||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail={
|
||||
"error": "Blocked by GraySwan Guardrail",
|
||||
"error": "Blocked by Gray Swan Guardrail",
|
||||
"violation": violation_score,
|
||||
"violated_rules": violated_rules,
|
||||
"mutation": mutation_detected,
|
||||
|
|
@ -351,7 +351,7 @@ class GraySwanGuardrail(CustomGuardrail):
|
|||
if normalised in self.SUPPORTED_REASONING_MODES:
|
||||
return normalised
|
||||
verbose_proxy_logger.warning(
|
||||
"GraySwan Guardrail: ignoring unsupported reasoning_mode '%s'",
|
||||
"Gray Swan Guardrail: ignoring unsupported reasoning_mode '%s'",
|
||||
candidate,
|
||||
)
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""GraySwan guardrail configuration models."""
|
||||
"""Gray Swan guardrail configuration models."""
|
||||
|
||||
from typing import Dict, Optional
|
||||
|
||||
|
|
@ -8,7 +8,7 @@ from .base import GuardrailConfigModel
|
|||
|
||||
|
||||
class GraySwanGuardrailConfigModelOptionalParams(BaseModel):
|
||||
"""Optional parameters for the GraySwan guardrail."""
|
||||
"""Optional parameters for the Gray Swan guardrail."""
|
||||
|
||||
on_flagged_action: Optional[str] = Field(
|
||||
default="monitor",
|
||||
|
|
@ -18,36 +18,36 @@ class GraySwanGuardrailConfigModelOptionalParams(BaseModel):
|
|||
default=0.5,
|
||||
ge=0.0,
|
||||
le=1.0,
|
||||
description="Threshold between 0 and 1 at which GraySwan violations trigger the configured action.",
|
||||
description="Threshold between 0 and 1 at which Gray Swan violations trigger the configured action.",
|
||||
)
|
||||
reasoning_mode: Optional[str] = Field(
|
||||
default=None,
|
||||
description="GraySwan reasoning mode override. Accepted values: 'off', 'hybrid', 'thinking'.",
|
||||
description="Gray Swan reasoning mode override. Accepted values: 'off', 'hybrid', 'thinking'.",
|
||||
)
|
||||
policy_id: Optional[str] = Field(
|
||||
default=None,
|
||||
description="GraySwan policy identifier to apply during monitoring.",
|
||||
description="Gray Swan policy identifier to apply during monitoring.",
|
||||
)
|
||||
categories: Optional[Dict[str, str]] = Field(
|
||||
default=None,
|
||||
description="Default GraySwan category definitions to send with each request.",
|
||||
description="Default Gray Swan category definitions to send with each request.",
|
||||
)
|
||||
|
||||
|
||||
class GraySwanGuardrailConfigModel(
|
||||
GuardrailConfigModel[GraySwanGuardrailConfigModelOptionalParams]
|
||||
):
|
||||
"""Configuration parameters for the GraySwan guardrail."""
|
||||
"""Configuration parameters for the Gray Swan guardrail."""
|
||||
|
||||
api_key: Optional[str] = Field(
|
||||
default=None,
|
||||
description="API key for GraySwan. Reads from the `GRAYSWAN_API_KEY` environment variable when omitted.",
|
||||
description="API key for Gray Swan. Reads from the `GRAYSWAN_API_KEY` environment variable when omitted.",
|
||||
)
|
||||
api_base: Optional[str] = Field(
|
||||
default=None,
|
||||
description="Override for the GraySwan API base URL. Defaults to https://api.grayswan.ai and can be set via `GRAYSWAN_API_BASE`.",
|
||||
description="Override for the Gray Swan API base URL. Defaults to https://api.grayswan.ai and can be set via `GRAYSWAN_API_BASE`.",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def ui_friendly_name() -> str:
|
||||
return "GraySwan Guardrail"
|
||||
return "Gray Swan Guardrail"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue