setChatInput: Filling the Chat Input
setChatInput fills the chat input box with a piece of text. The most typical use is choice-based interaction: put a few option buttons in a code block; when the user taps one, the line is filled into the input box, and the user confirms before sending.
Signature
type ChatInputMode = 'roleplay' | 'guide'
declare function setChatInput(
text: string,
option?: { mode?: ChatInputMode },
): Promise<'roleplay' | 'guide'>Parameters & Behavior
text is the full text to write into the input box. The operation overwrites the target input's current draft — it doesn't append, and it never auto-sends the message. Sending always stays in the user's hands.
option may only contain the optional mode field; extra fields are rejected:
mode | Target | Behavior |
|---|---|---|
omitted / roleplay | Roleplay input | Default; switches to Roleplay and fills in the text |
guide | Direct input | Only available with Deep Roleplay on; switches to Direct and fills in the text |
- On success, the Promise returns the mode actually used:
roleplayorguide - Filling one target doesn't clear the other target's existing draft
Note: the Direct input only exists when the user has Deep Roleplay enabled. Requesting guide without it rejects with Guide input requires deep roleplay mode — you can't assume users have Deep Roleplay on, so always handle the failure when using guide (show a hint, or fall back to the Roleplay input; see the example below).
Basic Example: Option Buttons
```html
<!doctype html>
<html>
<head>
<style>
.choices { display: flex; gap: 8px; }
</style>
</head>
<body>
<div class="choices">
<button data-text="I push the door open and scan the room first.">Enter carefully</button>
<button data-text="I call out her name.">Call out</button>
</div>
<p id="status" aria-live="polite"></p>
<script>
const status = document.querySelector('#status');
document.querySelectorAll('[data-text]').forEach((button) => {
button.addEventListener('click', async () => {
try {
await setChatInput(button.dataset.text);
status.textContent = 'Filled into the input box';
} catch (error) {
status.textContent = error.message;
}
});
});
</script>
</body>
</html>
```Using the Direct Input
```html
<!doctype html>
<html>
<body>
<button id="guide">Fill the Direct input</button>
<script>
document.querySelector('#guide').onclick = async () => {
const text = 'Shift the scene to nightfall and raise the tension.';
try {
await setChatInput(text, { mode: 'guide' });
} catch (error) {
// guide is unavailable without Deep Roleplay — fall back to the Roleplay input
await setChatInput(text);
}
};
</script>
</body>
</html>
```Tavern Helper Compatibility: triggerSlash & /setinput
So that existing Tavern Helper content runs without code changes, code blocks also get the compatibility function triggerSlash, currently supporting its most common /setinput usage:
declare function triggerSlash(command: string): Promise<string>await triggerSlash('/setinput I push the door open and step inside.');Equivalent to:
await setChatInput('I push the door open and step inside.');- The command name is case-insensitive
- On success it returns an empty string, matching Tavern Helper's calling convention
- Any command other than
/setinputrejects withOnly the /setinput slash command is supported
For new content, prefer setChatInput — clearer semantics, and it can specify the target input.
Capability Check & Error Handling
Confirm the function exists before calling, and handle Promise rejections (validation failures, operation failures, or the 10-second timeout all reject):
if (typeof window.setChatInput !== 'function') {
// Not supported here — hide the buttons or degrade to plain text
} else {
try {
await window.setChatInput('Text to fill in');
} catch (error) {
console.error(error.message);
}
}Tips
- Give users a status hint like the basic example does (filled / failure reason) for a more complete experience
- Content already using
/setinputneeds no rewrite —triggerSlashkeeps working