@cloudrise/openclaw-channel-rocketchat 0.1.14 → 0.1.16
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/README.md +5 -1
- package/index.ts +3 -0
- package/package.json +1 -1
- package/src/channel.ts +1 -1
- package/src/rocketchat/client.ts +48 -19
- package/src/rocketchat/send.ts +56 -0
package/README.md
CHANGED
|
@@ -145,6 +145,10 @@ Then restart the gateway.
|
|
|
145
145
|
|
|
146
146
|
## Features
|
|
147
147
|
|
|
148
|
+
- **Inbound attachments**: receives images, PDFs/documents, and audio; forwards them to OpenClaw for vision/document understanding and transcription.
|
|
149
|
+
- **Outbound attachments**: can send local file paths as real Rocket.Chat uploads (inline previews when supported).
|
|
150
|
+
- **Reactions**: can react to messages with emoji (via `chat.react`).
|
|
151
|
+
|
|
148
152
|
- **File attachments**: receives images, PDFs, documents, audio uploaded to Rocket.Chat and passes them to the vision model.
|
|
149
153
|
- **Model prefix**: honors `messages.responsePrefix` (e.g. `({model}) `) so replies can include the model name.
|
|
150
154
|
|
|
@@ -335,4 +339,4 @@ This repository is intended to be publishable (no secrets committed).
|
|
|
335
339
|
|
|
336
340
|
## License
|
|
337
341
|
|
|
338
|
-
MIT
|
|
342
|
+
MIT
|
package/index.ts
CHANGED
|
@@ -11,6 +11,9 @@ import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
|
11
11
|
import { rocketChatPlugin } from "./src/channel.js";
|
|
12
12
|
import { setRocketChatRuntime } from "./src/runtime.js";
|
|
13
13
|
|
|
14
|
+
// Re-export send/react functions for OpenClaw message tool
|
|
15
|
+
export { reactMessageRocketChat, sendMessageRocketChat } from "./src/rocketchat/send.js";
|
|
16
|
+
|
|
14
17
|
const plugin = {
|
|
15
18
|
id: "rocketchat",
|
|
16
19
|
name: "Rocket.Chat",
|
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "./rocketchat/accounts.js";
|
|
16
16
|
import { normalizeRocketChatBaseUrl } from "./rocketchat/client.js";
|
|
17
17
|
import { monitorRocketChatProvider } from "./rocketchat/monitor.js";
|
|
18
|
-
import { sendMessageRocketChat } from "./rocketchat/send.js";
|
|
18
|
+
import { reactMessageRocketChat, sendMessageRocketChat } from "./rocketchat/send.js";
|
|
19
19
|
import { getRocketChatRuntime } from "./runtime.js";
|
|
20
20
|
|
|
21
21
|
const meta = {
|
package/src/rocketchat/client.ts
CHANGED
|
@@ -245,7 +245,7 @@ export type RocketChatUploadResult = {
|
|
|
245
245
|
* Upload a file to a Rocket.Chat room.
|
|
246
246
|
* RC 8.x uses a two-step process:
|
|
247
247
|
* 1. POST /api/v1/rooms.media/{roomId} → returns file._id
|
|
248
|
-
* 2. POST /api/v1/
|
|
248
|
+
* 2. POST /api/v1/rooms.mediaConfirm/{roomId}/{fileId} → creates displayable message
|
|
249
249
|
*/
|
|
250
250
|
export async function uploadRocketChatFile(
|
|
251
251
|
client: RocketChatClient,
|
|
@@ -300,39 +300,68 @@ export async function uploadRocketChatFile(
|
|
|
300
300
|
throw new Error("Rocket.Chat media upload failed: no file ID returned");
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
-
// Step 2:
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
...(opts.tmid && { tmid: opts.tmid }),
|
|
310
|
-
},
|
|
311
|
-
};
|
|
303
|
+
// Step 2: Confirm media upload (generates thumbnail, dimensions, etc.)
|
|
304
|
+
const confirmUrl = `${client.baseUrl}/api/v1/rooms.mediaConfirm/${opts.roomId}/${uploadData.file._id}`;
|
|
305
|
+
|
|
306
|
+
const confirmPayload: Record<string, string> = {};
|
|
307
|
+
if (opts.description) confirmPayload.msg = opts.description;
|
|
308
|
+
if (opts.tmid) confirmPayload.tmid = opts.tmid;
|
|
312
309
|
|
|
313
|
-
const
|
|
310
|
+
const confirmRes = await client.fetch(confirmUrl, {
|
|
314
311
|
method: "POST",
|
|
315
312
|
headers: {
|
|
316
313
|
"X-Auth-Token": client.authToken,
|
|
317
314
|
"X-User-Id": client.userId,
|
|
318
315
|
"Content-Type": "application/json",
|
|
319
316
|
},
|
|
320
|
-
body: JSON.stringify(
|
|
317
|
+
body: JSON.stringify(confirmPayload),
|
|
321
318
|
});
|
|
322
319
|
|
|
323
|
-
if (!
|
|
324
|
-
const text = await
|
|
325
|
-
throw new Error(`Rocket.Chat
|
|
320
|
+
if (!confirmRes.ok) {
|
|
321
|
+
const text = await confirmRes.text().catch(() => "");
|
|
322
|
+
throw new Error(`Rocket.Chat media confirm error ${confirmRes.status}: ${text}`);
|
|
326
323
|
}
|
|
327
324
|
|
|
328
|
-
const
|
|
325
|
+
const confirmData = await confirmRes.json() as {
|
|
329
326
|
message: { _id: string; rid: string; ts: string };
|
|
330
327
|
success: boolean
|
|
331
328
|
};
|
|
332
329
|
|
|
333
330
|
return {
|
|
334
|
-
_id:
|
|
335
|
-
rid:
|
|
336
|
-
ts:
|
|
331
|
+
_id: confirmData.message._id,
|
|
332
|
+
rid: confirmData.message.rid,
|
|
333
|
+
ts: confirmData.message.ts,
|
|
337
334
|
};
|
|
338
335
|
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* React to a message with an emoji.
|
|
339
|
+
* @param emoji - Emoji name (e.g., "thumbsup", ":rocket:", or unicode "🚀")
|
|
340
|
+
* @param shouldReact - true to add reaction, false to remove (default: true)
|
|
341
|
+
*/
|
|
342
|
+
export async function reactRocketChatMessage(
|
|
343
|
+
client: RocketChatClient,
|
|
344
|
+
messageId: string,
|
|
345
|
+
emoji: string,
|
|
346
|
+
shouldReact = true
|
|
347
|
+
): Promise<void> {
|
|
348
|
+
// Normalize emoji format - RC accepts "thumbsup", ":thumbsup:", or unicode
|
|
349
|
+
const normalizedEmoji = emoji.startsWith(":") ? emoji : `:${emoji.replace(/:/g, "")}:`;
|
|
350
|
+
|
|
351
|
+
const res = await rcFetch<{ success: boolean }>(
|
|
352
|
+
client,
|
|
353
|
+
"/api/v1/chat.react",
|
|
354
|
+
{
|
|
355
|
+
method: "POST",
|
|
356
|
+
body: JSON.stringify({
|
|
357
|
+
messageId,
|
|
358
|
+
emoji: normalizedEmoji,
|
|
359
|
+
shouldReact,
|
|
360
|
+
}),
|
|
361
|
+
}
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
if (!res.success) {
|
|
365
|
+
throw new Error("Rocket.Chat reaction failed");
|
|
366
|
+
}
|
|
367
|
+
}
|
package/src/rocketchat/send.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
fetchRocketChatUserByUsername,
|
|
14
14
|
normalizeRocketChatBaseUrl,
|
|
15
15
|
postRocketChatMessage,
|
|
16
|
+
reactRocketChatMessage,
|
|
16
17
|
uploadRocketChatFile,
|
|
17
18
|
type RocketChatUser,
|
|
18
19
|
} from "./client.js";
|
|
@@ -261,3 +262,58 @@ export async function sendMessageRocketChat(
|
|
|
261
262
|
roomId: post.rid ?? roomId,
|
|
262
263
|
};
|
|
263
264
|
}
|
|
265
|
+
|
|
266
|
+
export type RocketChatReactOpts = {
|
|
267
|
+
accountId?: string;
|
|
268
|
+
shouldReact?: boolean;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* React to a Rocket.Chat message with an emoji.
|
|
273
|
+
* @param messageId - The message ID to react to
|
|
274
|
+
* @param emoji - Emoji name (e.g., "thumbsup", ":rocket:", "🚀")
|
|
275
|
+
*/
|
|
276
|
+
export async function reactMessageRocketChat(
|
|
277
|
+
messageId: string,
|
|
278
|
+
emoji: string,
|
|
279
|
+
opts: RocketChatReactOpts = {}
|
|
280
|
+
): Promise<void> {
|
|
281
|
+
const core = getRocketChatRuntime();
|
|
282
|
+
const logger = core?.logging?.getChildLogger?.({ module: "rocketchat" });
|
|
283
|
+
const cfg = core?.config?.loadConfig?.() ?? {};
|
|
284
|
+
|
|
285
|
+
const account = resolveRocketChatAccount({ cfg, accountId: opts.accountId });
|
|
286
|
+
|
|
287
|
+
const authToken = account.authToken?.trim();
|
|
288
|
+
if (!authToken) {
|
|
289
|
+
throw new Error(
|
|
290
|
+
`Rocket.Chat authToken missing for account "${account.accountId}"`
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const userId = account.userId?.trim();
|
|
295
|
+
if (!userId) {
|
|
296
|
+
throw new Error(
|
|
297
|
+
`Rocket.Chat userId missing for account "${account.accountId}"`
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const baseUrl = normalizeRocketChatBaseUrl(account.baseUrl);
|
|
302
|
+
if (!baseUrl) {
|
|
303
|
+
throw new Error(
|
|
304
|
+
`Rocket.Chat baseUrl missing for account "${account.accountId}"`
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const client = createRocketChatClient({ baseUrl, userId, authToken });
|
|
309
|
+
|
|
310
|
+
logger?.debug?.(`Reacting to message ${messageId} with ${emoji}`);
|
|
311
|
+
|
|
312
|
+
await reactRocketChatMessage(client, messageId, emoji, opts.shouldReact ?? true);
|
|
313
|
+
|
|
314
|
+
core?.channel?.activity?.record?.({
|
|
315
|
+
channel: "rocketchat",
|
|
316
|
+
accountId: account.accountId,
|
|
317
|
+
direction: "outbound",
|
|
318
|
+
});
|
|
319
|
+
}
|