v0.9.0¶
This release gives every character its own voice. The voice moves off the
speaking nodes and onto the agent as one voice profile. One workflow can
then serve a whole cast, and game code can switch a character's delivery
mode (angry, calm, whisper) mid-turn. LLM nodes can now load LoRA
adapters, a new ClassifyAttributesLLM node scores several traits of a
line in one call, and prompts can be localized through your game's own
string tables. Qwen3-TTS clones a voice in ten languages, and new Use
Cases and Model Benchmarks sections help you choose a design and a model.
The voice move, the classifier changes and the LoRA field all change the schema, and existing workflows need manual migration. See Breaking changes and behavior changes and Migrate to the agent voice before upgrading the plugin.
Highlights¶
- One voice per agent. A voice profile holds the TTS model, the speaker or reference clip, speed, language, lip sync and named delivery modes. Every speaking node of the agent uses it, so one workflow can drive many characters, each with its own voice. See Add voice output to an agent.
- Delivery modes. Define moods such as
angry,calmorwhisperon a profile and switch between them from game code at any time, even mid-turn. The new mode applies from the next sentence. See Delivery modes. - LoRA adapters on LLM nodes. Load a GGUF LoRA adapter trained for the node's model, with a scale, on any generating or classifying node. A small adapter can teach a small model a narrow job. See Generate.
- Score several traits in one call.
ClassifyAttributesLLMasks up to 16 specialist questions about a line in one batched call, with choice, true/false and 0–1 score answers written to slots. - Localized prompts from your string tables. Tick Localized on a prompt and Unity or Unreal resolves it through your own localization system before the agent is created. A language change updates live agents. See Localize prompts with your localization system.
- Qwen3-TTS. Voice cloning from a 3–10 s reference clip, in 10 languages, on the same GPU backends as the language models. See TTS models.
- Use Cases and Model Benchmarks. New docs sections that start from what the player experiences (Use Cases) and from how catalog models perform on Tryll's own jobs (Model Benchmarks).
Agent voice¶
- Voice profiles. A
VoiceProfileholds the TTS model (tts_model_name, now required), the base identity (speaker_id,reference_voiceorvoice_description),speed,lang,emit_visemesand named delivery modes. Unity has a Voice Profile asset (Create → Tryll → Voice Profile) assigned to the Voice field ofTryllAgentComponent. Unreal has a Tryll Voice Profile data asset assigned to the agent component's Voice Profile. Python passescreate_agent(graph, voice=...), and C++ setsAgentCreateOptions::voice. See Voice Profile, TryllVoiceProfile and the Blueprint catalog. - Delivery modes. A profile defines named moods. Switch with
set_delivery_mode(Python),SetDeliveryMode(C++),SetDeliveryModeAsync(Unity) or Set Delivery Mode (Unreal), with an optional 0–1 intensity.neutralis built in. What a mode can change depends on the model: a reference clip (Pocket TTS, Qwen3-TTS), a delivery clause with a low/medium/high intensity word (Maya1), or only speed (Supertonic 3). Orpheus modes must be empty. See Delivery modes by family and Clone a voice, where "one clip per mood" is now one delivery mode per mood. - Per-agent delivery override. Unity
TryllAgentComponent(OverrideVoiceDelivery/VoiceDelivery) and UnrealUTryllAgentComponent(Voice Delivery) can start one agent in a different mode without editing the shared profile asset. Changing it also switches a live agent in Play or in Chat. - Change the voice at runtime.
set_voice/SetVoice/SetVoiceAsync/ Set Voice replace the whole profile, model included, while the agent is idle. The new profile is checked and its clips are prepared before the swap, and if anything fails the old voice stays. The active mode is kept when the new profile defines it. Otherwise the new profile's default mode applies, and the acknowledgement carries a warning. See Change the voice or its delivery at runtime. - The voice is checked once, when it is set. A field the model cannot use fails with
3023 InvalidVoiceProfileand names the field. A missing TTS model is now3023. A non-emptylangon a fixed-language voice (Pocket TTS, Orpheus, Maya1) is now rejected instead of silently ignored. - Clips are prepared up front. By default every reference clip in a profile, including each mode's clip, is prepared when the voice is set, so switching mood adds no delay. Set
preparetoLazyto prepare each clip on first use. See Clip preparation. Speaknodes emit visemes.emit_visemesis on the voice, so every speaking node of a lip-synced character sends a viseme track, includingSpeaklines such as scripted refusals.- One audio stream per turn. The audio format is announced once per turn, by the first speaking node, and viseme offsets count from it across every speaking node of the turn. See Audio stream per turn.
- Agents that never speak load no TTS model, even if they have a voice.
- Model capabilities drive the editors.
ListModelsreportsexpressivenessandnum_speakersfor TTS models, and every shipped TTS model declares its capabilities. The Unity and Unreal profile editors show only the fields the chosen model accepts. See Model Management. - Maya1 delivery keywords match whole words.
unhappyno longer resolves to thehappyclause. - Diagnostics show the agent's voice. It appears under
ttsonGenerateAndSpeakand under a newvoicesection onSpeak, withdelivery_modeandintensity. The oldtts_lang/tts_voicekeys are nowlang/reference_voice. See Turn Diagnostics JSON.
Migrate to the agent voice¶
No migration helper ships. Unity drops the removed node fields from a workflow asset the next time it is saved, and Unreal drops them when an old asset loads. So record the values first.
Before upgrading the plugin, write down the TTS values of every Speak or
GenerateAndSpeak node in every workflow asset: Tts Model Name,
Speaker Id, Speed, Tts Lang, Tts Voice, Tts Voice
Description, Tts Delivery Instruction and Emit Visemes. Also note any
game code that sets these fields on node params (for example a per-character
speaker or speed) or changes them with ChangeParams / ChangeAgentParam.
Unity projects, after upgrading:
- Create one voice profile per character: Create → Tryll → Voice Profile.
- Fill it from your notes: Tts Model Name, Speaker Id, Speed, Lang (was Tts Lang), Reference Voice (was Tts Voice), Voice Description and Emit Visemes. Tts Model Name is now required. A node that left it empty used the first TTS model in the catalog, usually
Supertonic 3 (int8). Turn a Tts Delivery Instruction into a delivery mode with that Instruction, and select it from code withSetDeliveryModeAsync. - Assign the profile to the Voice field of each
TryllAgentComponentwhose workflow speaks. For characters spawned at runtime, setTryllAgentComponent.Voicebefore the agent is created. Replace code that patchedSpeakerId/Speedinto cloned node params with one profile per character. - Re-save each workflow asset so it no longer carries the removed fields.
- Replace runtime voice changes made with
ChangeParamsbySetVoiceAsync(identity) orSetDeliveryModeAsync(mood).
Unreal projects, after upgrading:
- Create one Tryll Voice Profile data asset per character and fill it from your notes, as for Unity. Check Emit Visemes for characters with lip sync. It now also covers
Speaknodes, so lines from aSpeaknode move the lips too. - Assign the profile to the Voice Profile property of each
UTryllAgentComponentwhose workflow speaks. - Open and re-save each workflow asset, and recompile Blueprints that read or set TTS fields on node params. They must not touch a removed field.
- Replace runtime voice changes made with Change Params by Set Voice (identity) or Set Delivery Mode (mood).
Python and C++ code:
- Move the
tts_*fields,speaker_id,speedandemit_visemesoffSpeakParams/GenerateAndSpeakParamsinto aVoiceProfile.tts_langbecomeslang,tts_voicebecomesreference_voice,tts_voice_descriptionbecomesvoice_description, andtts_delivery_instructionbecomes aDeliveryModewith thatinstruction. - Pass it at creation:
client.create_agent(graph, voice=profile)in Python,AgentCreateOptions::voicein C++. - Replace
change_param/ChangeParamscalls on voice fields withset_voice/SetVoiceorset_delivery_mode/SetDeliveryMode.
If two speaking nodes in one workflow had different voice settings, choose one. An agent now has exactly one voice.
LoRA adapters¶
- An
adaptationtable on every LLM node.Generate,ToolCall,ClassifyIntentLLM,ClassifyAttributesLLM,GenerateAndSpeakandSummarizetake a list of GGUF LoRA adapters (loras), each with a scale (1= as trained,0= off), up to 8 per node. Paths are relative to the storage root, like voice clips. An escaping path fails with3009 StorageOutsideRoot, and a missing file with3010 StorageFileNotFound. See Generate. - An adapter must be trained for the node's model. A file made for another model fails agent creation.
- Adapters are fixed at creation. Changing
adaptationon a live agent returns3006 ParamNotMutable. Workflows without it run on the base model as before. - Unity has a file picker for adapter paths, and the workflow validator flags an absolute or
..path as an error and a missing or non-.gguffile as a warning.
Classification¶
- New
ClassifyAttributesLLMnode. One node scores up to 16 specialist prompts in one cached, batched call. A Choice attribute writes a label and can trigger per option. A Boolean attribute writestrue/falsefor one statement. A Score attribute writes a normalised 0–1 level. Any trigger takestriggered_exit, otherwise the node takesdefault_exit. A Choice that missesthresholdormarginwritesuncertain_choice, which is one of its choice ids or the reserved#uncertain. Empty input never triggers. Engine failure followson_failure. Slots are named<output_name>_<attribute>, andnotify_clientemitsattributes_classifiedwith every measurement. Python, C++, Unity and Unreal all support it, including the editor palettes, inspectors and Dialog Lab attribute checks. ClassifyIntentLLMwrites its decision to a slot. Newoutput_name(empty = node name). The slot holds the winning id onfoundandnot_found_intenton everynot_foundpath, so aBranchcan route on it after either exit.not_found_intentalso accepts the reserved#uncertain. See Output slot.intentsis the only intent list. The comma-separatedintents_ids/intents_promptpair deprecated in v0.8.0 is removed (see Breaking changes).
Localization¶
- Localized prompts use your string tables. Tick Localized on a prompt field and the box becomes a Text ID. Before the agent is created, Unity or Unreal asks your text provider for the text and sends it. See Localize prompts with your localization system.
- A language change updates live agents. Ticked non-structural prompts (system prompt, template, instruction, acknowledge text) are updated from the next turn, and params you changed at runtime are kept. The update is all or nothing per agent. If a Text ID is missing in the new language, that agent's prompts stay as they were and
LocalizedTextFailed(Unity) /OnLocalizedTextFailed(Unreal) fires. ClassifyIntent entry prompts, files already bound and an open voice input still need the agent recreated or the input reopened. See Ship an agent in another language. - Unreal: wait for the new text.
OnLocalizedTextAppliedfires once an agent's new prompts are acknowledged, so a prefill or reset can wait for them. A server rejection of the update now also raisesOnLocalizedTextFailed. The Unreal text provider is None by default, so existing projects keep using the Tryll Locale field.
Models and catalogs¶
- Qwen3-TTS 12Hz 1.7B Base (Q4_K_M) is a public catalog voice. It clones its voice from a reference clip, so the profile's
reference_voiceis required. It speaks zh, en, de, it, pt, es, ja, ko, fr and ru throughlang, and it runs on the CPU, Vulkan and CUDA backends without ONNX Runtime. Delivery modes switch reference clips. See TTS models. - SenseVoice Multilingual and Streaming Paraformer zh-en are now public speech-to-text entries.
- LFM2.5 1.2B Thinking (Q4_K_M) joins the catalog. It always opens with a
<think>block, so it is not a good host for an immersion guard. - New Model Benchmarks section. Model cards and per-trait leaderboards for catalog models: the immersion guard (General and World classifiers), prefill and generation speed for a 1K and a 4K prompt, and VRAM at an 8K context. Treat the results as provisional.
Diagnostics and Agent Log¶
- Prefill and generation speed per node. Language-model nodes add
engine.llama_perfto turn diagnostics, with prompt and generation time and token counts for the node's context. See Turn Diagnostics JSON. - Agent Log export. Export writes the journal to one JSON file in Unity and Unreal. The file has a header describing the server, the capture and the agents, then the events with their payloads, then a turn index. The inspectors show the event's raw JSON. The file can contain player input, prompts and tool arguments, so treat it like a bug report. See Use the Agent Log and Agent Log format.
Unreal¶
- Play → Standalone Game starts its own server. A standalone game used to skip auto-launch silently and then fail every connect attempt. It now launches the bundled server on a free port, separate from the editor's server, and the server exits 60 s after the game closes. See Auto-launch the server.
- Saved assets survive node parameter changes. Workflow and agent assets saved by an older plugin load correctly after a node field is removed, renamed or given a new default. A saved
ClassifyIntentLLMCSV intent pair is converted intointentson load.
Documentation¶
- New Use Cases section. Each page starts from what the player experiences and lists the building blocks that produce it, with links to the how-to guides: Talking NPC step by step, Ambient world, Voice control, In-game assistant, and AI director, an idea we have not built yet.
- New reference pages: Voice Profile, TryllVoiceProfile, Classify Attributes (LLM) and Agent Log format. TTS models gains a per-family table of what a delivery mode can change.
Breaking changes and behavior changes¶
- The schema changed — rebuild every client. The agent voice,
ClassifyAttributesLLM, theClassifyIntentLLMchanges and LoRA adapters all change shape. Upgrade the server and every client together (Unity, Unreal, Python, C++). An older server would ignoreadaptationand quietly run the base model, so mismatched peers fail at connect: the client rejects the server's protocol version with5004 ProtocolVersionMismatch. See Wire Protocol. - One voice per agent.
SpeakandGenerateAndSpeaklosetts_model_name,speaker_id,speed,tts_lang,tts_voice,tts_voice_description,tts_delivery_instructionandemit_visemes. They keep only their text routing and chunking (min_sentence_chars,first_chunk_max_chars). A graph with a speaking node and no voice fails with3025 AgentVoiceRequired. An agent created without a voice cannot be given one later.ChangeAgentParamcan no longer change any voice field. Write down your TTS values before you upgrade the plugin, then follow Migrate to the agent voice. tts_model_nameis required. An empty name no longer means "the first TTS voice in the catalog", and a missing TTS model fails with3023 InvalidVoiceProfileinstead of3003 GraphCompilationFailed.- Fixed-language voices reject
lang. A non-emptylangon Pocket TTS, Orpheus or Maya1 fails with3023instead of being ignored. Leave it empty. - The audio format is announced once per turn. A turn with two speaking nodes no longer sends a second format frame or restarts the viseme clock. Code that reset playback on each format announcement now sees one per turn.
ClassifyIntentLLMCSV intents removed.intents_ids/intents_promptare gone, andintents(id + prompt pairs) must hold 2–26 entries. Unreal assets convert a saved CSV pair on load. If the two lists had different lengths, the missing entries are left empty and a warning is logged. Other assets that still carry a CSV pair must move it tointentsbefore upgrading. The diagnostics keyparameters.intents_idsis unchanged.- LoRA adapters are structural.
adaptationis fixed at agent creation. Changing it on a live agent returns3006 ParamNotMutable. - Unreal Play → Standalone Game launches a server. A standalone run that used to have no server now starts its own on a free port.
New error codes¶
3023 InvalidVoiceProfile— a voice profile field fails validation, names an unknown model, or uses a field the model cannot use.3024 UnknownDeliveryMode—SetAgentDeliveryModenamed a mode the voice does not define. The current mode stays.3025 AgentVoiceRequired— a speaking graph has no voice, or a voice call was made on an agent created without one.
See Error Codes for the full list.