@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
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Join room action for Matrix plugin.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Action, ActionResult, HandlerCallback, HandlerOptions, IAgentRuntime, Memory, State } from "@elizaos/core";
|
|
6
|
+
import { composePromptFromState, ModelType, parseJSONObjectFromText } from "@elizaos/core";
|
|
7
|
+
import { MatrixService } from "../service.js";
|
|
8
|
+
import { MATRIX_SERVICE_NAME, isValidMatrixRoomId, isValidMatrixRoomAlias } from "../types.js";
|
|
9
|
+
|
|
10
|
+
const JOIN_ROOM_TEMPLATE = `You are helping to extract a Matrix room identifier.
|
|
11
|
+
|
|
12
|
+
The user wants to join a Matrix room.
|
|
13
|
+
|
|
14
|
+
Recent conversation:
|
|
15
|
+
{{recentMessages}}
|
|
16
|
+
|
|
17
|
+
Extract the room ID (!room:server) or room alias (#alias:server) to join.
|
|
18
|
+
|
|
19
|
+
Respond with a JSON object like:
|
|
20
|
+
{
|
|
21
|
+
"room": "!room:matrix.org"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
or:
|
|
25
|
+
|
|
26
|
+
{
|
|
27
|
+
"room": "#alias:matrix.org"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
Only respond with the JSON object, no other text.`;
|
|
31
|
+
|
|
32
|
+
export const joinRoom: Action = {
|
|
33
|
+
name: "MATRIX_JOIN_ROOM",
|
|
34
|
+
similes: [
|
|
35
|
+
"JOIN_MATRIX_ROOM",
|
|
36
|
+
"ENTER_ROOM",
|
|
37
|
+
],
|
|
38
|
+
description: "Join a Matrix room by ID or alias",
|
|
39
|
+
|
|
40
|
+
validate: async (
|
|
41
|
+
runtime: IAgentRuntime,
|
|
42
|
+
message: Memory,
|
|
43
|
+
_state?: State
|
|
44
|
+
): Promise<boolean> => {
|
|
45
|
+
return message.content.source === "matrix";
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
handler: async (
|
|
49
|
+
runtime: IAgentRuntime,
|
|
50
|
+
message: Memory,
|
|
51
|
+
state?: State,
|
|
52
|
+
_options?: HandlerOptions,
|
|
53
|
+
callback?: HandlerCallback
|
|
54
|
+
): Promise<ActionResult | undefined> => {
|
|
55
|
+
const matrixService = runtime.getService(MATRIX_SERVICE_NAME) as MatrixService | undefined;
|
|
56
|
+
|
|
57
|
+
if (!matrixService || !matrixService.isConnected()) {
|
|
58
|
+
if (callback) {
|
|
59
|
+
await callback({ text: "Matrix service is not available.", source: "matrix" });
|
|
60
|
+
}
|
|
61
|
+
return { success: false, error: "Matrix service not available" };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Compose prompt - ensure state has required properties
|
|
65
|
+
const composedState: State = state ?? {
|
|
66
|
+
values: {},
|
|
67
|
+
data: {},
|
|
68
|
+
text: "",
|
|
69
|
+
};
|
|
70
|
+
const prompt = await composePromptFromState({
|
|
71
|
+
template: JOIN_ROOM_TEMPLATE,
|
|
72
|
+
state: composedState,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Extract room using LLM
|
|
76
|
+
let room: string | null = null;
|
|
77
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
78
|
+
const response = await runtime.useModel(ModelType.TEXT_SMALL, {
|
|
79
|
+
prompt,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const parsed = parseJSONObjectFromText(response as string);
|
|
83
|
+
if (parsed?.room) {
|
|
84
|
+
const roomStr = String(parsed.room).trim();
|
|
85
|
+
if (isValidMatrixRoomId(roomStr) || isValidMatrixRoomAlias(roomStr)) {
|
|
86
|
+
room = roomStr;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!room) {
|
|
93
|
+
if (callback) {
|
|
94
|
+
await callback({
|
|
95
|
+
text: "I couldn't understand which room you want me to join. Please specify a room ID (!room:server) or alias (#alias:server).",
|
|
96
|
+
source: "matrix",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return { success: false, error: "Could not extract room identifier" };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Join room
|
|
103
|
+
try {
|
|
104
|
+
const roomId = await matrixService.joinRoom(room);
|
|
105
|
+
|
|
106
|
+
if (callback) {
|
|
107
|
+
await callback({
|
|
108
|
+
text: `Joined room ${room}.`,
|
|
109
|
+
source: message.content.source as string,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
success: true,
|
|
115
|
+
data: {
|
|
116
|
+
roomId,
|
|
117
|
+
joined: room,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
} catch (err) {
|
|
121
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
122
|
+
if (callback) {
|
|
123
|
+
await callback({
|
|
124
|
+
text: `Failed to join room: ${error}`,
|
|
125
|
+
source: "matrix",
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return { success: false, error };
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
examples: [
|
|
133
|
+
[
|
|
134
|
+
{
|
|
135
|
+
name: "{{user1}}",
|
|
136
|
+
content: { text: "Join #general:matrix.org" },
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: "{{agent}}",
|
|
140
|
+
content: {
|
|
141
|
+
text: "I'll join that room.",
|
|
142
|
+
actions: ["MATRIX_JOIN_ROOM"],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
],
|
|
147
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List rooms action for Matrix plugin.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Action, ActionResult, HandlerCallback, HandlerOptions, IAgentRuntime, Memory, State } from "@elizaos/core";
|
|
6
|
+
import { MatrixService } from "../service.js";
|
|
7
|
+
import { MATRIX_SERVICE_NAME } from "../types.js";
|
|
8
|
+
|
|
9
|
+
export const listRooms: Action = {
|
|
10
|
+
name: "MATRIX_LIST_ROOMS",
|
|
11
|
+
similes: [
|
|
12
|
+
"LIST_MATRIX_ROOMS",
|
|
13
|
+
"SHOW_ROOMS",
|
|
14
|
+
"GET_ROOMS",
|
|
15
|
+
"MY_ROOMS",
|
|
16
|
+
],
|
|
17
|
+
description: "List all Matrix rooms the bot has joined",
|
|
18
|
+
|
|
19
|
+
validate: async (
|
|
20
|
+
runtime: IAgentRuntime,
|
|
21
|
+
message: Memory,
|
|
22
|
+
_state?: State
|
|
23
|
+
): Promise<boolean> => {
|
|
24
|
+
return message.content.source === "matrix";
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
handler: async (
|
|
28
|
+
runtime: IAgentRuntime,
|
|
29
|
+
message: Memory,
|
|
30
|
+
_state?: State,
|
|
31
|
+
_options?: HandlerOptions,
|
|
32
|
+
callback?: HandlerCallback
|
|
33
|
+
): Promise<ActionResult | undefined> => {
|
|
34
|
+
const matrixService = runtime.getService(MATRIX_SERVICE_NAME) as MatrixService | undefined;
|
|
35
|
+
|
|
36
|
+
if (!matrixService || !matrixService.isConnected()) {
|
|
37
|
+
if (callback) {
|
|
38
|
+
await callback({ text: "Matrix service is not available.", source: "matrix" });
|
|
39
|
+
}
|
|
40
|
+
return { success: false, error: "Matrix service not available" };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const rooms = await matrixService.getJoinedRooms();
|
|
44
|
+
|
|
45
|
+
// Format room list
|
|
46
|
+
const roomList = rooms.map((room) => {
|
|
47
|
+
const name = room.name || room.canonicalAlias || room.roomId;
|
|
48
|
+
const members = `${room.memberCount} members`;
|
|
49
|
+
const encrypted = room.isEncrypted ? " (encrypted)" : "";
|
|
50
|
+
return `- ${name} (${members})${encrypted}`;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const responseText =
|
|
54
|
+
rooms.length > 0
|
|
55
|
+
? `Joined ${rooms.length} room(s):\n\n${roomList.join("\n")}`
|
|
56
|
+
: "Not currently in any rooms.";
|
|
57
|
+
|
|
58
|
+
if (callback) {
|
|
59
|
+
await callback({
|
|
60
|
+
text: responseText,
|
|
61
|
+
source: message.content.source as string,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
success: true,
|
|
67
|
+
data: {
|
|
68
|
+
roomCount: rooms.length,
|
|
69
|
+
rooms: rooms.map((r) => ({
|
|
70
|
+
roomId: r.roomId,
|
|
71
|
+
name: r.name,
|
|
72
|
+
alias: r.canonicalAlias,
|
|
73
|
+
memberCount: r.memberCount,
|
|
74
|
+
isEncrypted: r.isEncrypted,
|
|
75
|
+
})),
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
examples: [
|
|
81
|
+
[
|
|
82
|
+
{
|
|
83
|
+
name: "{{user1}}",
|
|
84
|
+
content: { text: "What rooms are you in?" },
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "{{agent}}",
|
|
88
|
+
content: {
|
|
89
|
+
text: "I'll list the rooms I've joined.",
|
|
90
|
+
actions: ["MATRIX_LIST_ROOMS"],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
],
|
|
95
|
+
};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Send message action for Matrix plugin.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Action, ActionResult, HandlerCallback, HandlerOptions, IAgentRuntime, Memory, State } from "@elizaos/core";
|
|
6
|
+
import { composePromptFromState, ModelType, parseJSONObjectFromText } from "@elizaos/core";
|
|
7
|
+
import { MatrixService } from "../service.js";
|
|
8
|
+
import { MATRIX_SERVICE_NAME, isValidMatrixRoomId, isValidMatrixRoomAlias } from "../types.js";
|
|
9
|
+
|
|
10
|
+
const SEND_MESSAGE_TEMPLATE = `You are helping to extract send message parameters for Matrix.
|
|
11
|
+
|
|
12
|
+
The user wants to send a message to a Matrix room.
|
|
13
|
+
|
|
14
|
+
Recent conversation:
|
|
15
|
+
{{recentMessages}}
|
|
16
|
+
|
|
17
|
+
Extract the following:
|
|
18
|
+
1. text: The message text to send
|
|
19
|
+
2. roomId: The room ID (!room:server) or alias (#alias:server), or "current" for the current room
|
|
20
|
+
|
|
21
|
+
Respond with a JSON object like:
|
|
22
|
+
{
|
|
23
|
+
"text": "The message to send",
|
|
24
|
+
"roomId": "current"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Only respond with the JSON object, no other text.`;
|
|
28
|
+
|
|
29
|
+
interface SendMessageParams {
|
|
30
|
+
text: string;
|
|
31
|
+
roomId: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const sendMessage: Action = {
|
|
35
|
+
name: "MATRIX_SEND_MESSAGE",
|
|
36
|
+
similes: [
|
|
37
|
+
"SEND_MATRIX_MESSAGE",
|
|
38
|
+
"MESSAGE_MATRIX",
|
|
39
|
+
"MATRIX_TEXT",
|
|
40
|
+
],
|
|
41
|
+
description: "Send a message to a Matrix room",
|
|
42
|
+
|
|
43
|
+
validate: async (
|
|
44
|
+
runtime: IAgentRuntime,
|
|
45
|
+
message: Memory,
|
|
46
|
+
_state?: State
|
|
47
|
+
): Promise<boolean> => {
|
|
48
|
+
return message.content.source === "matrix";
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
handler: async (
|
|
52
|
+
runtime: IAgentRuntime,
|
|
53
|
+
message: Memory,
|
|
54
|
+
state?: State,
|
|
55
|
+
_options?: HandlerOptions,
|
|
56
|
+
callback?: HandlerCallback
|
|
57
|
+
): Promise<ActionResult | undefined> => {
|
|
58
|
+
const matrixService = runtime.getService(MATRIX_SERVICE_NAME) as MatrixService | undefined;
|
|
59
|
+
|
|
60
|
+
if (!matrixService || !matrixService.isConnected()) {
|
|
61
|
+
if (callback) {
|
|
62
|
+
await callback({ text: "Matrix service is not available.", source: "matrix" });
|
|
63
|
+
}
|
|
64
|
+
return { success: false, error: "Matrix service not available" };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Compose prompt - ensure state has required properties
|
|
68
|
+
const composedState: State = state ?? {
|
|
69
|
+
values: {},
|
|
70
|
+
data: {},
|
|
71
|
+
text: "",
|
|
72
|
+
};
|
|
73
|
+
const prompt = await composePromptFromState({
|
|
74
|
+
template: SEND_MESSAGE_TEMPLATE,
|
|
75
|
+
state: composedState,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Extract parameters using LLM
|
|
79
|
+
let messageInfo: SendMessageParams | null = null;
|
|
80
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
81
|
+
const response = await runtime.useModel(ModelType.TEXT_SMALL, {
|
|
82
|
+
prompt,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const parsed = parseJSONObjectFromText(response as string);
|
|
86
|
+
if (parsed?.text) {
|
|
87
|
+
messageInfo = {
|
|
88
|
+
text: String(parsed.text),
|
|
89
|
+
roomId: String(parsed.roomId || "current"),
|
|
90
|
+
};
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!messageInfo || !messageInfo.text) {
|
|
96
|
+
if (callback) {
|
|
97
|
+
await callback({
|
|
98
|
+
text: "I couldn't understand what message you want me to send. Please try again.",
|
|
99
|
+
source: "matrix",
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return { success: false, error: "Could not extract message parameters" };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Determine target room
|
|
106
|
+
let targetRoomId: string | undefined;
|
|
107
|
+
if (messageInfo.roomId && messageInfo.roomId !== "current") {
|
|
108
|
+
if (isValidMatrixRoomId(messageInfo.roomId) || isValidMatrixRoomAlias(messageInfo.roomId)) {
|
|
109
|
+
targetRoomId = messageInfo.roomId;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Get room from state context if available
|
|
114
|
+
const roomData = state?.data?.room as Record<string, string> | undefined;
|
|
115
|
+
if (!targetRoomId && roomData?.roomId) {
|
|
116
|
+
targetRoomId = roomData.roomId;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!targetRoomId) {
|
|
120
|
+
if (callback) {
|
|
121
|
+
await callback({
|
|
122
|
+
text: "I couldn't determine which room to send to. Please specify a room.",
|
|
123
|
+
source: "matrix",
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return { success: false, error: "Could not determine target room" };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Send message
|
|
130
|
+
const result = await matrixService.sendMessage(messageInfo.text, {
|
|
131
|
+
roomId: targetRoomId,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (!result.success) {
|
|
135
|
+
if (callback) {
|
|
136
|
+
await callback({
|
|
137
|
+
text: `Failed to send message: ${result.error}`,
|
|
138
|
+
source: "matrix",
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return { success: false, error: result.error };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (callback) {
|
|
145
|
+
await callback({
|
|
146
|
+
text: "Message sent successfully.",
|
|
147
|
+
source: message.content.source as string,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
success: true,
|
|
153
|
+
data: {
|
|
154
|
+
roomId: result.roomId,
|
|
155
|
+
eventId: result.eventId,
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
examples: [
|
|
161
|
+
[
|
|
162
|
+
{
|
|
163
|
+
name: "{{user1}}",
|
|
164
|
+
content: { text: "Send a message saying 'Hello everyone!'" },
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "{{agent}}",
|
|
168
|
+
content: {
|
|
169
|
+
text: "I'll send that message to the room.",
|
|
170
|
+
actions: ["MATRIX_SEND_MESSAGE"],
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
],
|
|
175
|
+
};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Send reaction action for Matrix plugin.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Action, ActionResult, HandlerCallback, HandlerOptions, IAgentRuntime, Memory, State } from "@elizaos/core";
|
|
6
|
+
import { composePromptFromState, ModelType, parseJSONObjectFromText } from "@elizaos/core";
|
|
7
|
+
import { MatrixService } from "../service.js";
|
|
8
|
+
import { MATRIX_SERVICE_NAME } from "../types.js";
|
|
9
|
+
|
|
10
|
+
const SEND_REACTION_TEMPLATE = `You are helping to extract reaction parameters for Matrix.
|
|
11
|
+
|
|
12
|
+
The user wants to react to a Matrix message with an emoji.
|
|
13
|
+
|
|
14
|
+
Recent conversation:
|
|
15
|
+
{{recentMessages}}
|
|
16
|
+
|
|
17
|
+
Extract the following:
|
|
18
|
+
1. emoji: The emoji to react with (single emoji character)
|
|
19
|
+
2. eventId: The event ID of the message to react to (starts with $)
|
|
20
|
+
|
|
21
|
+
Respond with a JSON object like:
|
|
22
|
+
{
|
|
23
|
+
"emoji": "👍",
|
|
24
|
+
"eventId": "$event123"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Only respond with the JSON object, no other text.`;
|
|
28
|
+
|
|
29
|
+
export const sendReaction: Action = {
|
|
30
|
+
name: "MATRIX_SEND_REACTION",
|
|
31
|
+
similes: [
|
|
32
|
+
"REACT_MATRIX",
|
|
33
|
+
"MATRIX_REACT",
|
|
34
|
+
"ADD_MATRIX_REACTION",
|
|
35
|
+
],
|
|
36
|
+
description: "React to a Matrix message with an emoji",
|
|
37
|
+
|
|
38
|
+
validate: async (
|
|
39
|
+
runtime: IAgentRuntime,
|
|
40
|
+
message: Memory,
|
|
41
|
+
_state?: State
|
|
42
|
+
): Promise<boolean> => {
|
|
43
|
+
return message.content.source === "matrix";
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
handler: async (
|
|
47
|
+
runtime: IAgentRuntime,
|
|
48
|
+
message: Memory,
|
|
49
|
+
state?: State,
|
|
50
|
+
_options?: HandlerOptions,
|
|
51
|
+
callback?: HandlerCallback
|
|
52
|
+
): Promise<ActionResult | undefined> => {
|
|
53
|
+
const matrixService = runtime.getService(MATRIX_SERVICE_NAME) as MatrixService | undefined;
|
|
54
|
+
|
|
55
|
+
if (!matrixService || !matrixService.isConnected()) {
|
|
56
|
+
if (callback) {
|
|
57
|
+
await callback({ text: "Matrix service is not available.", source: "matrix" });
|
|
58
|
+
}
|
|
59
|
+
return { success: false, error: "Matrix service not available" };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Compose prompt - ensure state has required properties
|
|
63
|
+
const composedState: State = state ?? {
|
|
64
|
+
values: {},
|
|
65
|
+
data: {},
|
|
66
|
+
text: "",
|
|
67
|
+
};
|
|
68
|
+
const prompt = await composePromptFromState({
|
|
69
|
+
template: SEND_REACTION_TEMPLATE,
|
|
70
|
+
state: composedState,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Extract parameters using LLM
|
|
74
|
+
let reactionInfo: { emoji: string; eventId: string } | null = null;
|
|
75
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
76
|
+
const response = await runtime.useModel(ModelType.TEXT_SMALL, {
|
|
77
|
+
prompt,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const parsed = parseJSONObjectFromText(response as string);
|
|
81
|
+
if (parsed?.emoji && parsed?.eventId) {
|
|
82
|
+
reactionInfo = {
|
|
83
|
+
emoji: String(parsed.emoji),
|
|
84
|
+
eventId: String(parsed.eventId),
|
|
85
|
+
};
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!reactionInfo) {
|
|
91
|
+
if (callback) {
|
|
92
|
+
await callback({
|
|
93
|
+
text: "I couldn't understand the reaction request. Please specify the emoji and message.",
|
|
94
|
+
source: "matrix",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return { success: false, error: "Could not extract reaction parameters" };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Get room from state
|
|
101
|
+
const roomData = state?.data?.room as Record<string, string> | undefined;
|
|
102
|
+
const roomId = roomData?.roomId;
|
|
103
|
+
if (!roomId) {
|
|
104
|
+
if (callback) {
|
|
105
|
+
await callback({
|
|
106
|
+
text: "I couldn't determine which room this is in.",
|
|
107
|
+
source: "matrix",
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return { success: false, error: "Could not determine room" };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Send reaction
|
|
114
|
+
const result = await matrixService.sendReaction(
|
|
115
|
+
roomId,
|
|
116
|
+
reactionInfo.eventId,
|
|
117
|
+
reactionInfo.emoji
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
if (!result.success) {
|
|
121
|
+
if (callback) {
|
|
122
|
+
await callback({
|
|
123
|
+
text: `Failed to add reaction: ${result.error}`,
|
|
124
|
+
source: "matrix",
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return { success: false, error: result.error };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (callback) {
|
|
131
|
+
await callback({
|
|
132
|
+
text: `Added ${reactionInfo.emoji} reaction.`,
|
|
133
|
+
source: message.content.source as string,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
success: true,
|
|
139
|
+
data: {
|
|
140
|
+
emoji: reactionInfo.emoji,
|
|
141
|
+
eventId: reactionInfo.eventId,
|
|
142
|
+
roomId,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
examples: [
|
|
148
|
+
[
|
|
149
|
+
{
|
|
150
|
+
name: "{{user1}}",
|
|
151
|
+
content: { text: "React to the last message with a thumbs up" },
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: "{{agent}}",
|
|
155
|
+
content: {
|
|
156
|
+
text: "I'll add a thumbs up reaction.",
|
|
157
|
+
actions: ["MATRIX_SEND_REACTION"],
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
],
|
|
162
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Matrix messaging integration plugin for ElizaOS.
|
|
3
|
+
*
|
|
4
|
+
* This plugin provides Matrix protocol integration using matrix-js-sdk.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Plugin, IAgentRuntime } from "@elizaos/core";
|
|
8
|
+
import { logger } from "@elizaos/core";
|
|
9
|
+
|
|
10
|
+
// Service
|
|
11
|
+
export { MatrixService } from "./service.js";
|
|
12
|
+
|
|
13
|
+
// Types
|
|
14
|
+
export * from "./types.js";
|
|
15
|
+
|
|
16
|
+
// Actions
|
|
17
|
+
import { sendMessage } from "./actions/sendMessage.js";
|
|
18
|
+
import { sendReaction } from "./actions/sendReaction.js";
|
|
19
|
+
import { listRooms } from "./actions/listRooms.js";
|
|
20
|
+
import { joinRoom } from "./actions/joinRoom.js";
|
|
21
|
+
|
|
22
|
+
export { sendMessage, sendReaction, listRooms, joinRoom };
|
|
23
|
+
|
|
24
|
+
// Providers
|
|
25
|
+
import { roomStateProvider } from "./providers/roomState.js";
|
|
26
|
+
import { userContextProvider } from "./providers/userContext.js";
|
|
27
|
+
|
|
28
|
+
export { roomStateProvider, userContextProvider };
|
|
29
|
+
|
|
30
|
+
// Import service for plugin
|
|
31
|
+
import { MatrixService } from "./service.js";
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Matrix plugin definition.
|
|
35
|
+
*/
|
|
36
|
+
const matrixPlugin: Plugin = {
|
|
37
|
+
name: "matrix",
|
|
38
|
+
description: "Matrix messaging integration plugin for ElizaOS with E2EE support",
|
|
39
|
+
|
|
40
|
+
services: [MatrixService],
|
|
41
|
+
|
|
42
|
+
actions: [sendMessage, sendReaction, listRooms, joinRoom],
|
|
43
|
+
|
|
44
|
+
providers: [roomStateProvider, userContextProvider],
|
|
45
|
+
|
|
46
|
+
tests: [],
|
|
47
|
+
|
|
48
|
+
init: async (
|
|
49
|
+
_config: Record<string, string>,
|
|
50
|
+
runtime: IAgentRuntime
|
|
51
|
+
): Promise<void> => {
|
|
52
|
+
const homeserver = runtime.getSetting("MATRIX_HOMESERVER");
|
|
53
|
+
const userId = runtime.getSetting("MATRIX_USER_ID");
|
|
54
|
+
const accessToken = runtime.getSetting("MATRIX_ACCESS_TOKEN");
|
|
55
|
+
|
|
56
|
+
logger.info("=".repeat(60));
|
|
57
|
+
logger.info("Matrix Plugin Configuration");
|
|
58
|
+
logger.info("=".repeat(60));
|
|
59
|
+
logger.info(` Homeserver: ${homeserver ? `✓ ${homeserver}` : "✗ Missing (required)"}`);
|
|
60
|
+
logger.info(` User ID: ${userId ? `✓ ${userId}` : "✗ Missing (required)"}`);
|
|
61
|
+
logger.info(` Access Token: ${accessToken ? "✓ Set" : "✗ Missing (required)"}`);
|
|
62
|
+
logger.info("=".repeat(60));
|
|
63
|
+
|
|
64
|
+
// Validate required settings
|
|
65
|
+
const missing: string[] = [];
|
|
66
|
+
if (!homeserver) missing.push("MATRIX_HOMESERVER");
|
|
67
|
+
if (!userId) missing.push("MATRIX_USER_ID");
|
|
68
|
+
if (!accessToken) missing.push("MATRIX_ACCESS_TOKEN");
|
|
69
|
+
|
|
70
|
+
if (missing.length > 0) {
|
|
71
|
+
logger.warn(
|
|
72
|
+
`Matrix plugin: Missing required configuration: ${missing.join(", ")}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Additional optional settings
|
|
77
|
+
const deviceId = runtime.getSetting("MATRIX_DEVICE_ID");
|
|
78
|
+
const rooms = runtime.getSetting("MATRIX_ROOMS");
|
|
79
|
+
const autoJoin = runtime.getSetting("MATRIX_AUTO_JOIN");
|
|
80
|
+
const encryption = runtime.getSetting("MATRIX_ENCRYPTION");
|
|
81
|
+
const requireMention = runtime.getSetting("MATRIX_REQUIRE_MENTION");
|
|
82
|
+
|
|
83
|
+
if (deviceId) {
|
|
84
|
+
logger.info(` Device ID: ${deviceId}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (rooms) {
|
|
88
|
+
logger.info(` Auto-join Rooms: ${rooms}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (autoJoin === "true") {
|
|
92
|
+
logger.info(" Auto-join Invites: ✓ Enabled");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (encryption === "true") {
|
|
96
|
+
logger.info(" End-to-End Encryption: ✓ Enabled");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (requireMention === "true") {
|
|
100
|
+
logger.info(" Require Mention: ✓ Enabled (will only respond to mentions in rooms)");
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export default matrixPlugin;
|