Thread
Represents a conversation thread with methods for posting, subscribing, and state management.
A Thread is provided to your event handlers and represents a conversation thread on any platform. You don't create threads directly — they come from handler callbacks or chat.openDM().
Properties
Prop
Type
post
Post a message to the thread. Accepts strings, structured messages, cards, and streams.
// Plain text
await thread.post("Hello!");
// Markdown
await thread.post({ markdown: "**Bold** text" });
// AST
await thread.post({ ast: root([paragraph([text("Hello")])]) });
// Card
await thread.post(Card({ title: "Hi", children: [Text("Hello")] }));
// Stream
await thread.post(result.textStream);Parameters: message: string | PostableMessage | CardJSXElement
Returns: Promise<SentMessage> — the sent message with edit(), delete(), addReaction(), and removeReaction() methods.
See Posting Messages for details on each format.
postEphemeral
Post a message visible only to a specific user.
await thread.postEphemeral(userId, "Only you can see this", {
fallbackToDM: true,
});Prop
Type
Returns: Promise<EphemeralMessage | null>
subscribe / unsubscribe
Manage thread subscriptions. Subscribed threads route all messages to onSubscribedMessage handlers.
await thread.subscribe();
await thread.unsubscribe();
const subscribed = await thread.isSubscribed();Subscriptions persist across restarts via your state adapter.
state
Store typed, per-thread state that persists across requests. State has a 30-day TTL.
// Read state
const state = await thread.state; // TState | null
// Merge into existing state
await thread.setState({ aiMode: true });
// Replace state entirely
await thread.setState({ aiMode: false }, { replace: true });startTyping
Show a typing indicator in the thread. No-op on platforms that don't support it.
await thread.startTyping();messages / allMessages
Iterate through message history.
// Newest first (auto-paginates)
for await (const msg of thread.messages) {
console.log(msg.text);
}
// Oldest first (auto-paginates)
for await (const msg of thread.allMessages) {
console.log(msg.text);
}refresh
Re-fetch messages from the API and update recentMessages.
await thread.refresh();mentionUser
Get a platform-specific @-mention string for a user.
await thread.post(`Hey ${thread.mentionUser(userId)}, check this out!`);Serialization
Threads can be serialized for workflow engines and external systems. The serialized thread includes the current message if one is available.
// Serialize
const json = thread.toJSON();
// Pass to a workflow
await workflow.start("my-workflow", {
thread: thread.toJSON(),
});The serialized format includes the thread ID, channel ID, adapter name, DM status, and the current message (if present).
Deserialization
Use bot.reviver() as a JSON.parse reviver to automatically restore Thread and Message objects from serialized payloads:
const data = JSON.parse(payload, bot.reviver());
await data.thread.post("Hello from workflow!");Under the hood, the reviver calls ThreadImpl.fromJSON() and Message.fromJSON() for any serialized objects it encounters.
SentMessage
Returned by thread.post(). Extends Message with mutation methods.
Prop
Type