UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

87 lines (60 loc) 4.13 kB
--- title: "Discord" description: "Reach your agent from Discord HTTP Interactions, including slash commands, components, and modals." type: integration --- The Discord channel wires your agent into Discord's HTTP Interactions, including slash and application commands, message components, and modal submissions. Discord enforces a three-second ACK deadline, so the channel verifies the Ed25519 signature headers, acknowledges the command right away, and runs the eve work in the background. See [Channels](./overview) for the contract this builds on. ## Add the channel ```ts title="agent/channels/discord.ts" import { discordChannel } from "eve/channels/discord"; export default discordChannel(); ``` ```bash DISCORD_PUBLIC_KEY=... # verifies X-Signature-Ed25519 + X-Signature-Timestamp DISCORD_APPLICATION_ID=... # edits the deferred response and sends followups DISCORD_BOT_TOKEN=... # proactive messages + fallback + typing indicators ``` To skip env vars, pass the same values through `credentials: { applicationId, botToken, publicKey }`. The route is `POST /eve/v1/discord` by default. Paste that public URL into your Discord application's Interactions Endpoint URL. ## Register a command Registering commands is on you, not the channel. Use Discord's API or the Developer Portal. A string option named `message` lines up with eve's default prompt extraction: ```bash curl -X PUT "https://discord.com/api/v10/applications/$DISCORD_APPLICATION_ID/commands" \ -H "Authorization: Bot $DISCORD_BOT_TOKEN" -H "Content-Type: application/json" \ -d '[{"name":"ask","description":"Ask the eve agent","type":1, "options":[{"name":"message","description":"What should the agent do?","type":3,"required":true}]}]' ``` Use guild commands during development for faster propagation. ## How the channel handles messages ### Dispatch `onCommand(ctx, interaction)` decides whether to dispatch and under what `auth`. Return `{ auth }` to proceed or `null` to drop the interaction. By default, auth comes from the invoking user. Event handlers receive `(eventData, channel, ctx)`, with Discord platform handles on `channel.discord`: ```ts import { discordChannel } from "eve/channels/discord"; export default discordChannel({ onCommand: (ctx, interaction) => ({ auth: { principalId: interaction.user.id, principalType: "user", authenticator: "discord", attributes: { channel_id: interaction.channelId, guild_id: interaction.guildId ?? "" }, }, }), events: { "message.completed"(eventData, channel, ctx) { if (eventData.finishReason === "tool-calls") return; if (eventData.message) channel.discord.post(eventData.message); }, }, }); ``` ### Delivery The default `message.completed` handler edits the deferred response for the first reply and sends followups after that. If the interaction token is rejected, it falls back to a bot-authenticated channel message. Long text is split to Discord's 2000-char limit, and generated messages default to `allowed_mentions: { parse: [] }`. Typing fires on `turn.started` and `actions.requested`, but only when a bot token is present. In custom hooks, call `channel.discord.startTyping()` yourself. ### Human-in-the-loop (HITL) HITL renders as Discord components. Confirmations and options become buttons, `display: "select"` becomes a string select, and freeform input becomes a button that opens a modal. When the user responds, the parked session (paused awaiting input) resumes. ### Proactive sessions Start a session without an inbound interaction through `receive(discord, { message, target, auth })` from a schedule `run` handler, or `args.receive(discord, ...)` from another channel. The proactive target shape is `{ channelId, conversationId?, initialMessage? }`. Either path needs `DISCORD_BOT_TOKEN`. ### Attachments Inbound file attachments are not supported on this channel today. ## What to read next - [Channels overview](./overview): the channel contract and every built-in channel - [Auth & route protection](../guides/auth-and-route-protection): authenticating inbound traffic