Skip to content

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.

String storage kinds

CannedResponseNode accepts any string storage kind (List, Map, Multimap) and uses the list view — values are iterated by position. Key-aware selection (picking a response by a runtime intent key) is planned as future work.

For intent-driven response routing today, use IntentToInstructionNode to inject a tone directive and let the Generate node produce the response.

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 response list. Structural because it materialises the underlying StringStorage at construction.
selection_strategy CannedResponseSelectionStrategy 2 How the next canned response is chosen from the storage list.

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
default default_exit Default exit target after emitting a canned response. Empty string = END.

Source resolution

Priority order: string_storage (named session storage) → inline_strings (authored inline) → server default file (default_canned_responses_path in server-config.json).

Exit routes

Route Fires when
default Always — the node never branches. Set default_exit to another node name to continue, or leave it empty to terminate the turn (END).

Side effects

  • Appends the chosen response to the current turn as the assistant's reply.
  • Emits one AnswerText frame (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.graph import (
    GraphDescription, HumanMessageGuardrailParams,
    CannedResponseParams, GenerateParams,
)

# 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", HumanMessageGuardrailParams(
        string_storage="jailbreak_patterns",
        triggered_exit="refuse",
        not_triggered_exit="answer",
    ))
    .add_node("refuse", CannedResponseParams(
        string_storage="refusal_lines",
        default_exit="",   # 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;

// 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
HumanMessageGuardrailParamsT guardP;
guardP.string_storage    = "jailbreak_patterns";
guardP.triggered_exit    = "refuse";
guardP.not_triggered_exit = "answer";

CannedResponseParamsT refuseP;
refuseP.string_storage = "refusal_lines";
// refuseP.default_exit = ""; // empty = END (the default)

GenerateParamsT answerP;
// answerP.default_exit = ""; // empty = END (the default)

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
    {
        StringStorage = "refusal_lines",
    })
    .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("refusal_lines"),
    { TEXT("I can't help with that request."),
      TEXT("That's outside what I can assist with.") });

UTryllHumanMessageGuardrailParams* GuardP = UTryllNodeParamsFactory::MakeHumanMessageGuardrailParams(this);
GuardP->bOverrideStringStorage = true;
GuardP->StringStorage    = TEXT("jailbreak_patterns");
GuardP->TriggeredExit    = TEXT("refuse");
GuardP->NotTriggeredExit = TEXT("answer");

UTryllCannedResponseParams* RefuseP = UTryllNodeParamsFactory::MakeCannedResponseParams(this);
RefuseP->bOverrideStringStorage = true;
RefuseP->StringStorage = TEXT("refusal_lines");

UTryllGenerateParams* AnswerP = UTryllNodeParamsFactory::MakeGenerateParams(this);

FTryllGraphDescription Graph = FTryllGraphBuilder()
    .AddNode(TEXT("guard"),  GuardP)
    .AddNode(TEXT("refuse"), RefuseP)
    .AddNode(TEXT("answer"), AnswerP)
    .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::AddCannedResponse(name, CannedResponseParamsT)GraphDescription.h
  • Python: GraphDescription.add_node(name, CannedResponseParams(...))tryll_client.graph
  • Unity: TryllGraphBuilder.AddCannedResponse(name, new TryllCannedResponseParams{...})Runtime/Generated/TryllGraphBuilder.Nodes.cs
  • Unreal: AddCannedResponseNode(builder, name, UTryllCannedResponseParams*)Generated/TryllGraphBuilder.Nodes.h