@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/src/types.ts
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the Matrix plugin.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Service, IAgentRuntime } from "@elizaos/core";
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Constants
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
/** Maximum message length for Matrix */
|
|
12
|
+
export const MAX_MATRIX_MESSAGE_LENGTH = 4000;
|
|
13
|
+
|
|
14
|
+
/** Service name constant */
|
|
15
|
+
export const MATRIX_SERVICE_NAME = "matrix";
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Event Types
|
|
19
|
+
// ============================================================================
|
|
20
|
+
|
|
21
|
+
/** Event types emitted by the Matrix plugin */
|
|
22
|
+
export enum MatrixEventTypes {
|
|
23
|
+
MESSAGE_RECEIVED = "MATRIX_MESSAGE_RECEIVED",
|
|
24
|
+
MESSAGE_SENT = "MATRIX_MESSAGE_SENT",
|
|
25
|
+
ROOM_JOINED = "MATRIX_ROOM_JOINED",
|
|
26
|
+
ROOM_LEFT = "MATRIX_ROOM_LEFT",
|
|
27
|
+
INVITE_RECEIVED = "MATRIX_INVITE_RECEIVED",
|
|
28
|
+
REACTION_RECEIVED = "MATRIX_REACTION_RECEIVED",
|
|
29
|
+
TYPING_RECEIVED = "MATRIX_TYPING_RECEIVED",
|
|
30
|
+
SYNC_COMPLETE = "MATRIX_SYNC_COMPLETE",
|
|
31
|
+
CONNECTION_READY = "MATRIX_CONNECTION_READY",
|
|
32
|
+
CONNECTION_LOST = "MATRIX_CONNECTION_LOST",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Configuration Types
|
|
37
|
+
// ============================================================================
|
|
38
|
+
|
|
39
|
+
/** Configuration settings for the Matrix plugin */
|
|
40
|
+
export interface MatrixSettings {
|
|
41
|
+
/** Matrix homeserver URL */
|
|
42
|
+
homeserver: string;
|
|
43
|
+
/** Matrix user ID (@user:homeserver) */
|
|
44
|
+
userId: string;
|
|
45
|
+
/** Access token for authentication */
|
|
46
|
+
accessToken: string;
|
|
47
|
+
/** Device ID for this session */
|
|
48
|
+
deviceId?: string;
|
|
49
|
+
/** Rooms to auto-join */
|
|
50
|
+
rooms: string[];
|
|
51
|
+
/** Whether to auto-accept invites */
|
|
52
|
+
autoJoin: boolean;
|
|
53
|
+
/** Enable end-to-end encryption */
|
|
54
|
+
encryption: boolean;
|
|
55
|
+
/** Require mention to respond in rooms */
|
|
56
|
+
requireMention: boolean;
|
|
57
|
+
/** Whether this configuration is enabled */
|
|
58
|
+
enabled: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// Message Types
|
|
63
|
+
// ============================================================================
|
|
64
|
+
|
|
65
|
+
/** Information about a Matrix user */
|
|
66
|
+
export interface MatrixUserInfo {
|
|
67
|
+
/** Matrix user ID (@user:homeserver) */
|
|
68
|
+
userId: string;
|
|
69
|
+
/** Display name */
|
|
70
|
+
displayName?: string;
|
|
71
|
+
/** Avatar URL */
|
|
72
|
+
avatarUrl?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Represents a Matrix room */
|
|
76
|
+
export interface MatrixRoom {
|
|
77
|
+
/** Room ID (!room:homeserver) */
|
|
78
|
+
roomId: string;
|
|
79
|
+
/** Room name */
|
|
80
|
+
name?: string;
|
|
81
|
+
/** Room topic */
|
|
82
|
+
topic?: string;
|
|
83
|
+
/** Room alias (#alias:homeserver) */
|
|
84
|
+
canonicalAlias?: string;
|
|
85
|
+
/** Whether room is encrypted */
|
|
86
|
+
isEncrypted: boolean;
|
|
87
|
+
/** Whether this is a direct message room */
|
|
88
|
+
isDirect: boolean;
|
|
89
|
+
/** Member count */
|
|
90
|
+
memberCount: number;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Represents a Matrix message */
|
|
94
|
+
export interface MatrixMessage {
|
|
95
|
+
/** Event ID */
|
|
96
|
+
eventId: string;
|
|
97
|
+
/** Room ID */
|
|
98
|
+
roomId: string;
|
|
99
|
+
/** Sender user ID */
|
|
100
|
+
sender: string;
|
|
101
|
+
/** Sender info */
|
|
102
|
+
senderInfo: MatrixUserInfo;
|
|
103
|
+
/** Message content */
|
|
104
|
+
content: string;
|
|
105
|
+
/** Message type (m.text, m.image, etc.) */
|
|
106
|
+
msgType: string;
|
|
107
|
+
/** Formatted body (HTML) */
|
|
108
|
+
formattedBody?: string;
|
|
109
|
+
/** Timestamp */
|
|
110
|
+
timestamp: number;
|
|
111
|
+
/** Thread root event ID */
|
|
112
|
+
threadId?: string;
|
|
113
|
+
/** Reply-to event ID */
|
|
114
|
+
replyTo?: string;
|
|
115
|
+
/** Whether this is an edit */
|
|
116
|
+
isEdit: boolean;
|
|
117
|
+
/** Original event ID if this is an edit */
|
|
118
|
+
replacesEventId?: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Options for sending a message */
|
|
122
|
+
export interface MatrixMessageSendOptions {
|
|
123
|
+
/** Room ID or alias to send to */
|
|
124
|
+
roomId?: string;
|
|
125
|
+
/** Event ID to reply to */
|
|
126
|
+
replyTo?: string;
|
|
127
|
+
/** Thread root event ID */
|
|
128
|
+
threadId?: string;
|
|
129
|
+
/** Format as HTML */
|
|
130
|
+
formatted?: boolean;
|
|
131
|
+
/** Media URL to attach */
|
|
132
|
+
mediaUrl?: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Result from sending a message */
|
|
136
|
+
export interface MatrixSendResult {
|
|
137
|
+
/** Whether the send succeeded */
|
|
138
|
+
success: boolean;
|
|
139
|
+
/** Event ID of the sent message */
|
|
140
|
+
eventId?: string;
|
|
141
|
+
/** Room ID */
|
|
142
|
+
roomId?: string;
|
|
143
|
+
/** Error message if failed */
|
|
144
|
+
error?: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ============================================================================
|
|
148
|
+
// Service Interface
|
|
149
|
+
// ============================================================================
|
|
150
|
+
|
|
151
|
+
/** Interface for the Matrix service */
|
|
152
|
+
export interface IMatrixService extends Service {
|
|
153
|
+
/** Check if the service is connected */
|
|
154
|
+
isConnected(): boolean;
|
|
155
|
+
|
|
156
|
+
/** Get the user ID */
|
|
157
|
+
getUserId(): string;
|
|
158
|
+
|
|
159
|
+
/** Get the homeserver URL */
|
|
160
|
+
getHomeserver(): string;
|
|
161
|
+
|
|
162
|
+
/** Get joined rooms */
|
|
163
|
+
getJoinedRooms(): Promise<MatrixRoom[]>;
|
|
164
|
+
|
|
165
|
+
/** Send a message */
|
|
166
|
+
sendMessage(
|
|
167
|
+
text: string,
|
|
168
|
+
options?: MatrixMessageSendOptions
|
|
169
|
+
): Promise<MatrixSendResult>;
|
|
170
|
+
|
|
171
|
+
/** Send a reaction */
|
|
172
|
+
sendReaction(
|
|
173
|
+
roomId: string,
|
|
174
|
+
eventId: string,
|
|
175
|
+
emoji: string
|
|
176
|
+
): Promise<MatrixSendResult>;
|
|
177
|
+
|
|
178
|
+
/** Join a room */
|
|
179
|
+
joinRoom(roomIdOrAlias: string): Promise<string>;
|
|
180
|
+
|
|
181
|
+
/** Leave a room */
|
|
182
|
+
leaveRoom(roomId: string): Promise<void>;
|
|
183
|
+
|
|
184
|
+
/** Send typing indicator */
|
|
185
|
+
sendTyping(roomId: string, typing: boolean, timeout?: number): Promise<void>;
|
|
186
|
+
|
|
187
|
+
/** Send read receipt */
|
|
188
|
+
sendReadReceipt(roomId: string, eventId: string): Promise<void>;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ============================================================================
|
|
192
|
+
// Event Payloads
|
|
193
|
+
// ============================================================================
|
|
194
|
+
|
|
195
|
+
/** Payload for MESSAGE_RECEIVED event */
|
|
196
|
+
export interface MatrixMessageReceivedPayload {
|
|
197
|
+
message: MatrixMessage;
|
|
198
|
+
room: MatrixRoom;
|
|
199
|
+
runtime: IAgentRuntime;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Payload for MESSAGE_SENT event */
|
|
203
|
+
export interface MatrixMessageSentPayload {
|
|
204
|
+
roomId: string;
|
|
205
|
+
eventId: string;
|
|
206
|
+
content: string;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Payload for ROOM_JOINED event */
|
|
210
|
+
export interface MatrixRoomJoinedPayload {
|
|
211
|
+
room: MatrixRoom;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Payload for INVITE_RECEIVED event */
|
|
215
|
+
export interface MatrixInviteReceivedPayload {
|
|
216
|
+
roomId: string;
|
|
217
|
+
inviter: string;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ============================================================================
|
|
221
|
+
// Utility Functions
|
|
222
|
+
// ============================================================================
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Check if a string is a valid Matrix user ID.
|
|
226
|
+
*/
|
|
227
|
+
export function isValidMatrixUserId(userId: string): boolean {
|
|
228
|
+
return /^@[^:]+:.+$/.test(userId);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Check if a string is a valid Matrix room ID.
|
|
233
|
+
*/
|
|
234
|
+
export function isValidMatrixRoomId(roomId: string): boolean {
|
|
235
|
+
return /^![^:]+:.+$/.test(roomId);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Check if a string is a valid Matrix room alias.
|
|
240
|
+
*/
|
|
241
|
+
export function isValidMatrixRoomAlias(alias: string): boolean {
|
|
242
|
+
return /^#[^:]+:.+$/.test(alias);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Extract the localpart from a Matrix ID.
|
|
247
|
+
*/
|
|
248
|
+
export function getMatrixLocalpart(matrixId: string): string {
|
|
249
|
+
const match = matrixId.match(/^[@#!]([^:]+):/);
|
|
250
|
+
return match ? match[1] : matrixId;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Extract the server part from a Matrix ID.
|
|
255
|
+
*/
|
|
256
|
+
export function getMatrixServerpart(matrixId: string): string {
|
|
257
|
+
const match = matrixId.match(/:(.+)$/);
|
|
258
|
+
return match ? match[1] : "";
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Get the best display name for a Matrix user.
|
|
263
|
+
*/
|
|
264
|
+
export function getMatrixUserDisplayName(user: MatrixUserInfo): string {
|
|
265
|
+
return user.displayName || getMatrixLocalpart(user.userId);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Convert a media URL to an HTTP URL via homeserver.
|
|
270
|
+
*/
|
|
271
|
+
export function matrixMxcToHttp(
|
|
272
|
+
mxcUrl: string,
|
|
273
|
+
homeserver: string
|
|
274
|
+
): string | undefined {
|
|
275
|
+
if (!mxcUrl.startsWith("mxc://")) {
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
const [serverName, mediaId] = mxcUrl.slice(6).split("/");
|
|
279
|
+
if (!serverName || !mediaId) {
|
|
280
|
+
return undefined;
|
|
281
|
+
}
|
|
282
|
+
const base = homeserver.replace(/\/$/, "");
|
|
283
|
+
return `${base}/_matrix/media/v3/download/${serverName}/${mediaId}`;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ============================================================================
|
|
287
|
+
// Custom Errors
|
|
288
|
+
// ============================================================================
|
|
289
|
+
|
|
290
|
+
/** Base error class for Matrix plugin errors */
|
|
291
|
+
export class MatrixPluginError extends Error {
|
|
292
|
+
constructor(message: string) {
|
|
293
|
+
super(message);
|
|
294
|
+
this.name = "MatrixPluginError";
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** Error when the Matrix service is not initialized */
|
|
299
|
+
export class MatrixServiceNotInitializedError extends MatrixPluginError {
|
|
300
|
+
constructor(message: string = "Matrix service is not initialized") {
|
|
301
|
+
super(message);
|
|
302
|
+
this.name = "MatrixServiceNotInitializedError";
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** Error when the Matrix client is not connected */
|
|
307
|
+
export class MatrixNotConnectedError extends MatrixPluginError {
|
|
308
|
+
constructor(message: string = "Matrix client is not connected") {
|
|
309
|
+
super(message);
|
|
310
|
+
this.name = "MatrixNotConnectedError";
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** Error when there is a configuration problem */
|
|
315
|
+
export class MatrixConfigurationError extends MatrixPluginError {
|
|
316
|
+
settingName?: string;
|
|
317
|
+
|
|
318
|
+
constructor(message: string, settingName?: string) {
|
|
319
|
+
super(message);
|
|
320
|
+
this.name = "MatrixConfigurationError";
|
|
321
|
+
this.settingName = settingName;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** Error when an API call fails */
|
|
326
|
+
export class MatrixApiError extends MatrixPluginError {
|
|
327
|
+
errcode?: string;
|
|
328
|
+
|
|
329
|
+
constructor(message: string, errcode?: string) {
|
|
330
|
+
super(message);
|
|
331
|
+
this.name = "MatrixApiError";
|
|
332
|
+
this.errcode = errcode;
|
|
333
|
+
}
|
|
334
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationMap": true,
|
|
8
|
+
"sourceMap": true,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"rootDir": "./src",
|
|
11
|
+
"strict": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"lib": ["ES2022"],
|
|
17
|
+
"types": ["bun-types"]
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*"],
|
|
20
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
21
|
+
}
|