@agentforge-ai/channels-discord 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +197 -0
- package/dist/index.d.ts +236 -0
- package/dist/index.js +875 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/discord-adapter.ts","../src/types.ts","../src/discord-channel.ts"],"sourcesContent":["/**\n * Discord Channel Adapter for AgentForge.\n *\n * Implements the ChannelAdapter interface for the Discord Bot API using discord.js v14.\n *\n * Features:\n * - Text messages in guild channels and DMs\n * - Thread support (forum and text threads)\n * - Reactions, message editing and deletion\n * - Typing indicators\n * - Slash command registration and handling\n * - Embeds via platformOptions.embeds\n * - Guild @mention detection\n * - Rate limiting\n * - Max 25MB file uploads, 2000 char text limit\n *\n * @packageDocumentation\n */\n\nimport {\n Client,\n GatewayIntentBits,\n Partials,\n Routes,\n type Message,\n type DMChannel,\n type TextChannel,\n type ThreadChannel,\n type NewsChannel,\n type VoiceChannel,\n type PartialMessage,\n type Interaction,\n type ChatInputCommandInteraction,\n type Channel,\n ChannelType,\n Events,\n} from 'discord.js';\nimport { REST } from '@discordjs/rest';\n\nimport {\n ChannelAdapter,\n MessageNormalizer,\n type ChannelConfig,\n type ChannelCapabilities,\n type HealthStatus,\n type InboundMessage,\n type OutboundMessage,\n type SendResult,\n type MediaAttachment,\n type ChatType,\n type CallbackAction,\n} from '@agentforge-ai/core';\n\nimport type { DiscordAdapterConfig, DiscordSlashCommand } from './types.js';\nimport { DISCORD_BOT_COMMANDS } from './types.js';\n\n// =====================================================\n// Sendable channel type union\n// =====================================================\n\ntype SendableChannel = TextChannel | DMChannel | NewsChannel | ThreadChannel | VoiceChannel;\n\n// =====================================================\n// Discord Adapter\n// =====================================================\n\n/**\n * Discord Bot channel adapter.\n *\n * @example\n * ```typescript\n * import { ChannelRegistry } from '@agentforge-ai/core';\n * import { DiscordAdapter } from '@agentforge-ai/channels-discord';\n *\n * const registry = new ChannelRegistry();\n * registry.registerFactory('discord', () => new DiscordAdapter());\n *\n * const adapter = await registry.createAdapter({\n * id: 'my-discord-bot',\n * platform: 'discord',\n * orgId: 'org-1',\n * agentId: 'agent-1',\n * enabled: true,\n * credentials: { botToken: 'BOT_TOKEN', clientId: 'CLIENT_ID' },\n * settings: {\n * mentionOnly: false,\n * respondToDMs: true,\n * },\n * });\n * ```\n */\nexport class DiscordAdapter extends ChannelAdapter {\n readonly platform = 'discord';\n\n private client: Client | null = null;\n private adapterConfig: DiscordAdapterConfig | null = null;\n private botUserId: string = '';\n\n // Rate limiting\n private messageTimestamps: number[] = [];\n private rateLimitPerSecond: number = 5;\n\n // ----- Lifecycle -----\n\n async connect(config: ChannelConfig): Promise<void> {\n const botToken = config.credentials.botToken;\n if (!botToken) {\n throw new Error('Discord bot token is required in credentials.botToken');\n }\n\n this.adapterConfig = {\n botToken,\n clientId: config.credentials.clientId ?? (config.settings?.clientId as string | undefined),\n guildId: config.credentials.guildId ?? (config.settings?.guildId as string | undefined),\n registerCommands: config.settings?.registerCommands as boolean ?? true,\n mentionOnly: config.settings?.mentionOnly as boolean ?? false,\n respondToDMs: config.settings?.respondToDMs as boolean ?? true,\n rateLimitPerSecond: config.settings?.rateLimitPerSecond as number ?? 5,\n };\n\n this.rateLimitPerSecond = this.adapterConfig.rateLimitPerSecond!;\n\n // Build intent list — MessageContent requires privileged intent in Discord dev portal\n const intents = [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.MessageContent,\n GatewayIntentBits.DirectMessages,\n GatewayIntentBits.GuildMessageReactions,\n ];\n\n this.client = new Client({\n intents,\n partials: [Partials.Channel, Partials.Message],\n });\n\n // Register event handlers before login\n this.registerClientEvents();\n\n // Log in — this throws if the token is invalid\n await this.client.login(botToken);\n\n // Wait for the ready event\n await this.waitForReady();\n\n // Register slash commands if configured\n if (this.adapterConfig.registerCommands && this.adapterConfig.clientId) {\n await this.registerSlashCommands(\n botToken,\n this.adapterConfig.clientId,\n DISCORD_BOT_COMMANDS,\n this.adapterConfig.guildId\n );\n }\n }\n\n async disconnect(): Promise<void> {\n if (this.client) {\n this.client.removeAllListeners();\n this.client.destroy();\n this.client = null;\n }\n\n this.botUserId = '';\n this.adapterConfig = null;\n }\n\n // ----- Message Sending -----\n\n async sendMessage(message: OutboundMessage): Promise<SendResult> {\n try {\n await this.enforceRateLimit();\n\n const targetChannelId = message.threadId ?? message.chatId;\n const channel = await this.resolveChannel(targetChannelId);\n if (!channel) {\n return { success: false, error: `Channel ${targetChannelId} not found` };\n }\n\n if (message.showTyping) {\n await this.sendTypingIndicator(message.chatId);\n if (message.typingDurationMs) {\n await this.sleep(message.typingDurationMs);\n }\n }\n\n const sendableChannel = channel as SendableChannel;\n\n // Build message payload\n const payload = this.buildMessagePayload(message);\n\n const sent = await sendableChannel.send(payload);\n\n return {\n success: true,\n platformMessageId: sent.id,\n deliveredAt: sent.createdAt,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n // ----- Capabilities -----\n\n getCapabilities(): ChannelCapabilities {\n return {\n supportedMedia: ['image', 'audio', 'video', 'file'],\n maxTextLength: 2000,\n supportsThreads: true,\n supportsReactions: true,\n supportsEditing: true,\n supportsDeleting: true,\n supportsTypingIndicator: true,\n supportsReadReceipts: false,\n supportsActions: false,\n supportsGroupChat: true,\n supportsMarkdown: true,\n maxFileSize: 25 * 1024 * 1024, // 25MB\n platformSpecific: {\n supportsEmbeds: true,\n supportsSlashCommands: true,\n supportsThreads: true,\n supportsForums: true,\n supportsNitroFileSize: 500 * 1024 * 1024, // 500MB for Nitro servers\n },\n };\n }\n\n // ----- Health Check -----\n\n async healthCheck(): Promise<{ status: HealthStatus; details?: string }> {\n if (!this.client || !this.client.isReady()) {\n return { status: 'disconnected', details: 'Discord client is not ready' };\n }\n\n try {\n const user = this.client.user;\n if (user) {\n return {\n status: 'healthy',\n details: `Bot ${user.tag} (ID: ${user.id}) is connected`,\n };\n }\n return { status: 'degraded', details: 'Client ready but user is null' };\n } catch (error) {\n return {\n status: 'unhealthy',\n details: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n // ----- Optional Overrides -----\n\n override async editMessage(\n platformMessageId: string,\n message: Partial<OutboundMessage>\n ): Promise<SendResult> {\n try {\n if (!message.text && !message.platformOptions?.embeds) {\n return { success: false, error: 'Text or embeds are required for editing' };\n }\n\n const targetChannelId = message.threadId ?? message.chatId;\n if (!targetChannelId) {\n return { success: false, error: 'chatId is required for editing' };\n }\n\n const channel = await this.resolveChannel(targetChannelId);\n if (!channel) {\n return { success: false, error: `Channel ${targetChannelId} not found` };\n }\n\n const textChannel = channel as TextChannel | DMChannel | ThreadChannel;\n const msg = await textChannel.messages.fetch(platformMessageId);\n const editPayload = this.buildMessagePayload(message as OutboundMessage);\n await msg.edit(editPayload);\n\n return { success: true, platformMessageId };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n override async deleteMessage(\n platformMessageId: string,\n chatId: string\n ): Promise<boolean> {\n try {\n const channel = await this.resolveChannel(chatId);\n if (!channel) return false;\n\n const textChannel = channel as TextChannel | DMChannel | ThreadChannel;\n const msg = await textChannel.messages.fetch(platformMessageId);\n await msg.delete();\n return true;\n } catch {\n return false;\n }\n }\n\n override async sendTypingIndicator(chatId: string): Promise<void> {\n try {\n const channel = await this.resolveChannel(chatId);\n if (!channel) return;\n const sendable = channel as SendableChannel;\n await sendable.sendTyping();\n } catch {\n // Ignore typing indicator errors\n }\n }\n\n override async addReaction(\n platformMessageId: string,\n chatId: string,\n emoji: string\n ): Promise<boolean> {\n try {\n const channel = await this.resolveChannel(chatId);\n if (!channel) return false;\n\n const textChannel = channel as TextChannel | DMChannel | ThreadChannel;\n const msg = await textChannel.messages.fetch(platformMessageId);\n await msg.react(emoji);\n return true;\n } catch {\n return false;\n }\n }\n\n // ----- Internal: Client Events -----\n\n private registerClientEvents(): void {\n if (!this.client) return;\n\n this.client.on(Events.MessageCreate, (message: Message) => {\n this.handleDiscordMessage(message);\n });\n\n this.client.on(Events.MessageUpdate, (_old: Message | PartialMessage, newMessage: Message | PartialMessage) => {\n if (newMessage.partial) return;\n this.handleDiscordMessage(newMessage as Message, true);\n });\n\n this.client.on(Events.InteractionCreate, (interaction: Interaction) => {\n if (interaction.isChatInputCommand()) {\n this.handleSlashCommand(interaction);\n }\n });\n\n this.client.on(Events.Error, (error: Error) => {\n this.emit({\n type: 'error',\n data: { error, recoverable: true },\n });\n });\n }\n\n // ----- Internal: Message Handling -----\n\n private handleDiscordMessage(message: Message, isEdit = false): void {\n // Ignore messages from the bot itself\n if (message.author.id === this.botUserId) return;\n // Ignore other bots\n if (message.author.bot) return;\n\n // Guild channel: apply mention filter if configured\n if (message.guild && this.adapterConfig?.mentionOnly) {\n if (!this.isBotMentioned(message)) return;\n }\n\n // DM filter\n if (!message.guild && !this.adapterConfig?.respondToDMs) return;\n\n const normalized = this.normalizeDiscordMessage(message, isEdit);\n\n if (isEdit) {\n this.emit({ type: 'message_edited', data: normalized });\n } else {\n this.emitMessage(normalized);\n }\n }\n\n private handleSlashCommand(interaction: ChatInputCommandInteraction): void {\n // Emit as a regular inbound message so the channel runner can handle commands\n const normalized = this.normalizeSlashCommand(interaction);\n this.emitMessage(normalized);\n }\n\n // ----- Internal: Message Normalization -----\n\n private normalizeDiscordMessage(message: Message, isEdit: boolean): InboundMessage {\n const chatId = message.channelId;\n const threadId = message.thread?.id;\n const chatType = this.mapChannelType(message.channel);\n\n // Strip bot @mention from content\n let text = message.content;\n if (this.botUserId && text) {\n text = text.replace(new RegExp(`<@!?${this.botUserId}>`, 'g'), '').trim();\n }\n\n const media = this.extractMedia(message);\n\n return MessageNormalizer.normalize({\n platformMessageId: message.id,\n channelId: this.config?.id ?? '',\n platform: 'discord',\n chatId,\n chatType,\n senderId: message.author.id,\n senderName: message.member?.displayName ?? message.author.displayName,\n senderUsername: message.author.username,\n senderAvatar: message.author.displayAvatarURL(),\n text: text || undefined,\n media,\n replyToId: message.reference?.messageId,\n threadId: threadId ?? (chatType === 'thread' ? chatId : undefined),\n rawData: {\n guildId: message.guildId,\n channelId: message.channelId,\n messageType: message.type,\n },\n timestamp: message.createdAt,\n isEdit,\n });\n }\n\n private normalizeSlashCommand(interaction: ChatInputCommandInteraction): InboundMessage {\n const chatType = this.mapChannelType(interaction.channel);\n\n return MessageNormalizer.normalize({\n platformMessageId: interaction.id,\n channelId: this.config?.id ?? '',\n platform: 'discord',\n chatId: interaction.channelId,\n chatType,\n senderId: interaction.user.id,\n senderName: interaction.member\n ? (interaction.member as { displayName?: string }).displayName ?? interaction.user.displayName\n : interaction.user.displayName,\n senderUsername: interaction.user.username,\n senderAvatar: interaction.user.displayAvatarURL(),\n text: `/${interaction.commandName}`,\n rawData: {\n guildId: interaction.guildId,\n channelId: interaction.channelId,\n interactionId: interaction.id,\n commandName: interaction.commandName,\n isSlashCommand: true,\n },\n timestamp: interaction.createdAt,\n });\n }\n\n private extractMedia(message: Message): MediaAttachment[] | undefined {\n if (message.attachments.size === 0) return undefined;\n\n const media: MediaAttachment[] = [];\n\n for (const attachment of message.attachments.values()) {\n const mimeType = attachment.contentType ?? undefined;\n const mediaType = this.mapMimeTypeToMediaType(mimeType);\n\n media.push({\n type: mediaType,\n url: attachment.url,\n fileName: attachment.name ?? undefined,\n mimeType,\n sizeBytes: attachment.size,\n width: attachment.width ?? undefined,\n height: attachment.height ?? undefined,\n });\n }\n\n return media.length > 0 ? media : undefined;\n }\n\n private mapMimeTypeToMediaType(\n mimeType: string | undefined\n ): 'image' | 'audio' | 'video' | 'file' {\n if (!mimeType) return 'file';\n if (mimeType.startsWith('image/')) return 'image';\n if (mimeType.startsWith('audio/')) return 'audio';\n if (mimeType.startsWith('video/')) return 'video';\n return 'file';\n }\n\n private mapChannelType(channel: Channel | null): ChatType {\n if (!channel) return 'channel';\n\n switch (channel.type) {\n case ChannelType.DM:\n case ChannelType.GroupDM:\n return 'dm';\n case ChannelType.PublicThread:\n case ChannelType.PrivateThread:\n case ChannelType.AnnouncementThread:\n return 'thread';\n case ChannelType.GuildText:\n case ChannelType.GuildAnnouncement:\n case ChannelType.GuildForum:\n case ChannelType.GuildVoice:\n return 'channel';\n default:\n return 'channel';\n }\n }\n\n // ----- Internal: Message Payload Builder -----\n\n private buildMessagePayload(message: OutboundMessage | Partial<OutboundMessage>): Record<string, unknown> {\n const payload: Record<string, unknown> = {};\n\n if (message.text) {\n payload['content'] = message.text;\n }\n\n // Support Discord embeds via platformOptions\n const embeds = message.platformOptions?.embeds;\n if (embeds) {\n payload['embeds'] = embeds;\n }\n\n // Reply reference\n if (message.replyToMessageId) {\n payload['reply'] = { messageReference: message.replyToMessageId };\n }\n\n return payload;\n }\n\n // ----- Internal: @Mention Detection -----\n\n private isBotMentioned(message: Message): boolean {\n if (!this.botUserId) return false;\n return message.mentions.users.has(this.botUserId);\n }\n\n // ----- Internal: Channel Resolution -----\n\n private async resolveChannel(channelId: string): Promise<Channel | null> {\n if (!this.client) return null;\n\n try {\n const cached = this.client.channels.cache.get(channelId);\n if (cached) return cached;\n\n return await this.client.channels.fetch(channelId);\n } catch {\n return null;\n }\n }\n\n // ----- Internal: Slash Command Registration -----\n\n private async registerSlashCommands(\n botToken: string,\n clientId: string,\n commands: DiscordSlashCommand[],\n guildId?: string\n ): Promise<void> {\n try {\n const rest = new REST({ version: '10' }).setToken(botToken);\n const route = guildId\n ? Routes.applicationGuildCommands(clientId, guildId)\n : Routes.applicationCommands(clientId);\n\n await rest.put(route, { body: commands });\n } catch {\n // Non-fatal: log but don't throw — bot can still work without slash commands\n this.emit({\n type: 'error',\n data: {\n error: new Error('Failed to register Discord slash commands'),\n recoverable: true,\n },\n });\n }\n }\n\n // ----- Internal: Ready Wait -----\n\n private waitForReady(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.client) {\n reject(new Error('Discord client is not initialized'));\n return;\n }\n\n if (this.client.isReady()) {\n this.botUserId = this.client.user!.id;\n resolve();\n return;\n }\n\n const onReady = () => {\n this.botUserId = this.client!.user!.id;\n resolve();\n };\n\n const onError = (error: Error) => {\n reject(error);\n };\n\n this.client.once(Events.ClientReady, onReady);\n this.client.once(Events.Error, onError);\n\n // Timeout after 30 seconds\n const timeout = setTimeout(() => {\n this.client?.off(Events.ClientReady, onReady);\n this.client?.off(Events.Error, onError);\n reject(new Error('Discord client did not become ready within 30 seconds'));\n }, 30000);\n\n this.client.once(Events.ClientReady, () => clearTimeout(timeout));\n });\n }\n\n // ----- Internal: Rate Limiting -----\n\n private async enforceRateLimit(): Promise<void> {\n const now = Date.now();\n this.messageTimestamps = this.messageTimestamps.filter((t) => now - t < 1000);\n\n if (this.messageTimestamps.length >= this.rateLimitPerSecond) {\n const oldestInWindow = this.messageTimestamps[0];\n const waitMs = 1000 - (now - oldestInWindow);\n if (waitMs > 0) {\n await this.sleep(waitMs);\n }\n }\n\n this.messageTimestamps.push(Date.now());\n }\n\n // ----- Utility -----\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","/**\n * Discord-specific types for the AgentForge Discord channel adapter.\n *\n * @packageDocumentation\n */\n\n// =====================================================\n// Discord Adapter Configuration\n// =====================================================\n\n/**\n * Configuration for the DiscordAdapter.\n * Passed via ChannelConfig.credentials and ChannelConfig.settings.\n */\nexport interface DiscordAdapterConfig {\n /** Discord bot token */\n botToken: string;\n /** Application/client ID (required for slash command registration) */\n clientId?: string;\n /** Guild (server) ID for guild-scoped slash command registration. If omitted, registers globally. */\n guildId?: string;\n /** Whether to register slash commands on connect. Default: true */\n registerCommands?: boolean;\n /** Whether to respond only to @mentions in guild channels. Default: false */\n mentionOnly?: boolean;\n /** Whether to respond to DMs. Default: true */\n respondToDMs?: boolean;\n /** Rate limit: max messages per second. Default: 5 */\n rateLimitPerSecond?: number;\n}\n\n/**\n * Configuration for the DiscordChannel runner (Convex integration).\n */\nexport interface DiscordChannelConfig {\n /** Discord bot token from Developer Portal */\n botToken: string;\n /** Application/client ID */\n clientId?: string;\n /** Guild ID for guild-scoped commands */\n guildId?: string;\n /** Agent ID to route messages to */\n agentId: string;\n /** Convex deployment URL */\n convexUrl: string;\n /** Whether to respond only to @mentions in guild channels. Default: false */\n mentionOnly?: boolean;\n /** Whether to respond to DMs. Default: true */\n respondToDMs?: boolean;\n /** User ID for Convex operations (default: 'discord') */\n userId?: string;\n /** Log level. Default: 'info' */\n logLevel?: 'debug' | 'info' | 'warn' | 'error';\n}\n\n// =====================================================\n// Discord Slash Command Definition\n// =====================================================\n\n/**\n * Simplified slash command definition for registration.\n */\nexport interface DiscordSlashCommand {\n name: string;\n description: string;\n}\n\n/**\n * Discord's built-in slash commands registered by the adapter.\n */\nexport const DISCORD_BOT_COMMANDS: DiscordSlashCommand[] = [\n { name: 'start', description: 'Start a new conversation with the AI agent' },\n { name: 'new', description: 'Reset the current conversation thread' },\n { name: 'help', description: 'Show available commands and usage information' },\n];\n","/**\n * Discord Channel for AgentForge.\n *\n * Bridges the DiscordAdapter with the AgentForge Convex chat pipeline.\n * This module:\n * - Starts the Discord bot\n * - Routes incoming messages through the agent execution pipeline\n * - Creates/reuses Convex threads per Discord channel\n * - Stores all messages in the Convex messages table\n * - Sends agent responses back to the Discord user\n *\n * @packageDocumentation\n */\n\nimport { DiscordAdapter } from './discord-adapter.js';\nimport type { DiscordChannelConfig } from './types.js';\nimport type {\n ChannelConfig,\n InboundMessage,\n ChannelEvent,\n} from '@agentforge-ai/core';\n\n// =====================================================\n// Thread mapping\n// =====================================================\n\n/** Map Discord channelId → Convex threadId */\ntype ThreadMap = Map<string, string>;\n\n// =====================================================\n// Logger\n// =====================================================\n\ninterface Logger {\n debug: (...args: unknown[]) => void;\n info: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n}\n\nconst LOG_LEVELS: Record<string, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nfunction createLogger(level: string = 'info'): Logger {\n const threshold = LOG_LEVELS[level] ?? 1;\n const prefix = '[agentforge:discord]';\n\n return {\n debug: (...args: unknown[]) => {\n if (threshold <= 0) console.log(`${prefix} [DEBUG]`, ...args);\n },\n info: (...args: unknown[]) => {\n if (threshold <= 1) console.log(`${prefix}`, ...args);\n },\n warn: (...args: unknown[]) => {\n if (threshold <= 2) console.warn(`${prefix} [WARN]`, ...args);\n },\n error: (...args: unknown[]) => {\n if (threshold <= 3) console.error(`${prefix} [ERROR]`, ...args);\n },\n };\n}\n\n// =====================================================\n// Convex HTTP Client\n// =====================================================\n\n/**\n * Minimal Convex HTTP client for calling queries, mutations, and actions.\n * Matches the pattern used by TelegramChannel.\n */\nclass ConvexHttpApi {\n private baseUrl: string;\n\n constructor(deploymentUrl: string) {\n this.baseUrl = deploymentUrl.replace(/\\/$/, '');\n }\n\n async query(functionPath: string, args: Record<string, unknown> = {}): Promise<unknown> {\n const url = `${this.baseUrl}/api/query`;\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ path: functionPath, args }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Convex query ${functionPath} failed: ${response.status} ${text}`);\n }\n\n const data = await response.json() as { value?: unknown; status?: string; errorMessage?: string };\n if (data.status === 'error') {\n throw new Error(`Convex query ${functionPath} error: ${data.errorMessage}`);\n }\n return data.value;\n }\n\n async mutation(functionPath: string, args: Record<string, unknown> = {}): Promise<unknown> {\n const url = `${this.baseUrl}/api/mutation`;\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ path: functionPath, args }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Convex mutation ${functionPath} failed: ${response.status} ${text}`);\n }\n\n const data = await response.json() as { value?: unknown; status?: string; errorMessage?: string };\n if (data.status === 'error') {\n throw new Error(`Convex mutation ${functionPath} error: ${data.errorMessage}`);\n }\n return data.value;\n }\n\n async action(functionPath: string, args: Record<string, unknown> = {}): Promise<unknown> {\n const url = `${this.baseUrl}/api/action`;\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ path: functionPath, args }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Convex action ${functionPath} failed: ${response.status} ${text}`);\n }\n\n const data = await response.json() as { value?: unknown; status?: string; errorMessage?: string };\n if (data.status === 'error') {\n throw new Error(`Convex action ${functionPath} error: ${data.errorMessage}`);\n }\n return data.value;\n }\n}\n\n// =====================================================\n// Discord Channel Runner\n// =====================================================\n\n/**\n * Runs a Discord bot that routes messages through the AgentForge\n * Convex chat pipeline.\n *\n * @example\n * ```typescript\n * import { DiscordChannel } from '@agentforge-ai/channels-discord';\n *\n * const channel = new DiscordChannel({\n * botToken: process.env.DISCORD_BOT_TOKEN!,\n * clientId: process.env.DISCORD_CLIENT_ID!,\n * agentId: 'my-agent',\n * convexUrl: process.env.CONVEX_URL!,\n * });\n *\n * await channel.start();\n * ```\n */\nexport class DiscordChannel {\n private adapter: DiscordAdapter;\n private convex: ConvexHttpApi;\n private config: DiscordChannelConfig;\n private threadMap: ThreadMap = new Map();\n private logger: Logger;\n private processingMessages: Set<string> = new Set();\n private isRunning: boolean = false;\n\n constructor(config: DiscordChannelConfig) {\n this.config = config;\n this.adapter = new DiscordAdapter();\n this.convex = new ConvexHttpApi(config.convexUrl);\n this.logger = createLogger(config.logLevel);\n }\n\n /**\n * Start the Discord channel bot.\n * Connects to Discord and begins listening for messages.\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n this.logger.warn('Discord channel is already running');\n return;\n }\n\n this.logger.info('Starting Discord channel...');\n this.logger.info(`Agent ID: ${this.config.agentId}`);\n this.logger.info(`Convex URL: ${this.config.convexUrl}`);\n\n // Verify the agent exists in Convex\n try {\n const agent = await this.convex.query('agents:get', { id: this.config.agentId });\n if (!agent) {\n throw new Error(\n `Agent \"${this.config.agentId}\" not found in Convex. ` +\n `Create it first with: agentforge agents create`\n );\n }\n const agentData = agent as { name: string; model: string; provider: string };\n this.logger.info(`Agent: ${agentData.name} (${agentData.model} via ${agentData.provider})`);\n } catch (error) {\n if (error instanceof Error && error.message.includes('not found')) {\n throw error;\n }\n this.logger.warn('Could not verify agent (Convex may be unreachable). Continuing...');\n }\n\n // Wire up event handler\n this.adapter.on(this.handleEvent.bind(this));\n\n // Build the ChannelConfig for the adapter\n const channelConfig: ChannelConfig = {\n id: `discord-${this.config.agentId}`,\n platform: 'discord',\n orgId: 'default',\n agentId: this.config.agentId,\n enabled: true,\n credentials: {\n botToken: this.config.botToken,\n ...(this.config.clientId ? { clientId: this.config.clientId } : {}),\n ...(this.config.guildId ? { guildId: this.config.guildId } : {}),\n },\n settings: {\n mentionOnly: this.config.mentionOnly ?? false,\n respondToDMs: this.config.respondToDMs ?? true,\n registerCommands: true,\n },\n autoReconnect: true,\n reconnectIntervalMs: 5000,\n maxReconnectAttempts: 20,\n };\n\n // Start the adapter\n await this.adapter.start(channelConfig);\n this.isRunning = true;\n\n this.logger.info('Discord channel started successfully!');\n this.logger.info('Bot is listening for messages...');\n this.logger.info('Press Ctrl+C to stop.');\n }\n\n /**\n * Stop the Discord channel bot.\n */\n async stop(): Promise<void> {\n if (!this.isRunning) return;\n\n this.logger.info('Stopping Discord channel...');\n await this.adapter.stop();\n this.isRunning = false;\n this.threadMap.clear();\n this.processingMessages.clear();\n this.logger.info('Discord channel stopped.');\n }\n\n /**\n * Get the current thread map (for debugging).\n */\n getThreadMap(): ReadonlyMap<string, string> {\n return this.threadMap;\n }\n\n /**\n * Get the underlying DiscordAdapter instance.\n */\n getAdapter(): DiscordAdapter {\n return this.adapter;\n }\n\n /**\n * Check if the channel is running.\n */\n get running(): boolean {\n return this.isRunning;\n }\n\n // ----- Internal: Event Handling -----\n\n private async handleEvent(event: ChannelEvent): Promise<void> {\n switch (event.type) {\n case 'message':\n await this.handleInboundMessage(event.data as InboundMessage);\n break;\n\n case 'connection_state':\n this.logger.debug('Connection state:', (event.data as { state: string }).state);\n break;\n\n case 'error':\n this.logger.error('Adapter error:', (event.data as { error: Error }).error.message);\n break;\n\n default:\n this.logger.debug('Unhandled event type:', event.type);\n }\n }\n\n private async handleInboundMessage(message: InboundMessage): Promise<void> {\n if (!message.text?.trim()) {\n this.logger.debug('Skipping empty message');\n return;\n }\n\n // Dedup: prevent processing the same message twice\n const dedupKey = `${message.chatId}:${message.platformMessageId}`;\n if (this.processingMessages.has(dedupKey)) {\n this.logger.debug('Skipping duplicate message:', dedupKey);\n return;\n }\n this.processingMessages.add(dedupKey);\n\n const senderName = message.sender.displayName ?? message.sender.username ?? 'Unknown';\n this.logger.info(`Message from ${senderName} (channel ${message.chatId}): ${message.text}`);\n\n try {\n // Handle /start slash command\n if (message.text.startsWith('/start')) {\n await this.handleStartCommand(message);\n return;\n }\n\n // Handle /new slash command — reset thread\n if (message.text.startsWith('/new')) {\n this.threadMap.delete(message.chatId);\n await this.adapter.sendMessage({\n chatId: message.chatId,\n text: 'New conversation started. Send me a message!',\n });\n return;\n }\n\n // Handle /help slash command\n if (message.text.startsWith('/help')) {\n await this.handleHelpCommand(message);\n return;\n }\n\n // Route through the agent execution pipeline\n await this.routeToAgent(message);\n } catch (error) {\n this.logger.error('Error handling message:', error);\n try {\n await this.adapter.sendMessage({\n chatId: message.chatId,\n text: 'Sorry, I encountered an error processing your message. Please try again.',\n });\n } catch {\n this.logger.error('Failed to send error message to user');\n }\n } finally {\n setTimeout(() => {\n this.processingMessages.delete(dedupKey);\n }, 30000);\n }\n }\n\n // ----- Internal: Agent Routing -----\n\n /**\n * Route a message through the AgentForge chat pipeline:\n * 1. Get or create a Convex thread for this Discord channel\n * 2. Call chat.sendMessage action\n * 3. Send the agent response back to Discord\n */\n private async routeToAgent(message: InboundMessage): Promise<void> {\n await this.adapter.sendTypingIndicator(message.chatId);\n\n const threadId = await this.getOrCreateThread(\n message.chatId,\n message.sender.displayName\n );\n\n const userId = this.config.userId ?? `discord:${message.sender.platformUserId}`;\n\n this.logger.debug(`Sending to agent ${this.config.agentId}, thread ${threadId}`);\n\n const result = await this.convex.action('chat:sendMessage', {\n agentId: this.config.agentId,\n threadId,\n content: message.text!,\n userId,\n }) as { success: boolean; response: string; usage?: { totalTokens: number } };\n\n if (result?.response) {\n // Discord max message length is 2000 chars\n const chunks = this.splitMessage(result.response, 2000);\n for (const chunk of chunks) {\n await this.adapter.sendMessage({\n chatId: message.chatId,\n text: chunk,\n replyToMessageId:\n chunks.length === 1 ? message.platformMessageId : undefined,\n });\n }\n\n if (result.usage) {\n this.logger.debug(`Tokens used: ${result.usage.totalTokens}`);\n }\n } else {\n await this.adapter.sendMessage({\n chatId: message.chatId,\n text: \"I received your message but couldn't generate a response. Please try again.\",\n });\n }\n }\n\n // ----- Internal: Thread Management -----\n\n /**\n * Get or create a Convex thread for a Discord channel.\n * Threads are cached in memory and created lazily.\n */\n private async getOrCreateThread(channelId: string, senderName?: string): Promise<string> {\n const cached = this.threadMap.get(channelId);\n if (cached) return cached;\n\n const threadName = senderName\n ? `Discord: ${senderName}`\n : `Discord Channel ${channelId}`;\n\n const userId = this.config.userId ?? `discord:${channelId}`;\n\n const threadId = await this.convex.mutation('chat:createThread', {\n agentId: this.config.agentId,\n name: threadName,\n userId,\n }) as string;\n\n this.threadMap.set(channelId, threadId);\n this.logger.info(`Created new thread ${threadId} for channel ${channelId}`);\n\n try {\n await this.convex.mutation('logs:add', {\n level: 'info',\n source: 'discord',\n message: `New Discord conversation started by ${senderName ?? channelId}`,\n metadata: { channelId, threadId, agentId: this.config.agentId },\n userId,\n });\n } catch {\n // Non-critical, ignore\n }\n\n return threadId;\n }\n\n // ----- Internal: Command Handlers -----\n\n private async handleStartCommand(message: InboundMessage): Promise<void> {\n this.threadMap.delete(message.chatId);\n\n let agentName = 'AI Assistant';\n try {\n const agent = await this.convex.query('agents:get', { id: this.config.agentId });\n if (agent) {\n agentName = (agent as { name: string }).name;\n }\n } catch {\n // Use default name\n }\n\n await this.adapter.sendMessage({\n chatId: message.chatId,\n text:\n `Welcome! I'm **${agentName}**, powered by AgentForge.\\n\\n` +\n `Send me a message and I'll respond using AI.\\n\\n` +\n `**Commands:**\\n` +\n `/new — Start a new conversation\\n` +\n `/help — Show help information`,\n });\n }\n\n private async handleHelpCommand(message: InboundMessage): Promise<void> {\n await this.adapter.sendMessage({\n chatId: message.chatId,\n text:\n `**AgentForge Discord Bot**\\n\\n` +\n `Just send me a message and I'll respond using AI.\\n\\n` +\n `**Commands:**\\n` +\n `/start — Reset and show welcome message\\n` +\n `/new — Start a fresh conversation thread\\n` +\n `/help — Show this help message\\n\\n` +\n `*Powered by AgentForge — agentforge.dev*`,\n });\n }\n\n // ----- Internal: Utilities -----\n\n /**\n * Split a long message into chunks that fit Discord's 2000 char limit.\n */\n private splitMessage(text: string, maxLength: number): string[] {\n if (text.length <= maxLength) return [text];\n\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= maxLength) {\n chunks.push(remaining);\n break;\n }\n\n // Try to split at a paragraph break\n let splitIdx = remaining.lastIndexOf('\\n\\n', maxLength);\n if (splitIdx === -1 || splitIdx < maxLength / 2) {\n splitIdx = remaining.lastIndexOf('\\n', maxLength);\n }\n if (splitIdx === -1 || splitIdx < maxLength / 2) {\n splitIdx = remaining.lastIndexOf(' ', maxLength);\n }\n if (splitIdx === -1 || splitIdx < maxLength / 2) {\n splitIdx = maxLength;\n }\n\n chunks.push(remaining.substring(0, splitIdx));\n remaining = remaining.substring(splitIdx).trimStart();\n }\n\n return chunks;\n }\n}\n\n// =====================================================\n// Convenience Factory\n// =====================================================\n\n/**\n * Create and start a Discord channel from environment variables.\n *\n * Required env vars:\n * - DISCORD_BOT_TOKEN\n * - CONVEX_URL\n *\n * Optional env vars:\n * - DISCORD_CLIENT_ID\n * - DISCORD_GUILD_ID\n * - AGENTFORGE_AGENT_ID\n *\n * @example\n * ```typescript\n * import { startDiscordChannel } from '@agentforge-ai/channels-discord';\n *\n * await startDiscordChannel({ agentId: 'my-agent' });\n * ```\n */\nexport async function startDiscordChannel(\n overrides: Partial<DiscordChannelConfig> = {}\n): Promise<DiscordChannel> {\n const botToken = overrides.botToken ?? process.env.DISCORD_BOT_TOKEN;\n const convexUrl = overrides.convexUrl ?? process.env.CONVEX_URL;\n const agentId = overrides.agentId ?? process.env.AGENTFORGE_AGENT_ID;\n\n if (!botToken) {\n throw new Error(\n 'DISCORD_BOT_TOKEN is required. ' +\n 'Set it in your .env file or pass it as botToken in the config.'\n );\n }\n\n if (!convexUrl) {\n throw new Error(\n 'CONVEX_URL is required. ' +\n 'Set it in your .env file or pass it as convexUrl in the config.'\n );\n }\n\n if (!agentId) {\n throw new Error(\n 'Agent ID is required. ' +\n 'Pass it as agentId in the config or set AGENTFORGE_AGENT_ID env var.'\n );\n }\n\n const channel = new DiscordChannel({\n botToken,\n convexUrl,\n agentId,\n clientId: overrides.clientId ?? process.env.DISCORD_CLIENT_ID,\n guildId: overrides.guildId ?? process.env.DISCORD_GUILD_ID,\n mentionOnly: overrides.mentionOnly,\n respondToDMs: overrides.respondToDMs,\n userId: overrides.userId,\n logLevel: overrides.logLevel,\n });\n\n // Handle graceful shutdown\n const shutdown = async () => {\n console.log('\\nShutting down Discord channel...');\n await channel.stop();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n await channel.start();\n return channel;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentforge-ai/channels-discord",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Discord channel adapter for AgentForge",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"discord.js": "^14.16.0",
|
|
20
|
+
"@discordjs/rest": "^2.4.0"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"@agentforge-ai/core": ">=0.5.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"tsup": "^8.0.0",
|
|
27
|
+
"typescript": "^5.5.0",
|
|
28
|
+
"vitest": "^2.0.0",
|
|
29
|
+
"@agentforge-ai/core": "0.6.0"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"ai",
|
|
33
|
+
"agents",
|
|
34
|
+
"discord",
|
|
35
|
+
"channels",
|
|
36
|
+
"agentforge"
|
|
37
|
+
],
|
|
38
|
+
"license": "Apache-2.0",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/Agentic-Engineering-Agency/agentforge.git",
|
|
42
|
+
"directory": "packages/channels-discord"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"clean": "rm -rf dist"
|
|
49
|
+
}
|
|
50
|
+
}
|