@elizaos/plugin-matrix 2.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build.ts +16 -0
- package/dist/index.js +1045 -0
- package/package.json +34 -0
- package/src/__tests__/matrix.test.ts +550 -0
- package/src/actions/joinRoom.ts +147 -0
- package/src/actions/listRooms.ts +95 -0
- package/src/actions/sendMessage.ts +175 -0
- package/src/actions/sendReaction.ts +162 -0
- package/src/index.ts +105 -0
- package/src/providers/roomState.ts +95 -0
- package/src/providers/userContext.ts +79 -0
- package/src/service.ts +483 -0
- package/src/types.ts +334 -0
- package/tsconfig.json +21 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1045 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { logger as logger2 } from "@elizaos/core";
|
|
3
|
+
|
|
4
|
+
// src/service.ts
|
|
5
|
+
import { Service, logger } from "@elizaos/core";
|
|
6
|
+
import * as sdk from "matrix-js-sdk";
|
|
7
|
+
|
|
8
|
+
// src/types.ts
|
|
9
|
+
var MAX_MATRIX_MESSAGE_LENGTH = 4000;
|
|
10
|
+
var MATRIX_SERVICE_NAME = "matrix";
|
|
11
|
+
var MatrixEventTypes;
|
|
12
|
+
((MatrixEventTypes2) => {
|
|
13
|
+
MatrixEventTypes2["MESSAGE_RECEIVED"] = "MATRIX_MESSAGE_RECEIVED";
|
|
14
|
+
MatrixEventTypes2["MESSAGE_SENT"] = "MATRIX_MESSAGE_SENT";
|
|
15
|
+
MatrixEventTypes2["ROOM_JOINED"] = "MATRIX_ROOM_JOINED";
|
|
16
|
+
MatrixEventTypes2["ROOM_LEFT"] = "MATRIX_ROOM_LEFT";
|
|
17
|
+
MatrixEventTypes2["INVITE_RECEIVED"] = "MATRIX_INVITE_RECEIVED";
|
|
18
|
+
MatrixEventTypes2["REACTION_RECEIVED"] = "MATRIX_REACTION_RECEIVED";
|
|
19
|
+
MatrixEventTypes2["TYPING_RECEIVED"] = "MATRIX_TYPING_RECEIVED";
|
|
20
|
+
MatrixEventTypes2["SYNC_COMPLETE"] = "MATRIX_SYNC_COMPLETE";
|
|
21
|
+
MatrixEventTypes2["CONNECTION_READY"] = "MATRIX_CONNECTION_READY";
|
|
22
|
+
MatrixEventTypes2["CONNECTION_LOST"] = "MATRIX_CONNECTION_LOST";
|
|
23
|
+
})(MatrixEventTypes ||= {});
|
|
24
|
+
function isValidMatrixUserId(userId) {
|
|
25
|
+
return /^@[^:]+:.+$/.test(userId);
|
|
26
|
+
}
|
|
27
|
+
function isValidMatrixRoomId(roomId) {
|
|
28
|
+
return /^![^:]+:.+$/.test(roomId);
|
|
29
|
+
}
|
|
30
|
+
function isValidMatrixRoomAlias(alias) {
|
|
31
|
+
return /^#[^:]+:.+$/.test(alias);
|
|
32
|
+
}
|
|
33
|
+
function getMatrixLocalpart(matrixId) {
|
|
34
|
+
const match = matrixId.match(/^[@#!]([^:]+):/);
|
|
35
|
+
return match ? match[1] : matrixId;
|
|
36
|
+
}
|
|
37
|
+
function getMatrixServerpart(matrixId) {
|
|
38
|
+
const match = matrixId.match(/:(.+)$/);
|
|
39
|
+
return match ? match[1] : "";
|
|
40
|
+
}
|
|
41
|
+
function getMatrixUserDisplayName(user) {
|
|
42
|
+
return user.displayName || getMatrixLocalpart(user.userId);
|
|
43
|
+
}
|
|
44
|
+
function matrixMxcToHttp(mxcUrl, homeserver) {
|
|
45
|
+
if (!mxcUrl.startsWith("mxc://")) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const [serverName, mediaId] = mxcUrl.slice(6).split("/");
|
|
49
|
+
if (!serverName || !mediaId) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const base = homeserver.replace(/\/$/, "");
|
|
53
|
+
return `${base}/_matrix/media/v3/download/${serverName}/${mediaId}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class MatrixPluginError extends Error {
|
|
57
|
+
constructor(message) {
|
|
58
|
+
super(message);
|
|
59
|
+
this.name = "MatrixPluginError";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
class MatrixServiceNotInitializedError extends MatrixPluginError {
|
|
64
|
+
constructor(message = "Matrix service is not initialized") {
|
|
65
|
+
super(message);
|
|
66
|
+
this.name = "MatrixServiceNotInitializedError";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class MatrixNotConnectedError extends MatrixPluginError {
|
|
71
|
+
constructor(message = "Matrix client is not connected") {
|
|
72
|
+
super(message);
|
|
73
|
+
this.name = "MatrixNotConnectedError";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
class MatrixConfigurationError extends MatrixPluginError {
|
|
78
|
+
settingName;
|
|
79
|
+
constructor(message, settingName) {
|
|
80
|
+
super(message);
|
|
81
|
+
this.name = "MatrixConfigurationError";
|
|
82
|
+
this.settingName = settingName;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
class MatrixApiError extends MatrixPluginError {
|
|
87
|
+
errcode;
|
|
88
|
+
constructor(message, errcode) {
|
|
89
|
+
super(message);
|
|
90
|
+
this.name = "MatrixApiError";
|
|
91
|
+
this.errcode = errcode;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/service.ts
|
|
96
|
+
class MatrixService extends Service {
|
|
97
|
+
static serviceType = MATRIX_SERVICE_NAME;
|
|
98
|
+
capabilityDescription = "Matrix messaging service for chat communication";
|
|
99
|
+
settings;
|
|
100
|
+
client;
|
|
101
|
+
connected = false;
|
|
102
|
+
syncing = false;
|
|
103
|
+
static async start(runtime) {
|
|
104
|
+
const service = new MatrixService;
|
|
105
|
+
await service.initialize(runtime);
|
|
106
|
+
return service;
|
|
107
|
+
}
|
|
108
|
+
static async stopRuntime(runtime) {
|
|
109
|
+
const service = runtime.getService(MATRIX_SERVICE_NAME);
|
|
110
|
+
if (service) {
|
|
111
|
+
await service.stop();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async initialize(runtime) {
|
|
115
|
+
this.runtime = runtime;
|
|
116
|
+
this.settings = this.loadSettings();
|
|
117
|
+
this.validateSettings();
|
|
118
|
+
this.client = sdk.createClient({
|
|
119
|
+
baseUrl: this.settings.homeserver,
|
|
120
|
+
userId: this.settings.userId,
|
|
121
|
+
accessToken: this.settings.accessToken,
|
|
122
|
+
deviceId: this.settings.deviceId
|
|
123
|
+
});
|
|
124
|
+
this.setupEventHandlers();
|
|
125
|
+
await this.connect();
|
|
126
|
+
logger.info(`Matrix service initialized for ${this.settings.userId} on ${this.settings.homeserver}`);
|
|
127
|
+
}
|
|
128
|
+
loadSettings() {
|
|
129
|
+
const getStringSetting = (key) => {
|
|
130
|
+
const value = this.runtime.getSetting(key);
|
|
131
|
+
return typeof value === "string" ? value : undefined;
|
|
132
|
+
};
|
|
133
|
+
const homeserver = getStringSetting("MATRIX_HOMESERVER");
|
|
134
|
+
const userId = getStringSetting("MATRIX_USER_ID");
|
|
135
|
+
const accessToken = getStringSetting("MATRIX_ACCESS_TOKEN");
|
|
136
|
+
const deviceId = getStringSetting("MATRIX_DEVICE_ID");
|
|
137
|
+
const roomsStr = getStringSetting("MATRIX_ROOMS");
|
|
138
|
+
const autoJoinStr = getStringSetting("MATRIX_AUTO_JOIN");
|
|
139
|
+
const encryptionStr = getStringSetting("MATRIX_ENCRYPTION");
|
|
140
|
+
const requireMentionStr = getStringSetting("MATRIX_REQUIRE_MENTION");
|
|
141
|
+
const rooms = roomsStr ? roomsStr.split(",").map((r) => r.trim()).filter(Boolean) : [];
|
|
142
|
+
return {
|
|
143
|
+
homeserver: homeserver || "",
|
|
144
|
+
userId: userId || "",
|
|
145
|
+
accessToken: accessToken || "",
|
|
146
|
+
deviceId,
|
|
147
|
+
rooms,
|
|
148
|
+
autoJoin: autoJoinStr === "true",
|
|
149
|
+
encryption: encryptionStr === "true",
|
|
150
|
+
requireMention: requireMentionStr === "true",
|
|
151
|
+
enabled: true
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
validateSettings() {
|
|
155
|
+
if (!this.settings.homeserver) {
|
|
156
|
+
throw new MatrixConfigurationError("MATRIX_HOMESERVER is required", "MATRIX_HOMESERVER");
|
|
157
|
+
}
|
|
158
|
+
if (!this.settings.userId) {
|
|
159
|
+
throw new MatrixConfigurationError("MATRIX_USER_ID is required", "MATRIX_USER_ID");
|
|
160
|
+
}
|
|
161
|
+
if (!this.settings.accessToken) {
|
|
162
|
+
throw new MatrixConfigurationError("MATRIX_ACCESS_TOKEN is required", "MATRIX_ACCESS_TOKEN");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
setupEventHandlers() {
|
|
166
|
+
this.client.on(sdk.ClientEvent.Sync, (state) => {
|
|
167
|
+
if (state === "PREPARED") {
|
|
168
|
+
this.syncing = true;
|
|
169
|
+
logger.info("Matrix sync complete");
|
|
170
|
+
this.runtime.emitEvent("MATRIX_SYNC_COMPLETE" /* SYNC_COMPLETE */, {
|
|
171
|
+
runtime: this.runtime
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
this.client.on(sdk.RoomEvent.Timeline, (event, room, toStartOfTimeline) => {
|
|
176
|
+
if (toStartOfTimeline)
|
|
177
|
+
return;
|
|
178
|
+
if (event.getType() !== "m.room.message")
|
|
179
|
+
return;
|
|
180
|
+
if (event.getSender() === this.settings.userId)
|
|
181
|
+
return;
|
|
182
|
+
this.handleRoomMessage(event, room);
|
|
183
|
+
});
|
|
184
|
+
this.client.on(sdk.RoomMemberEvent.Membership, (event, member) => {
|
|
185
|
+
if (member.userId !== this.settings.userId)
|
|
186
|
+
return;
|
|
187
|
+
if (member.membership === "invite" && this.settings.autoJoin) {
|
|
188
|
+
const roomId = event.getRoomId();
|
|
189
|
+
if (roomId) {
|
|
190
|
+
logger.info(`Auto-joining room ${roomId}`);
|
|
191
|
+
this.client.joinRoom(roomId).catch((err) => {
|
|
192
|
+
logger.error(`Failed to auto-join room: ${err.message}`);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
handleRoomMessage(event, room) {
|
|
199
|
+
const content = event.getContent();
|
|
200
|
+
const msgType = content.msgtype;
|
|
201
|
+
if (msgType !== "m.text")
|
|
202
|
+
return;
|
|
203
|
+
const roomId = event.getRoomId();
|
|
204
|
+
if (!roomId || !room)
|
|
205
|
+
return;
|
|
206
|
+
if (this.settings.requireMention) {
|
|
207
|
+
const body = content.body || "";
|
|
208
|
+
const localpart = getMatrixLocalpart(this.settings.userId);
|
|
209
|
+
const mentionPattern = new RegExp(`@?${localpart}`, "i");
|
|
210
|
+
if (!mentionPattern.test(body)) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const sender = event.getSender();
|
|
215
|
+
const senderMember = room.getMember(sender || "");
|
|
216
|
+
const senderInfo = {
|
|
217
|
+
userId: sender || "",
|
|
218
|
+
displayName: senderMember?.name,
|
|
219
|
+
avatarUrl: senderMember?.getMxcAvatarUrl() || undefined
|
|
220
|
+
};
|
|
221
|
+
const relatesTo = content["m.relates_to"];
|
|
222
|
+
const isEdit = relatesTo?.rel_type === "m.replace";
|
|
223
|
+
const threadId = relatesTo?.rel_type === "m.thread" ? relatesTo.event_id : undefined;
|
|
224
|
+
const replyTo = relatesTo?.["m.in_reply_to"]?.event_id;
|
|
225
|
+
const message = {
|
|
226
|
+
eventId: event.getId() || "",
|
|
227
|
+
roomId,
|
|
228
|
+
sender: sender || "",
|
|
229
|
+
senderInfo,
|
|
230
|
+
content: content.body || "",
|
|
231
|
+
msgType,
|
|
232
|
+
formattedBody: content.formatted_body,
|
|
233
|
+
timestamp: event.getTs(),
|
|
234
|
+
threadId,
|
|
235
|
+
replyTo,
|
|
236
|
+
isEdit,
|
|
237
|
+
replacesEventId: isEdit ? relatesTo?.event_id : undefined
|
|
238
|
+
};
|
|
239
|
+
const matrixRoom = {
|
|
240
|
+
roomId,
|
|
241
|
+
name: room.name,
|
|
242
|
+
topic: room.currentState.getStateEvents("m.room.topic", "")?.getContent()?.topic,
|
|
243
|
+
canonicalAlias: room.getCanonicalAlias() || undefined,
|
|
244
|
+
isEncrypted: room.hasEncryptionStateEvent(),
|
|
245
|
+
isDirect: this.client.getAccountData("m.direct")?.getContent()?.[sender || ""]?.includes(roomId) || false,
|
|
246
|
+
memberCount: room.getJoinedMemberCount()
|
|
247
|
+
};
|
|
248
|
+
logger.debug(`Matrix message from ${senderInfo.displayName || sender} in ${room.name || roomId}: ${message.content.slice(0, 50)}...`);
|
|
249
|
+
this.runtime.emitEvent("MATRIX_MESSAGE_RECEIVED" /* MESSAGE_RECEIVED */, {
|
|
250
|
+
message,
|
|
251
|
+
room: matrixRoom,
|
|
252
|
+
runtime: this.runtime
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
async connect() {
|
|
256
|
+
await this.client.startClient({ initialSyncLimit: 10 });
|
|
257
|
+
this.connected = true;
|
|
258
|
+
await new Promise((resolve) => {
|
|
259
|
+
const listener = (state) => {
|
|
260
|
+
if (state === "PREPARED") {
|
|
261
|
+
this.client.removeListener(sdk.ClientEvent.Sync, listener);
|
|
262
|
+
resolve();
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
this.client.on(sdk.ClientEvent.Sync, listener);
|
|
266
|
+
});
|
|
267
|
+
for (const room of this.settings.rooms) {
|
|
268
|
+
try {
|
|
269
|
+
await this.joinRoom(room);
|
|
270
|
+
} catch (err) {
|
|
271
|
+
logger.warn(`Failed to join room ${room}: ${err}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
async stop() {
|
|
276
|
+
if (this.client) {
|
|
277
|
+
this.client.stopClient();
|
|
278
|
+
}
|
|
279
|
+
this.connected = false;
|
|
280
|
+
logger.info("Matrix service stopped");
|
|
281
|
+
}
|
|
282
|
+
isConnected() {
|
|
283
|
+
return this.connected && this.syncing;
|
|
284
|
+
}
|
|
285
|
+
getUserId() {
|
|
286
|
+
return this.settings.userId;
|
|
287
|
+
}
|
|
288
|
+
getHomeserver() {
|
|
289
|
+
return this.settings.homeserver;
|
|
290
|
+
}
|
|
291
|
+
async getJoinedRooms() {
|
|
292
|
+
const rooms = this.client.getRooms();
|
|
293
|
+
return rooms.filter((room) => room.getMyMembership() === "join").map((room) => ({
|
|
294
|
+
roomId: room.roomId,
|
|
295
|
+
name: room.name,
|
|
296
|
+
topic: room.currentState.getStateEvents("m.room.topic", "")?.getContent()?.topic,
|
|
297
|
+
canonicalAlias: room.getCanonicalAlias() || undefined,
|
|
298
|
+
isEncrypted: room.hasEncryptionStateEvent(),
|
|
299
|
+
isDirect: false,
|
|
300
|
+
memberCount: room.getJoinedMemberCount()
|
|
301
|
+
}));
|
|
302
|
+
}
|
|
303
|
+
async sendMessage(text, options) {
|
|
304
|
+
if (!this.isConnected()) {
|
|
305
|
+
throw new MatrixNotConnectedError;
|
|
306
|
+
}
|
|
307
|
+
const roomId = options?.roomId;
|
|
308
|
+
if (!roomId) {
|
|
309
|
+
return { success: false, error: "Room ID is required" };
|
|
310
|
+
}
|
|
311
|
+
let resolvedRoomId = roomId;
|
|
312
|
+
if (isValidMatrixRoomAlias(roomId)) {
|
|
313
|
+
const resolved = await this.client.getRoomIdForAlias(roomId);
|
|
314
|
+
resolvedRoomId = resolved.room_id;
|
|
315
|
+
}
|
|
316
|
+
const content = {
|
|
317
|
+
msgtype: "m.text",
|
|
318
|
+
body: text
|
|
319
|
+
};
|
|
320
|
+
if (options?.formatted) {
|
|
321
|
+
content.format = "org.matrix.custom.html";
|
|
322
|
+
content.formatted_body = text;
|
|
323
|
+
}
|
|
324
|
+
if (options?.threadId || options?.replyTo) {
|
|
325
|
+
content["m.relates_to"] = {};
|
|
326
|
+
if (options.threadId) {
|
|
327
|
+
content["m.relates_to"].rel_type = "m.thread";
|
|
328
|
+
content["m.relates_to"].event_id = options.threadId;
|
|
329
|
+
}
|
|
330
|
+
if (options.replyTo) {
|
|
331
|
+
content["m.relates_to"]["m.in_reply_to"] = {
|
|
332
|
+
event_id: options.replyTo
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const response = await this.client.sendMessage(resolvedRoomId, content);
|
|
337
|
+
const eventId = response.event_id;
|
|
338
|
+
this.runtime.emitEvent("MATRIX_MESSAGE_SENT" /* MESSAGE_SENT */, {
|
|
339
|
+
roomId: resolvedRoomId,
|
|
340
|
+
eventId,
|
|
341
|
+
content: text,
|
|
342
|
+
runtime: this.runtime
|
|
343
|
+
});
|
|
344
|
+
return {
|
|
345
|
+
success: true,
|
|
346
|
+
eventId,
|
|
347
|
+
roomId: resolvedRoomId
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
async sendReaction(roomId, eventId, emoji) {
|
|
351
|
+
if (!this.isConnected()) {
|
|
352
|
+
throw new MatrixNotConnectedError;
|
|
353
|
+
}
|
|
354
|
+
const content = {
|
|
355
|
+
"m.relates_to": {
|
|
356
|
+
rel_type: "m.annotation",
|
|
357
|
+
event_id: eventId,
|
|
358
|
+
key: emoji
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
const response = await this.client.sendEvent(roomId, "m.reaction", content);
|
|
362
|
+
return {
|
|
363
|
+
success: true,
|
|
364
|
+
eventId: response.event_id,
|
|
365
|
+
roomId
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
async joinRoom(roomIdOrAlias) {
|
|
369
|
+
if (!this.isConnected()) {
|
|
370
|
+
throw new MatrixNotConnectedError;
|
|
371
|
+
}
|
|
372
|
+
const response = await this.client.joinRoom(roomIdOrAlias);
|
|
373
|
+
const roomId = response.roomId;
|
|
374
|
+
logger.info(`Joined room ${roomId}`);
|
|
375
|
+
this.runtime.emitEvent("MATRIX_ROOM_JOINED" /* ROOM_JOINED */, {
|
|
376
|
+
room: { roomId },
|
|
377
|
+
runtime: this.runtime
|
|
378
|
+
});
|
|
379
|
+
return roomId;
|
|
380
|
+
}
|
|
381
|
+
async leaveRoom(roomId) {
|
|
382
|
+
if (!this.isConnected()) {
|
|
383
|
+
throw new MatrixNotConnectedError;
|
|
384
|
+
}
|
|
385
|
+
await this.client.leave(roomId);
|
|
386
|
+
logger.info(`Left room ${roomId}`);
|
|
387
|
+
this.runtime.emitEvent("MATRIX_ROOM_LEFT" /* ROOM_LEFT */, {
|
|
388
|
+
roomId,
|
|
389
|
+
runtime: this.runtime
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
async sendTyping(roomId, typing, timeout = 30000) {
|
|
393
|
+
if (!this.isConnected()) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
await this.client.sendTyping(roomId, typing, timeout);
|
|
397
|
+
}
|
|
398
|
+
async sendReadReceipt(roomId, eventId) {
|
|
399
|
+
if (!this.isConnected()) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
await this.client.sendReadReceipt(new sdk.MatrixEvent({ event_id: eventId, room_id: roomId }));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
// src/actions/sendMessage.ts
|
|
406
|
+
import { composePromptFromState, ModelType, parseJSONObjectFromText } from "@elizaos/core";
|
|
407
|
+
var SEND_MESSAGE_TEMPLATE = `You are helping to extract send message parameters for Matrix.
|
|
408
|
+
|
|
409
|
+
The user wants to send a message to a Matrix room.
|
|
410
|
+
|
|
411
|
+
Recent conversation:
|
|
412
|
+
{{recentMessages}}
|
|
413
|
+
|
|
414
|
+
Extract the following:
|
|
415
|
+
1. text: The message text to send
|
|
416
|
+
2. roomId: The room ID (!room:server) or alias (#alias:server), or "current" for the current room
|
|
417
|
+
|
|
418
|
+
Respond with a JSON object like:
|
|
419
|
+
{
|
|
420
|
+
"text": "The message to send",
|
|
421
|
+
"roomId": "current"
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
Only respond with the JSON object, no other text.`;
|
|
425
|
+
var sendMessage = {
|
|
426
|
+
name: "MATRIX_SEND_MESSAGE",
|
|
427
|
+
similes: [
|
|
428
|
+
"SEND_MATRIX_MESSAGE",
|
|
429
|
+
"MESSAGE_MATRIX",
|
|
430
|
+
"MATRIX_TEXT"
|
|
431
|
+
],
|
|
432
|
+
description: "Send a message to a Matrix room",
|
|
433
|
+
validate: async (runtime, message, _state) => {
|
|
434
|
+
return message.content.source === "matrix";
|
|
435
|
+
},
|
|
436
|
+
handler: async (runtime, message, state, _options, callback) => {
|
|
437
|
+
const matrixService = runtime.getService(MATRIX_SERVICE_NAME);
|
|
438
|
+
if (!matrixService || !matrixService.isConnected()) {
|
|
439
|
+
if (callback) {
|
|
440
|
+
await callback({ text: "Matrix service is not available.", source: "matrix" });
|
|
441
|
+
}
|
|
442
|
+
return { success: false, error: "Matrix service not available" };
|
|
443
|
+
}
|
|
444
|
+
const composedState = state ?? {
|
|
445
|
+
values: {},
|
|
446
|
+
data: {},
|
|
447
|
+
text: ""
|
|
448
|
+
};
|
|
449
|
+
const prompt = await composePromptFromState({
|
|
450
|
+
template: SEND_MESSAGE_TEMPLATE,
|
|
451
|
+
state: composedState
|
|
452
|
+
});
|
|
453
|
+
let messageInfo = null;
|
|
454
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
455
|
+
const response = await runtime.useModel(ModelType.TEXT_SMALL, {
|
|
456
|
+
prompt
|
|
457
|
+
});
|
|
458
|
+
const parsed = parseJSONObjectFromText(response);
|
|
459
|
+
if (parsed?.text) {
|
|
460
|
+
messageInfo = {
|
|
461
|
+
text: String(parsed.text),
|
|
462
|
+
roomId: String(parsed.roomId || "current")
|
|
463
|
+
};
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
if (!messageInfo || !messageInfo.text) {
|
|
468
|
+
if (callback) {
|
|
469
|
+
await callback({
|
|
470
|
+
text: "I couldn't understand what message you want me to send. Please try again.",
|
|
471
|
+
source: "matrix"
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
return { success: false, error: "Could not extract message parameters" };
|
|
475
|
+
}
|
|
476
|
+
let targetRoomId;
|
|
477
|
+
if (messageInfo.roomId && messageInfo.roomId !== "current") {
|
|
478
|
+
if (isValidMatrixRoomId(messageInfo.roomId) || isValidMatrixRoomAlias(messageInfo.roomId)) {
|
|
479
|
+
targetRoomId = messageInfo.roomId;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
const roomData = state?.data?.room;
|
|
483
|
+
if (!targetRoomId && roomData?.roomId) {
|
|
484
|
+
targetRoomId = roomData.roomId;
|
|
485
|
+
}
|
|
486
|
+
if (!targetRoomId) {
|
|
487
|
+
if (callback) {
|
|
488
|
+
await callback({
|
|
489
|
+
text: "I couldn't determine which room to send to. Please specify a room.",
|
|
490
|
+
source: "matrix"
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
return { success: false, error: "Could not determine target room" };
|
|
494
|
+
}
|
|
495
|
+
const result = await matrixService.sendMessage(messageInfo.text, {
|
|
496
|
+
roomId: targetRoomId
|
|
497
|
+
});
|
|
498
|
+
if (!result.success) {
|
|
499
|
+
if (callback) {
|
|
500
|
+
await callback({
|
|
501
|
+
text: `Failed to send message: ${result.error}`,
|
|
502
|
+
source: "matrix"
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
return { success: false, error: result.error };
|
|
506
|
+
}
|
|
507
|
+
if (callback) {
|
|
508
|
+
await callback({
|
|
509
|
+
text: "Message sent successfully.",
|
|
510
|
+
source: message.content.source
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
return {
|
|
514
|
+
success: true,
|
|
515
|
+
data: {
|
|
516
|
+
roomId: result.roomId,
|
|
517
|
+
eventId: result.eventId
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
},
|
|
521
|
+
examples: [
|
|
522
|
+
[
|
|
523
|
+
{
|
|
524
|
+
name: "{{user1}}",
|
|
525
|
+
content: { text: "Send a message saying 'Hello everyone!'" }
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
name: "{{agent}}",
|
|
529
|
+
content: {
|
|
530
|
+
text: "I'll send that message to the room.",
|
|
531
|
+
actions: ["MATRIX_SEND_MESSAGE"]
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
]
|
|
535
|
+
]
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
// src/actions/sendReaction.ts
|
|
539
|
+
import { composePromptFromState as composePromptFromState2, ModelType as ModelType2, parseJSONObjectFromText as parseJSONObjectFromText2 } from "@elizaos/core";
|
|
540
|
+
var SEND_REACTION_TEMPLATE = `You are helping to extract reaction parameters for Matrix.
|
|
541
|
+
|
|
542
|
+
The user wants to react to a Matrix message with an emoji.
|
|
543
|
+
|
|
544
|
+
Recent conversation:
|
|
545
|
+
{{recentMessages}}
|
|
546
|
+
|
|
547
|
+
Extract the following:
|
|
548
|
+
1. emoji: The emoji to react with (single emoji character)
|
|
549
|
+
2. eventId: The event ID of the message to react to (starts with $)
|
|
550
|
+
|
|
551
|
+
Respond with a JSON object like:
|
|
552
|
+
{
|
|
553
|
+
"emoji": "\uD83D\uDC4D",
|
|
554
|
+
"eventId": "$event123"
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
Only respond with the JSON object, no other text.`;
|
|
558
|
+
var sendReaction = {
|
|
559
|
+
name: "MATRIX_SEND_REACTION",
|
|
560
|
+
similes: [
|
|
561
|
+
"REACT_MATRIX",
|
|
562
|
+
"MATRIX_REACT",
|
|
563
|
+
"ADD_MATRIX_REACTION"
|
|
564
|
+
],
|
|
565
|
+
description: "React to a Matrix message with an emoji",
|
|
566
|
+
validate: async (runtime, message, _state) => {
|
|
567
|
+
return message.content.source === "matrix";
|
|
568
|
+
},
|
|
569
|
+
handler: async (runtime, message, state, _options, callback) => {
|
|
570
|
+
const matrixService = runtime.getService(MATRIX_SERVICE_NAME);
|
|
571
|
+
if (!matrixService || !matrixService.isConnected()) {
|
|
572
|
+
if (callback) {
|
|
573
|
+
await callback({ text: "Matrix service is not available.", source: "matrix" });
|
|
574
|
+
}
|
|
575
|
+
return { success: false, error: "Matrix service not available" };
|
|
576
|
+
}
|
|
577
|
+
const composedState = state ?? {
|
|
578
|
+
values: {},
|
|
579
|
+
data: {},
|
|
580
|
+
text: ""
|
|
581
|
+
};
|
|
582
|
+
const prompt = await composePromptFromState2({
|
|
583
|
+
template: SEND_REACTION_TEMPLATE,
|
|
584
|
+
state: composedState
|
|
585
|
+
});
|
|
586
|
+
let reactionInfo = null;
|
|
587
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
588
|
+
const response = await runtime.useModel(ModelType2.TEXT_SMALL, {
|
|
589
|
+
prompt
|
|
590
|
+
});
|
|
591
|
+
const parsed = parseJSONObjectFromText2(response);
|
|
592
|
+
if (parsed?.emoji && parsed?.eventId) {
|
|
593
|
+
reactionInfo = {
|
|
594
|
+
emoji: String(parsed.emoji),
|
|
595
|
+
eventId: String(parsed.eventId)
|
|
596
|
+
};
|
|
597
|
+
break;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
if (!reactionInfo) {
|
|
601
|
+
if (callback) {
|
|
602
|
+
await callback({
|
|
603
|
+
text: "I couldn't understand the reaction request. Please specify the emoji and message.",
|
|
604
|
+
source: "matrix"
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
return { success: false, error: "Could not extract reaction parameters" };
|
|
608
|
+
}
|
|
609
|
+
const roomData = state?.data?.room;
|
|
610
|
+
const roomId = roomData?.roomId;
|
|
611
|
+
if (!roomId) {
|
|
612
|
+
if (callback) {
|
|
613
|
+
await callback({
|
|
614
|
+
text: "I couldn't determine which room this is in.",
|
|
615
|
+
source: "matrix"
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
return { success: false, error: "Could not determine room" };
|
|
619
|
+
}
|
|
620
|
+
const result = await matrixService.sendReaction(roomId, reactionInfo.eventId, reactionInfo.emoji);
|
|
621
|
+
if (!result.success) {
|
|
622
|
+
if (callback) {
|
|
623
|
+
await callback({
|
|
624
|
+
text: `Failed to add reaction: ${result.error}`,
|
|
625
|
+
source: "matrix"
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
return { success: false, error: result.error };
|
|
629
|
+
}
|
|
630
|
+
if (callback) {
|
|
631
|
+
await callback({
|
|
632
|
+
text: `Added ${reactionInfo.emoji} reaction.`,
|
|
633
|
+
source: message.content.source
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
return {
|
|
637
|
+
success: true,
|
|
638
|
+
data: {
|
|
639
|
+
emoji: reactionInfo.emoji,
|
|
640
|
+
eventId: reactionInfo.eventId,
|
|
641
|
+
roomId
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
},
|
|
645
|
+
examples: [
|
|
646
|
+
[
|
|
647
|
+
{
|
|
648
|
+
name: "{{user1}}",
|
|
649
|
+
content: { text: "React to the last message with a thumbs up" }
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
name: "{{agent}}",
|
|
653
|
+
content: {
|
|
654
|
+
text: "I'll add a thumbs up reaction.",
|
|
655
|
+
actions: ["MATRIX_SEND_REACTION"]
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
]
|
|
659
|
+
]
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
// src/actions/listRooms.ts
|
|
663
|
+
var listRooms = {
|
|
664
|
+
name: "MATRIX_LIST_ROOMS",
|
|
665
|
+
similes: [
|
|
666
|
+
"LIST_MATRIX_ROOMS",
|
|
667
|
+
"SHOW_ROOMS",
|
|
668
|
+
"GET_ROOMS",
|
|
669
|
+
"MY_ROOMS"
|
|
670
|
+
],
|
|
671
|
+
description: "List all Matrix rooms the bot has joined",
|
|
672
|
+
validate: async (runtime, message, _state) => {
|
|
673
|
+
return message.content.source === "matrix";
|
|
674
|
+
},
|
|
675
|
+
handler: async (runtime, message, _state, _options, callback) => {
|
|
676
|
+
const matrixService = runtime.getService(MATRIX_SERVICE_NAME);
|
|
677
|
+
if (!matrixService || !matrixService.isConnected()) {
|
|
678
|
+
if (callback) {
|
|
679
|
+
await callback({ text: "Matrix service is not available.", source: "matrix" });
|
|
680
|
+
}
|
|
681
|
+
return { success: false, error: "Matrix service not available" };
|
|
682
|
+
}
|
|
683
|
+
const rooms = await matrixService.getJoinedRooms();
|
|
684
|
+
const roomList = rooms.map((room) => {
|
|
685
|
+
const name = room.name || room.canonicalAlias || room.roomId;
|
|
686
|
+
const members = `${room.memberCount} members`;
|
|
687
|
+
const encrypted = room.isEncrypted ? " (encrypted)" : "";
|
|
688
|
+
return `- ${name} (${members})${encrypted}`;
|
|
689
|
+
});
|
|
690
|
+
const responseText = rooms.length > 0 ? `Joined ${rooms.length} room(s):
|
|
691
|
+
|
|
692
|
+
${roomList.join(`
|
|
693
|
+
`)}` : "Not currently in any rooms.";
|
|
694
|
+
if (callback) {
|
|
695
|
+
await callback({
|
|
696
|
+
text: responseText,
|
|
697
|
+
source: message.content.source
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
return {
|
|
701
|
+
success: true,
|
|
702
|
+
data: {
|
|
703
|
+
roomCount: rooms.length,
|
|
704
|
+
rooms: rooms.map((r) => ({
|
|
705
|
+
roomId: r.roomId,
|
|
706
|
+
name: r.name,
|
|
707
|
+
alias: r.canonicalAlias,
|
|
708
|
+
memberCount: r.memberCount,
|
|
709
|
+
isEncrypted: r.isEncrypted
|
|
710
|
+
}))
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
},
|
|
714
|
+
examples: [
|
|
715
|
+
[
|
|
716
|
+
{
|
|
717
|
+
name: "{{user1}}",
|
|
718
|
+
content: { text: "What rooms are you in?" }
|
|
719
|
+
},
|
|
720
|
+
{
|
|
721
|
+
name: "{{agent}}",
|
|
722
|
+
content: {
|
|
723
|
+
text: "I'll list the rooms I've joined.",
|
|
724
|
+
actions: ["MATRIX_LIST_ROOMS"]
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
]
|
|
728
|
+
]
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
// src/actions/joinRoom.ts
|
|
732
|
+
import { composePromptFromState as composePromptFromState3, ModelType as ModelType3, parseJSONObjectFromText as parseJSONObjectFromText3 } from "@elizaos/core";
|
|
733
|
+
var JOIN_ROOM_TEMPLATE = `You are helping to extract a Matrix room identifier.
|
|
734
|
+
|
|
735
|
+
The user wants to join a Matrix room.
|
|
736
|
+
|
|
737
|
+
Recent conversation:
|
|
738
|
+
{{recentMessages}}
|
|
739
|
+
|
|
740
|
+
Extract the room ID (!room:server) or room alias (#alias:server) to join.
|
|
741
|
+
|
|
742
|
+
Respond with a JSON object like:
|
|
743
|
+
{
|
|
744
|
+
"room": "!room:matrix.org"
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
or:
|
|
748
|
+
|
|
749
|
+
{
|
|
750
|
+
"room": "#alias:matrix.org"
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
Only respond with the JSON object, no other text.`;
|
|
754
|
+
var joinRoom = {
|
|
755
|
+
name: "MATRIX_JOIN_ROOM",
|
|
756
|
+
similes: [
|
|
757
|
+
"JOIN_MATRIX_ROOM",
|
|
758
|
+
"ENTER_ROOM"
|
|
759
|
+
],
|
|
760
|
+
description: "Join a Matrix room by ID or alias",
|
|
761
|
+
validate: async (runtime, message, _state) => {
|
|
762
|
+
return message.content.source === "matrix";
|
|
763
|
+
},
|
|
764
|
+
handler: async (runtime, message, state, _options, callback) => {
|
|
765
|
+
const matrixService = runtime.getService(MATRIX_SERVICE_NAME);
|
|
766
|
+
if (!matrixService || !matrixService.isConnected()) {
|
|
767
|
+
if (callback) {
|
|
768
|
+
await callback({ text: "Matrix service is not available.", source: "matrix" });
|
|
769
|
+
}
|
|
770
|
+
return { success: false, error: "Matrix service not available" };
|
|
771
|
+
}
|
|
772
|
+
const composedState = state ?? {
|
|
773
|
+
values: {},
|
|
774
|
+
data: {},
|
|
775
|
+
text: ""
|
|
776
|
+
};
|
|
777
|
+
const prompt = await composePromptFromState3({
|
|
778
|
+
template: JOIN_ROOM_TEMPLATE,
|
|
779
|
+
state: composedState
|
|
780
|
+
});
|
|
781
|
+
let room = null;
|
|
782
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
783
|
+
const response = await runtime.useModel(ModelType3.TEXT_SMALL, {
|
|
784
|
+
prompt
|
|
785
|
+
});
|
|
786
|
+
const parsed = parseJSONObjectFromText3(response);
|
|
787
|
+
if (parsed?.room) {
|
|
788
|
+
const roomStr = String(parsed.room).trim();
|
|
789
|
+
if (isValidMatrixRoomId(roomStr) || isValidMatrixRoomAlias(roomStr)) {
|
|
790
|
+
room = roomStr;
|
|
791
|
+
break;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
if (!room) {
|
|
796
|
+
if (callback) {
|
|
797
|
+
await callback({
|
|
798
|
+
text: "I couldn't understand which room you want me to join. Please specify a room ID (!room:server) or alias (#alias:server).",
|
|
799
|
+
source: "matrix"
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
return { success: false, error: "Could not extract room identifier" };
|
|
803
|
+
}
|
|
804
|
+
try {
|
|
805
|
+
const roomId = await matrixService.joinRoom(room);
|
|
806
|
+
if (callback) {
|
|
807
|
+
await callback({
|
|
808
|
+
text: `Joined room ${room}.`,
|
|
809
|
+
source: message.content.source
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
return {
|
|
813
|
+
success: true,
|
|
814
|
+
data: {
|
|
815
|
+
roomId,
|
|
816
|
+
joined: room
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
} catch (err) {
|
|
820
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
821
|
+
if (callback) {
|
|
822
|
+
await callback({
|
|
823
|
+
text: `Failed to join room: ${error}`,
|
|
824
|
+
source: "matrix"
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
return { success: false, error };
|
|
828
|
+
}
|
|
829
|
+
},
|
|
830
|
+
examples: [
|
|
831
|
+
[
|
|
832
|
+
{
|
|
833
|
+
name: "{{user1}}",
|
|
834
|
+
content: { text: "Join #general:matrix.org" }
|
|
835
|
+
},
|
|
836
|
+
{
|
|
837
|
+
name: "{{agent}}",
|
|
838
|
+
content: {
|
|
839
|
+
text: "I'll join that room.",
|
|
840
|
+
actions: ["MATRIX_JOIN_ROOM"]
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
]
|
|
844
|
+
]
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
// src/providers/roomState.ts
|
|
848
|
+
var roomStateProvider = {
|
|
849
|
+
name: "matrixRoomState",
|
|
850
|
+
description: "Provides information about the current Matrix room context",
|
|
851
|
+
get: async (runtime, message, state) => {
|
|
852
|
+
if (message.content.source !== "matrix") {
|
|
853
|
+
return {
|
|
854
|
+
data: {},
|
|
855
|
+
values: {},
|
|
856
|
+
text: ""
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
const matrixService = runtime.getService(MATRIX_SERVICE_NAME);
|
|
860
|
+
if (!matrixService || !matrixService.isConnected()) {
|
|
861
|
+
return {
|
|
862
|
+
data: { connected: false },
|
|
863
|
+
values: { connected: false },
|
|
864
|
+
text: ""
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
const agentName = state?.agentName || "The agent";
|
|
868
|
+
const room = state?.data?.room;
|
|
869
|
+
const roomId = room?.roomId;
|
|
870
|
+
const roomName = room?.name;
|
|
871
|
+
const isEncrypted = room?.isEncrypted;
|
|
872
|
+
const isDirect = room?.isDirect;
|
|
873
|
+
const memberCount = room?.memberCount;
|
|
874
|
+
const userId = matrixService.getUserId();
|
|
875
|
+
const displayName = getMatrixLocalpart(userId);
|
|
876
|
+
let responseText = "";
|
|
877
|
+
if (isDirect) {
|
|
878
|
+
responseText = `${agentName} is in a direct message conversation on Matrix.`;
|
|
879
|
+
} else {
|
|
880
|
+
const roomLabel = roomName || roomId || "a Matrix room";
|
|
881
|
+
responseText = `${agentName} is currently in Matrix room "${roomLabel}".`;
|
|
882
|
+
if (memberCount) {
|
|
883
|
+
responseText += ` The room has ${memberCount} members.`;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
if (isEncrypted) {
|
|
887
|
+
responseText += " This room has end-to-end encryption enabled.";
|
|
888
|
+
}
|
|
889
|
+
responseText += `
|
|
890
|
+
|
|
891
|
+
Matrix is a decentralized communication protocol. ${agentName} is logged in as ${userId}.`;
|
|
892
|
+
return {
|
|
893
|
+
data: {
|
|
894
|
+
roomId,
|
|
895
|
+
roomName,
|
|
896
|
+
isEncrypted: isEncrypted || false,
|
|
897
|
+
isDirect: isDirect || false,
|
|
898
|
+
memberCount: memberCount || 0,
|
|
899
|
+
userId,
|
|
900
|
+
displayName,
|
|
901
|
+
homeserver: matrixService.getHomeserver(),
|
|
902
|
+
connected: true
|
|
903
|
+
},
|
|
904
|
+
values: {
|
|
905
|
+
roomId,
|
|
906
|
+
roomName,
|
|
907
|
+
isEncrypted: isEncrypted || false,
|
|
908
|
+
isDirect: isDirect || false,
|
|
909
|
+
memberCount: memberCount || 0,
|
|
910
|
+
userId
|
|
911
|
+
},
|
|
912
|
+
text: responseText
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
|
|
917
|
+
// src/providers/userContext.ts
|
|
918
|
+
var userContextProvider = {
|
|
919
|
+
name: "matrixUserContext",
|
|
920
|
+
description: "Provides information about the Matrix user in the current conversation",
|
|
921
|
+
get: async (runtime, message, state) => {
|
|
922
|
+
if (message.content.source !== "matrix") {
|
|
923
|
+
return {
|
|
924
|
+
data: {},
|
|
925
|
+
values: {},
|
|
926
|
+
text: ""
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
const matrixService = runtime.getService(MATRIX_SERVICE_NAME);
|
|
930
|
+
if (!matrixService || !matrixService.isConnected()) {
|
|
931
|
+
return {
|
|
932
|
+
data: {},
|
|
933
|
+
values: {},
|
|
934
|
+
text: ""
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
const agentName = state?.agentName || "The agent";
|
|
938
|
+
const metadata = message.content.metadata;
|
|
939
|
+
const senderInfo = metadata?.senderInfo;
|
|
940
|
+
if (!senderInfo) {
|
|
941
|
+
return {
|
|
942
|
+
data: {},
|
|
943
|
+
values: {},
|
|
944
|
+
text: ""
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
const displayName = getMatrixUserDisplayName(senderInfo);
|
|
948
|
+
const localpart = getMatrixLocalpart(senderInfo.userId);
|
|
949
|
+
const responseText = `${agentName} is talking to ${displayName} (${senderInfo.userId}) on Matrix.`;
|
|
950
|
+
return {
|
|
951
|
+
data: {
|
|
952
|
+
userId: senderInfo.userId,
|
|
953
|
+
displayName,
|
|
954
|
+
localpart,
|
|
955
|
+
avatarUrl: senderInfo.avatarUrl
|
|
956
|
+
},
|
|
957
|
+
values: {
|
|
958
|
+
userId: senderInfo.userId,
|
|
959
|
+
displayName,
|
|
960
|
+
localpart
|
|
961
|
+
},
|
|
962
|
+
text: responseText
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
// src/index.ts
|
|
968
|
+
var matrixPlugin = {
|
|
969
|
+
name: "matrix",
|
|
970
|
+
description: "Matrix messaging integration plugin for ElizaOS with E2EE support",
|
|
971
|
+
services: [MatrixService],
|
|
972
|
+
actions: [sendMessage, sendReaction, listRooms, joinRoom],
|
|
973
|
+
providers: [roomStateProvider, userContextProvider],
|
|
974
|
+
tests: [],
|
|
975
|
+
init: async (_config, runtime) => {
|
|
976
|
+
const homeserver = runtime.getSetting("MATRIX_HOMESERVER");
|
|
977
|
+
const userId = runtime.getSetting("MATRIX_USER_ID");
|
|
978
|
+
const accessToken = runtime.getSetting("MATRIX_ACCESS_TOKEN");
|
|
979
|
+
logger2.info("=".repeat(60));
|
|
980
|
+
logger2.info("Matrix Plugin Configuration");
|
|
981
|
+
logger2.info("=".repeat(60));
|
|
982
|
+
logger2.info(` Homeserver: ${homeserver ? `✓ ${homeserver}` : "✗ Missing (required)"}`);
|
|
983
|
+
logger2.info(` User ID: ${userId ? `✓ ${userId}` : "✗ Missing (required)"}`);
|
|
984
|
+
logger2.info(` Access Token: ${accessToken ? "✓ Set" : "✗ Missing (required)"}`);
|
|
985
|
+
logger2.info("=".repeat(60));
|
|
986
|
+
const missing = [];
|
|
987
|
+
if (!homeserver)
|
|
988
|
+
missing.push("MATRIX_HOMESERVER");
|
|
989
|
+
if (!userId)
|
|
990
|
+
missing.push("MATRIX_USER_ID");
|
|
991
|
+
if (!accessToken)
|
|
992
|
+
missing.push("MATRIX_ACCESS_TOKEN");
|
|
993
|
+
if (missing.length > 0) {
|
|
994
|
+
logger2.warn(`Matrix plugin: Missing required configuration: ${missing.join(", ")}`);
|
|
995
|
+
}
|
|
996
|
+
const deviceId = runtime.getSetting("MATRIX_DEVICE_ID");
|
|
997
|
+
const rooms = runtime.getSetting("MATRIX_ROOMS");
|
|
998
|
+
const autoJoin = runtime.getSetting("MATRIX_AUTO_JOIN");
|
|
999
|
+
const encryption = runtime.getSetting("MATRIX_ENCRYPTION");
|
|
1000
|
+
const requireMention = runtime.getSetting("MATRIX_REQUIRE_MENTION");
|
|
1001
|
+
if (deviceId) {
|
|
1002
|
+
logger2.info(` Device ID: ${deviceId}`);
|
|
1003
|
+
}
|
|
1004
|
+
if (rooms) {
|
|
1005
|
+
logger2.info(` Auto-join Rooms: ${rooms}`);
|
|
1006
|
+
}
|
|
1007
|
+
if (autoJoin === "true") {
|
|
1008
|
+
logger2.info(" Auto-join Invites: ✓ Enabled");
|
|
1009
|
+
}
|
|
1010
|
+
if (encryption === "true") {
|
|
1011
|
+
logger2.info(" End-to-End Encryption: ✓ Enabled");
|
|
1012
|
+
}
|
|
1013
|
+
if (requireMention === "true") {
|
|
1014
|
+
logger2.info(" Require Mention: ✓ Enabled (will only respond to mentions in rooms)");
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
var src_default = matrixPlugin;
|
|
1019
|
+
export {
|
|
1020
|
+
userContextProvider,
|
|
1021
|
+
sendReaction,
|
|
1022
|
+
sendMessage,
|
|
1023
|
+
roomStateProvider,
|
|
1024
|
+
matrixMxcToHttp,
|
|
1025
|
+
listRooms,
|
|
1026
|
+
joinRoom,
|
|
1027
|
+
isValidMatrixUserId,
|
|
1028
|
+
isValidMatrixRoomId,
|
|
1029
|
+
isValidMatrixRoomAlias,
|
|
1030
|
+
getMatrixUserDisplayName,
|
|
1031
|
+
getMatrixServerpart,
|
|
1032
|
+
getMatrixLocalpart,
|
|
1033
|
+
src_default as default,
|
|
1034
|
+
MatrixServiceNotInitializedError,
|
|
1035
|
+
MatrixService,
|
|
1036
|
+
MatrixPluginError,
|
|
1037
|
+
MatrixNotConnectedError,
|
|
1038
|
+
MatrixEventTypes,
|
|
1039
|
+
MatrixConfigurationError,
|
|
1040
|
+
MatrixApiError,
|
|
1041
|
+
MAX_MATRIX_MESSAGE_LENGTH,
|
|
1042
|
+
MATRIX_SERVICE_NAME
|
|
1043
|
+
};
|
|
1044
|
+
|
|
1045
|
+
//# debugId=35E58066575BB30D64756E2164756E21
|