Skip to content

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

ts
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:

modeTargetBehavior
omitted / roleplayRoleplay inputDefault; switches to Roleplay and fills in the text
guideDirect inputOnly available with Deep Roleplay on; switches to Direct and fills in the text
  • On success, the Promise returns the mode actually used: roleplay or guide
  • 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

markdown
```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

markdown
```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:

ts
declare function triggerSlash(command: string): Promise<string>
js
await triggerSlash('/setinput I push the door open and step inside.');

Equivalent to:

js
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 /setinput rejects with Only 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):

js
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 /setinput needs no rewrite — triggerSlash keeps working