Skip to main content
The @commandkit/ai plugin integrates AI capabilities into your CommandKit bot using the Vercel AI SDK. Enable natural language command execution, conversational interactions, and intelligent responses powered by any AI model.

Installation

npm install @commandkit/ai ai

Setup

1

Import and configure the plugin

Import the AI plugin and configure it with your preferred AI model.
src/index.ts
import { CommandKit } from 'commandkit';
import { ai, configureAI } from '@commandkit/ai';
import { google } from '@ai-sdk/google';

// Configure AI behavior
configureAI({
  selectAiModel: async (ctx, message) => ({
    model: google('gemini-2.0-flash-exp'),
    maxSteps: 5,
  }),
});

new CommandKit({
  client,
  plugins: [ai()],
});
2

Create AI-enabled commands

Define commands that can be executed by AI using natural language.
src/commands/weather.ts
import { z } from 'zod';
import type { AiCommand } from '@commandkit/ai';

export const data = {
  name: 'weather',
  description: 'Get weather information for a location',
};

export const aiConfig = {
  description: 'Fetches current weather for a specified location',
  inputSchema: z.object({
    location: z.string().describe('City name or coordinates'),
    units: z.enum(['celsius', 'fahrenheit']).optional(),
  }),
};

export const ai: AiCommand<typeof aiConfig> = async ({ ai }) => {
  const { location, units = 'celsius' } = ai.params;
  
  // Fetch weather data
  const weather = await fetchWeather(location, units);
  
  return {
    success: true,
    data: `Weather in ${location}: ${weather.temp}° ${units}, ${weather.condition}`,
  };
};
3

Interact with AI

Users can now mention your bot and interact using natural language.
User: @YourBot what's the weather in London?
Bot: Weather in London: 15° celsius, Partly cloudy

Configuration

Customize AI behavior using configureAI():
selectAiModel
function
required
Function that selects the AI model to use for processing messages.Parameters:
  • ctx - AI context object
  • message - Discord message that triggered the AI
Returns: Object with:
  • model - The AI model from Vercel AI SDK
  • maxSteps - Maximum tool call steps (optional)
  • tools - Additional custom tools (optional)
  • Other AI SDK options
selectAiModel: async (ctx, message) => ({
  model: google('gemini-2.0-flash-exp'),
  maxSteps: 5,
  temperature: 0.7,
})
messageFilter
function
Filter which messages should be processed by AI.Default: Processes messages that mention the bot and don’t start with a command prefix.
messageFilter: async (commandkit, message) => {
  // Only respond in specific channels
  return message.channel.id === 'ai-channel-id';
}
prepareSystemPrompt
function
Customize the system prompt sent to the AI model.
prepareSystemPrompt: async (ctx, message) => {
  return 'You are a helpful Discord bot assistant...';
}
preparePrompt
function
Customize the user prompt or conversation history.
preparePrompt: async (ctx, message) => {
  return message.content;
}
onResult
function
Handle the AI response before sending it to Discord.
onResult: async (ctx, message, result) => {
  await message.reply(result.text);
}
onError
function
Handle errors during AI processing.
onError: async (ctx, message, error) => {
  console.error('AI Error:', error);
  await message.reply('Sorry, I encountered an error.');
}
disableBuiltInTools
boolean
default:"false"
Disable built-in tools like getAvailableCommands, getUserById, etc.
disableBuiltInTools: true

Built-in Tools

The AI plugin includes several built-in tools accessible from @commandkit/ai:
import { defaultTools } from '@commandkit/ai';

defaultTools.getAvailableCommands  // Get list of bot commands
defaultTools.getUserById           // Fetch user information
defaultTools.getChannelById        // Get channel details
defaultTools.getGuildById          // Get server information
defaultTools.getMemberById         // Get member details
defaultTools.getCurrentClientInfo  // Get bot information
defaultTools.createEmbed           // Create Discord embeds

Custom Tools

Add custom tools for the AI to use:
import { tool } from 'ai';
import { z } from 'zod';

configureAI({
  selectAiModel: async (ctx, message) => ({
    model: google('gemini-2.0-flash-exp'),
    tools: {
      calculateAge: tool({
        description: 'Calculate age from birth year',
        parameters: z.object({
          birthYear: z.number(),
        }),
        execute: async ({ birthYear }) => {
          const age = new Date().getFullYear() - birthYear;
          return { age };
        },
      }),
    },
  }),
});

Context API

Access AI context in your commands:
src/commands/example.ts
import { useAI, useAIContext } from '@commandkit/ai';

export const ai: AiCommand<typeof aiConfig> = async ({ ai }) => {
  // Access AI parameters
  const params = ai.params;
  
  // Access message and client
  const message = ai.message;
  const client = ai.client;
  
  // Use the store for temporary data
  ai.store.set('key', 'value');
  
  return { success: true };
};

Hooks

import { useAI } from '@commandkit/ai';

const aiPlugin = useAI();
await aiPlugin.executeAI(message);

Advanced Examples

Multi-step Commands

src/commands/playlist.ts
import { z } from 'zod';
import type { AiCommand } from '@commandkit/ai';

export const aiConfig = {
  description: 'Create and manage music playlists',
  inputSchema: z.object({
    action: z.enum(['create', 'add', 'remove', 'list']),
    playlistName: z.string().optional(),
    song: z.string().optional(),
  }),
};

export const ai: AiCommand<typeof aiConfig> = async ({ ai }) => {
  const { action, playlistName, song } = ai.params;
  
  switch (action) {
    case 'create':
      await db.playlists.create({ name: playlistName });
      return { success: true, message: `Created playlist: ${playlistName}` };
    
    case 'add':
      await db.playlists.addSong(playlistName, song);
      return { success: true, message: `Added ${song} to ${playlistName}` };
    
    // ... other actions
  }
};

Context-aware Responses

src/index.ts
configureAI({
  prepareSystemPrompt: async (ctx, message) => {
    const userStats = await db.getUserStats(message.author.id);
    
    return `You are a helpful Discord bot. The user has been a member for ${userStats.memberDays} days and has sent ${userStats.messageCount} messages.`;
  },
  
  selectAiModel: async (ctx, message) => ({
    model: google('gemini-2.0-flash-exp'),
    maxSteps: 10,
  }),
});

Best Practices

Validate Inputs

Use Zod schemas to validate AI command parameters and ensure type safety.

Set Step Limits

Configure maxSteps to prevent excessive tool calls and control costs.

Handle Errors

Always implement onError to gracefully handle AI failures.

Filter Messages

Use messageFilter to limit AI processing to relevant channels or users.

TypeScript Support

Full type inference for AI command parameters:
import type { AiCommand, AiCommandContext } from '@commandkit/ai';

export const aiConfig = {
  inputSchema: z.object({
    userId: z.string(),
  }),
};

// Parameters are automatically typed
export const ai: AiCommand<typeof aiConfig> = async ({ ai }) => {
  ai.params.userId; // ✅ string (type-safe)
  ai.params.unknown; // ❌ TypeScript error
};

API Reference

ai(options?)

Creates the AI plugin instance. Returns: [AiPlugin, AiCliPlugin]

configureAI(config)

Configures global AI behavior. See Configuration for all options.

useAI()

Returns the active AI plugin instance. Throws: Error if AI plugin is not registered.

useAIContext()

Returns the current AI context within a command execution. Returns: AiContext

executeAI(message)

Manually triggers AI processing for a message. Parameters:
  • message - Discord.js Message object
Returns: Promise<void>

Build docs developers (and LLMs) love