Skip to main content

Action System

AI characters can trigger actions in your Unity scene by embedding XML tags in their responses. Use actions to drive animations, gameplay logic, navigation, sound effects, and UI from natural conversation.

How It Works

When the AI character responds with text like:

Sure, let me wave at you! <action name="wave" />

The SDK:

  1. Parses the <action> tag, extracting name="wave"
  2. Fires OnActionReceived on the EstuaryCharacter
  3. Strips the tag from the display text (so the user sees "Sure, let me wave at you!")
  4. Routes the action to any registered EstuaryActionManager handlers

EstuaryActionManager Component

The EstuaryActionManager component listens to characters and routes actions to handlers. Add it to any GameObject in your scene.

Inspector Setup

  1. Add the Estuary Action Manager component
  2. In Characters, drag your EstuaryCharacter (or leave empty to auto-use the active character)
  3. In Action Bindings, add entries for each action you want to handle:
Action NameOn Action (UnityEvent)
waveAnimator.SetTrigger("Wave")
sitAnimator.SetTrigger("Sit")
navigateMyScript.HandleNavigate

Code Setup

using Estuary;
using Estuary.Models;

public class CharacterActions : MonoBehaviour
{
[SerializeField] private EstuaryActionManager actionManager;
[SerializeField] private Animator animator;

void Start()
{
// Listen for any action
actionManager.OnAnyActionReceived += HandleAction;
}

void HandleAction(AgentAction action)
{
switch (action.Name)
{
case "wave":
animator.SetTrigger("Wave");
break;

case "navigate":
var target = action.GetParameter("target");
NavigateTo(target);
break;

case "emote":
var type = action.GetParameter("type", "happy");
var intensity = action.GetParameterFloat("intensity", 1f);
PlayEmote(type, intensity);
break;
}
}
}

Dynamic Character Binding

// Add a character at runtime
actionManager.AddCharacter(newCharacter);

// Remove a character
actionManager.RemoveCharacter(oldCharacter);

// Invoke an action programmatically (same path as AI actions)
actionManager.InvokeAction("wave");

Direct Event Handling

You can also handle actions directly on EstuaryCharacter without the EstuaryActionManager:

character.OnActionReceived += (AgentAction action) =>
{
Debug.Log($"Action: {action.Name}");
foreach (var param in action.Parameters)
{
Debug.Log($" {param.Key} = {param.Value}");
}
};

AgentAction API

MethodReturnDescription
NamestringAction name (e.g., "wave")
ParametersIReadOnlyDictionaryAll parameters
HasParameter(name)boolCheck if parameter exists
GetParameter(name, default)stringGet string parameter
GetParameterInt(name, default)intGet integer parameter
GetParameterFloat(name, default)floatGet float parameter
GetParameterBool(name, default)boolGet boolean parameter

Action Tag Format

Actions use self-closing XML tags:

<!-- Basic action -->
<action name="wave" />

<!-- Action with parameters -->
<action name="navigate" target="door" speed="walk" />

<!-- Multiple actions in one response -->
I'll walk over and wave. <action name="navigate" target="player" /> <action name="wave" />

The name attribute is required. All other attributes become parameters.


Stripping Actions from Text

By default, EstuaryCharacter strips action tags from the response text before updating CurrentPartialResponse. This prevents tags from showing in your chat UI.

To disable stripping:

// In Inspector: uncheck "Strip Actions From Text"
// Or in code:
character.StripActionsFromText = false;

To manually strip actions:

using Estuary.Utilities;

string raw = "Hello! <action name=\"wave\" />";
string clean = ActionParser.StripActions(raw);
// clean = "Hello!"

Configuring Actions on Characters

Actions are defined in your character's configuration in the Estuary Dashboard. The LLM uses these definitions to know when to emit actions. See Action Protocol for details.


Next Steps