Skip to content

Agent filters

Import built-in filters as filter or f from @xmtp/agent-sdk.

FilterChecks
fromSelf(message, client)Sender is the current client
hasContent(message)Content is known, with a decoded value for custom content
isDM(conversation)Conversation is a direct message
isGroup(conversation)Conversation is a group
isGroupAdminAsync(conversation, message)Sender is a group admin
isGroupSuperAdminAsync(conversation, message)Sender is a group super admin
usesCodec(message, Codec)Codec authority, type name, and major version match; content is decoded
import {
const filter: {
fromSelf: (message: Message, client: Client) => boolean;
hasContent: (message: Message) => message is DecodedMessageWithContent;
isDM: (conversation: Group | Dm) => conversation is Dm;
isGroup: (conversation: Group | Dm) => conversation is Group;
isGroupAdminAsync: (conversation: Group | Dm, message: Message) => Promise<boolean>;
isGroupSuperAdminAsync: (conversation: Group | Dm, message: Message) => Promise<boolean>;
usesCodec: <T extends AnyContentCodec>(message: Message, codecClass: new () => T) => message is DecodedMessageWithContent<ReturnType<T["decode"]>>;
}

Message and conversation tests for agent middleware.

filter
} from "@xmtp/agent-sdk";
const agent: Agent<unknown>
agent
.
NodeJS.EventEmitter<EventHandlerMap<unknown>>.on<"message">(eventName: keyof EventEmitterEventMap | "actions" | "attachment" | "conversation" | "group-update" | "dm" | "group" | "inline-attachment" | "intent" | "leave-request" | "markdown" | "message" | "multi-attachment" | "reaction" | "read-receipt" | "reply" | "start" | "stop" | "text" | "transaction-reference" | "unhandledError" | "unknownMessage" | "wallet-send-calls", listener: (ctx: MessageContext<unknown, unknown>) => void): Agent<unknown>

Adds the listener function to the end of the listeners array for the event named eventName. No checks are made to see if the listener has already been added. Multiple calls passing the same combination of eventName and listener will result in the listener being added, and called, multiple times.

server.on('connection', (stream) => {
console.log('someone connected!');
});

Returns a reference to the EventEmitter, so that calls can be chained.

By default, event listeners are invoked in the order they are added. The emitter.prependListener() method can be used as an alternative to add the event listener to the beginning of the listeners array.

import { EventEmitter } from 'node:events';
const myEE = new EventEmitter();
myEE.on('foo', () => console.log('a'));
myEE.prependListener('foo', () => console.log('b'));
myEE.emit('foo');
// Prints:
// b
// a

@since ― v0.1.101

@param ― eventName The name of the event.

@param ― listener The callback function

on
("message", async (
ctx: MessageContext<unknown, unknown>
ctx
) => {
if (
const filter: {
fromSelf: (message: Message, client: Client) => boolean;
hasContent: (message: Message) => message is DecodedMessageWithContent;
isDM: (conversation: Group | Dm) => conversation is Dm;
isGroup: (conversation: Group | Dm) => conversation is Group;
isGroupAdminAsync: (conversation: Group | Dm, message: Message) => Promise<boolean>;
isGroupSuperAdminAsync: (conversation: Group | Dm, message: Message) => Promise<boolean>;
usesCodec: <T extends AnyContentCodec>(message: Message, codecClass: new () => T) => message is DecodedMessageWithContent<ReturnType<T["decode"]>>;
}

Message and conversation tests for agent middleware.

filter
.
fromSelf: (message: Message, client: Client) => boolean

Check whether the client sent the message.

fromSelf
(
ctx: MessageContext<unknown, unknown>
ctx
.
MessageContext<unknown, unknown>.message: Message

The SDK message, including its tagged content and retained bytes.

message
,
ctx: MessageContext<unknown, unknown>
ctx
.
ClientContext<unknown>.client: Client

Return the wrapped XMTP client.

client
)) return;
if (
const filter: {
fromSelf: (message: Message, client: Client) => boolean;
hasContent: (message: Message) => message is DecodedMessageWithContent;
isDM: (conversation: Group | Dm) => conversation is Dm;
isGroup: (conversation: Group | Dm) => conversation is Group;
isGroupAdminAsync: (conversation: Group | Dm, message: Message) => Promise<boolean>;
isGroupSuperAdminAsync: (conversation: Group | Dm, message: Message) => Promise<boolean>;
usesCodec: <T extends AnyContentCodec>(message: Message, codecClass: new () => T) => message is DecodedMessageWithContent<ReturnType<T["decode"]>>;
}

Message and conversation tests for agent middleware.

filter
.
hasContent: (message: Message) => message is DecodedMessageWithContent

Check whether the content type is known and has decoded custom content.

hasContent
(
ctx: MessageContext<unknown, unknown>
ctx
.
MessageContext<unknown, unknown>.message: Message

The SDK message, including its tagged content and retained bytes.

message
) &&
ctx: MessageContext<unknown, unknown>
ctx
.
MessageContext<unknown, unknown>.isText(): this is MessageContext<string, unknown>

Narrow this context to a text message.

isText
() &&
(await
const filter: {
fromSelf: (message: Message, client: Client) => boolean;
hasContent: (message: Message) => message is DecodedMessageWithContent;
isDM: (conversation: Group | Dm) => conversation is Dm;
isGroup: (conversation: Group | Dm) => conversation is Group;
isGroupAdminAsync: (conversation: Group | Dm, message: Message) => Promise<boolean>;
isGroupSuperAdminAsync: (conversation: Group | Dm, message: Message) => Promise<boolean>;
usesCodec: <T extends AnyContentCodec>(message: Message, codecClass: new () => T) => message is DecodedMessageWithContent<ReturnType<T["decode"]>>;
}

Message and conversation tests for agent middleware.

filter
.
isGroupAdminAsync: (conversation: Group | Dm, message: Message) => Promise<boolean>

Await this check before granting group admin access.

isGroupAdminAsync
(
ctx: MessageContext<string, unknown>
ctx
.
ConversationContext<unknown, Conversation>.conversation: Conversation

Return the conversation that triggered this context.

conversation
,
ctx: MessageContext<string, unknown>
ctx
.
MessageContext<Content = unknown, ContentTypes = unknown>.message: DecodedMessageWithContent<unknown>

The SDK message, including its tagged content and retained bytes.

message
))
) {
await
ctx: MessageContext<string, unknown>
ctx
.
MessageContext<string, unknown>.sendTextReply(text: string): Promise<void>

Send a text reply to this message with push disabled.

sendTextReply
("Received text");
}
});
await
const agent: Agent<unknown>
agent
.
Agent<unknown>.start(options?: AgentStreamingOptions): Promise<void>

Start conversation and message streams. Calling this while running is a no-op.

start
();

Await isGroupAdminAsync and isGroupSuperAdminAsync before an access check. The examples use the async name to make this requirement clear.

MessageContext also supplies type guards for Markdown, text, replies, reactions, read receipts, remote attachments, transaction references, and wallet send calls.

usesCodec does not compare the minor version. hasContent accepts built-in content, including read receipts. It rejects unknown content and custom content that has no decoded value. After a context guard, read its decoded value from ctx.content.