Class UserInputRole
java.lang.Object
com.tnsai.roles.Role
com.tnsai.integration.scop.examples.UserInputRole
@RoleSpec(name="UserInputAgent",
description="Validates and sanitises user-supplied text before it reaches the LLM or downstream services.",
version="0.1.0",
llm=@LLMSpec(provider=OPENAI,model="gpt-4o-mini",temperature=0.2f))
@InputGuardrail(maxLength=16384,
blockPatterns={"(?i)ignore\\s++previous\\s++instructions","(?i)disregard\\s++the\\s++system\\s++prompt","<script\\b"},
onFailure=REJECT)
public class UserInputRole
extends com.tnsai.roles.Role
Reference example: declarative
@InputGuardrail +
@OutputGuardrail composition (issue #171, Phase 1).
Demonstrates the four documented dispositions for hostile input
and over-budget output, all enforced by the framework's
InputGuardrailEnforcer / OutputGuardrailEnforcer
inside ActionExecutor.executeInternal — no per-action
imperative validation in the Role:
REJECTon input — anything matching a denylist regex throwsGuardrailViolationException(wrapped asActionExecutionException(VALIDATION)at the dispatcher's edge). Use for prompt-injection defence, length DoS, schema enforcement.WARNon input — log but proceed; useful when telemetry is more important than blocking (e.g. tracking borderline values in a staging tenant).SANITIZEon input — strip C0 control chars, truncate tomaxLength; the action body sees a cleaned value rather than failing.TRUNCATE/FALLBACKon output — clip oversized responses tomaxChars, or substitute a safe fallback string. Symmetric pair to SANITIZE on the output side.
Class-level default + method-level override
The class-levelInputGuardrail below sets a baseline
(16KB max, no obvious prompt-injection markers) that every action
inherits. Per-method annotations override the class default
entirely — there is no merging. summarize
keeps the class default; formatJson narrows to a JSON-only
allowlist; adminCommand escalates to REJECT on
top of length bounds.
How SCOP routes these
Every@ActionSpec on this role is dispatched through
ActionExecutor.executeInternal, which calls
InputGuardrailEnforcer.enforce immediately after
preconditions and before the action body, and
OutputGuardrailEnforcer.enforce immediately after the
action body returns and before postconditions. Violations
surface as ActionExecutionException of category
VALIDATION — the same surface consumers already handle
for ActionValidator.validateParameters failures.
Phase 2+ deferred
The@InputGuardrail.validators / .sanitizers /
.jsonSchema / .detectInjection /
.moderateContent fields and @OutputGuardrail's
.maskPII / .checkHallucination / .format
fields are not exercised in Phase 1 (they need
SPI design or external services — tracked separately on #171).- Since:
- 0.5.4 (issue #171, Phase 1 — guardrail cookbook)
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionadminCommand(String command) Hardest-locked path: short bound, strict allowlist (only lowercase commands),REVIEWdisposition routes any violation to a human-approval queue rather than simply blocking it.formatJson(String json) Method-level override: tighter length, allowlist limited to what looks like JSON.com.tnsai.models.role.RoleIdentityInherits the class-level guardrail defaults.Methods inherited from class com.tnsai.roles.Role
create, getAction, getActionCount, getActions, getDomain, getGoal, getInputGuardrailConfig, getLLM, getMinimalPrompt, getName, getOutputGuardrailConfig, getResilienceConfig, getSpec, getSystemPrompt, hasAction, hasLLM, identity, setLLM, toString
-
Constructor Details
-
UserInputRole
public UserInputRole()
-
-
Method Details
-
getIdentity
public com.tnsai.models.role.RoleIdentity getIdentity()- Specified by:
getIdentityin classcom.tnsai.roles.Role
-
summarize
@ActionSpec(type=LOCAL, description="Summarize user-provided text in plain language.") @OutputGuardrail(maxChars=2000, onFailure=TRUNCATE) public String summarize(String text) Inherits the class-level guardrail defaults. The action body sees a value that's already passed length + denylist checks. Output is bounded to a sensible summary length. -
formatJson
@ActionSpec(type=LOCAL, description="Format a JSON-shaped payload (object or array).") @InputGuardrail(minLength=2, maxLength=4096, allowPatterns="^\\s*[\\{\\[]", onFailure=SANITIZE) @OutputGuardrail(maxChars=4096, onFailure=TRUNCATE) public String formatJson(String json) Method-level override: tighter length, allowlist limited to what looks like JSON.SANITIZEon a borderline payload strips control characters and truncates rather than failing. -
adminCommand
@ActionSpec(type=LOCAL, description="Issue a privileged admin command.") @InputGuardrail(maxLength=64, allowPatterns="^[a-z][a-z0-9_-]{0,62}$", onFailure=REVIEW, errorMessage="Admin commands must be lowercase identifiers; routing to human review.") @OutputGuardrail(maxChars=256, onFailure=FALLBACK, fallback="(redacted: admin output exceeded budget)") public String adminCommand(String command) Hardest-locked path: short bound, strict allowlist (only lowercase commands),REVIEWdisposition routes any violation to a human-approval queue rather than simply blocking it.FALLBACKon output substitutes a safe placeholder if the action body produces too much.
-