Event-driven architecture
Subscribe only to what you need using Node’s EventEmitter
interface. Events you can listen for:
-
Message events
attachment
: a new incoming remote attachment messagemessage
: all incoming messages (fires for every message regardless of type)group-update
: group members have been added or removed or metadata has been updatedreaction
: a new incoming reaction messagereply
: a new incoming reply messagetext
: a new incoming text messageunknownMessage
: a message that doesn't match any specific type
-
Conversation events
conversation
: a new group or DM conversationdm
: a new DM conversationgroup
: a new group conversation
-
Lifecycle events
start
/stop
: agent lifecycle eventsunhandledError
: unhandled errors
Example
// Listen to specific message types
agent.on('text', async (ctx) => {
console.log(`Text message: ${ctx.message.content}`);
});
agent.on('reaction', async (ctx) => {
console.log(`Reaction: ${ctx.message.content}`);
});
agent.on('reply', async (ctx) => {
console.log(`Reply to: ${ctx.message.content.reference}`);
});
// Listen to new conversations
agent.on('dm', async (ctx) => {
await ctx.conversation.send('Welcome to our DM!');
});
agent.on('group', async (ctx) => {
await ctx.conversation.send('Hello group!');
});
// Listen to unhandled events
agent.on('unhandledError', (error) => {
console.error(`Agent error: ${error}`);
});
agent.on('unknownMessage', (ctx) => {
// handle the unknown message
});
Best practice example
import { filter } from '@xmtp/agent-sdk';
const agent = await Agent.createFromEnv();
agent.on('message', async (ctx) => {
// Filter for specific message types
if (filter.isText(ctx.message)) {
await ctx.sendText(`Echo: ${ctx.message.content}`);
}
});
Next steps
- Learn about middleware and routing to add cross-cutting behavior
- Explore message filters to process messages selectively
- Understand context and helpers for rich message handling