feat(lasso): Upgrade to Lasso API v3 and fix ULID generation (#15941)

* 1. add v3 classify
2. add new classifix for masking
3. support same id for the conversation for pre and post
working with duplicates

* clean code, remove some debug and run tests

* update liter errors

* improvment for Code Organization, httpx Error Handling Specificity, Logging Improvements and Type

* transfer test test_lasso_guard_config to the new location

* Fix type hints and linting errors in lasso.py

- Add type: ignore for httpx module when None
- Fix return type issues in _handle_classification and _handle_masking
- Ensure masked_messages is not None before passing to _apply_masking_to_model_response
- Convert LassoResponse to dict for _log_masking_applied call

* feat(lasso): Upgrade to Lasso API v3 and fix ULID generation

- Update Lasso API endpoints from v2 to v3 (/gateway/v3/classify)
- Update masking endpoints from v1 to v3 (/gateway/v3/classifix)
- Fix ULID generation: use ulid.new() instead of ULID() constructor
- Resolve MemoryView error that occurred with incorrect ULID usage

Tested with real proxy server and verified:
- Malicious content (jailbreak) properly blocked
- Safe content passes through guardrail
- PII detection and masking works correctly
- No ULID generation errors

* docs(lasso): Add ulid-py>=1.1.0 dependency prerequisite

Add Prerequisites section documenting the required ulid-py package
(version 1.1.0 or higher) for Lasso guardrail conversation tracking.

* update docs with the right api_key format
This commit is contained in:
oroxenberg
2025-10-26 10:08:52 -07:00
committed by GitHub
parent 06a17ac1af
commit a75e75ae1a
2 changed files with 18 additions and 7 deletions
@@ -6,6 +6,16 @@ import TabItem from '@theme/TabItem';
Use [Lasso Security](https://www.lasso.security/) to protect your LLM applications from prompt injection attacks, harmful content generation, and other security threats through comprehensive input and output validation.
## Prerequisites
The Lasso guardrail requires the `ulid-py` package (version 1.1.0 or higher) for generating unique conversation identifiers:
```shell
pip install ulid-py>=1.1.0
```
This package is used to create lexicographically sortable identifiers for tracking conversations and sessions in the Lasso Security platform.
## Quick Start
### 1. Define Guardrails on your LiteLLM config.yaml
@@ -25,7 +35,7 @@ guardrails:
guardrail: lasso
mode: "pre_call"
api_key: os.environ/LASSO_API_KEY
api_base: "https://server.lasso.security/gateway/v3/classify" # Optional: defaults to v3 endpoint
api_base: "https://server.lasso.security"
- guardrail_name: "lasso-post-guard"
litellm_params:
guardrail: lasso
@@ -10,10 +10,11 @@ import uuid
from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Type, Union, TypedDict
try:
from ulid import ULID
import ulid
ULID_AVAILABLE = True
except ImportError:
ulid = None # type: ignore
ULID_AVAILABLE = False
try:
@@ -114,8 +115,8 @@ class LassoGuardrail(CustomGuardrail):
Generate a ULID (Universally Unique Lexicographically Sortable Identifier).
Falls back to UUID if ULID library is not available.
"""
if ULID_AVAILABLE:
return str(ULID()) # type: ignore
if ULID_AVAILABLE and ulid is not None:
return str(ulid.new()) # type: ignore
else:
verbose_proxy_logger.debug("ULID library not available, using UUID")
return str(uuid.uuid4())
@@ -222,7 +223,7 @@ class LassoGuardrail(CustomGuardrail):
if self.mask:
headers = self._prepare_headers(response_data)
payload = self._prepare_payload(response_messages, "COMPLETION", response_data)
api_url = f"{self.api_base}/gateway/v1/classifix"
api_url = f"{self.api_base}/gateway/v3/classifix"
try:
lasso_response = await self._call_lasso_api(headers=headers, payload=payload, api_url=api_url)
@@ -370,7 +371,7 @@ class LassoGuardrail(CustomGuardrail):
try:
headers = self._prepare_headers(data, cache)
payload = self._prepare_payload(messages, message_type, data, cache)
api_url = f"{self.api_base}/gateway/v1/classifix"
api_url = f"{self.api_base}/gateway/v3/classifix"
response = await self._call_lasso_api(headers=headers, payload=payload, api_url=api_url)
self._process_lasso_response(response)
@@ -513,7 +514,7 @@ class LassoGuardrail(CustomGuardrail):
api_url: Optional[str] = None,
) -> LassoResponse:
"""Call the Lasso API and return the response."""
url = api_url or f"{self.api_base}/gateway/v2/classify"
url = api_url or f"{self.api_base}/gateway/v3/classify"
verbose_proxy_logger.debug(f"Calling Lasso API with messageType: {payload.get('messageType')}")
response = await self.async_handler.post(
url=url,