AI Context and Hooks
CommandKit's AI system provides powerful context management and built-in tools to enhance your AI-powered commands.
AI Context
The AiContext
class provides comprehensive access to the AI execution environment:
Context Properties
import { AiCommand } from '@commandkit/ai';
export const ai: AiCommand<typeof aiConfig> = async (ctx) => {
// AI-generated parameters based on your schema
const params = ctx.ai.params;
// Original Discord message that triggered the AI
const message = ctx.message;
// Discord client instance
const client = ctx.client;
// CommandKit instance
const commandkit = ctx.commandkit;
// Key-value store for temporary data
const store = ctx.store;
};
Using the Store
The context store allows you to persist data during command execution:
export const ai: AiCommand<typeof aiConfig> = async (ctx) => {
// Store data
ctx.store.set('startTime', Date.now());
ctx.store.set('userPreferences', { theme: 'dark', lang: 'en' });
// Retrieve data
const startTime = ctx.store.get('startTime');
const preferences = ctx.store.get('userPreferences');
// Check if data exists
if (ctx.store.has('processedUsers')) {
// Handle already processed users
}
// Delete data
ctx.store.delete('temporaryData');
};
AI Hooks
CommandKit provides several hooks to interact with the AI system:
useAIContext()
Access the current AI context from anywhere in your code:
import { useAIContext } from '@commandkit/ai';
function someUtilityFunction() {
try {
const ctx = useAIContext();
console.log('Current AI parameters:', ctx.ai.params);
return ctx.message.author.id;
} catch (error) {
// Not in an AI context
return null;
}
}
useAI()
Get access to the AI plugin instance:
import { useAI } from '@commandkit/ai';
async function executeAICommand(message: Message) {
const aiPlugin = useAI();
await aiPlugin.executeAI(message);
}
Built-in AI Tools
CommandKit provides several built-in tools that the AI can use to gather information:
Available Tools
getAvailableCommands
- Lists all available commandsgetChannelById
- Fetches channel information by IDgetCurrentClientInfo
- Gets information about the botgetGuildById
- Fetches guild information by IDgetUserById
- Fetches user information by ID
Example Tool Usage
The AI can automatically use these tools. For example, if a user asks "What commands are available?", the AI will use the getAvailableCommands
tool:
// This happens automatically when the AI needs command information
const commands = await getAvailableCommands.execute({}, {});
console.log(commands);
// Output: [
// { name: 'ping', description: 'Check bot latency', category: 'utility', supportsAI: false },
// { name: 'greet', description: 'Greet a user', category: 'social', supportsAI: true },
// // ... more commands
// ]
Creating Custom Tools
You can create custom tools for the AI to use:
import { createTool } from '@commandkit/ai';
import { z } from 'zod';
export const getWeather = createTool({
name: 'getWeather',
description: 'Get current weather information for a location',
parameters: z.object({
location: z.string().describe('The city or location to get weather for'),
units: z.enum(['celsius', 'fahrenheit']).default('celsius'),
}),
async execute(ctx, params) {
const { location, units } = params;
// Fetch weather data from an API
const weatherData = await fetchWeatherAPI(location);
return {
location,
temperature: units === 'celsius' ? weatherData.tempC : weatherData.tempF,
condition: weatherData.condition,
humidity: weatherData.humidity,
windSpeed: weatherData.windSpeed,
};
},
});
Tool Parameters
Tools support comprehensive parameter validation:
export const calculateTax = createTool({
name: 'calculateTax',
description: 'Calculate tax amount for a given price and tax rate',
parameters: z.object({
price: z.number().positive().describe('The base price amount'),
taxRate: z
.number()
.min(0)
.max(1)
.describe('Tax rate as decimal (e.g., 0.08 for 8%)'),
currency: z.string().default('USD').describe('Currency code'),
}),
async execute(ctx, params) {
const { price, taxRate, currency } = params;
const taxAmount = price * taxRate;
const total = price + taxAmount;
return {
basePrice: price,
taxRate: taxRate * 100, // Convert to percentage
taxAmount,
total,
currency,
};
},
});
Advanced Context Usage
Accessing Discord Objects
The AI context provides access to all Discord.js objects:
export const ai: AiCommand<typeof aiConfig> = async (ctx) => {
const { message, client } = ctx;
// Access guild information
if (message.inGuild()) {
const guild = message.guild;
const member = message.member;
console.log(`Guild: ${guild.name}`);
console.log(
`Member roles: ${member.roles.cache.map((r) => r.name).join(', ')}`,
);
}
// Access channel information
const channel = message.channel;
if (channel.isTextBased()) {
console.log(`Channel: ${channel.name || 'DM'}`);
}
// Access bot information
const botUser = client.user;
console.log(`Bot: ${botUser.username}#${botUser.discriminator}`);
};
Error Handling in Context
Implement robust error handling in your AI commands:
export const ai: AiCommand<typeof aiConfig> = async (ctx) => {
try {
const { userId } = ctx.ai.params;
// Attempt to fetch user
const user = await ctx.client.users.fetch(userId).catch(() => null);
if (!user) {
await ctx.message.reply('❌ User not found.');
return;
}
// Process the user
await processUser(user);
} catch (error) {
// Log error with context
console.error('AI command error:', {
command: 'example',
userId: ctx.message.author.id,
guildId: ctx.message.guildId,
error: error.message,
});
await ctx.message.reply('❌ An unexpected error occurred.');
}
};
Context Lifecycle
Understanding the AI context lifecycle helps with proper resource management:
export const ai: AiCommand<typeof aiConfig> = async (ctx) => {
// 1. Context is created when AI processes the message
console.log('AI context created');
// 2. Parameters are set based on AI model output
console.log('Parameters:', ctx.ai.params);
// 3. Your command executes
await performAction(ctx.ai.params);
// 4. Context is cleaned up automatically
// Note: Store data is automatically cleared after execution
};
Best Practices
- Resource Cleanup: The context store is automatically cleared, but clean up external resources manually
- Error Boundaries: Always wrap potentially failing operations in try-catch blocks
- Validation: Validate AI-generated parameters even with Zod schemas
- Logging: Use the context information for detailed logging
- Performance: Avoid storing large objects in the context store
export const ai: AiCommand<typeof aiConfig> = async (ctx) => {
// Good: Validate critical parameters
const { amount } = ctx.ai.params;
if (amount <= 0 || amount > 1000000) {
await ctx.message.reply('❌ Invalid amount specified.');
return;
}
// Good: Log operations with context
console.log(
`Processing payment: ${amount} for user ${ctx.message.author.id}`,
);
// Good: Handle external API failures
try {
const result = await processPayment(amount);
await ctx.message.reply(`✅ Payment processed: ${result.transactionId}`);
} catch (error) {
console.error('Payment failed:', error);
await ctx.message.reply('❌ Payment processing failed. Please try again.');
}
};