Skip to content

Commit d650595

Browse files
authored
Merge pull request #239 from underctrl-io/ai
feat: ai plugin
2 parents a254b43 + 0264992 commit d650595

File tree

18 files changed

+893
-4
lines changed

18 files changed

+893
-4
lines changed

.github/workflows/publish-dev.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ jobs:
5959
"@commandkit/devtools:packages/devtools"
6060
"@commandkit/cache:packages/cache"
6161
"@commandkit/analytics:packages/analytics"
62+
"@commandkit/ai:packages/ai"
6263
)
6364
6465
for entry in "${PACKAGES[@]}"; do
@@ -80,6 +81,7 @@ jobs:
8081
"@commandkit/devtools"
8182
"@commandkit/cache"
8283
"@commandkit/analytics"
84+
"@commandkit/ai"
8385
)
8486
8587
for pkg in "${PACKAGES[@]}"; do

apps/test-bot/commandkit.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import { legacy } from '@commandkit/legacy';
33
import { i18n } from '@commandkit/i18n';
44
import { devtools } from '@commandkit/devtools';
55
import { cache } from '@commandkit/cache';
6+
import { ai } from '@commandkit/ai';
67

78
export default defineConfig({
89
plugins: [
910
i18n(),
1011
legacy({ skipBuiltInValidations: true }),
1112
devtools(),
1213
cache(),
14+
ai(),
1315
],
1416
});

apps/test-bot/package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,18 @@
1010
"node": "node"
1111
},
1212
"dependencies": {
13+
"@ai-sdk/google": "^1.2.19",
14+
"@commandkit/ai": "workspace:*",
1315
"@commandkit/cache": "workspace:*",
1416
"@commandkit/devtools": "workspace:*",
1517
"@commandkit/i18n": "workspace:*",
1618
"@commandkit/legacy": "workspace:*",
1719
"commandkit": "workspace:*",
1820
"discord.js": "^14.19.1",
19-
"dotenv": "^16.4.7"
21+
"dotenv": "^16.4.7",
22+
"zod": "^3.25.56"
2023
},
2124
"devDependencies": {
2225
"tsx": "^4.7.0"
2326
}
24-
}
27+
}

apps/test-bot/src/ai.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { createGoogleGenerativeAI } from '@ai-sdk/google';
2+
import { configureAI } from '@commandkit/ai';
3+
4+
const google = createGoogleGenerativeAI({
5+
apiKey: process.env.GOOGLE_API_KEY,
6+
});
7+
8+
const model = google.languageModel('gemini-2.0-flash');
9+
10+
configureAI({
11+
selectAiModel: async () => {
12+
return { model };
13+
},
14+
messageFilter: async (message) => {
15+
return (
16+
message.inGuild() && message.mentions.users.has(message.client.user.id)
17+
);
18+
},
19+
});

apps/test-bot/src/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Client } from 'discord.js';
22
import { Logger, commandkit } from 'commandkit';
3+
import './ai';
34

45
const client = new Client({
56
intents: [

apps/test-bot/src/app/commands/(leveling)/xp.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
import { ChatInputCommandContext, CommandData } from 'commandkit';
2-
import { database } from '../../../database/store.ts';
2+
import { database } from '@/database/store.ts';
33
import { cacheTag } from '@commandkit/cache';
4+
import { AiConfig, AiContext } from '@commandkit/ai';
5+
import { z } from 'zod';
46

57
export const command: CommandData = {
68
name: 'xp',
79
description: 'This is an xp command.',
810
};
911

12+
export const aiConfig: AiConfig = {
13+
description: 'Get the XP of a user in a guild.',
14+
parameters: z.object({
15+
guildId: z.string().describe('The ID of the guild.'),
16+
userId: z.string().describe('The ID of the user.'),
17+
}),
18+
};
19+
1020
async function getUserXP(guildId: string, userId: string) {
1121
'use cache';
1222

@@ -39,3 +49,26 @@ export async function chatInput({ interaction }: ChatInputCommandContext) {
3949
],
4050
});
4151
}
52+
53+
export async function ai(ctx: AiContext) {
54+
const message = ctx.message;
55+
56+
if (!message.inGuild()) {
57+
return {
58+
error: 'This tool can only be used in a guild.',
59+
};
60+
}
61+
62+
const { guildId, userId } = ctx.params as {
63+
guildId: string;
64+
userId: string;
65+
};
66+
67+
const xp = await getUserXP(guildId, userId);
68+
69+
return {
70+
userId,
71+
guildId,
72+
xp,
73+
};
74+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
title: AI Plugin
3+
description: Learn how to use the AI plugin to power your bot's commands and events.
4+
---
5+
6+
## AI Plugin
7+
8+
The AI plugin allows you to execute your bot commands using large language models. This enables you to use your bot's features entirely through natural language.
9+
10+
Please refer to the [AI Powered Commands](../../13-ai-powered-commands/01-introduction.mdx) guide for more details.
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
---
2+
title: AI Powered Commands
3+
description: Learn how to use a large language model to power your commands.
4+
---
5+
6+
## Introduction
7+
8+
CommandKit's `@commandkit/ai` plugin allows you to execute your bot commands using large language models. This enables you to use your bot's features entirely through natural language.
9+
10+
:::warning
11+
This is an experimental feature and is subject to change.
12+
:::
13+
14+
## Installation
15+
16+
```bash
17+
npm install @commandkit/ai
18+
```
19+
20+
## Usage
21+
22+
```typescript title="commandkit.config.ts"
23+
import { defineConfig } from 'commandkit';
24+
import { ai } from '@commandkit/ai';
25+
26+
export default defineConfig({
27+
plugins: [ai()],
28+
});
29+
```
30+
31+
## Setting up the AI model
32+
33+
CommandKit allows you to dynamically specify the AI model to use for your bot.
34+
35+
```typescript title="src/ai.ts"
36+
import { createGoogleGenerativeAI } from '@ai-sdk/google';
37+
import { configureAI } from '@commandkit/ai';
38+
39+
const google = createGoogleGenerativeAI({
40+
apiKey: process.env.GOOGLE_API_KEY,
41+
});
42+
43+
const model = google.languageModel('gemini-2.0-flash');
44+
45+
configureAI({
46+
// commandkit will call this function
47+
// to determine which AI model to use
48+
selectAiModel: async () => {
49+
return { model };
50+
},
51+
messageFilter: async (message) => {
52+
// only respond to messages in guilds that mention the bot
53+
return (
54+
message.inGuild() && message.mentions.users.has(message.client.user.id)
55+
);
56+
},
57+
});
58+
```
59+
60+
Now you can simply import this file in your `app.ts`,
61+
62+
```ts title="app.ts"
63+
import { Client } from 'discord.js';
64+
// simply import the ai file
65+
import './ai';
66+
67+
const client = new Client({...});
68+
69+
export default client;
70+
```
71+
72+
## Creating AI commands
73+
74+
AI commands can be created by exporting a function called `ai` from your command file. You can also export `aiConfig` object along with the `ai` function to specify the parameters for the command.
75+
76+
```typescript title="src/commands/balance.ts"
77+
import { ApplicationCommandOptionType } from 'discord.js';
78+
import { CommandData, ChatInputCommand } from 'commandkit';
79+
import { AiCommand } from '@commandkit/ai';
80+
import { z } from 'zod';
81+
82+
export const command: CommandData = {
83+
name: 'balance',
84+
description: 'Get the current balance of the user.',
85+
options: [
86+
{
87+
name: 'user',
88+
description: 'The user to get the balance for.',
89+
type: ApplicationCommandOptionType.User,
90+
},
91+
],
92+
};
93+
94+
export const aiConfig: AiConfig = {
95+
parameters: z.object({
96+
userId: z.string().describe('The ID of the user to get the balance of'),
97+
}),
98+
};
99+
100+
export const chatInput: ChatInputCommand = async (ctx) => {
101+
const { interaction } = ctx;
102+
const user = interaction.options.getUser('user');
103+
const balance = await db.getBalance(user.id);
104+
105+
await interaction.reply({
106+
content: `The balance of ${user.username} is ${balance}`,
107+
});
108+
};
109+
110+
// AI will call this function to get the balance of the user
111+
export const ai: AiCommand = async (ctx) => {
112+
const { userId } = ctx.params;
113+
const balance = await db.getBalance(userId);
114+
115+
// return object with the balance
116+
return {
117+
userId,
118+
balance,
119+
};
120+
};
121+
```
122+
123+
Now, you can simply mention the bot in a message to get the balance of the user. Eg:
124+
125+
```text
126+
@bot what is the balance of @user?
127+
```
128+
129+
AI can also call multiple commands in a single message. Eg:
130+
131+
```text
132+
@bot show me the basic details of the user @user and also include the balance of that user.
133+
```
134+
135+
The above prompt will call the built-in `getUserInfo` tool and the `balance` command.

packages/ai/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# `@commandkit/ai`
2+
3+
Supercharge your CommandKit project with AI capabilities.
4+
5+
## Installation
6+
7+
```bash
8+
npm install @commandkit/ai
9+
```
10+
11+
## Usage
12+
13+
```ts
14+
import { ai } from '@commandkit/ai';
15+
16+
export default defineConfig({
17+
plugins: [ai()],
18+
})
19+
```

packages/ai/package.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "@commandkit/ai",
3+
"version": "0.1.0",
4+
"description": "Supercharge your CommandKit bot with AI capabilities",
5+
"files": [
6+
"dist"
7+
],
8+
"main": "dist/index.js",
9+
"types": "dist/index.d.ts",
10+
"scripts": {
11+
"lint": "tsc --noEmit",
12+
"build": "tsc"
13+
},
14+
"repository": {
15+
"type": "git",
16+
"url": "git+https://github.com/underctrl-io/commandkit.git"
17+
},
18+
"keywords": [
19+
"commandkit",
20+
"ai"
21+
],
22+
"author": "twilight <[email protected]>",
23+
"license": "MIT",
24+
"bugs": {
25+
"url": "https://github.com/underctrl-io/commandkit/issues"
26+
},
27+
"homepage": "https://github.com/underctrl-io/commandkit#readme",
28+
"devDependencies": {
29+
"commandkit": "workspace:*",
30+
"discord.js": "^14.19.3",
31+
"tsconfig": "workspace:*",
32+
"typescript": "^5.7.3"
33+
},
34+
"dependencies": {
35+
"ai": "^4.3.16",
36+
"zod": "^3.25.48"
37+
}
38+
}

0 commit comments

Comments
 (0)