Skip to content

Commit b2f477d

Browse files
feat(guardrails): add decorator framework to uipath-platform
Move @guardrail decorator, validators, actions, and adapter registry from uipath-langchain into uipath-platform as a framework-agnostic subpackage. Includes PIIValidator, PromptInjectionValidator, CustomValidator, BlockAction, LogAction, and GuardrailTargetAdapter Protocol. Bump version to 0.1.18. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 96e1894 commit b2f477d

17 files changed

Lines changed: 2075 additions & 2 deletions

File tree

packages/uipath-platform/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath-platform"
3-
version = "0.1.17"
3+
version = "0.1.18"
44
description = "HTTP client library for programmatic access to UiPath Platform"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"

packages/uipath-platform/src/uipath/platform/guardrails/__init__.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,24 @@
1414
)
1515

1616
from ._guardrails_service import GuardrailsService
17+
from .decorators import (
18+
BlockAction,
19+
CustomValidator,
20+
GuardrailAction,
21+
GuardrailBlockException,
22+
GuardrailExecutionStage,
23+
GuardrailTargetAdapter,
24+
GuardrailValidatorBase,
25+
LogAction,
26+
LoggingSeverityLevel,
27+
PIIDetectionEntity,
28+
PIIDetectionEntityType,
29+
PIIValidator,
30+
PromptInjectionValidator,
31+
RuleFunction,
32+
guardrail,
33+
register_guardrail_adapter,
34+
)
1735
from .guardrails import (
1836
BuiltInValidatorGuardrail,
1937
EnumListParameterValue,
@@ -22,7 +40,9 @@
2240
)
2341

2442
__all__ = [
43+
# Service
2544
"GuardrailsService",
45+
# Guardrail models
2646
"BuiltInValidatorGuardrail",
2747
"GuardrailType",
2848
"GuardrailValidationResultType",
@@ -33,4 +53,21 @@
3353
"GuardrailValidationResult",
3454
"EnumListParameterValue",
3555
"MapEnumParameterValue",
56+
# Decorator framework
57+
"guardrail",
58+
"GuardrailValidatorBase",
59+
"PIIValidator",
60+
"PromptInjectionValidator",
61+
"CustomValidator",
62+
"RuleFunction",
63+
"PIIDetectionEntity",
64+
"PIIDetectionEntityType",
65+
"GuardrailExecutionStage",
66+
"GuardrailAction",
67+
"LogAction",
68+
"BlockAction",
69+
"LoggingSeverityLevel",
70+
"GuardrailBlockException",
71+
"GuardrailTargetAdapter",
72+
"register_guardrail_adapter",
3673
]
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""Guardrail decorator framework for UiPath Platform.
2+
3+
Provides the ``@guardrail`` decorator, built-in validators, actions, and an
4+
adapter registry that framework integrations (e.g. *uipath-langchain*) use to
5+
teach the decorator how to wrap their specific object types.
6+
7+
Quick start::
8+
9+
from uipath.platform.guardrails.decorators import (
10+
guardrail,
11+
PIIValidator,
12+
LogAction,
13+
BlockAction,
14+
PIIDetectionEntity,
15+
PIIDetectionEntityType,
16+
GuardrailExecutionStage,
17+
)
18+
19+
pii = PIIValidator(entities=[PIIDetectionEntity(PIIDetectionEntityType.EMAIL)])
20+
21+
# Applied to a factory function (LangChain adapter must be imported first):
22+
@guardrail(validator=pii, action=LogAction(), name="LLM PII")
23+
def create_llm():
24+
...
25+
"""
26+
27+
from ._actions import BlockAction, LogAction, LoggingSeverityLevel
28+
from ._enums import GuardrailExecutionStage, PIIDetectionEntityType
29+
from ._exceptions import GuardrailBlockException
30+
from ._guardrail import guardrail
31+
from ._models import GuardrailAction, PIIDetectionEntity
32+
from ._registry import GuardrailTargetAdapter, register_guardrail_adapter
33+
from .validators import (
34+
CustomValidator,
35+
GuardrailValidatorBase,
36+
PIIValidator,
37+
PromptInjectionValidator,
38+
RuleFunction,
39+
)
40+
41+
__all__ = [
42+
# Decorator
43+
"guardrail",
44+
# Validators
45+
"GuardrailValidatorBase",
46+
"PIIValidator",
47+
"PromptInjectionValidator",
48+
"CustomValidator",
49+
"RuleFunction",
50+
# Models & enums
51+
"PIIDetectionEntity",
52+
"PIIDetectionEntityType",
53+
"GuardrailExecutionStage",
54+
"GuardrailAction",
55+
# Actions
56+
"LogAction",
57+
"BlockAction",
58+
"LoggingSeverityLevel",
59+
# Exception
60+
"GuardrailBlockException",
61+
# Adapter registry
62+
"GuardrailTargetAdapter",
63+
"register_guardrail_adapter",
64+
]
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""Built-in GuardrailAction implementations."""
2+
3+
import logging
4+
from dataclasses import dataclass
5+
from enum import Enum
6+
from typing import Any, Optional
7+
8+
from uipath.core.guardrails import (
9+
GuardrailValidationResult,
10+
GuardrailValidationResultType,
11+
)
12+
13+
from ._exceptions import GuardrailBlockException
14+
from ._models import GuardrailAction
15+
16+
17+
class LoggingSeverityLevel(int, Enum):
18+
"""Logging severity level for :class:`LogAction`."""
19+
20+
ERROR = logging.ERROR
21+
INFO = logging.INFO
22+
WARNING = logging.WARNING
23+
DEBUG = logging.DEBUG
24+
25+
26+
@dataclass
27+
class LogAction(GuardrailAction):
28+
"""Log guardrail violations without stopping execution.
29+
30+
Args:
31+
severity_level: Python logging level. Defaults to ``WARNING``.
32+
message: Custom log message. If omitted, the validation reason is used.
33+
"""
34+
35+
severity_level: LoggingSeverityLevel = LoggingSeverityLevel.WARNING
36+
message: Optional[str] = None
37+
38+
def handle_validation_result(
39+
self,
40+
result: GuardrailValidationResult,
41+
data: str | dict[str, Any],
42+
guardrail_name: str,
43+
) -> str | dict[str, Any] | None:
44+
"""Log the violation and return ``None`` (no data modification)."""
45+
if result.result == GuardrailValidationResultType.VALIDATION_FAILED:
46+
msg = self.message or f"Failed: {result.reason}"
47+
logging.getLogger(__name__).log(
48+
self.severity_level,
49+
"[GUARDRAIL] [%s] %s",
50+
guardrail_name,
51+
msg,
52+
)
53+
return None
54+
55+
56+
@dataclass
57+
class BlockAction(GuardrailAction):
58+
"""Block execution by raising :class:`GuardrailBlockException`.
59+
60+
Framework adapters catch ``GuardrailBlockException`` at the wrapper boundary
61+
and convert it to their own runtime error type.
62+
63+
Args:
64+
title: Exception title. Defaults to a message derived from the guardrail name.
65+
detail: Exception detail. Defaults to the validation reason.
66+
"""
67+
68+
title: Optional[str] = None
69+
detail: Optional[str] = None
70+
71+
def handle_validation_result(
72+
self,
73+
result: GuardrailValidationResult,
74+
data: str | dict[str, Any],
75+
guardrail_name: str,
76+
) -> str | dict[str, Any] | None:
77+
"""Raise :class:`GuardrailBlockException` when validation fails."""
78+
if result.result == GuardrailValidationResultType.VALIDATION_FAILED:
79+
title = self.title or f"Guardrail [{guardrail_name}] blocked execution"
80+
detail = self.detail or result.reason or "Guardrail validation failed"
81+
raise GuardrailBlockException(title=title, detail=detail)
82+
return None

0 commit comments

Comments
 (0)