Voxta supports scripting in scenarios, scenarios, events and actions. Scripts use JavaScript modules, and supports most modern features of JavaScript. Scripts can be used to generate replies, modify state, and interact with the app running the chat.
Because scripts are modules, you can import { chat} from "@voxta";
to access Voxta’s chat state, and you can use import
with scenario scripts (import { myCode } from "./my_file";
). Scripts live for the duration of the chat instance, so if you exit the chat, variables will be reset; use chat.setFlags()
and chat.variables
to persist data across chat sessions.
Triggers
Scripts must export a function called trigger
, that will be called when the event or action happens.
import { chat } from "@voxta";
export function trigger(e) {
// Your code here
}
The chat
object
You can import the chat
object from the @voxta
package to act on the current chat.
Sending a message
You can use script to generate replies. Here is an example of all possible reply types you can see. See Messages for more information.
export function trigger(e) {
// Message types:
chat.instructions('Instructions');
chat.note('Note');
chat.secret('Secret');
chat.event('Event');
chat.story('Story');
// Reply as one of the participants:
chat.userMessage('User');
chat.characterMessage('Character');
chat.roleMessage('main', 'Your message here');
// Customize the reply, e.g. generate a secret using story writer:
chat.customMessage({
role: 'Secret',
text: 'Generated Secret',
useStoryWriter: true,
maxNewTokens: 10,
maxSentences: 5,
});
}
Examples:
- Trigger a reply as the user (you):
import { chat } from "@voxta";
export function trigger(e) {
chat.userMessage('Hey, How are you?');
}
- Trigger a reply as a character:
import { chat } from "@voxta";
export function trigger(e) {
chat.characterMessage('Hey, I am Voxta, nice to meet you!');
}
3.Trigger a reply as a character with an assigned scenario role.
import { chat } from "@voxta";
export function trigger(e) {
chat.roleMessage('role2', 'How are you doing today?');
}
Character
You can get the main character by doing e.character
import { chat } from "@voxta";
export function trigger(e) {
const name = e.character.name;
}
You can also access other characters by their role, for example chat.roles.role1
.
import { chat } from "@voxta";
export function trigger(e) {
const name = chat.roles.role1.name;
}
User
Get the user’s name using e.user.name
.
import { chat } from "@voxta";
export function trigger(e) {
const name = e.user.name;
}
Arguments
Get the action invocation arguments using e.arguments["some_name"]
or e.arguments.some_name
.
Note: Arguments can only be defined by providers at the moment.
import { chat } from "@voxta";
export function trigger(e) {
const speed = e.arguments.speed;
}
Stateful variables and flags
You can use variables
and flags
to store data across chat sessions. variables
is a map (dictionary) in which you can store values of integers, strings, booleans or floats. Flags are a set of values that can be present or missing, and can then be used to filter contexts and actions (see Flags).
export function trigger(e) {
// Set a variable
chat.variables.myVariable = 123;
// Or
chat.set("myVariable", 123);
// Get a variable, remember that it can be undefined!
const myVariable1 = chat.variables.myVariable;
// Or, using a default value
const myVariable2 = chat.get("myVariable", 0);
// Set a single flag
chat.setFlag('my_flag');
// Set multiple flag (set flag, set enum flag, unset flag)
chat.setFlags('my_flag', 'my_enum_flag.enum_value', '!another_flag');
// Check flags
if (chat.hasFlag('my_flag')) {
// Do something
}
};
It is often a good idea to initialize values in your scenario initialization script, for example:
import { chat } from "@voxta";
chat.addEventListener('start', () => {
chat.variables.myVariable = 0;
});
Because those are normal variables, you can also do things like chat.variables.counter++
or chat.variables.score += 5
when they are correctly initialized.
Expiring flags
You can set flags that expire after a certain amount of time. This is useful for temporary flags that should only be active for a short period of time, such as cooldowns.
export function trigger(e) {
// Set a flag that expires in 10 conversation messages (excluding events)
chat.setFlag('cooldown_flag', { messages: 10 });
// Set a flag that expires in 2 minutes
chat.setFlag('cooldown_flag', { seconds: 2 * 60 });
};
Enable or disable roles
Use this to toggle whether a character assigned to a role is included in the chat or not.
export function trigger(e) {
chat.setRoleEnabled("role2", true);
};
App Triggers
This is a very powerful way to interact with the app running your chat. See your application’s documentation for more details on the triggers it provides.
export function trigger(e) {
// Trigger an app event, provide arguments as strings, booleans or floats
chat.appTrigger('my_event', "arg1", "arg2");
};
You can also run app triggers in the messages queue, for example if you want a sound to play after some messages.
export function trigger(e) {
chat.queueAppTrigger('my_event', "arg1", "arg2");
};
Chat Time
You can get the time in seconds since the chat started using chat.time
.
The e
object
The e
object is passed to the trigger
function and contains information about the action and message.
Message
You can read the role and text of the incoming message that triggered the script using e.message
.
export function trigger(e) {
// NOTE: Role can be User, Assistant, Story, etc.
const role = e.message.role;
const text = e.message.text;
};
When the script is triggered by a character message, you can read the character’s name and scenario role using e.character
.
export function trigger(e) {
// NOTE: This is the scenario role, e.g. role1
const scenarioRole = e.character.scenarioRole;
const name = e.character.name;
};
You can also access id
, senderId
(the character or user ID that sent the message), index
(the index of the message), conversationIndex
(only counting user and character messages), and role
(which can be Assistant
, User
, Event
etc.).
Chat Flow
You can force the next reply to be a specific character or user, overriding the normal flow of the chat.
import { chat } from "@voxta";
export function trigger(e) {
// Force the next reply to be from a specific character
e.chatFlow(chat.roles.main);
// Force the next reply to be from the user
e.chatFlow(chat.user);
};
Evaluate Next Event
By default, when an event is evaluated, no other events are evaluated. You can force the next event to be evaluated by calling e.evaluateNextEvent()
. This can be useful when you want an event to evaluate before others or if you need multiple events to work in tandem.
export function trigger(e) {
// Instead of stopping, the next valid event will be executed
e.evaluateNextEvent();
};
The character
object
The character
object has these properties:
id
: The character’s unique identifier.name
: The character’s name.scenarioRole
: The character’s role in the scenario.assets
: A list of asset paths for that character.
Import and Export
You can create reusable functions and values in scenario scripts. For example, in your scenario script you could define a function like this in a file named lib
:
import { chat } from "@voxta";
export function winRound(e, points) {
const newScore = chat.set("score", chat.get("score", 0) + points);
chat.note(`${e.character.name} won this round! The score is now: ${score} points`);
};
In your trigger, you can now use it like this:
import { winRound } from './lib';
export function trigger(e) {
winRound(e, 10);
};
You can also export variables, however remember than if you expert a scalar (e.g. export let score = 5;
) you cannot update it, due to the way modules work. You should do instead export let score = { value: 5 };
and then update it as score.value += 10;
. Do prefer chat variables for anything that should be persisted.
Event listeners
You can listen to events in the chat using chat.addEventListener(event, callback)
. The callback will be called when the event happens. You can use this to trigger actions or modify the chat state.
List: start, userMessageReceived generating speechStart speechComplete
Init event (init
)
The init
event is triggered when starting a session, this is typically used to initialize local variables.
import { chat } from "@voxta";
chat.addEventListener('init', () => {
console.log("Initializing...");
});
Start event (start
)
The start
event is triggered when the chat begins, before any messages are sent.
import { chat } from "@voxta";
chat.addEventListener('start', () => {
console.log("Chat started!");
});
Transcription started event (transcriptionStarted
)
The transcriptionStarted
event is triggered when the user starts talking (at least two words).
import { chat } from "@voxta";
chat.addEventListener('transcriptionStarted', (e) => {
console.log(`User started talking...`);
});
Transcription finished event (transcriptionFinished
)
The transcriptionFinished
event is triggered when the user starts talking (at least two words).
import { chat } from "@voxta";
chat.addEventListener('transcriptionFinished', (e) => {
if (e.text) {
console.log(`User said: ${e.text}`);
} else {
console.log(`User stopped talking...`);
}
});
User message received event (userMessageReceived
)
The userMessageReceived
event is triggered when the user sends a message.
import { chat } from "@voxta";
chat.addEventListener('userMessageReceived', (e) => {
console.log(`User message received: ${e.message.text}`;
});
You can re-write the user’s message when receiving userMessageReceived
:
chat.addEventListener("userMessageReceived", (e) => {
e.rewriteUserMessage(e.message.text.replace(/John/, 'Jane'));
});
Generating speech event (generating
)
The generating
event is triggered when the chat is generating a reply.
import { chat } from "@voxta";
chat.addEventListener('generating', (e) => {
console.log(`Generating reply from ${e.character.name}...`);
});
Speech start event (speechStart
)
The speechStart
event is triggered when the chat starts speaking. Not triggered if voice is disabled.
import { chat } from "@voxta";
chat.addEventListener('speechStart', (e) => {
console.log(`Speech chunk from ${e.character.name}: ${e.text}`);
});
Speech complete event (speechComplete
)
The speechComplete
event is triggered when the chat finishes speaking. Triggered even when the voice is disabled.
import { chat } from "@voxta";
chat.addEventListener('speechComplete', (e) => {
console.log(`Speech completed for ${e.character.name}.`);
});