Skip to main content

Action System

Handle action tags embedded in bot responses to trigger application-side behavior like navigation, animations, or UI updates.

How Actions Work​

Estuary characters can include action tags in their text responses. These are XML-style tags that the AI embeds when it decides to perform an action:

Sure, let me show you the shop! <action name="navigate" destination="shop" />

The SDK automatically parses action tags from bot responses. When an action tag is detected:

  1. The tag is stripped from botResponse.text so you receive clean display text
  2. A characterAction event is emitted with the parsed action data

For more details on how actions are configured, see the Action Protocol platform documentation.

Listening for Actions​

The recommended approach is to listen for characterAction events on the client:

import { EstuaryClient } from '@estuary-ai/sdk';

const client = new EstuaryClient({
serverUrl: 'https://api.estuary-ai.com',
apiKey: 'est_your_api_key',
characterId: 'your-character-uuid',
playerId: 'user-123',
});

// Listen for parsed actions
client.on('characterAction', (action) => {
console.log('Action:', action.name, action.params);

switch (action.name) {
case 'navigate':
console.log('Navigating to:', action.params.destination);
// router.push(action.params.destination);
break;

case 'emote':
console.log('Playing emote:', action.params.animation);
// playAnimation(action.params.animation);
break;

case 'show_item':
console.log('Showing item:', action.params.itemId);
// openItemModal(action.params.itemId);
break;

default:
console.warn('Unhandled action:', action.name);
}
});

// botResponse.text is already cleaned -- no action tags
client.on('botResponse', (response) => {
if (response.isFinal) {
console.log('Bot:', response.text);
// Output: "Sure, let me show you the shop!"
// (action tag has been stripped)
}
});

await client.connect();
client.sendText('Take me to the shop');

CharacterAction Type​

Each characterAction event provides a CharacterAction object:

interface CharacterAction {
name: string; // Action name (e.g., "navigate", "emote")
params: Record<string, string>; // All other attributes as key-value pairs
messageId: string; // Message ID of the bot response
}

The name comes from the name attribute of the action tag. All other attributes are collected into params:

<action name="navigate" destination="shop" tab="weapons" />

Produces:

{
name: "navigate",
params: { destination: "shop", tab: "weapons" },
messageId: "msg-abc123"
}

One-Shot Parsing with parseActions()​

The SDK also exports a parseActions() utility for parsing actions from any text string outside of the streaming context:

import { parseActions } from '@estuary-ai/sdk';

const text = 'Hello! <action name="wave" speed="fast" /> How are you?';
const { actions, cleanText } = parseActions(text);

console.log(cleanText); // "Hello! How are you?"
console.log(actions); // [{ name: "wave", params: { speed: "fast" } }]

This is useful for processing stored messages or testing action parsing independently.

Common Action Patterns​

<action name="navigate" destination="shop" />
<action name="navigate" destination="inventory" tab="weapons" />

Animations and Emotes​

<action name="emote" animation="wave" />
<action name="emote" animation="think" duration="2000" />

UI Updates​

<action name="show_item" itemId="sword-001" />
<action name="open_dialog" dialogId="quest-complete" />
<action name="set_mood" mood="happy" />

Game State​

<action name="give_item" itemId="gold-coin" quantity="10" />
<action name="start_quest" questId="find-the-artifact" />
tip

The action names and attributes are entirely defined by your character's system prompt configuration. The SDK does not enforce any specific action schema -- you define what actions your character can perform and how your application handles them.

Next Steps​