Source code for smarter.apps.guardrail.models.guardail

"""All models for the OpenAI Function Calling API app."""

from django.conf import settings
from django.db import models

from smarter.apps.account.models import (
    MetaDataWithOwnershipModel,
)
from smarter.lib import logging
from smarter.lib.django.waffle.switches import SmarterWaffleSwitches

logger = logging.getSmarterLogger(__name__, any_switches=[SmarterWaffleSwitches.GUARDRAIL_LOGGING])


class GuardrailType(models.TextChoices):
    INPUT = "input", "Input (pre-prompt)"
    OUTPUT = "output", "Output (post-completion)"
    BOTH = "both", "Input & Output"


class GuardrailCategory(models.TextChoices):
    PII = "pii", "PII / Sensitive Data"
    JAILBREAK = "jailbreak", "Jailbreak / Prompt Injection"
    TOXICITY = "toxicity", "Toxicity / Harassment"
    HALLUCINATION = "hallucination", "Hallucination / Factuality"
    OFF_TOPIC = "off_topic", "Off-topic / Scope Drift"
    COMPLIANCE = "compliance", "Regulatory / Compliance"
    CUSTOM = "custom", "Custom"


class MatchStrategy(models.TextChoices):
    REGEX = "regex", "Regex"
    KEYWORD = "keyword", "Keyword List"
    SEMANTIC = "semantic", "Semantic / Embedding Similarity"
    MODEL = "model", "Classifier Model Call"
    LLM_JUDGE = "llm_judge", "LLM-as-Judge"


class GuardrailAction(models.TextChoices):
    ALLOW = "allow", "Allow (log only)"
    FLAG = "flag", "Flag for Review"
    REDACT = "redact", "Redact & Continue"
    TRANSFORM = "transform", "Transform/Rewrite"
    BLOCK = "block", "Block Request"
    ESCALATE = "escalate", "Escalate to Human"


[docs] class Guardrail(MetaDataWithOwnershipModel): """Implements the Guardrail API model.""" # pylint: disable=C0115 class Meta: verbose_name_plural = "Guardrails" unique_together = ("user_profile", "name") # --- classification --- guardrail_type = models.CharField(max_length=16, choices=GuardrailType.choices) category = models.CharField(max_length=32, choices=GuardrailCategory.choices) # --- detection logic --- match_strategy = models.CharField(max_length=16, choices=MatchStrategy.choices) pattern = models.TextField( blank=True, help_text="Regex, keyword list (newline/comma), or judge prompt template depending on match_strategy.", ) config = models.JSONField( default=dict, blank=True, help_text="Strategy-specific params: similarity_threshold, model_id, temperature, few-shot examples, etc.", ) # --- response behavior --- action = models.CharField(max_length=16, choices=GuardrailAction.choices) severity = models.PositiveSmallIntegerField( default=1, help_text="1=low ... 5=critical; drives alerting/escalation thresholds.", ) confidence_threshold = models.FloatField( null=True, blank=True, help_text="Minimum confidence score to trigger action, for model/semantic strategies.", ) # --- lifecycle --- is_active = models.BooleanField(default=True) is_blocking = models.BooleanField( default=False, help_text="If False, action runs in shadow/log-only mode regardless of `action`.", ) priority = models.PositiveSmallIntegerField( default=100, help_text="Execution order when multiple guardrails match; lower runs first.", ) # --- versioning / provenance --- fallback_message = models.TextField( blank=True, help_text="User-facing message returned when action=BLOCK.", )
__all__ = ["Guardrail"]