Canned Response¶
The Canned Response node emits a fixed reply chosen from a
string storage according to its
selection_strategy, and ends its turn without invoking a
language model. Use it for scripted
answers, refusal lines, and branches where you do not want the cost or
variability of a generation pass.
NodeType: CannedResponse.
Parameters¶
All parameters are optional. The node resolves its string source in priority order; the first matching source wins.
Source resolution (priority order)¶
| Priority | Key | Mutable | Description |
|---|---|---|---|
| 1 | string_storage |
Yes | Name of a string storage created earlier in the session via CreateStringStorageRequest. Can be rebound at runtime via ChangeParam. |
| 2 | response_0, response_1, ... |
No | Inline responses directly on the node params. At least one must be present to take this path. |
| 3 | (none) | — | The server default file (default_canned_responses_path in server-config.json) is loaded lazily. |
Selection behaviour¶
After the source is resolved, the node picks one string from that
source each time it runs and emits it. The selection_strategy param
controls how that index is chosen.
| Key | Mutable | Default | Description |
|---|---|---|---|
selection_strategy |
Yes | random |
How the node picks a response from the resolved source. random — uniform random pick each run. first — always the first entry (deterministic; useful in tests). round_robin — cycles through entries in order; the internal counter resets when string_storage is rebound. |
Exit routes¶
| Route | Fires when |
|---|---|
default |
Always — the node never branches. Wire this to "END" to terminate the turn, or to another node to continue. |
Side effects¶
- Appends the chosen response to the current turn as the assistant's reply.
- Emits one
AnswerTextframe (non-streaming:is_delta = false,is_final = true) with the full response.
No model inference, no KV-cache work, no network I/O beyond the
AnswerText frame itself.
Minimum working example¶
from tryll_client import GraphDescription, NodeType
# 1. Create the storage first
client.create_string_storage(
name="refusal_lines",
strings=[
"I can't help with that request.",
"That's outside what I can assist with.",
],
)
# 2. Reference it from the node
graph = (
GraphDescription()
.add_node("guard", NodeType.HumanMessageGuardrail,
{"string_storage": "jailbreak_patterns"})
.add_node("refuse", NodeType.CannedResponse,
{"string_storage": "refusal_lines"})
.add_node("answer", NodeType.Generate)
.wire("guard", "triggered", "refuse")
.wire("guard", "not_triggered", "answer")
.wire("refuse", "default", "END")
.wire("answer", "default", "END")
.set_start_node("guard")
.set_default_model_name("My Local Model")
)
agent = client.create_agent(graph)
namespace TC = Tryll::Client;
// 1. Create the storage first
client.CreateStringStorage("refusal_lines", {
"I can't help with that request.",
"That's outside what I can assist with.",
});
// 2. Reference it from the node
TC::GraphDescription graph;
graph.AddNode("guard", TC::NodeType::HumanMessageGuardrail,
{{"string_storage", "jailbreak_patterns"}})
.AddNode("refuse", TC::NodeType::CannedResponse,
{{"string_storage", "refusal_lines"}})
.AddNode("answer", TC::NodeType::Generate)
.Wire("guard", "triggered", "refuse")
.Wire("guard", "not_triggered", "answer")
.Wire("refuse", "default", "END")
.Wire("answer", "default", "END")
.SetStartNode("guard")
.SetDefaultModelName("My Local Model");
auto agent = client.CreateAgent(graph);
auto* subsystem = GetGameInstance()->GetSubsystem<UTryllSubsystem>();
subsystem->RequestCreateStringStorage(
TEXT("refusal_lines"),
{ TEXT("I can't help with that request."),
TEXT("That's outside what I can assist with.") });
FTryllGraphDescription Graph = FTryllGraphBuilder()
.AddNode(TEXT("guard"), ETryllNodeType::HumanMessageGuardrail,
{{TEXT("string_storage"), TEXT("jailbreak_patterns")}})
.AddNode(TEXT("refuse"), ETryllNodeType::CannedResponse,
{{TEXT("string_storage"), TEXT("refusal_lines")}})
.AddNode(TEXT("answer"), ETryllNodeType::Generate)
.Wire(TEXT("guard"), TEXT("triggered"), TEXT("refuse"))
.Wire(TEXT("guard"), TEXT("not_triggered"), TEXT("answer"))
.Wire(TEXT("refuse"), TEXT("default"), TEXT("END"))
.Wire(TEXT("answer"), TEXT("default"), TEXT("END"))
.SetStartNode(TEXT("guard"))
.SetDefaultModelName(TEXT("My Local Model"))
.Build();
See the full flow in How to use canned responses and guardrails.
Client bindings¶
- C++:
Tryll::Client::GraphDescription::AddNode(name, NodeType::CannedResponse, params)—GraphDescription.h - Python:
tryll_client.GraphDescription.add_node(name, NodeType.CannedResponse, params)—graph.py - Unreal: add an
FTryllNodeDescwithType = CannedResponsetoFTryllGraphDescription.Nodes—TryllGraphDescription.h
Related¶
- String Storage
- Human-Message Guardrail — the common upstream node.
- How to use canned responses and guardrails
- Server Configuration — default file
- Glossary