Skip to content

C++ Client API Reference

Full API reference for the Tryll:: C++ client library, auto-generated from Doxygen documentation blocks in tryll/clients/cpp/include/tryll/. Browse individual classes and structs in the sidebar.

Entry points

Type Role
Tryll::Client::TryllClient TCP session — connect, configure, manage models, create agents, enumerate/save/load mutable KBs
Tryll::Client::ConnectedSession RAII pair: owns a ManagedServer + TryllClient; returned by RunAndConnect
Tryll::Client::AgentProxy Per-agent handle — SendText, receive streaming tokens, destroy
Tryll::Client::MutableKb Experimental session-scoped named store — write/query/list/export/import
Tryll::Client::AgentVariables Per-agent Variables mirror — typed setters/getters, deferred flush
Tryll::Client::AgentKvCacheStatus Aggregate residency and reusable-prefix state for an agent
Tryll::Client::GraphDescription Fluent graph builder — add typed nodes, set start node and default model
Tryll::Client::ManagedServer RAII handle that spawns tryll_server and waits for TCP readiness
Tryll::Client::ManagedServerOptions Configuration for ManagedServer::Start
Tryll::Client::MessageResult Empty placeholder reserved for future per-turn metadata. AgentProxy::SendText returns void; results arrive through the callbacks
Tryll::Client::TryllError Error type carrying a numeric code and human-readable message

Supporting types

Type Role
Tryll::Client::SessionConfig All session-configuration options, passed to CreateSession
Tryll::Client::GraphDescription::NodeDesc Single node inside a graph: name plus typed params (NodeParamsVariant)
Tryll::NodeParams::<Node>ParamsT Typed node params (FlatBuffers object-API types, e.g. GenerateParamsT, ToolCallParamsT) passed to AddXxx. Exits are string fields on these params (<exit>_exit); an empty exit routes to END
Tryll::ModelInfoT Model catalog entry returned by ListModels (FlatBuffers object-API type)
Tryll::MemorySnapshotT Server-wide RAM/VRAM snapshot returned by GetMemoryConsumption
Tryll::NodeParams::ToolDefinitionT Tool declaration, stored in ToolCallParamsT::tools on a ToolCall node
Tryll::NodeParams::ToolParamDefinitionT Single parameter within a ToolDefinitionT (name, type, description)
Tryll::Client::AgentVariableDecl Name + typed initial value, passed on CreateAgent to declare a variable
Tryll::Client::TryllClient::EmbeddedStorageInfo Embedded-storage descriptor returned by CreateEmbeddedStringStorage and CreateEmbeddedStringStorageFromStrings
Tryll::Client::MutableKbSnapshot Text-only TMKB store snapshot (vectors are never persisted)
Tryll::Client::GameMemorySnapshot Whole-session mutable-KB snapshot (save_id + stores)
Tryll::Client::MutableKbEmbedTiming Now or Lazy — required on LoadGameMemory; Unspecified is rejected

Selected method signatures

TryllClient::CreateSession

struct EngineSelection
{
    ::Tryll::ModelRole       role;
    ::Tryll::InferenceEngine engine;
};

struct SessionConfig
{
    std::vector<EngineSelection>    engines;         // optional warm-up hint
    std::vector<ModelPlacementHint> placementHints;  // optional, per model
    std::string                     gameName;
    std::string                     locale;          // BCP-47, empty = unset
    std::chrono::milliseconds       timeout = std::chrono::seconds{30};
};

void CreateSession(const SessionConfig& cfg);

The process storage root is set when the server starts (--storage-root / storage_root / mode default). Protocol v24 removed CreateSessionRequest.storage_data_folder. Managed launchers pass --project-name, --project-dir, and --storage-root when they spawn the server.

There is no engine to choose: each model's catalog entry names the engine that runs it. engines is an optional hint — the server starts the named engines at CreateSession instead of at first use, which helps when a cold start is slow. An empty list is legal and normal. Only an out-of-range ordinal is rejected (InvalidEngineSet, 2005).

// Most sessions
client.CreateSession({});

// Warm up llama.cpp and the STT engine at session creation
client.CreateSession({
    .engines = {
        {::Tryll::ModelRole_Language, ::Tryll::InferenceEngine_LlamaCpp},
        {::Tryll::ModelRole_Stt,      ::Tryll::InferenceEngine_SherpaOnnx},
    },
});

CreateAgent, CreateEmbeddedStringStorage, and CreateVoiceInput fail fast if a referenced model is not already on disk — acquire models explicitly beforehand (e.g. via DownloadModel or the editor Model Manager) rather than relying on the call itself to fetch them.

GraphDescription wiring and tools

There is no separate route list. Each node's typed params carry its exits as string fields (<exit>_exit): an empty string routes to END, and a non-empty name must match a node in the graph. Tools are ToolDefinitionT objects on the ToolCall node's tools field.

using namespace Tryll::NodeParams;

auto city = std::make_unique<ToolParamDefinitionT>();
city->name        = "city";
city->type        = "string";
city->description = "City to look up";

auto weather = std::make_unique<ToolDefinitionT>();
weather->name        = "get_weather";
weather->description = "Look up the current weather";
weather->parameters.push_back(std::move(city));

ToolCallParamsT tools;
tools.model_name          = "qwen2.5-0.5b-instruct";
tools.tools.push_back(std::move(weather));
tools.no_tool_called_exit = "chat";   // tool_called_exit left empty = END

GenerateParamsT chat;
chat.model_name = "qwen2.5-0.5b-instruct";

auto graph = Tryll::Client::GraphDescription{}
    .AddToolCall("tools", std::move(tools))
    .AddGenerate("chat", std::move(chat))
    .SetStartNode("tools");

TryllClient::GetMemoryConsumption

[[nodiscard]] ::Tryll::MemorySnapshotT GetMemoryConsumption(
    std::chrono::milliseconds timeout = std::chrono::seconds{10});

Session-scoped (must follow CreateSession) but the snapshot is server-wide. Never throws AgentBusy. See Inspect Server Memory.

AgentProxy callbacks

All callbacks are registered on an AgentProxy instance before the first SendText call. SendText is fire-and-forget: it returns void, and the turn's output arrives only through these callbacks. They fire on the reader thread — they must return quickly and must not call any blocking TryllClient or AgentProxy methods.

Dispatch priority: typed callbacks (SetOnToolCall, SetOnIntentClassified, SetOnIntentLlmClassified, SetOnPaused) take precedence. If no typed callback is registered for an incoming NodeEvent, the SetOnNodeEvent fallback fires instead.

Method Callback type Fires when
SetOnAnswerText(cb) void(string_view nodeName, string_view text, bool isDelta, bool isFinal) Each AnswerText frame during a turn. nodeName identifies the producing node (multi-sender graphs).
SetOnTurnComplete(cb) void(TurnStatus status, string_view debugInfoJson, int32_t tokensGenerated) TurnComplete arrives.
SetOnError(cb) void(const TryllError& error) Server-reported error or disconnect mid-turn. Does not fire for TurnStatus_Error turns (those arrive via SetOnTurnComplete).
SetOnToolCall(cb) void(string_view toolName, string_view argumentsJson) NodeEvent with event_type="tool_call" (ToolCall node with a notifying disposition: Notify, NotifyAndAcknowledge, Pause, PauseAndAcknowledge, or AwaitResult).
SetOnToolCallWithId(cb) void(string_view callId, string_view toolName, string_view argumentsJson) Same event, call-ID-aware — echo callId in a ToolResult passed to ResumeWithToolResult(s)(Async).
SetOnToolCallEvent(cb) void(const ToolCallEvent& event) Preferred form: an owning {callId, toolName, argumentsJson, nodeName, disposition} struct safe to capture beyond the callback (the string_view-based callbacks above alias the current frame).
SetOnIntentClassified(cb) void(const IntentClassifiedEvent&) NodeEvent with event_type="intent_classified" (ClassifyIntent, notify_client OnFound/Always).
SetOnIntentLlmClassified(cb) void(const IntentLlmClassifiedEvent&) NodeEvent with event_type="intent_llm_classified" (ClassifyIntentLLM).
SetOnPaused(cb) void(string_view nodeName, string_view pendingExit) NodeEvent with event_type="paused" — the executor paused the turn between nodes (Pause node, or a ToolCall node with disposition in Pause / PauseAndAcknowledge / AwaitResult). See How to pause and resume a turn.
SetOnNodeEvent(cb) void(string_view nodeName, string_view eventType, const vector<NodeEventKeyValue>& kvPairs) Any NodeEvent whose event_type is unrecognised or whose typed callback is not set.

Pass a default-constructed std::function to unregister a callback.

Resume(resumeNode = "") / ResumeAsync(resumeNode = "") continue a paused turn — empty follows the paused node's pending exit, non-empty jumps to that node by name. Both throw/reject with TryllError on AgentNotPaused (3012) or UnknownNode (3005). ResumeWithToolResult(s) / ResumeWithToolResult(s)Async attach a ToolResult{callId, result} batch for a paused AwaitResult call — required (and validated as a complete, unique batch) whenever AwaitResult calls are pending, or rejected with InvalidToolResults (3016). None of the Resume* overloads are reentrant-safe to call blocking from inside one of the callbacks above (they run on the reader thread); use the *Async overloads there.

// Register callbacks before the first SendText call.
agent.SetOnAnswerText([&](std::string_view /*nodeName*/, std::string_view text,
                          bool /*isDelta*/, bool isFinal) {
    std::cout << text;
    if (isFinal) std::cout << '\n';
});

agent.SetOnIntentClassified([&](const AgentProxy::IntentClassifiedEvent& ev) {
    std::cout << "Intent: " << ev.intent
              << " (record " << ev.recordId
              << ", dist " << ev.distance << ")\n";
});

// Generic fallback for any other NodeEvent types.
agent.SetOnNodeEvent([](std::string_view nodeName,
                        std::string_view eventType,
                        const std::vector<Tryll::Client::AgentProxy::NodeEventKeyValue>& kv) {
    std::cout << "[NodeEvent] " << nodeName << " / " << eventType << '\n';
    for (auto& [k, v] : kv)
        std::cout << "  " << k << "=" << v << '\n';
});

See the AgentProxy Doxygen page for the full documentation of each callback type.

AgentProxy::Variables()

Returns the agent's AgentVariables mirror — typed setters (SetInt/SetFloat/SetString/SetBool/AddToSet/RemoveFromSet/Reset) and typed getters (GetInt/GetFloat/... returning std::optional<T>). Writes update the local mirror synchronously; the wire update is batched and flushed automatically immediately before the next SendText/Resume/ChangeParams call.

auto& vars = agent.Variables();
vars.SetInt("level", 13);
vars.AddToSet("quests_reached", "lost_amulet");
std::int64_t level = vars.GetInt("level").value_or(0);

An unknown name or type mismatch throws a TryllError immediately (no wire round-trip), using the same 3013/3014 codes the server would return. (The C++ setters return void and throw on invalid input — unlike the Unity/Unreal setters, which return an FTryllError/ TryllError.)

AgentProxy KV-cache lifecycle

AgentProxy exposes PrefillKvCacheAsync / PrefillKvCache, EvictKvCacheAsync / EvictKvCache, and GetKvCacheStatusAsync / GetKvCacheStatus. The result types in tryll/AgentKvCache.h are aggregate: AgentKvCacheStatus provides applicable, residency, prefixStatus, eligibleNodeCount, and optional diagnostics; prefill adds creation/decode/reuse counts and eviction adds the evicted-context count.

Set AgentCreateOptions::kvCacheInitialization to the generated AgentKvCacheInitialization enum (AllocateOnly, Prefill, or DeferAllocation) when creating the agent. Calls are idle-only. Sending after eviction restores the cache automatically; there is no separate restore method. See Manage an Agent's KV Cache.

AgentProxy voice

An agent's voice is a generated Tryll::VoiceProfileT (from tryll/schema/voice.fbs). Pass it in AgentCreateOptions::voice when the graph has a Speak or GenerateAndSpeak node; without it, creation throws TryllError with AgentVoiceRequired (3025).

Tryll::VoiceProfileT voice;
voice.tts_model_name = "Supertonic 3 (int8)";
voice.speaker_id     = 5;

Tryll::Client::AgentCreateOptions opts;
opts.voice = std::move(voice);
auto agent = client.CreateAgent(graph, std::move(opts));

agent.SetDeliveryMode("angry", 0.8f);   // any time; from the next sentence
agent.SetVoice(otherVoice);             // idle only

SetVoiceAsync / SetVoice replace the voice (AgentBusy 3004 while a turn runs or is paused; InvalidVoiceProfile 3023 leaves the old voice in place). SetDeliveryModeAsync / SetDeliveryMode switch the delivery mode (UnknownDeliveryMode 3024). See Voice Profile.

AgentProxy dialog mutation

Append or tail-remove scripted user/assistant history without running the graph. Both calls are strict idle-only (AgentBusy 3004 while running, paused, or during a KV-cache lifecycle operation). Responses return counts; there is no TurnComplete.

struct DialogInteraction
{
    std::string userMessage;      // empty → omit user side
    std::string assistantMessage; // empty → omit assistant side; both empty → skipped
};

std::uint32_t appended = agent.AppendInteractions({
    {"", "Welcome! How can I help?"},           // assistant-only opener
    {"I need directions.", "Turn left at the well."},
});

std::uint32_t removed = agent.RemoveInteractionsFromEnd(1); // drop last interaction

Async variants: AppendInteractionsAsync, RemoveInteractionsFromEndAsync. See Seed and edit dialog history.

ExportDialog / ImportDialog capture or replace the completed dialog as a DialogSnapshot. EncodeFlatBuffer / DecodeFlatBuffer produce canonical TDLG bytes; the game owns storage. File variants SaveDialog / LoadDialog resolve relative paths against the server's process storage root and carry a caller save_id. See Export and import dialog and Save and load agent state for multi-agent envelopes, variables, and restore ordering.

Experimental mutable knowledge bases

TryllClient::EnsureMutableKb(name, schema) returns a MutableKb handle. Enumerate, SaveGameMemory, and LoadGameMemory live on TryllClient, not AgentProxy. LoadGameMemory requires MutableKbEmbedTiming::Now or Lazy — Unspecified is rejected client-side (8107). Snapshots are text-only (TMKB); first use and eager loads re-embed. Place Retrieve before WriteToMemory in the same turn if the model should see prior memory.

auto store = client.EnsureMutableKb("notes", "player_log");
store.Write({Tryll::Client::MutableKbUpsert{"g1", "garlic grows in Honeywood"}});
auto hits = store.Query("where does garlic grow");
client.SaveGameMemory("saves/slot-a.tmkb", "slot-a");
client.LoadGameMemory(
    "saves/slot-a.tmkb",
    Tryll::Client::MutableKbEmbedTiming::Now);

GPU throttling and background agents

SetInferenceThrottle tells the server how hard to yield the GPU back to your game: 0.0f = full speed (the default for a session that never calls it), 1.0f = maximum yielding. It is fire-and-forget — no request_id, no response, not even an Ack — so it is safe to call from a render or simulation loop with nothing to await. It never changes what is generated, only how fast.

// From your load loop — most-stressed session wins server-wide.
client.SetInferenceThrottle(0.0f);   // full speed
client.SetInferenceThrottle(1.0f);   // hand the GPU back

// Agents nobody waits on give way first under pressure.
Tryll::Client::AgentCreateOptions opts;
opts.workload = Tryll::AgentWorkload_Background;
auto worldLogic = client.CreateAgent(graph, opts);

Everything else the server classifies from the graph itself, per turn — streamed Generate text is protected, spoken and buffered work absorbs the slack. See Wire Protocol and Server configuration.

Headers

Header Declares
tryll/TryllClient.h TryllClient, ConnectedSession, session-level types
tryll/AgentProxy.h AgentProxy and all callback types
tryll/AgentCreateOptions.h AgentCreateOptions, including KV-cache initialization and the agent's voice
tryll/AgentKvCache.h KV-cache status and operation result types
tryll/AgentVariables.h AgentVariables, AgentVariableDecl
tryll/GraphDescription.h GraphDescription and its nested types
tryll/ManagedServer.h ManagedServer, ManagedServerOptions
tryll/MessageResult.h MessageResult
tryll/TryllError.h TryllError
tryll/MutableKb.h MutableKb handle and per-op result types
tryll/MkbSnapshot.h TMKB / GameMemory snapshot DTOs and codecs