Skip to content

Commit 44573c1

Browse files
refactor: use GuardrailsService directly in guardrail validators
1 parent d809f17 commit 44573c1

5 files changed

Lines changed: 43 additions & 92 deletions

File tree

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

Lines changed: 0 additions & 33 deletions
This file was deleted.

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

Lines changed: 0 additions & 19 deletions
This file was deleted.

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from ..common._execution_context import UiPathExecutionContext
1717
from ..common._job_context import header_job_key
1818
from ..common._models import Endpoint, RequestSpec
19+
from ..common.auth import build_api_config, resolve_config_from_env
1920
from ..errors import EnrichedException
2021
from .guardrails import BYO_VALIDATOR_TYPE, BuiltInValidatorGuardrail
2122

@@ -203,3 +204,11 @@ def evaluate_guardrail(
203204
model_data["spanId"] = span_id
204205

205206
return GuardrailValidationResult.model_validate(model_data)
207+
208+
209+
def default_guardrails_service() -> GuardrailsService:
210+
"""Build a guardrails service configured from environment variables."""
211+
base_url, secret = resolve_config_from_env(None, None)
212+
return GuardrailsService(
213+
build_api_config(base_url, secret), UiPathExecutionContext()
214+
)

packages/uipath-platform/src/uipath/platform/guardrails/decorators/validators/_base.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55

66
from uipath.core.guardrails import GuardrailValidationResult
77

8-
from uipath.platform.guardrails._default_evaluator import DefaultGuardrailEvaluator
9-
from uipath.platform.guardrails._evaluator import GuardrailEvaluator
8+
from ..._guardrails_service import (
9+
GuardrailsService,
10+
default_guardrails_service,
11+
)
1012
from uipath.platform.guardrails.guardrails import BuiltInValidatorGuardrail
1113

1214
from .._enums import GuardrailExecutionStage
@@ -80,7 +82,7 @@ def get_built_in_guardrail(self, name, description, enabled_for_evals):
8082
)
8183
"""
8284

83-
_evaluator: GuardrailEvaluator | None = None
85+
_service: GuardrailsService | None = None
8486

8587
@abstractmethod
8688
def get_built_in_guardrail(
@@ -113,13 +115,13 @@ def run(
113115
) -> GuardrailValidationResult:
114116
"""Evaluate via the UiPath Guardrails API.
115117
116-
Lazily initialises the guardrail evaluator on the first call and
118+
Lazily initialises the guardrails service on the first call and
117119
reuses it for all subsequent invocations.
118120
"""
119121
built_in = self.get_built_in_guardrail(name, description, enabled_for_evals)
120-
if self._evaluator is None:
121-
self._evaluator = DefaultGuardrailEvaluator()
122-
return self._evaluator.evaluate_guardrail(data, built_in)
122+
if self._service is None:
123+
self._service = default_guardrails_service()
124+
return self._service.evaluate_guardrail(data, built_in)
123125

124126

125127
class CustomGuardrailValidator(GuardrailValidatorBase, ABC):

packages/uipath-platform/tests/services/test_guardrails_decorators.py

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -989,8 +989,8 @@ def test_custom_validator_path_delegates_to_run(self):
989989
)
990990
assert result == _PASSED
991991

992-
def test_built_in_validator_uses_injected_evaluator(self):
993-
"""BuiltInGuardrailValidator.run() delegates to an injected evaluator."""
992+
def test_built_in_validator_uses_injected_service(self):
993+
"""BuiltInGuardrailValidator.run() delegates to an injected service."""
994994
from uipath.platform.guardrails.decorators.validators import (
995995
BuiltInGuardrailValidator,
996996
)
@@ -1003,20 +1003,20 @@ def get_built_in_guardrail(self, name, description, enabled_for_evals):
10031003
return mock_built_in
10041004

10051005
validator = _TestBuiltIn()
1006-
fake_evaluator = MagicMock()
1007-
fake_evaluator.evaluate_guardrail.return_value = _PASSED
1008-
validator._evaluator = fake_evaluator
1006+
fake_service = MagicMock()
1007+
fake_service.evaluate_guardrail.return_value = _PASSED
1008+
validator._service = fake_service
10091009
evaluator = _make_evaluator(validator, "G", None, True)
10101010

10111011
result = evaluator({"text": "hello"}, GuardrailExecutionStage.PRE, None, None)
10121012

1013-
fake_evaluator.evaluate_guardrail.assert_called_once_with(
1013+
fake_service.evaluate_guardrail.assert_called_once_with(
10141014
{"text": "hello"}, mock_built_in
10151015
)
10161016
assert result == _PASSED
10171017

1018-
def test_built_in_validator_path_lazy_initializes_default_evaluator(self):
1019-
"""BuiltInGuardrailValidator.run() creates the default evaluator once."""
1018+
def test_built_in_validator_path_lazy_initializes_default_service(self):
1019+
"""BuiltInGuardrailValidator.run() creates the default service once."""
10201020
from uipath.platform.guardrails.decorators.validators import (
10211021
BuiltInGuardrailValidator,
10221022
)
@@ -1032,7 +1032,7 @@ def get_built_in_guardrail(self, name, description, enabled_for_evals):
10321032
evaluator = _make_evaluator(validator, "G", None, True)
10331033

10341034
with patch(
1035-
"uipath.platform.guardrails.decorators.validators._base.DefaultGuardrailEvaluator"
1035+
"uipath.platform.guardrails.decorators.validators._base.default_guardrails_service"
10361036
) as mock_default:
10371037
mock_default.return_value.evaluate_guardrail.return_value = _PASSED
10381038
evaluator({"text": "hello"}, GuardrailExecutionStage.PRE, None, None)
@@ -1072,33 +1072,25 @@ def get_built_in_guardrail(self, name, description, enabled_for_evals):
10721072

10731073

10741074
# ---------------------------------------------------------------------------
1075-
# 15b. DefaultGuardrailEvaluator
1075+
# 15b. default_guardrails_service
10761076
# ---------------------------------------------------------------------------
10771077

10781078

1079-
class TestDefaultGuardrailEvaluator:
1080-
def test_constructs_service_from_env_and_delegates(self, monkeypatch):
1081-
"""The default evaluator builds a GuardrailsService from env config."""
1082-
from uipath.platform.guardrails._default_evaluator import (
1083-
DefaultGuardrailEvaluator,
1079+
class TestDefaultGuardrailsService:
1080+
def test_builds_guardrails_service_from_env(self, monkeypatch):
1081+
"""The default factory builds a GuardrailsService from env config."""
1082+
from uipath.platform.guardrails._guardrails_service import (
1083+
GuardrailsService,
1084+
default_guardrails_service,
10841085
)
1085-
from uipath.platform.guardrails._guardrails_service import GuardrailsService
1086-
from uipath.platform.guardrails.guardrails import BuiltInValidatorGuardrail
10871086

10881087
monkeypatch.setenv("UIPATH_URL", "https://test.uipath.com")
10891088
monkeypatch.setenv("UIPATH_ACCESS_TOKEN", "token")
10901089

1091-
evaluator = DefaultGuardrailEvaluator()
1092-
assert isinstance(evaluator._service, GuardrailsService)
1093-
1094-
mock_built_in = MagicMock(spec=BuiltInValidatorGuardrail)
1095-
with patch.object(
1096-
evaluator._service, "evaluate_guardrail", return_value=_PASSED
1097-
) as mock_evaluate:
1098-
result = evaluator.evaluate_guardrail("hello", mock_built_in)
1099-
1100-
mock_evaluate.assert_called_once_with("hello", mock_built_in)
1101-
assert result == _PASSED
1090+
service = default_guardrails_service()
1091+
assert isinstance(service, GuardrailsService)
1092+
assert service._config.base_url == "https://test.uipath.com"
1093+
assert service._config.secret == "token"
11021094

11031095

11041096
# ---------------------------------------------------------------------------
@@ -1305,8 +1297,8 @@ def test_real_validator_block_end_to_end_mocked_backend(self):
13051297
"""Real LLMAsJudgeValidator.run() path with the UiPath API mocked."""
13061298
from uipath.platform.guardrails.decorators import LLMAsJudgeValidator
13071299

1308-
mock_evaluator = MagicMock()
1309-
mock_evaluator.evaluate_guardrail.return_value = _FAILED
1300+
mock_service = MagicMock()
1301+
mock_service.evaluate_guardrail.return_value = _FAILED
13101302

13111303
@guardrail(
13121304
validator=LLMAsJudgeValidator(
@@ -1319,9 +1311,9 @@ def joke(topic: str) -> str:
13191311
return f"joke about {topic}"
13201312

13211313
with patch(
1322-
"uipath.platform.guardrails.decorators.validators._base.DefaultGuardrailEvaluator",
1323-
return_value=mock_evaluator,
1314+
"uipath.platform.guardrails.decorators.validators._base.default_guardrails_service",
1315+
return_value=mock_service,
13241316
):
13251317
with pytest.raises(GuardrailBlockException):
13261318
joke("cats")
1327-
mock_evaluator.evaluate_guardrail.assert_called_once()
1319+
mock_service.evaluate_guardrail.assert_called_once()

0 commit comments

Comments
 (0)