Hazel

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.

On this page