Human Message Guardrail¶
The Human Message Guardrail node matches the current user message against a list of regex patterns (one per string in a string storage) and branches the graph on the result. Typical use: short-circuit disallowed, off-topic, or jailbreak-style inputs to a canned-response node before they reach a Generate node.
Patterns are compiled once at agent creation and matched with
std::regex_search — i.e. a pattern hits if it matches anywhere
in the message, case-insensitively.
NodeType: HumanMessageGuardrail.
String storage kinds
HumanMessageGuardrailNode accepts any string storage kind (List,
Map, Multimap) and uses the list view — each value is treated
as a regex pattern regardless of any key. Topic-tagged deflection
(writing the matched pattern's category key onto the interaction for
use by a downstream CannedResponseNode) is planned as future work.
Parameters¶
| Param | Type | Default | Range | Structural | Description |
|---|---|---|---|---|---|
string_storage |
Optional[str] | inherit model default | — | — | Named session string storage. Mutable — rebinds the underlying storage. |
inline_strings |
Optional[Any] | inherit model default | — | ✓ | Inline pattern list. Structural because it materialises the underlying StringStorage at construction; rebinding goes through string_storage. |
Exits¶
Each exit is a structural string field on the node's params; its value names the target node (empty = END).
| Exit | Param field | Description |
|---|---|---|
triggered |
triggered_exit |
Exit taken when the human message matches a guardrail pattern. Empty string = END. |
not_triggered |
not_triggered_exit |
Exit taken when no pattern matches. Empty string = END. |
Source resolution
Priority order: string_storage (named session storage) → inline_strings (authored
inline) → server default file (default_guardrail_patterns_path in server-config.json).
Patterns are matched case-insensitively. Compilation errors at agent-creation time
fail graph validation with error 3003.
Exit routes¶
| Route | Fires when |
|---|---|
triggered |
At least one pattern matched the user message. |
not_triggered |
No patterns matched. |
Both routes must be wired.
Side effects¶
None on the dialog. The node does not modify the current
interaction, does not emit AnswerText
frames, and does not touch the KV cache. It is pure routing.
Minimum working example¶
from tryll_client.graph import (
GraphDescription, HumanMessageGuardrailParams,
CannedResponseParams, GenerateParams,
)
client.create_string_storage(
name="jailbreak_patterns",
strings=[
r"ignore\s+previous\s+instructions?",
r"you\s+are\s+DAN",
],
)
graph = (
GraphDescription()
.add_node("guard", HumanMessageGuardrailParams(
string_storage="jailbreak_patterns",
triggered_exit="refuse",
not_triggered_exit="answer",
))
.add_node("refuse", CannedResponseParams(
default_exit="", # uses server default; empty = END
))
.add_node("answer", GenerateParams(
default_exit="", # empty = END
))
.set_start_node("guard")
.set_default_model_name("My Local Model")
)
agent = client.create_agent(graph)
using namespace Tryll::Client;
using namespace Tryll::NodeParams;
client.CreateStringStorage("jailbreak_patterns", {
R"(ignore\s+previous\s+instructions?)",
R"(you\s+are\s+DAN)",
});
HumanMessageGuardrailParamsT guardP;
guardP.string_storage = "jailbreak_patterns";
guardP.triggered_exit = "refuse";
guardP.not_triggered_exit = "answer";
// refuseP and answerP use defaults (server default canned responses / END)
CannedResponseParamsT refuseP;
GenerateParamsT answerP;
GraphDescription graph;
graph.AddHumanMessageGuardrail("guard", std::move(guardP))
.AddCannedResponse("refuse", std::move(refuseP))
.AddGenerate("answer", std::move(answerP))
.SetStartNode("guard")
.SetDefaultModelName("My Local Model");
auto agent = client.CreateAgent(graph);
using Tryll.Client;
var graph = new TryllGraphBuilder()
.AddHumanMessageGuardrail("guard", new TryllHumanMessageGuardrailParams
{
StringStorage = "jailbreak_patterns",
TriggeredExit = "refuse",
NotTriggeredExit = "answer",
})
.AddCannedResponse("refuse", new TryllCannedResponseParams())
.AddGenerate("answer", new TryllGenerateParams())
.SetStartNode("guard")
.SetDefaultModelName("My Local Model")
.Build();
#include "Generated/TryllGraphBuilder.Nodes.h"
#include "Generated/TryllNodeParamsFactory.h"
auto* Subsystem = GetGameInstance()->GetSubsystem<UTryllSubsystem>();
Subsystem->RequestCreateStringStorage(
TEXT("jailbreak_patterns"),
{ TEXT(R"(ignore\s+previous\s+instructions?)"),
TEXT(R"(you\s+are\s+DAN)") });
UTryllHumanMessageGuardrailParams* GuardP = UTryllNodeParamsFactory::MakeHumanMessageGuardrailParams(this);
GuardP->bOverrideStringStorage = true;
GuardP->StringStorage = TEXT("jailbreak_patterns");
GuardP->TriggeredExit = TEXT("refuse");
GuardP->NotTriggeredExit = TEXT("answer");
FTryllGraphDescription Graph = FTryllGraphBuilder()
.AddNode(TEXT("guard"), GuardP)
.AddNode(TEXT("refuse"), UTryllNodeParamsFactory::MakeCannedResponseParams(this))
.AddNode(TEXT("answer"), UTryllNodeParamsFactory::MakeGenerateParams(this))
.SetStartNode(TEXT("guard"))
.SetDefaultModelName(TEXT("My Local Model"))
.Build();
See the full flow in How to use canned responses and guardrails.
Client bindings¶
- C++:
GraphDescription::AddHumanMessageGuardrail(name, HumanMessageGuardrailParamsT)—GraphDescription.h - Python:
GraphDescription.add_node(name, HumanMessageGuardrailParams(...))—tryll_client.graph - Unity:
TryllGraphBuilder.AddHumanMessageGuardrail(name, new TryllHumanMessageGuardrailParams{...})—Runtime/Generated/TryllGraphBuilder.Nodes.cs - Unreal:
AddHumanMessageGuardrailNode(builder, name, UTryllHumanMessageGuardrailParams*)—Generated/TryllGraphBuilder.Nodes.h
Related¶
- String Storage
- Canned Response — the common downstream
node on the
triggeredroute. - How to use canned responses and guardrails
- Server Configuration — default file
- Glossary