{"slug": "building-ai-discord-bots-with-neurolink", "title": "Building AI Discord Bots with NeuroLink", "summary": "A developer built a fully-featured AI Discord bot using Discord.js and NeuroLink's generation API. The bot includes slash commands, multi-turn conversations, AI-powered moderation, and production deployment, with NeuroLink handling AI generation. The tutorial covers setup, configuration, and integration of NeuroLink as the AI backend.", "body_md": "You will build a fully-featured AI Discord bot using Discord.js and NeuroLink's generation API. By the end of this tutorial, you will have slash commands, multi-turn conversations, AI-powered moderation, and production deployment -- all using NeuroLink as the AI backend.\n\nTip:This tutorial builds a custom Discord bot from scratch. NeuroLink does not provide a built-in Discord integration -- you will build the bot infrastructure yourself using Discord.js, with NeuroLink handling AI generation.\n\n{: .prompt-tip }\n\nThis tutorial requires several npm packages for building Discord bots:\n\n```\nnpm install @juspay/neurolink discord.js\nnpm install dotenv\nnpm install -D typescript @types/node ts-node nodemon\n```\n\n**Required Packages:**\n\n`@juspay/neurolink`\n\n- NeuroLink SDK for AI generation`discord.js`\n\n(v14.x) - Discord's official JavaScript library`dotenv`\n\n- Environment variable management`typescript`\n\nand `@types/node`\n\n- TypeScript support`ts-node`\n\nand `nodemon`\n\n- Development toolsBefore we begin, ensure you have the following:\n\nImportant: This tutorial uses Discord.js v14.x. If you're upgrading from v13 or earlier, review the[Discord.js v14 migration guide].\n\nFirst, we need to create a Discord application and bot user through the Discord Developer Portal.\n\nUnder the Bot section, configure these essential settings:\n\n```\nPrivileged Gateway Intents:\n- MESSAGE CONTENT INTENT: Enabled (required for reading messages)\n- SERVER MEMBERS INTENT: Enabled (if tracking member events)\n- PRESENCE INTENT: Optional (for user status features)\n```\n\nNavigate to OAuth2 > URL Generator and select:\n\n`bot`\n\n, `applications.commands`\n\n`Send Messages`\n\n, `Read Message History`\n\n, `Use Slash Commands`\n\n, `Embed Links`\n\n, `Attach Files`\n\nCopy the generated URL and use it to invite your bot to your test server.\n\nLet's initialize our project and install the necessary dependencies.\n\n```\nmkdir neurolink-discord-bot\ncd neurolink-discord-bot\nnpm init -y\n```\n\nInstall the required packages:\n\n```\nnpm install discord.js @juspay/neurolink dotenv\nnpm install -D typescript @types/node ts-node nodemon\n```\n\nInitialize TypeScript:\n\n```\nnpx tsc --init\n```\n\nUpdate your `tsconfig.json`\n\n:\n\n```\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"commonjs\",\n    \"lib\": [\"ES2022\"],\n    \"outDir\": \"./dist\",\n    \"rootDir\": \"./src\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"resolveJsonModule\": true\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n```\n\nOrganize your project with a clean structure:\n\n```\nneurolink-discord-bot/\n├── src/\n│   ├── index.ts           # Main entry point\n│   ├── config.ts          # Configuration\n│   ├── commands/          # Slash commands\n│   │   ├── index.ts\n│   │   ├── ask.ts\n│   │   ├── chat.ts\n│   │   └── summarize.ts\n│   ├── events/            # Discord event handlers\n│   │   ├── ready.ts\n│   │   └── interactionCreate.ts\n│   ├── services/          # NeuroLink integration\n│   │   ├── neurolink.ts\n│   │   └── conversation.ts\n│   └── utils/             # Helper functions\n│       ├── embed.ts\n│       └── logger.ts\n├── .env\n├── package.json\n└── tsconfig.json\n```\n\nCreate a `.env`\n\nfile in your project root:\n\n```\nDISCORD_TOKEN=your_discord_bot_token\nDISCORD_CLIENT_ID=your_application_client_id\nNEUROLINK_API_KEY=your_neurolink_api_key\n```\n\nCreate `src/config.ts`\n\n:\n\n``` python\nimport dotenv from 'dotenv';\ndotenv.config();\n\nexport const config = {\n  discord: {\n    token: process.env.DISCORD_TOKEN!,\n    clientId: process.env.DISCORD_CLIENT_ID!,\n  },\n  neurolink: {\n    apiKey: process.env.NEUROLINK_API_KEY!,\n  },\n};\n\n// Validate required environment variables\nconst requiredEnvVars = ['DISCORD_TOKEN', 'DISCORD_CLIENT_ID', 'NEUROLINK_API_KEY'];\nfor (const envVar of requiredEnvVars) {\n  if (!process.env[envVar]) {\n    throw new Error(`Missing required environment variable: ${envVar}`);\n  }\n}\n```\n\nCreate the NeuroLink service layer in `src/services/neurolink.ts`\n\n:\n\n``` js\nimport { NeuroLink } from '@juspay/neurolink';\nimport { config } from '../config';\n\nconst neurolink = new NeuroLink();\n\nexport interface ChatMessage {\n  role: 'user' | 'assistant' | 'system';\n  content: string;\n}\n\nexport interface GenerateOptions {\n  systemPrompt?: string;\n  maxTokens?: number;\n  temperature?: number;\n}\n\nexport async function generateResponse(\n  prompt: string,\n  options: GenerateOptions = {}\n): Promise<string> {\n  const {\n    systemPrompt = 'You are a helpful Discord bot assistant. Be concise, friendly, and informative.',\n    maxTokens = 1000,\n    temperature = 0.7,\n  } = options;\n\n  try {\n    const result = await neurolink.generate({\n      input: { text: prompt },\n      systemPrompt,\n      provider: 'openai',\n      model: 'gpt-4o-mini',\n      maxTokens,\n      temperature,\n    });\n\n    return result?.content ?? 'I could not generate a response.';\n  } catch (error) {\n    console.error('NeuroLink API error:', error);\n    throw new Error('Failed to generate AI response');\n  }\n}\n\nexport async function generateChatResponse(\n  messages: ChatMessage[],\n  systemPrompt?: string\n): Promise<string> {\n  // Build conversation text from message history\n  const conversationText = messages\n    .map((msg) => `${msg.role}: ${msg.content}`)\n    .join('\\n');\n\n  try {\n    const result = await neurolink.generate({\n      input: { text: conversationText },\n      systemPrompt: systemPrompt || 'You are a helpful assistant.',\n      provider: 'openai',\n      model: 'gpt-4o-mini',\n      maxTokens: 1000,\n      temperature: 0.7,\n    });\n\n    return result?.content ?? 'I could not generate a response.';\n  } catch (error) {\n    console.error('NeuroLink API error:', error);\n    throw new Error('Failed to generate AI response');\n  }\n}\n\nexport async function summarizeText(text: string): Promise<string> {\n  return generateResponse(text, {\n    systemPrompt: 'Summarize the following text concisely while preserving key information.',\n    maxTokens: 500,\n    temperature: 0.3,\n  });\n}\n```\n\nFor multi-turn conversations, we need to track message history. Create `src/services/conversation.ts`\n\n:\n\n``` js\nimport { ChatMessage } from './neurolink';\n\ninterface Conversation {\n  messages: ChatMessage[];\n  lastActivity: number;\n  channelId: string;\n  userId: string;\n}\n\nclass ConversationManager {\n  private conversations: Map<string, Conversation> = new Map();\n  private readonly maxMessages = 20;\n  private readonly timeoutMs = 30 * 60 * 1000; // 30 minutes\n\n  private getKey(userId: string, channelId: string): string {\n    return `${userId}-${channelId}`;\n  }\n\n  getConversation(userId: string, channelId: string): ChatMessage[] {\n    const key = this.getKey(userId, channelId);\n    const conversation = this.conversations.get(key);\n\n    if (!conversation) {\n      return [];\n    }\n\n    // Check if conversation has expired\n    if (Date.now() - conversation.lastActivity > this.timeoutMs) {\n      this.conversations.delete(key);\n      return [];\n    }\n\n    return conversation.messages;\n  }\n\n  addMessage(userId: string, channelId: string, message: ChatMessage): void {\n    const key = this.getKey(userId, channelId);\n    let conversation = this.conversations.get(key);\n\n    if (!conversation) {\n      conversation = {\n        messages: [],\n        lastActivity: Date.now(),\n        channelId,\n        userId,\n      };\n      this.conversations.set(key, conversation);\n    }\n\n    conversation.messages.push(message);\n    conversation.lastActivity = Date.now();\n\n    // Trim old messages if exceeding limit\n    if (conversation.messages.length > this.maxMessages) {\n      conversation.messages = conversation.messages.slice(-this.maxMessages);\n    }\n  }\n\n  clearConversation(userId: string, channelId: string): void {\n    const key = this.getKey(userId, channelId);\n    this.conversations.delete(key);\n  }\n\n  // Cleanup expired conversations periodically\n  cleanup(): void {\n    const now = Date.now();\n    for (const [key, conversation] of this.conversations.entries()) {\n      if (now - conversation.lastActivity > this.timeoutMs) {\n        this.conversations.delete(key);\n      }\n    }\n  }\n}\n\nexport const conversationManager = new ConversationManager();\n\n// Run cleanup every 10 minutes\nsetInterval(() => conversationManager.cleanup(), 10 * 60 * 1000);\n```\n\nCreate `src/commands/index.ts`\n\nto handle command registration:\n\n``` js\nimport { REST, Routes, SlashCommandBuilder } from 'discord.js';\nimport { config } from '../config';\n\nexport const commands = [\n  new SlashCommandBuilder()\n    .setName('ask')\n    .setDescription('Ask the AI a question')\n    .addStringOption((option) =>\n      option\n        .setName('question')\n        .setDescription('Your question for the AI')\n        .setRequired(true)\n    ),\n\n  new SlashCommandBuilder()\n    .setName('chat')\n    .setDescription('Have a conversation with the AI')\n    .addStringOption((option) =>\n      option\n        .setName('message')\n        .setDescription('Your message to the AI')\n        .setRequired(true)\n    ),\n\n  new SlashCommandBuilder()\n    .setName('summarize')\n    .setDescription('Summarize recent channel messages')\n    .addIntegerOption((option) =>\n      option\n        .setName('count')\n        .setDescription('Number of messages to summarize (default: 20)')\n        .setMinValue(5)\n        .setMaxValue(100)\n    ),\n\n  new SlashCommandBuilder()\n    .setName('clear')\n    .setDescription('Clear your conversation history with the AI'),\n\n  new SlashCommandBuilder()\n    .setName('help')\n    .setDescription('Show available commands and how to use them'),\n];\n\nexport async function registerCommands(): Promise<void> {\n  const rest = new REST().setToken(config.discord.token);\n\n  try {\n    console.log('Registering slash commands...');\n\n    await rest.put(Routes.applicationCommands(config.discord.clientId), {\n      body: commands.map((cmd) => cmd.toJSON()),\n    });\n\n    console.log('Slash commands registered successfully!');\n  } catch (error) {\n    console.error('Error registering commands:', error);\n    throw error;\n  }\n}\n```\n\nCreate `src/commands/ask.ts`\n\n:\n\n``` js\nimport { ChatInputCommandInteraction, EmbedBuilder } from 'discord.js';\nimport { generateResponse } from '../services/neurolink';\n\nexport async function handleAskCommand(\n  interaction: ChatInputCommandInteraction\n): Promise<void> {\n  const question = interaction.options.getString('question', true);\n\n  await interaction.deferReply();\n\n  try {\n    const response = await generateResponse(question);\n\n    const embed = new EmbedBuilder()\n      .setColor(0x5865f2)\n      .setTitle('AI Response')\n      .setDescription(response)\n      .setFooter({\n        text: `Asked by ${interaction.user.username}`,\n        iconURL: interaction.user.displayAvatarURL(),\n      })\n      .setTimestamp();\n\n    await interaction.editReply({ embeds: [embed] });\n  } catch (error) {\n    console.error('Error in ask command:', error);\n    await interaction.editReply({\n      content: 'Sorry, I encountered an error while processing your question. Please try again.',\n    });\n  }\n}\n```\n\nCreate `src/commands/chat.ts`\n\n:\n\n``` js\nimport { ChatInputCommandInteraction, EmbedBuilder } from 'discord.js';\nimport { generateChatResponse, ChatMessage } from '../services/neurolink';\nimport { conversationManager } from '../services/conversation';\n\nconst CHAT_SYSTEM_PROMPT = `You are a friendly and helpful Discord bot assistant named NeuroBot.\nYou can engage in natural conversations, answer questions, help with coding, and provide information.\nKeep responses concise but informative. Use markdown formatting when appropriate.\nRemember context from previous messages in the conversation.`;\n\nexport async function handleChatCommand(\n  interaction: ChatInputCommandInteraction\n): Promise<void> {\n  const message = interaction.options.getString('message', true);\n  const userId = interaction.user.id;\n  const channelId = interaction.channelId;\n\n  await interaction.deferReply();\n\n  try {\n    // Get existing conversation history\n    const history = conversationManager.getConversation(userId, channelId);\n\n    // Add user's new message\n    const userMessage: ChatMessage = { role: 'user', content: message };\n    conversationManager.addMessage(userId, channelId, userMessage);\n\n    // Generate response with full history\n    const response = await generateChatResponse(\n      [...history, userMessage],\n      CHAT_SYSTEM_PROMPT\n    );\n\n    // Store assistant's response in history\n    conversationManager.addMessage(userId, channelId, {\n      role: 'assistant',\n      content: response,\n    });\n\n    const embed = new EmbedBuilder()\n      .setColor(0x57f287)\n      .setDescription(response)\n      .setFooter({\n        text: `Conversation with ${interaction.user.username} | Use /clear to reset`,\n        iconURL: interaction.user.displayAvatarURL(),\n      });\n\n    await interaction.editReply({ embeds: [embed] });\n  } catch (error) {\n    console.error('Error in chat command:', error);\n    await interaction.editReply({\n      content: 'Sorry, I encountered an error. Please try again.',\n    });\n  }\n}\n```\n\nCreate `src/commands/summarize.ts`\n\n:\n\n``` js\nimport {\n  ChatInputCommandInteraction,\n  EmbedBuilder,\n  TextChannel,\n  ChannelType,\n} from 'discord.js';\nimport { summarizeText } from '../services/neurolink';\n\nexport async function handleSummarizeCommand(\n  interaction: ChatInputCommandInteraction\n): Promise<void> {\n  const count = interaction.options.getInteger('count') || 20;\n\n  if (interaction.channel?.type !== ChannelType.GuildText) {\n    await interaction.reply({\n      content: 'This command can only be used in text channels.',\n      ephemeral: true,\n    });\n    return;\n  }\n\n  await interaction.deferReply();\n\n  try {\n    const channel = interaction.channel as TextChannel;\n    const messages = await channel.messages.fetch({ limit: count });\n\n    // Filter out bot messages and format for summarization\n    const humanMessages = messages\n      .filter((msg) => !msg.author.bot && msg.content.length > 0)\n      .reverse()\n      .map((msg) => `${msg.author.username}: ${msg.content}`)\n      .join('\\n');\n\n    if (!humanMessages) {\n      await interaction.editReply({\n        content: 'No messages found to summarize.',\n      });\n      return;\n    }\n\n    const summary = await summarizeText(humanMessages);\n\n    const embed = new EmbedBuilder()\n      .setColor(0xfee75c)\n      .setTitle(`Summary of Last ${count} Messages`)\n      .setDescription(summary)\n      .setFooter({\n        text: `Requested by ${interaction.user.username}`,\n        iconURL: interaction.user.displayAvatarURL(),\n      })\n      .setTimestamp();\n\n    await interaction.editReply({ embeds: [embed] });\n  } catch (error) {\n    console.error('Error in summarize command:', error);\n    await interaction.editReply({\n      content: 'Sorry, I could not summarize the messages. Please try again.',\n    });\n  }\n}\n```\n\nCreate `src/events/ready.ts`\n\n:\n\n``` js\nimport { Client, ActivityType } from 'discord.js';\n\nexport function handleReady(client: Client<true>): void {\n  console.log(`Bot is online as ${client.user.tag}`);\n  console.log(`Serving ${client.guilds.cache.size} server(s)`);\n\n  // Set bot status\n  client.user.setPresence({\n    activities: [\n      {\n        name: '/help for commands',\n        type: ActivityType.Listening,\n      },\n    ],\n    status: 'online',\n  });\n}\n```\n\nCreate `src/events/interactionCreate.ts`\n\n:\n\n``` js\nimport { Interaction, EmbedBuilder } from 'discord.js';\nimport { handleAskCommand } from '../commands/ask';\nimport { handleChatCommand } from '../commands/chat';\nimport { handleSummarizeCommand } from '../commands/summarize';\nimport { conversationManager } from '../services/conversation';\n\nexport async function handleInteraction(interaction: Interaction): Promise<void> {\n  if (!interaction.isChatInputCommand()) return;\n\n  const { commandName } = interaction;\n\n  try {\n    switch (commandName) {\n      case 'ask':\n        await handleAskCommand(interaction);\n        break;\n\n      case 'chat':\n        await handleChatCommand(interaction);\n        break;\n\n      case 'summarize':\n        await handleSummarizeCommand(interaction);\n        break;\n\n      case 'clear':\n        conversationManager.clearConversation(\n          interaction.user.id,\n          interaction.channelId\n        );\n        await interaction.reply({\n          content: 'Your conversation history has been cleared!',\n          ephemeral: true,\n        });\n        break;\n\n      case 'help':\n        await handleHelpCommand(interaction);\n        break;\n\n      default:\n        await interaction.reply({\n          content: 'Unknown command.',\n          ephemeral: true,\n        });\n    }\n  } catch (error) {\n    console.error(`Error handling command ${commandName}:`, error);\n\n    const errorMessage = 'An error occurred while processing your command.';\n    if (interaction.deferred || interaction.replied) {\n      await interaction.editReply({ content: errorMessage });\n    } else {\n      await interaction.reply({ content: errorMessage, ephemeral: true });\n    }\n  }\n}\n\nasync function handleHelpCommand(interaction: Interaction): Promise<void> {\n  if (!interaction.isChatInputCommand()) return;\n\n  const embed = new EmbedBuilder()\n    .setColor(0x5865f2)\n    .setTitle('NeuroLink Bot Commands')\n    .setDescription('Here are all available commands:')\n    .addFields(\n      {\n        name: '/ask <question>',\n        value: 'Ask a one-off question to the AI',\n      },\n      {\n        name: '/chat <message>',\n        value: 'Have a conversation with the AI (remembers context)',\n      },\n      {\n        name: '/summarize [count]',\n        value: 'Summarize recent messages in the channel',\n      },\n      {\n        name: '/clear',\n        value: 'Clear your conversation history',\n      },\n      {\n        name: '/help',\n        value: 'Show this help message',\n      }\n    )\n    .setFooter({ text: 'Powered by NeuroLink AI' });\n\n  await interaction.reply({ embeds: [embed], ephemeral: true });\n}\n```\n\nCreate `src/index.ts`\n\n:\n\n``` js\nimport { Client, GatewayIntentBits, Partials } from 'discord.js';\nimport { config } from './config';\nimport { registerCommands } from './commands';\nimport { handleReady } from './events/ready';\nimport { handleInteraction } from './events/interactionCreate';\n\nconst client = new Client({\n  intents: [\n    GatewayIntentBits.Guilds,\n    GatewayIntentBits.GuildMessages,\n    GatewayIntentBits.MessageContent,\n    GatewayIntentBits.GuildMembers,\n  ],\n  partials: [Partials.Message, Partials.Channel],\n});\n\n// Event handlers\nclient.once('ready', (c) => handleReady(c));\nclient.on('interactionCreate', handleInteraction);\n\n// Error handling\nclient.on('error', (error) => {\n  console.error('Discord client error:', error);\n});\n\nprocess.on('unhandledRejection', (error) => {\n  console.error('Unhandled promise rejection:', error);\n});\n\n// Start the bot\nasync function main(): Promise<void> {\n  try {\n    await registerCommands();\n    await client.login(config.discord.token);\n  } catch (error) {\n    console.error('Failed to start bot:', error);\n    process.exit(1);\n  }\n}\n\nmain();\n```\n\nProtect your API usage with rate limiting. Create `src/utils/rateLimiter.ts`\n\n:\n\n```\ninterface RateLimitEntry {\n  count: number;\n  resetTime: number;\n}\n\nclass RateLimiter {\n  private limits: Map<string, RateLimitEntry> = new Map();\n  private readonly maxRequests: number;\n  private readonly windowMs: number;\n\n  constructor(maxRequests = 10, windowMs = 60000) {\n    this.maxRequests = maxRequests;\n    this.windowMs = windowMs;\n  }\n\n  isRateLimited(userId: string): boolean {\n    const now = Date.now();\n    const entry = this.limits.get(userId);\n\n    if (!entry || now > entry.resetTime) {\n      this.limits.set(userId, {\n        count: 1,\n        resetTime: now + this.windowMs,\n      });\n      return false;\n    }\n\n    if (entry.count >= this.maxRequests) {\n      return true;\n    }\n\n    entry.count++;\n    return false;\n  }\n\n  getRemainingTime(userId: string): number {\n    const entry = this.limits.get(userId);\n    if (!entry) return 0;\n    return Math.max(0, entry.resetTime - Date.now());\n  }\n}\n\nexport const rateLimiter = new RateLimiter(10, 60000); // 10 requests per minute\n```\n\nFor long responses, implement streaming updates:\n\n``` js\nimport { ChatInputCommandInteraction, EmbedBuilder } from 'discord.js';\nimport { NeuroLink } from '@juspay/neurolink';\n\nexport async function handleStreamingResponse(\n  interaction: ChatInputCommandInteraction,\n  prompt: string\n): Promise<void> {\n  await interaction.deferReply();\n\n  const neurolink = new NeuroLink();\n\n  let fullResponse = '';\n  let lastUpdate = Date.now();\n  const updateInterval = 1500; // Update every 1.5 seconds\n\n  const result = await neurolink.stream({\n    input: { text: prompt },\n    systemPrompt: 'You are a helpful Discord bot assistant.',\n    provider: 'openai',\n    model: 'gpt-4o',\n  });\n\n  for await (const chunk of result.stream) {\n    if ('content' in chunk) {\n      fullResponse += chunk.content;\n    }\n\n    // Update message periodically to avoid rate limits\n    if (Date.now() - lastUpdate > updateInterval) {\n      const embed = new EmbedBuilder()\n        .setDescription(fullResponse + ' ...')\n        .setColor(0x5865f2);\n\n      await interaction.editReply({ embeds: [embed] });\n      lastUpdate = Date.now();\n    }\n  }\n\n  // Final update\n  const finalEmbed = new EmbedBuilder()\n    .setDescription(fullResponse)\n    .setColor(0x57f287)\n    .setFooter({ text: 'Response complete' });\n\n  await interaction.editReply({ embeds: [finalEmbed] });\n}\n```\n\nAdd automatic responses to @mentions:\n\n``` js\n// Add to src/index.ts\nclient.on('messageCreate', async (message) => {\n  // Ignore bots and messages without mentions\n  if (message.author.bot) return;\n  if (!message.mentions.has(client.user!)) return;\n\n  // Remove the mention from the message\n  const content = message.content\n    .replace(/<@!?\\d+>/g, '')\n    .trim();\n\n  if (!content) {\n    await message.reply('How can I help you? Ask me anything!');\n    return;\n  }\n\n  try {\n    await message.channel.sendTyping();\n\n    const response = await generateResponse(content, {\n      systemPrompt: 'You are a helpful Discord bot. Keep responses brief and friendly.',\n      maxTokens: 500,\n    });\n\n    await message.reply(response);\n  } catch (error) {\n    console.error('Error responding to mention:', error);\n    await message.reply('Sorry, I encountered an error. Please try again.');\n  }\n});\n```\n\nUpdate `package.json`\n\n:\n\n```\n{\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"start\": \"node dist/index.js\",\n    \"dev\": \"nodemon --exec ts-node src/index.ts\",\n    \"register\": \"ts-node src/commands/index.ts\"\n  }\n}\n```\n\nCreate a `Dockerfile`\n\n:\n\n```\nFROM node:20-alpine\n\nWORKDIR /app\n\nCOPY package*.json ./\nRUN npm ci --only=production\n\nCOPY dist/ ./dist/\n\nENV NODE_ENV=production\n\nCMD [\"node\", \"dist/index.js\"]\n```\n\nCreate `docker-compose.yml`\n\n:\n\n```\nversion: '3.8'\nservices:\n  bot:\n    build: .\n    restart: unless-stopped\n    env_file:\n      - .env\n    logging:\n      driver: json-file\n      options:\n        max-size: \"10m\"\n        max-file: \"3\"\n```\n\n**Railway:**\n\n```\nrailway login\nrailway init\nrailway up\n```\n\n**Fly.io:**\n\n```\nfly launch\nfly secrets set DISCORD_TOKEN=xxx NEUROLINK_API_KEY=xxx\nfly deploy\n```\n\n**DigitalOcean App Platform:**\n\nAlways wrap API calls in try-catch blocks and provide user-friendly error messages:\n\n``` js\ntry {\n  const response = await generateResponse(prompt);\n  await interaction.editReply({ content: response });\n} catch (error) {\n  if (error.code === 'RATE_LIMITED') {\n    await interaction.editReply({\n      content: 'I\\'m receiving too many requests. Please wait a moment.',\n    });\n  } else {\n    await interaction.editReply({\n      content: 'Something went wrong. Please try again later.',\n    });\n  }\n  console.error('API Error:', error);\n}\n```\n\nNote:Timeout-based cancellation is available via the`timeout`\n\nparameter in NeuroLink.\n\nCreate a simple test script:\n\n``` js\n// src/test.ts\nimport { generateResponse } from './services/neurolink';\n\nasync function test() {\n  console.log('Testing NeuroLink integration...');\n\n  const response = await generateResponse('What is Discord?');\n  console.log('Response:', response);\n\n  console.log('Test completed successfully!');\n}\n\ntest().catch(console.error);\n```\n\nRun with: `npx ts-node src/test.ts`\n\nYou built an AI Discord bot with slash commands, multi-turn conversations, thread summarization, and mention responses using Discord.js and NeuroLink's generation API. The bot handles natural language queries, maintains conversation context per thread, and provides AI-powered moderation and analysis.\n\nContinue with these related tutorials:\n\n*Have questions about building Discord bots with NeuroLink? Join our Discord community or reach out on Twitter.*\n\n**Related posts:**", "url": "https://wpnews.pro/news/building-ai-discord-bots-with-neurolink", "canonical_source": "https://dev.to/neurolink/building-ai-discord-bots-with-neurolink-7i4", "published_at": "2026-07-04 04:02:14+00:00", "updated_at": "2026-07-04 04:19:24.970824+00:00", "lang": "en", "topics": ["developer-tools", "artificial-intelligence", "large-language-models"], "entities": ["NeuroLink", "Discord.js", "Juspay", "Discord"], "alternates": {"html": "https://wpnews.pro/news/building-ai-discord-bots-with-neurolink", "markdown": "https://wpnews.pro/news/building-ai-discord-bots-with-neurolink.md", "text": "https://wpnews.pro/news/building-ai-discord-bots-with-neurolink.txt", "jsonld": "https://wpnews.pro/news/building-ai-discord-bots-with-neurolink.jsonld"}}