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:
- Parses the
<action>tag, extractingname="wave" - Fires
OnActionReceivedon theEstuaryCharacter - Strips the tag from the display text (so the user sees "Sure, let me wave at you!")
- Routes the action to any registered
EstuaryActionManagerhandlers
EstuaryActionManager Component
The EstuaryActionManager component listens to characters and routes actions to handlers. Add it to any GameObject in your scene.
Inspector Setup
- Add the Estuary Action Manager component
- In Characters, drag your
EstuaryCharacter(or leave empty to auto-use the active character) - In Action Bindings, add entries for each action you want to handle:
| Action Name | On Action (UnityEvent) |
|---|---|
wave | → Animator.SetTrigger("Wave") |
sit | → Animator.SetTrigger("Sit") |
navigate | → MyScript.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
| Method | Return | Description |
|---|---|---|
Name | string | Action name (e.g., "wave") |
Parameters | IReadOnlyDictionary | All parameters |
HasParameter(name) | bool | Check if parameter exists |
GetParameter(name, default) | string | Get string parameter |
GetParameterInt(name, default) | int | Get integer parameter |
GetParameterFloat(name, default) | float | Get float parameter |
GetParameterBool(name, default) | bool | Get 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
- User Management -- Manage player identities
- API Reference: Action Components -- Full API reference