Looking for the chatbot template? It's now here.

Chat

The main entry point for creating a multi-platform chat bot.

The Chat class coordinates adapters, state, and event handlers. Create one instance and register handlers for different event types.

import { Chat } from "chat";

Constructor

const bot = new Chat(config);

Prop

Type

Event handlers

onNewMention

Fires when the bot is @-mentioned in a thread it has not subscribed to. This is the primary entry point for new conversations.

bot.onNewMention(async (thread, message) => {
  await thread.subscribe();
  await thread.post("Hello!");
});

Prop

Type

onSubscribedMessage

Fires for every new message in a subscribed thread. Once subscribed, all messages (including @-mentions) route here instead of onNewMention.

bot.onSubscribedMessage(async (thread, message) => {
  if (message.isMention) {
    // User @-mentioned us in a thread we're already watching
  }
  await thread.post(`Got: ${message.text}`);
});

onNewMessage

Fires for messages matching a regex pattern in unsubscribed threads.

bot.onNewMessage(/^!help/i, async (thread, message) => {
  await thread.post("Available commands: !help, !status");
});

Prop

Type

onReaction

Fires when a user adds or removes an emoji reaction.

import { emoji } from "chat";

// Filter to specific emoji
bot.onReaction([emoji.thumbs_up, emoji.heart], async (event) => {
  if (event.added) {
    await event.thread.post(`Thanks for the ${event.emoji}!`);
  }
});

// Handle all reactions
bot.onReaction(async (event) => { /* ... */ });

Prop

Type

onAction

Fires when a user clicks a button or selects an option in a card.

// Single action
bot.onAction("approve", async (event) => {
  await event.thread.post("Approved!");
});

// Multiple actions
bot.onAction(["approve", "reject"], async (event) => { /* ... */ });

// All actions
bot.onAction(async (event) => { /* ... */ });

Prop

Type

onModalSubmit

Fires when a user submits a modal form.

bot.onModalSubmit("feedback", async (event) => {
  const comment = event.values.comment;
  if (event.relatedThread) {
    await event.relatedThread.post(`Feedback: ${comment}`);
  }
});

Prop

Type

Returns ModalResponse | undefined to control the modal after submission:

  • { action: "close" } — close the modal
  • { action: "errors", errors: { fieldId: "message" } } — show validation errors
  • { action: "update", modal: ModalElement } — replace the modal content
  • { action: "push", modal: ModalElement } — push a new modal view onto the stack

onSlashCommand

Fires when a user invokes a /command in the message composer. Currently supported on Slack.

// Specific command
bot.onSlashCommand("/status", async (event) => {
  await event.channel.post("All systems operational!");
});

// Multiple commands
bot.onSlashCommand(["/help", "/info"], async (event) => {
  await event.channel.post(`You invoked ${event.command}`);
});

// Catch-all
bot.onSlashCommand(async (event) => {
  console.log(`${event.command} ${event.text}`);
});

Prop

Type

onModalClose

Fires when a user closes a modal (requires notifyOnClose: true on the modal).

bot.onModalClose("feedback", async (event) => { /* ... */ });

onAssistantThreadStarted

Fires when a user opens a new assistant thread (Slack Assistants API). Use this to set suggested prompts, show a status indicator, or send an initial greeting.

bot.onAssistantThreadStarted(async (event) => {
  const slack = bot.getAdapter("slack") as SlackAdapter;
  await slack.setSuggestedPrompts(event.channelId, event.threadTs, [
    { title: "Get started", message: "What can you help me with?" },
  ]);
});

Prop

Type

onAssistantContextChanged

Fires when a user navigates to a different channel while the assistant panel is open (Slack Assistants API). Use this to update suggested prompts or context based on the new channel.

bot.onAssistantContextChanged(async (event) => {
  const slack = bot.getAdapter("slack") as SlackAdapter;
  await slack.setAssistantStatus(event.channelId, event.threadTs, "Updating context...");
});

The event shape is identical to onAssistantThreadStarted.

onAppHomeOpened

Fires when a user opens the bot's Home tab in Slack. Use this to publish a dynamic Home tab view.

bot.onAppHomeOpened(async (event) => {
  const slack = bot.getAdapter("slack") as SlackAdapter;
  await slack.publishHomeView(event.userId, {
    type: "home",
    blocks: [{ type: "section", text: { type: "mrkdwn", text: "Welcome!" } }],
  });
});

Prop

Type

Utility methods

webhooks

Type-safe webhook handlers keyed by adapter name. Pass these to your HTTP route handler.

bot.webhooks.slack(request, { waitUntil });
bot.webhooks.teams(request, { waitUntil });

getAdapter

Get an adapter instance by name.

const slack = bot.getAdapter("slack");

openDM

Open a direct message thread with a user.

const dm = await bot.openDM("U123456");
await dm.post("Hello via DM!");

// Or with an Author object
const dm = await bot.openDM(message.author);

channel

Get a Channel by its channel ID.

const channel = bot.channel("slack:C123ABC");

for await (const msg of channel.messages) {
  console.log(msg.text);
}

initialize / shutdown

Manually manage the lifecycle. Initialization happens automatically on the first webhook, but you can call it explicitly for non-webhook use cases.

await bot.initialize();
// ... do work ...
await bot.shutdown();

reviver

Get a JSON.parse reviver that deserializes Thread and Message objects from workflow payloads.

const data = JSON.parse(payload, bot.reviver());
await data.thread.post("Hello from workflow!");