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