CopilotKitDocs
  • Docs
  • Reference
  • Cookbook
Get Enterprise Intelligence free
CopilotKitDocs
DocsReferenceCookbook
DocsReferenceCookbook

@copilotkit/bot

@copilotkit/bot-slack

@copilotkit/bot-discord

discordrenderComponentsdefaultDiscordToolsdefaultDiscordContextDISCORD_LIMITS
ReferencebotDiscord

discord

The Discord platform adapter factory — Gateway ingress via discord.js, Components V2 egress, streaming replies, and slash-command registration.


Overview

discord(opts) returns a DiscordAdapter — the Discord implementation of the engine's PlatformAdapter boundary. It handles ingress via discord.js (Gateway WebSocket), renders the JSX vocabulary to Discord's Components V2 within per-message budgets, streams agent replies by editing the reply message in place, and registers slash commands on startup. @copilotkit/bot-discord is the only package in the stack that talks to Discord.

For app creation, tokens, and first run, see the Discord quickstart.

Signature

import { discord } from "@copilotkit/bot-discord";

function discord(opts: DiscordAdapterOptions): DiscordAdapter;

Parameters

Prop

Type

Return Value

A DiscordAdapter to pass into createBot({ adapters }). It advertises platform: "discord", ackDeadlineMs: 3000, and:

capabilities: {
  supportsStreaming: true,
  supportsModals: false,
  supportsTyping: true,
  supportsReactions: true,
  maxBlocksPerMessage: 40,
}

The capability-gated Thread methods are all backed: getMessages() via channel history fetch, lookupUser(query) via guild member search, and postFile(...) via attachment upload. Inbound file attachments are downloaded and delivered to the agent as multimodal content parts.

Usage

import { createBot } from "@copilotkit/bot";
import { discord, defaultDiscordTools, defaultDiscordContext } from "@copilotkit/bot-discord";

const bot = createBot({
  adapters: [
    discord({
      botToken: process.env.DISCORD_BOT_TOKEN!, // Bot …
      appId: process.env.DISCORD_APP_ID!,
      guildId: process.env.DISCORD_GUILD_ID,    // omit for global commands
    }),
  ],
  agent: (threadId) => makeAgent(threadId),
  tools: [...defaultDiscordTools, ...appTools],
  context: [...defaultDiscordContext, ...appContext],
});

Behavior

Ingress

The Discord listener pre-filters Gateway events to the turns the bot should answer — @-mentions in guild channels, replies in threads it owns, and DMs — so a single onMention handler covers the common cases. Conversation history is rebuilt from Discord (channel messages fetch) on every turn: Discord is the source of truth, so bot restarts don't lose conversations.

Slash Commands

On bot.start() the adapter calls the Discord REST API to register (or update) slash commands. Guild-scoped registration (guildId) is instant; global registration propagates within an hour. Commands are defined via defineBotCommand and run through the same agent pipeline as @-mention turns.

Streaming

thread.runAgent() and thread.stream(...) send an initial reply and then edit it in place as text arrives. Edit calls are queued per message with a minimum gap between flushes (default 1100 ms); long replies roll over into follow-up messages at a soft 1900-character limit (under Discord's 2000), breaking at the last newline or space and keeping fenced code blocks whole. Dangling markdown is auto-closed on each flush so the in-flight message always renders.

Components V2

When the reply contains interactive components (<Button>, <Select>, etc.) the adapter renders them using Discord's Components V2 system (available in supported channels). renderComponents maps the JSX component tree to the Discord components payload, and DISCORD_LIMITS documents the per-message budgets. The IS_COMPONENTS_V2_ENABLED flag on the message flags field must be set; the adapter sets it automatically.

Gateway Intents

The intents are fixed (not configurable): the client requests Guilds, GuildMessages, MessageContent (privileged), DirectMessages, and GuildMembers (privileged). Two of these are privileged and must be enabled in the Discord Developer Portal under Bot → Privileged Gateway Intents:

  • MessageContent — required to read the body of messages the bot receives (otherwise only the author and channel metadata are visible).
  • GuildMembers — required for user lookup; it powers Thread's lookupUser(query), which resolves members via guild.members.search.

If either privileged intent is left disabled in the portal, the bot will fail to receive message content or to look up users, respectively.

Interactions (ack-first)

Every interaction (button click, select menu choice) is acknowledged within Discord's 3-second deadline (ackDeadlineMs: 3000), then handled asynchronously. decodeInteraction extracts the opaque minted id (ck:…), the component's value, and the message ref — those are the only things that ride in the Discord payload; handler code, other props, and bind() args stay server-side.

Initialization

The underlying discord.js Client is constructed lazily — construction is side-effect-free, and bot.start() owns initialization (Gateway login + an awaited ready event to resolve the bot's own user id), so auth and config errors surface to the caller instead of firing in the background.

What's NOT in v1

  • True modal / multi-step form flows
  • OAuth / multi-server bot installation (single bot token only)
  • Durable (Redis/DB) ActionStore — in-memory only; actions expire on restart
  • Proactive posting (the bot replies only to turns it's part of)
  • Voice channel support

Related

  • renderComponents — the JSX → Components V2 mapping and per-element budgets
  • defaultDiscordTools / defaultDiscordContext — the shipped built-ins
  • DISCORD_LIMITS — per-message component and character budgets
  • Discord quickstart — app creation, token setup, first run
027b1de