Skip to content

Build an agent

Use the XMTP Agent SDK to build a Node.js agent that listens for messages and responds.

Use Agent SDK 8.0.0-rc1 with backend 8.0.0-rc1.

Terminal window
npm i --save-exact @xmtp/agent-sdk@8.0.0-rc1

Create a .env file. Load it into process.env before you call Agent.createFromEnv(). The SDK does not read the file itself:

Terminal window
XMTP_BACKEND_URL=https://your-backend.example.com
XMTP_WALLET_KEY=0x...
XMTP_DB_ENCRYPTION_KEY=0x...
XMTP_ENV=my-app

XMTP_BACKEND_URL is required and must include its scheme. XMTP_ENV is only a label for a directory under the storage root. The wallet key must use 0x hex format. The database encryption key is 32 bytes.

import {
class Agent<ContentTypes = unknown>

Event-driven XMTP agent that routes conversations and messages to middleware.

Agent
} from "@xmtp/agent-sdk";
const
const agent: Agent<unknown>
agent
= await
class Agent<ContentTypes = unknown>

Event-driven XMTP agent that routes conversations and messages to middleware.

Agent
.
Agent<ContentTypes = unknown>.createFromEnv<[]>(options?: Partial<AgentCreateOptions<[]>> | undefined): Promise<Agent<unknown>>

Create an agent from XMTP_* variables. XMTP_BACKEND_URL overrides options.backend; one must be supplied. Pass backend.credentials in options for backend authentication.

createFromEnv
();
const agent: Agent<unknown>
agent
.
NodeJS.EventEmitter<EventHandlerMap<unknown>>.on<"text">(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<string, 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
("text", async (
ctx: MessageContext<string, unknown>
ctx
) => {
await
ctx: MessageContext<string, unknown>
ctx
.
ConversationContext<unknown, Conversation>.conversation: Conversation

Return the conversation that triggered this context.

conversation
.
function sendText(text: string, options?: SendOptions): Promise<MessageId>
sendText
("Hello from my XMTP agent!", {
shouldPush?: boolean | undefined
shouldPush
: false,
});
});
const agent: Agent<unknown>
agent
.
NodeJS.EventEmitter<EventHandlerMap<unknown>>.on<"start">(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: ClientContext<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
("start", () => {
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
(`Agent address: ${
const agent: Agent<unknown>
agent
.
Agent<unknown>.address: string

Return the agent account address, when the client has one.

address
}`);
});
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
();

Agent.createFromEnv() creates the client and registers its installation. agent.start() starts message and conversation readers. The start event means that the local readers are ready. The backend can still be offline.

Use Node.js 22.12.0 or later. A minimal container image must include CA certificates for an HTTPS backend.