showcase/shell-docs/src/content/reference/bot/classes/Thread.mdx
A Thread is the per-conversation handle passed to every handler, tool context, and interaction context. It posts UI (JSX from the component vocabulary or plain strings), drives the agent run loop, resolves human-in-the-loop choices, and exposes platform power through capability-gated methods that degrade gracefully on surfaces that don't support them.
interface Thread {
readonly platform: string;
post(ui: Renderable): Promise<MessageRef>;
update(ref: MessageRef, ui: Renderable): Promise<MessageRef>;
delete(ref: MessageRef): Promise<void>;
stream(src: string | AsyncIterable<string>): Promise<MessageRef>;
runAgent(input?: {
context?: ContextEntry[];
tools?: BotTool[];
prompt?: string;
}): Promise<MessageRef | undefined>;
resume(value: unknown): Promise<MessageRef | undefined>;
awaitChoice<T = unknown>(ui: Renderable): Promise<T>;
getMessages(): Promise<ThreadMessage[]>;
lookupUser(query: string): Promise<PlatformUser | undefined>;
postFile(args: {
bytes: Uint8Array;
filename: string;
title?: string;
altText?: string;
}): Promise<{ ok: boolean; fileId?: string; error?: string }>;
}
bot.onMention(async ({ thread, message }) => {
// Run the agent with extra per-run context:
await thread.runAgent({
context: [
{ description: "Requesting user", value: message.user.name ?? message.user.id },
],
});
});
// Inside a tool: read the thread, then block on approval.
async handler({ summary }, { thread }) {
const choice = await thread.awaitChoice<{ confirmed: boolean }>(
<ConfirmWrite action={summary} />,
);
return choice ?? { confirmed: false }; // serialized for the agent automatically
}
getMessages / lookupUser / postFile delegate to the adapter when supported and degrade gracefully ([] / undefined / { ok: false }) when not, so the same tool runs on any surface.runAgent's tools and context apply to that run only, layered on top of the bot-level defaults.agent.messages are rebuilt from Slack history each turn; the platform is the source of truth, so bot restarts don't lose conversations.ctx.threadawaitChoice