4. Message Operations
Send, reply, update, delete, and react to messages
The Bot SDK provides several operations for interacting with messages.
Send a Message
Use bot.message.send to send a new message to a channel:
yield * bot.message.send(channelId, "Hello, world!")The method returns the created message:
const sentMessage = yield * bot.message.send(channelId, "Hello!")
yield * Effect.log(`Sent message: ${sentMessage.id}`)Reply to a Message
Use bot.message.reply to reply to a specific message:
yield *
bot.onMessage((message) =>
Effect.gen(function* () {
yield* bot.message.reply(message, "Got it!")
}),
)React with an Emoji
Use bot.message.react to add a reaction:
yield * bot.message.react(message, "👍")For our Task Bot, let's react with a checkmark when a task is added:
yield *
bot.onCommand(AddTaskCommand, (ctx) =>
Effect.gen(function* () {
tasks.push(ctx.args.title)
// Send confirmation
const confirmation = yield* bot.message.send(ctx.channelId, `Added: ${ctx.args.title}`)
// React to our own message
yield* bot.message.react(confirmation, "✅")
}),
)Update a Message
Use bot.message.update to edit an existing message:
const message = yield * bot.message.send(channelId, "Loading...")
// Do some work...
yield * Effect.sleep("2 seconds")
// Update the message
yield * bot.message.update(message, "Done!")Delete a Message
Use bot.message.delete to remove a message:
yield * bot.message.delete(messageId)Rate Limiting
The SDK automatically rate-limits message operations to 10 per second. This prevents hitting API limits and ensures reliable delivery.
If you send messages faster than the limit, they'll be queued and sent at the allowed rate.
Complete Example
Here's our Task Bot with all message operations:
import { Effect, Schema } from "effect"
import { Command, CommandGroup, runHazelBot } from "@hazel/bot-sdk"
const tasks: string[] = []
const AddTaskCommand = Command.make("task-add", {
description: "Add a new task",
args: { title: Schema.String },
})
const ListTasksCommand = Command.make("task-list", {
description: "List all tasks",
})
const ClearTasksCommand = Command.make("task-clear", {
description: "Clear all tasks",
})
const commands = CommandGroup.make(AddTaskCommand, ListTasksCommand, ClearTasksCommand)
runHazelBot({
commands,
setup: (bot) =>
Effect.gen(function* () {
yield* Effect.log("Task Bot is starting...")
// Add task with confirmation and reaction
yield* bot.onCommand(AddTaskCommand, (ctx) =>
Effect.gen(function* () {
tasks.push(ctx.args.title)
const msg = yield* bot.message.send(ctx.channelId, `Added: ${ctx.args.title}`)
yield* bot.message.react(msg, "✅")
}),
)
// List tasks
yield* bot.onCommand(ListTasksCommand, (ctx) =>
Effect.gen(function* () {
if (tasks.length === 0) {
yield* bot.message.send(ctx.channelId, "No tasks yet! Use /task-add to add one.")
return
}
const list = tasks.map((t, i) => `${i + 1}. ${t}`).join("\n")
yield* bot.message.send(ctx.channelId, `**Tasks (${tasks.length}):**\n${list}`)
}),
)
// Clear tasks with "deleting" feedback
yield* bot.onCommand(ClearTasksCommand, (ctx) =>
Effect.gen(function* () {
const count = tasks.length
if (count === 0) {
yield* bot.message.send(ctx.channelId, "No tasks to clear!")
return
}
const msg = yield* bot.message.send(ctx.channelId, "Clearing tasks...")
tasks.length = 0
yield* bot.message.update(msg, `Cleared ${count} task${count === 1 ? "" : "s"}!`)
yield* bot.message.react(msg, "🗑️")
}),
)
// React to task mentions
yield* bot.onMessage((message) =>
Effect.gen(function* () {
if (message.content.toLowerCase().includes("task")) {
yield* bot.message.react(message, "📝")
}
}),
)
}),
})What's Next?
Let's add proper error handling to make the bot more robust.