Back to Copilotkit

Slack

showcase/shell-docs/src/content/docs/channels/platforms/slack.mdx

1.64.13.5 KB
Original Source

Connect Slack yourself with the Slack adapter. It runs over Socket Mode by default, so no public URL is needed for local development.

Install

bash
npm install @copilotkit/channels @copilotkit/runtime @tanstack/ai @tanstack/ai-openai

Credentials

From your Slack app:

bash
SLACK_BOT_TOKEN=xoxb-...   # Bot User OAuth token
SLACK_APP_TOKEN=xapp-...   # App-level token, for Socket Mode

# The runtime runs every channel, so a CopilotKit Intelligence key is required
# even for a direct adapter (free tier available).
COPILOTKIT_API_KEY=cpk-...

Connect

ts
import { createChannel } from "@copilotkit/channels";
import { slack, defaultSlackContext } from "@copilotkit/channels/slack";
import { CopilotRuntime, CopilotKitIntelligence } from "@copilotkit/runtime/v2";
import { createCopilotNodeListener } from "@copilotkit/runtime/v2/node";
import { agent } from "./agent"; // your TanStack AI agent, see the Quickstart

const channel = createChannel({
  name: "support-bot",
  agent,
  // Slack output-formatting guidance so replies render well in Slack.
  context: [...defaultSlackContext],
  adapters: [
    slack({
      botToken: process.env.SLACK_BOT_TOKEN!,
      appToken: process.env.SLACK_APP_TOKEN!,
      respondTo: {
        directMessages: true,
        appMentions: { reply: "thread" },
        threadReplies: "mentionsOnly",
      },
    }),
  ],
});

channel.onMessage(async ({ thread, message }) => {
  await thread.runAgent({ prompt: message.text });
});

// The runtime drives the channel — it starts the Slack adapter, you don't call
// channel.start() yourself. A CopilotKit Intelligence key runs every channel,
// direct adapters included (free tier available); `ready()` activates it.
const runtime = new CopilotRuntime({
  agents: {},
  intelligence: new CopilotKitIntelligence({
    // apiUrl and wsUrl default to the managed Intelligence platform. Override
    // both together only for a self-hosted deployment.
    apiKey: process.env.COPILOTKIT_API_KEY!,
  }),
  identifyUser: () => ({ id: "demo-user", name: "Demo User" }),
  channels: [channel],
});

const listener = createCopilotNodeListener({ runtime });
await listener.channels.ready();

respondTo controls when the bot answers: DMs, mentions, and whether it keeps listening in a thread it is part of.

Streaming

The Slack adapter streams replies as they are produced. The streaming option picks the transport:

  • "native" (default) uses Slack's chat.startStream in threads, and falls back automatically in flat DMs or workspaces where the streaming API is not available.
  • "legacy" edits a single message with repeated chat.update calls.
ts
slack({
  botToken: process.env.SLACK_BOT_TOKEN!,
  appToken: process.env.SLACK_APP_TOKEN!,
  streaming: "native",
});
<Callout type="info" title="Declare slash commands in the manifest"> A `/command` only reaches your bot if it is declared in your Slack app manifest with the same name you pass to `defineChannelCommand`. See [commands and reactions](/channels/commands-and-reactions). </Callout>

Built-in tools and context

The Slack adapter ships helpers you can spread into your channel: a set of tools (including a Slack user-lookup tool) and context that guides Slack formatting and tagging.

ts
import { slack, defaultSlackTools, defaultSlackContext } from "@copilotkit/channels/slack";

createChannel({
  name: "support-bot",
  agent,
  tools: [...defaultSlackTools],
  context: [...defaultSlackContext],
  adapters: [slack({ /* ...credentials */ })],
});