@elizaos/plugin-roblox 2.0.0-alpha.7 → 2.0.11-beta.7

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.
Files changed (39) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +123 -0
  3. package/package.json +23 -23
  4. package/dist/__tests__/suite.d.ts +0 -7
  5. package/dist/__tests__/suite.d.ts.map +0 -1
  6. package/dist/actions/executeGameAction.d.ts +0 -4
  7. package/dist/actions/executeGameAction.d.ts.map +0 -1
  8. package/dist/actions/getPlayerInfo.d.ts +0 -4
  9. package/dist/actions/getPlayerInfo.d.ts.map +0 -1
  10. package/dist/actions/index.d.ts +0 -7
  11. package/dist/actions/index.d.ts.map +0 -1
  12. package/dist/actions/sendGameMessage.d.ts +0 -4
  13. package/dist/actions/sendGameMessage.d.ts.map +0 -1
  14. package/dist/client/RobloxClient.d.ts +0 -29
  15. package/dist/client/RobloxClient.d.ts.map +0 -1
  16. package/dist/client/index.d.ts +0 -2
  17. package/dist/client/index.d.ts.map +0 -1
  18. package/dist/generated/specs/specs.d.ts +0 -63
  19. package/dist/generated/specs/specs.d.ts.map +0 -1
  20. package/dist/index.browser.d.ts +0 -4
  21. package/dist/index.browser.d.ts.map +0 -1
  22. package/dist/index.d.ts +0 -6
  23. package/dist/index.d.ts.map +0 -1
  24. package/dist/index.js +0 -1133
  25. package/dist/index.js.map +0 -21
  26. package/dist/providers/gameStateProvider.d.ts +0 -3
  27. package/dist/providers/gameStateProvider.d.ts.map +0 -1
  28. package/dist/providers/index.d.ts +0 -5
  29. package/dist/providers/index.d.ts.map +0 -1
  30. package/dist/services/RobloxService.d.ts +0 -44
  31. package/dist/services/RobloxService.d.ts.map +0 -1
  32. package/dist/services/index.d.ts +0 -2
  33. package/dist/services/index.d.ts.map +0 -1
  34. package/dist/types/index.d.ts +0 -125
  35. package/dist/types/index.d.ts.map +0 -1
  36. package/dist/utils/config.d.ts +0 -12
  37. package/dist/utils/config.d.ts.map +0 -1
  38. package/dist/utils/index.d.ts +0 -2
  39. package/dist/utils/index.d.ts.map +0 -1
package/dist/index.js DELETED
@@ -1,1133 +0,0 @@
1
- // types/index.ts
2
- var ROBLOX_SERVICE_NAME = "roblox";
3
-
4
- // __tests__/suite.ts
5
- class RobloxTestSuite {
6
- name = "roblox";
7
- description = "Test suite for Roblox plugin";
8
- tests = [
9
- {
10
- name: "Service initialization",
11
- fn: async (runtime) => {
12
- const service = runtime.getService(ROBLOX_SERVICE_NAME);
13
- const apiKey = runtime.getSetting("ROBLOX_API_KEY");
14
- const universeId = runtime.getSetting("ROBLOX_UNIVERSE_ID");
15
- if (apiKey && universeId) {
16
- if (!service) {
17
- throw new Error("Roblox service should be initialized when API key and Universe ID are provided");
18
- }
19
- } else {
20
- runtime.logger.info("Roblox service not initialized - missing configuration (expected)");
21
- }
22
- }
23
- },
24
- {
25
- name: "Configuration validation",
26
- fn: async (runtime) => {
27
- const apiKey = runtime.getSetting("ROBLOX_API_KEY");
28
- const universeId = runtime.getSetting("ROBLOX_UNIVERSE_ID");
29
- if (apiKey && universeId) {
30
- const service = runtime.getService(ROBLOX_SERVICE_NAME);
31
- if (!service) {
32
- throw new Error("Service should exist when properly configured");
33
- }
34
- const client = service.getClient(runtime.agentId);
35
- if (!client) {
36
- throw new Error("Client should exist for agent");
37
- }
38
- const config = client.getConfig();
39
- if (config.universeId !== universeId) {
40
- throw new Error("Universe ID mismatch in config");
41
- }
42
- }
43
- }
44
- },
45
- {
46
- name: "Actions registered",
47
- fn: async (runtime) => {
48
- runtime.logger.info("Roblox actions registration check passed");
49
- }
50
- }
51
- ];
52
- }
53
-
54
- // actions/executeGameAction.ts
55
- import {
56
- logger
57
- } from "@elizaos/core";
58
- var actionName = "EXECUTE_ROBLOX_ACTION";
59
- var executeGameActionExamples = [
60
- [
61
- {
62
- name: actionName,
63
- content: {
64
- text: "Start a fireworks show in the game"
65
- }
66
- },
67
- {
68
- name: actionName,
69
- content: {
70
- text: "I'll trigger the fireworks show for everyone in the game!",
71
- action: "EXECUTE_ROBLOX_ACTION"
72
- }
73
- }
74
- ],
75
- [
76
- {
77
- name: "{{user1}}",
78
- content: {
79
- text: "Give player456 100 coins as a reward"
80
- }
81
- },
82
- {
83
- name: "{{agentName}}",
84
- content: {
85
- text: "I'll give player456 100 coins right away!",
86
- action: "EXECUTE_ROBLOX_ACTION"
87
- }
88
- }
89
- ],
90
- [
91
- {
92
- name: "{{user1}}",
93
- content: {
94
- text: "Teleport everyone to the lobby"
95
- }
96
- },
97
- {
98
- name: "{{agentName}}",
99
- content: {
100
- text: "Teleporting all players to the lobby now!",
101
- action: "EXECUTE_ROBLOX_ACTION"
102
- }
103
- }
104
- ]
105
- ];
106
- var KNOWN_ACTIONS = [
107
- {
108
- name: "move_npc",
109
- patterns: [
110
- /(?:move|walk)\s+(?:the\s+)?(?:npc|bot|agent)?\s*(?:to|towards)\s+(?:the\s+)?(\w+)/i,
111
- /(?:move|walk)\s+to\s+\(?(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\)?/i
112
- ],
113
- extractParams: (match) => {
114
- if (match.length >= 4 && match[1] && match[2] && match[3]) {
115
- return {
116
- x: Number.parseFloat(match[1]),
117
- y: Number.parseFloat(match[2]),
118
- z: Number.parseFloat(match[3])
119
- };
120
- }
121
- return { waypoint: match[1] || "" };
122
- }
123
- },
124
- {
125
- name: "give_coins",
126
- patterns: [/give\s+(?:player\s*)?(\d+)\s+(\d+)\s+coins?/i],
127
- extractParams: (match) => ({
128
- playerId: parseInt(match[1], 10),
129
- amount: parseInt(match[2], 10)
130
- })
131
- },
132
- {
133
- name: "teleport",
134
- patterns: [/teleport\s+(?:everyone|all)\s+to\s+(?:the\s+)?(\w+)/i],
135
- extractParams: (match) => ({
136
- destination: match[1]
137
- })
138
- },
139
- {
140
- name: "spawn_entity",
141
- patterns: [/spawn\s+(?:a\s+)?(\w+)\s+at\s+(\w+)/i],
142
- extractParams: (match) => ({
143
- entityType: match[1],
144
- location: match[2]
145
- })
146
- },
147
- {
148
- name: "start_event",
149
- patterns: [/start\s+(?:a\s+)?(\w+)\s+(?:show|event|celebration)/i],
150
- extractParams: (match) => ({
151
- eventType: match[1]
152
- })
153
- }
154
- ];
155
- function parseGameAction(message) {
156
- for (const action of KNOWN_ACTIONS) {
157
- for (const pattern of action.patterns) {
158
- const match = message.match(pattern);
159
- if (match) {
160
- return {
161
- actionName: action.name,
162
- parameters: action.extractParams(match)
163
- };
164
- }
165
- }
166
- }
167
- const genericMatch = message.match(/(?:execute|run|do)\s+(\w+)/i);
168
- if (genericMatch) {
169
- return {
170
- actionName: genericMatch[1].toLowerCase(),
171
- parameters: {}
172
- };
173
- }
174
- return null;
175
- }
176
- var executeGameAction = {
177
- name: actionName,
178
- similes: [],
179
- description: "Execute an action in the connected Roblox game.",
180
- examples: executeGameActionExamples,
181
- validate: async (runtime, message, state, options) => {
182
- const __avTextRaw = typeof message?.content?.text === "string" ? message.content.text : "";
183
- const __avText = __avTextRaw.toLowerCase();
184
- const __avKeywords = ["execute", "roblox"];
185
- const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
186
- const __avRegex = /\b(?:execute|roblox)\b/i;
187
- const __avRegexOk = __avRegex.test(__avText);
188
- const __avSource = String(message?.content?.source ?? message?.source ?? "");
189
- const __avExpectedSource = "";
190
- const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || runtime?.agentId || runtime?.getService);
191
- const __avOptions = options && typeof options === "object" ? options : {};
192
- const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean(message?.content && typeof message.content === "object");
193
- if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
194
- return false;
195
- }
196
- const __avLegacyValidate = async (runtime2) => {
197
- const apiKey = runtime2.getSetting("ROBLOX_API_KEY");
198
- const universeId = runtime2.getSetting("ROBLOX_UNIVERSE_ID");
199
- return Boolean(apiKey && universeId);
200
- };
201
- try {
202
- return Boolean(await __avLegacyValidate(runtime, message, state, options));
203
- } catch {
204
- return false;
205
- }
206
- },
207
- handler: async (runtime, message, state, _options, callback) => {
208
- try {
209
- const service = runtime.getService(ROBLOX_SERVICE_NAME);
210
- if (!service) {
211
- logger.error("Roblox service not found");
212
- if (callback) {
213
- callback({
214
- text: "Roblox service not available.",
215
- action: "EXECUTE_ROBLOX_ACTION"
216
- });
217
- }
218
- return {
219
- success: false,
220
- error: "Roblox service not found"
221
- };
222
- }
223
- const messageContent = state?.message || message.content.text || "";
224
- const parsedAction = parseGameAction(messageContent);
225
- if (!parsedAction) {
226
- logger.warn("Could not parse game action from message");
227
- if (callback) {
228
- callback({
229
- text: "Could not parse action from message.",
230
- action: "EXECUTE_ROBLOX_ACTION"
231
- });
232
- }
233
- return {
234
- success: false,
235
- error: "Could not parse game action from message"
236
- };
237
- }
238
- const { actionName: actionName2, parameters } = parsedAction;
239
- const playerIdMatch = messageContent.match(/player\s*(\d+)/i);
240
- const targetPlayerIds = playerIdMatch ? [parseInt(playerIdMatch[1], 10)] : undefined;
241
- await service.executeAction(runtime.agentId, actionName2, parameters, targetPlayerIds);
242
- logger.info({ actionName: actionName2, parameters, targetPlayerIds }, "Executed Roblox game action");
243
- if (callback) {
244
- callback({
245
- text: `I've triggered the "${actionName2}" action in the game.`,
246
- action: "EXECUTE_ROBLOX_ACTION"
247
- });
248
- }
249
- return {
250
- success: true,
251
- text: `Executed "${actionName2}" action in the game`,
252
- data: {
253
- actionName: actionName2,
254
- parameters,
255
- targetPlayerIds: targetPlayerIds || undefined
256
- }
257
- };
258
- } catch (error) {
259
- logger.error({ error }, "Failed to execute Roblox action");
260
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
261
- if (callback) {
262
- callback({
263
- text: "Error executing action.",
264
- action: "EXECUTE_ROBLOX_ACTION"
265
- });
266
- }
267
- return {
268
- success: false,
269
- error: errorMessage
270
- };
271
- }
272
- }
273
- };
274
- var executeGameAction_default = executeGameAction;
275
-
276
- // actions/getPlayerInfo.ts
277
- import {
278
- logger as logger2
279
- } from "@elizaos/core";
280
- var actionName2 = "GET_ROBLOX_PLAYER";
281
- var getPlayerInfoExamples = [
282
- [
283
- {
284
- name: actionName2,
285
- content: {
286
- text: "Who is player 12345678?"
287
- }
288
- },
289
- {
290
- name: actionName2,
291
- content: {
292
- text: "Let me look up that player's information for you.",
293
- action: "GET_ROBLOX_PLAYER"
294
- }
295
- }
296
- ],
297
- [
298
- {
299
- name: "{{user1}}",
300
- content: {
301
- text: "Look up the Roblox user JohnDoe123"
302
- }
303
- },
304
- {
305
- name: "{{agentName}}",
306
- content: {
307
- text: "I'll find the information for JohnDoe123.",
308
- action: "GET_ROBLOX_PLAYER"
309
- }
310
- }
311
- ]
312
- ];
313
- function extractUserIdentifier(message) {
314
- const idMatch = message.match(/\b(?:player|user|id)\s*[:#]?\s*(\d{5,})\b/i);
315
- if (idMatch) {
316
- return { type: "id", value: parseInt(idMatch[1], 10) };
317
- }
318
- const usernameMatch = message.match(/\b(?:user(?:name)?|player)\s*[:#]?\s*([A-Za-z0-9_]{3,20})\b/i);
319
- if (usernameMatch) {
320
- const username = usernameMatch[1];
321
- if (!/^\d+$/.test(username)) {
322
- return { type: "username", value: username };
323
- }
324
- }
325
- return null;
326
- }
327
- var getPlayerInfo = {
328
- name: actionName2,
329
- similes: [],
330
- description: "Fetch Roblox player information by username or user id.",
331
- examples: getPlayerInfoExamples,
332
- validate: async (runtime, message, state, options) => {
333
- const __avTextRaw = typeof message?.content?.text === "string" ? message.content.text : "";
334
- const __avText = __avTextRaw.toLowerCase();
335
- const __avKeywords = ["get", "roblox", "player"];
336
- const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
337
- const __avRegex = /\b(?:get|roblox|player)\b/i;
338
- const __avRegexOk = __avRegex.test(__avText);
339
- const __avSource = String(message?.content?.source ?? message?.source ?? "");
340
- const __avExpectedSource = "";
341
- const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || runtime?.agentId || runtime?.getService);
342
- const __avOptions = options && typeof options === "object" ? options : {};
343
- const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean(message?.content && typeof message.content === "object");
344
- if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
345
- return false;
346
- }
347
- const __avLegacyValidate = async (runtime2) => {
348
- const apiKey = runtime2.getSetting("ROBLOX_API_KEY");
349
- return Boolean(apiKey);
350
- };
351
- try {
352
- return Boolean(await __avLegacyValidate(runtime, message, state, options));
353
- } catch {
354
- return false;
355
- }
356
- },
357
- handler: async (runtime, message, state, _options, callback) => {
358
- try {
359
- const service = runtime.getService(ROBLOX_SERVICE_NAME);
360
- if (!service) {
361
- logger2.error("Roblox service not found");
362
- if (callback) {
363
- callback({
364
- text: "I couldn't connect to the Roblox service.",
365
- action: "GET_ROBLOX_PLAYER"
366
- });
367
- }
368
- return {
369
- success: false,
370
- error: "Roblox service not found"
371
- };
372
- }
373
- const client = service.getClient(runtime.agentId);
374
- if (!client) {
375
- logger2.error("Roblox client not found for agent");
376
- if (callback) {
377
- callback({
378
- text: "The Roblox client isn't available right now.",
379
- action: "GET_ROBLOX_PLAYER"
380
- });
381
- }
382
- return {
383
- success: false,
384
- error: "Roblox client not found for agent"
385
- };
386
- }
387
- const messageContent = state?.message || message.content.text || "";
388
- const identifier = extractUserIdentifier(messageContent);
389
- if (!identifier) {
390
- logger2.warn("Could not extract user identifier from message");
391
- if (callback) {
392
- callback({
393
- text: "I need a player ID or username to look up. Please provide one.",
394
- action: "GET_ROBLOX_PLAYER"
395
- });
396
- }
397
- return {
398
- success: false,
399
- error: "Could not extract user identifier from message"
400
- };
401
- }
402
- let user;
403
- if (identifier.type === "id") {
404
- user = await client.getUserById(identifier.value);
405
- } else {
406
- user = await client.getUserByUsername(identifier.value);
407
- }
408
- if (!user) {
409
- if (callback) {
410
- callback({
411
- text: `I couldn't find a Roblox user with that ${identifier.type === "id" ? "ID" : "username"}.`,
412
- action: "GET_ROBLOX_PLAYER"
413
- });
414
- }
415
- return {
416
- success: true,
417
- text: `User not found with ${identifier.type === "id" ? "ID" : "username"}: ${identifier.value}`
418
- };
419
- }
420
- const avatarUrl = await client.getAvatarUrl(user.id);
421
- user.avatarUrl = avatarUrl;
422
- logger2.info({ userId: user.id, username: user.username }, "Found Roblox user");
423
- if (callback) {
424
- const createdDate = user.createdAt ? user.createdAt.toLocaleDateString() : "Unknown";
425
- const bannedStatus = user.isBanned ? " (Banned)" : "";
426
- callback({
427
- text: `**${user.displayName}** (@${user.username})${bannedStatus}
428
- - User ID: ${user.id}
429
- - Account created: ${createdDate}`,
430
- action: "GET_ROBLOX_PLAYER"
431
- });
432
- }
433
- return {
434
- success: true,
435
- text: `Found Roblox user: ${user.displayName} (@${user.username})`,
436
- data: {
437
- userId: user.id,
438
- username: user.username,
439
- displayName: user.displayName,
440
- avatarUrl: avatarUrl || undefined,
441
- isBanned: user.isBanned,
442
- createdAt: user.createdAt ? user.createdAt.toISOString() : undefined
443
- }
444
- };
445
- } catch (error) {
446
- logger2.error({ error }, "Failed to get Roblox player info");
447
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
448
- if (callback) {
449
- callback({
450
- text: "I encountered an error looking up that player. Please try again.",
451
- action: "GET_ROBLOX_PLAYER"
452
- });
453
- }
454
- return {
455
- success: false,
456
- error: errorMessage
457
- };
458
- }
459
- }
460
- };
461
- var getPlayerInfo_default = getPlayerInfo;
462
-
463
- // actions/sendGameMessage.ts
464
- import {
465
- logger as logger3
466
- } from "@elizaos/core";
467
- var actionName3 = "SEND_ROBLOX_MESSAGE";
468
- var sendGameMessageExamples = [
469
- [
470
- {
471
- name: actionName3,
472
- content: {
473
- text: "Tell everyone in the game that there's a special event happening"
474
- }
475
- },
476
- {
477
- name: actionName3,
478
- content: {
479
- text: "I'll announce the special event to all players in the game!",
480
- action: "SEND_ROBLOX_MESSAGE"
481
- }
482
- }
483
- ],
484
- [
485
- {
486
- name: "{{user1}}",
487
- content: {
488
- text: "Send a message to player123 welcoming them to the game"
489
- }
490
- },
491
- {
492
- name: "{{agentName}}",
493
- content: {
494
- text: "I'll send a personalized welcome message to player123.",
495
- action: "SEND_ROBLOX_MESSAGE"
496
- }
497
- }
498
- ]
499
- ];
500
- var sendGameMessage = {
501
- name: actionName3,
502
- similes: [],
503
- description: "Send a message to players in the Roblox game.",
504
- examples: sendGameMessageExamples,
505
- validate: async (runtime, message, state, options) => {
506
- const __avTextRaw = typeof message?.content?.text === "string" ? message.content.text : "";
507
- const __avText = __avTextRaw.toLowerCase();
508
- const __avKeywords = ["send", "roblox", "message"];
509
- const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
510
- const __avRegex = /\b(?:send|roblox|message)\b/i;
511
- const __avRegexOk = __avRegex.test(__avText);
512
- const __avSource = String(message?.content?.source ?? message?.source ?? "");
513
- const __avExpectedSource = "";
514
- const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || runtime?.agentId || runtime?.getService);
515
- const __avOptions = options && typeof options === "object" ? options : {};
516
- const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean(message?.content && typeof message.content === "object");
517
- if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
518
- return false;
519
- }
520
- const __avLegacyValidate = async (runtime2) => {
521
- const apiKey = runtime2.getSetting("ROBLOX_API_KEY");
522
- const universeId = runtime2.getSetting("ROBLOX_UNIVERSE_ID");
523
- return Boolean(apiKey && universeId);
524
- };
525
- try {
526
- return Boolean(await __avLegacyValidate(runtime, message, state, options));
527
- } catch {
528
- return false;
529
- }
530
- },
531
- handler: async (runtime, message, state, _options, callback) => {
532
- try {
533
- const service = runtime.getService(ROBLOX_SERVICE_NAME);
534
- if (!service) {
535
- logger3.error("Roblox service not found");
536
- if (callback) {
537
- callback({
538
- text: "Roblox service not available.",
539
- action: "SEND_ROBLOX_MESSAGE"
540
- });
541
- }
542
- return {
543
- success: false,
544
- error: "Roblox service not found"
545
- };
546
- }
547
- const messageContent = state?.message || message.content.text || "";
548
- if (!messageContent) {
549
- logger3.warn("No message content to send");
550
- if (callback) {
551
- callback({
552
- text: "I need a message to send to the game.",
553
- action: "SEND_ROBLOX_MESSAGE"
554
- });
555
- }
556
- return {
557
- success: false,
558
- error: "No message content to send"
559
- };
560
- }
561
- const targetPlayerIds = extractPlayerIds(messageContent);
562
- await service.sendMessage(runtime.agentId, messageContent, targetPlayerIds);
563
- logger3.info({ targetPlayerIds, messageLength: messageContent.length }, "Sent message to Roblox game");
564
- if (callback) {
565
- const targetInfo = targetPlayerIds && targetPlayerIds.length > 0 ? `to ${targetPlayerIds.length} specific player(s)` : "to all players";
566
- callback({
567
- text: `I've sent the message ${targetInfo} in the game.`,
568
- action: "SEND_ROBLOX_MESSAGE"
569
- });
570
- }
571
- return {
572
- success: true,
573
- text: `Sent message ${targetPlayerIds && targetPlayerIds.length > 0 ? `to ${targetPlayerIds.length} specific player(s)` : "to all players"} in the game`,
574
- data: {
575
- targetPlayerIds,
576
- messageLength: messageContent.length
577
- }
578
- };
579
- } catch (error) {
580
- logger3.error({ error }, "Failed to send Roblox message");
581
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
582
- if (callback) {
583
- callback({
584
- text: "Error sending message.",
585
- action: "SEND_ROBLOX_MESSAGE"
586
- });
587
- }
588
- return {
589
- success: false,
590
- error: errorMessage
591
- };
592
- }
593
- }
594
- };
595
- function extractPlayerIds(message) {
596
- const playerIdPattern = /\bplayer\s*(\d+)\b/gi;
597
- const matches = [...message.matchAll(playerIdPattern)];
598
- if (matches.length > 0) {
599
- return matches.map((m) => parseInt(m[1], 10));
600
- }
601
- return;
602
- }
603
- var sendGameMessage_default = sendGameMessage;
604
-
605
- // actions/index.ts
606
- var robloxActions = [sendGameMessage_default, executeGameAction_default, getPlayerInfo_default];
607
-
608
- // providers/gameStateProvider.ts
609
- var providerName = "roblox-game-state";
610
- var gameStateProvider = {
611
- name: providerName,
612
- description: "Provides information about the connected Roblox game/experience",
613
- get: async (runtime, _message, _state) => {
614
- try {
615
- const service = runtime.getService(ROBLOX_SERVICE_NAME);
616
- if (!service) {
617
- return { text: "", data: {}, values: {} };
618
- }
619
- const client = service.getClient(runtime.agentId);
620
- if (!client) {
621
- return { text: "", data: {}, values: {} };
622
- }
623
- const config = client.getConfig();
624
- let experienceInfo = null;
625
- try {
626
- experienceInfo = await client.getExperienceInfo();
627
- } catch {
628
- experienceInfo = null;
629
- }
630
- const parts = [
631
- "## Roblox Game Connection",
632
- "",
633
- `- **Universe ID**: ${config.universeId}`
634
- ];
635
- if (config.placeId) {
636
- parts.push(`- **Place ID**: ${config.placeId}`);
637
- }
638
- if (experienceInfo) {
639
- parts.push(`- **Experience Name**: ${experienceInfo.name}`);
640
- if (experienceInfo.playing !== undefined) {
641
- parts.push(`- **Active Players**: ${experienceInfo.playing}`);
642
- }
643
- if (experienceInfo.visits !== undefined) {
644
- parts.push(`- **Total Visits**: ${experienceInfo.visits.toLocaleString()}`);
645
- }
646
- parts.push(`- **Creator**: ${experienceInfo.creator.name} (${experienceInfo.creator.type})`);
647
- }
648
- parts.push(`- **Messaging Topic**: ${config.messagingTopic}`);
649
- if (config.dryRun) {
650
- parts.push("");
651
- parts.push("*Dry run mode is enabled - actions are simulated*");
652
- }
653
- return { text: parts.join(`
654
- `), data: {}, values: {} };
655
- } catch (error) {
656
- runtime.logger.error({ error }, "Error in gameStateProvider");
657
- return { text: "", data: {}, values: {} };
658
- }
659
- }
660
- };
661
-
662
- // providers/index.ts
663
- var robloxProviders = [gameStateProvider];
664
-
665
- // services/RobloxService.ts
666
- import { Service } from "@elizaos/core";
667
-
668
- // client/RobloxClient.ts
669
- var ROBLOX_API_BASE = "https://apis.roblox.com";
670
- var USERS_API_BASE = "https://users.roblox.com";
671
-
672
- class RobloxApiError extends Error {
673
- statusCode;
674
- endpoint;
675
- details;
676
- constructor(message, statusCode, endpoint, details) {
677
- super(message);
678
- this.statusCode = statusCode;
679
- this.endpoint = endpoint;
680
- this.details = details;
681
- this.name = "RobloxApiError";
682
- }
683
- }
684
-
685
- class RobloxClient {
686
- config;
687
- constructor(config) {
688
- this.config = config;
689
- }
690
- async request(endpoint, options = {}, baseUrl = ROBLOX_API_BASE) {
691
- const url = `${baseUrl}${endpoint}`;
692
- const headers = {
693
- "x-api-key": this.config.apiKey,
694
- "Content-Type": "application/json",
695
- ...options.headers || {}
696
- };
697
- const response = await fetch(url, {
698
- ...options,
699
- headers
700
- });
701
- if (!response.ok) {
702
- let details;
703
- try {
704
- details = await response.json();
705
- } catch {
706
- details = await response.text();
707
- }
708
- throw new RobloxApiError(`Roblox API error: ${response.statusText}`, response.status, endpoint, details);
709
- }
710
- const text = await response.text();
711
- if (!text) {
712
- return {};
713
- }
714
- return JSON.parse(text);
715
- }
716
- async publishMessage(topic, data, universeId) {
717
- if (this.config.dryRun) {
718
- return;
719
- }
720
- const targetUniverseId = universeId || this.config.universeId;
721
- await this.request(`/messaging-service/v1/universes/${targetUniverseId}/topics/${encodeURIComponent(topic)}`, {
722
- method: "POST",
723
- body: JSON.stringify({ message: JSON.stringify(data) })
724
- });
725
- }
726
- async sendAgentMessage(message) {
727
- const payload = {
728
- ...message.data
729
- };
730
- if (message.sender) {
731
- payload.sender = message.sender;
732
- }
733
- await this.publishMessage(message.topic, payload);
734
- }
735
- async getDataStoreEntry(datastoreName, key, scope = "global") {
736
- try {
737
- const response = await this.request(`/datastores/v1/universes/${this.config.universeId}/standard-datastores/datastore/entries/entry?datastoreName=${encodeURIComponent(datastoreName)}&scope=${encodeURIComponent(scope)}&entryKey=${encodeURIComponent(key)}`);
738
- return {
739
- key,
740
- value: JSON.parse(response.value),
741
- version: response.version,
742
- createdAt: new Date(response.createdTime),
743
- updatedAt: new Date(response.updatedTime)
744
- };
745
- } catch (error) {
746
- if (error instanceof RobloxApiError && error.statusCode === 404) {
747
- return null;
748
- }
749
- throw error;
750
- }
751
- }
752
- async setDataStoreEntry(datastoreName, key, value, scope = "global") {
753
- if (this.config.dryRun) {
754
- console.log(`[DRY RUN] Would set DataStore entry "${key}":`, value);
755
- return {
756
- key,
757
- value,
758
- version: "dry-run",
759
- createdAt: new Date,
760
- updatedAt: new Date
761
- };
762
- }
763
- const response = await this.request(`/datastores/v1/universes/${this.config.universeId}/standard-datastores/datastore/entries/entry?datastoreName=${encodeURIComponent(datastoreName)}&scope=${encodeURIComponent(scope)}&entryKey=${encodeURIComponent(key)}`, {
764
- method: "POST",
765
- body: JSON.stringify(value)
766
- });
767
- return {
768
- key,
769
- value,
770
- version: response.version,
771
- createdAt: new Date(response.createdTime),
772
- updatedAt: new Date(response.updatedTime)
773
- };
774
- }
775
- async deleteDataStoreEntry(datastoreName, key, scope = "global") {
776
- if (this.config.dryRun) {
777
- console.log(`[DRY RUN] Would delete DataStore entry "${key}"`);
778
- return;
779
- }
780
- await this.request(`/datastores/v1/universes/${this.config.universeId}/standard-datastores/datastore/entries/entry?datastoreName=${encodeURIComponent(datastoreName)}&scope=${encodeURIComponent(scope)}&entryKey=${encodeURIComponent(key)}`, { method: "DELETE" });
781
- }
782
- async listDataStoreEntries(datastoreName, scope = "global", prefix, limit = 100) {
783
- let url = `/datastores/v1/universes/${this.config.universeId}/standard-datastores/datastore/entries?datastoreName=${encodeURIComponent(datastoreName)}&scope=${encodeURIComponent(scope)}&limit=${limit}`;
784
- if (prefix) {
785
- url += `&prefix=${encodeURIComponent(prefix)}`;
786
- }
787
- const response = await this.request(url);
788
- return {
789
- keys: response.keys.map((k) => k.key),
790
- nextPageCursor: response.nextPageCursor
791
- };
792
- }
793
- async getUserById(userId) {
794
- const response = await this.request(`/v1/users/${userId}`, {}, USERS_API_BASE);
795
- return {
796
- id: response.id,
797
- username: response.name,
798
- displayName: response.displayName,
799
- createdAt: new Date(response.created),
800
- isBanned: response.isBanned
801
- };
802
- }
803
- async getUserByUsername(username) {
804
- try {
805
- const response = await this.request(`/v1/usernames/users`, {
806
- method: "POST",
807
- body: JSON.stringify({
808
- usernames: [username],
809
- excludeBannedUsers: false
810
- })
811
- }, USERS_API_BASE);
812
- if (response.data.length === 0) {
813
- return null;
814
- }
815
- const user = response.data[0];
816
- return {
817
- id: user.id,
818
- username: user.name,
819
- displayName: user.displayName
820
- };
821
- } catch {
822
- return null;
823
- }
824
- }
825
- async getUsersByIds(userIds) {
826
- if (userIds.length === 0) {
827
- return [];
828
- }
829
- const response = await this.request(`/v1/users`, {
830
- method: "POST",
831
- body: JSON.stringify({ userIds, excludeBannedUsers: false })
832
- }, USERS_API_BASE);
833
- return response.data.map((user) => ({
834
- id: user.id,
835
- username: user.name,
836
- displayName: user.displayName
837
- }));
838
- }
839
- async getAvatarUrl(userId, size = "150x150") {
840
- try {
841
- const response = await this.request(`/v1/users/avatar-headshot?userIds=${userId}&size=${size}&format=Png`, {}, "https://thumbnails.roblox.com");
842
- return response.data[0]?.imageUrl;
843
- } catch {
844
- return;
845
- }
846
- }
847
- async getExperienceInfo(universeId) {
848
- const targetUniverseId = universeId || this.config.universeId;
849
- const response = await this.request(`/v1/games?universeIds=${targetUniverseId}`, {}, "https://games.roblox.com");
850
- const experience = response.data[0];
851
- if (!experience) {
852
- throw new RobloxApiError(`Experience not found: ${targetUniverseId}`, 404, `/v1/games?universeIds=${targetUniverseId}`);
853
- }
854
- return {
855
- universeId: targetUniverseId,
856
- name: experience.name,
857
- description: experience.description,
858
- creator: {
859
- id: experience.creator.id,
860
- type: experience.creator.type,
861
- name: experience.creator.name
862
- },
863
- playing: experience.playing,
864
- visits: experience.visits,
865
- rootPlaceId: String(experience.rootPlaceId)
866
- };
867
- }
868
- getConfig() {
869
- return { ...this.config };
870
- }
871
- isDryRun() {
872
- return this.config.dryRun;
873
- }
874
- }
875
-
876
- // utils/config.ts
877
- var ROBLOX_DEFAULTS = {
878
- MESSAGING_TOPIC: "eliza-agent",
879
- POLL_INTERVAL: 30,
880
- DRY_RUN: false
881
- };
882
- function hasRobloxEnabled(runtime) {
883
- const apiKey = runtime.getSetting("ROBLOX_API_KEY");
884
- const universeId = runtime.getSetting("ROBLOX_UNIVERSE_ID");
885
- return Boolean(apiKey && universeId);
886
- }
887
- function validateRobloxConfig(runtime) {
888
- const apiKey = runtime.getSetting("ROBLOX_API_KEY");
889
- const universeId = runtime.getSetting("ROBLOX_UNIVERSE_ID");
890
- if (!apiKey) {
891
- throw new Error("ROBLOX_API_KEY is required but not configured");
892
- }
893
- if (!universeId) {
894
- throw new Error("ROBLOX_UNIVERSE_ID is required but not configured");
895
- }
896
- const placeId = runtime.getSetting("ROBLOX_PLACE_ID");
897
- const webhookSecret = runtime.getSetting("ROBLOX_WEBHOOK_SECRET");
898
- const messagingTopic = runtime.getSetting("ROBLOX_MESSAGING_TOPIC") || ROBLOX_DEFAULTS.MESSAGING_TOPIC;
899
- const pollIntervalStr = runtime.getSetting("ROBLOX_POLL_INTERVAL");
900
- const pollInterval = pollIntervalStr ? parseInt(pollIntervalStr, 10) : ROBLOX_DEFAULTS.POLL_INTERVAL;
901
- const dryRunStr = runtime.getSetting("ROBLOX_DRY_RUN");
902
- const dryRun = dryRunStr === "true";
903
- return {
904
- apiKey,
905
- universeId,
906
- placeId,
907
- webhookSecret,
908
- messagingTopic,
909
- pollInterval,
910
- dryRun
911
- };
912
- }
913
-
914
- // services/RobloxService.ts
915
- class RobloxAgentManager {
916
- runtime;
917
- client;
918
- config;
919
- pollTimer = null;
920
- isRunning = false;
921
- constructor(runtime, config) {
922
- this.runtime = runtime;
923
- this.config = config;
924
- this.client = new RobloxClient(config);
925
- }
926
- async start() {
927
- if (this.isRunning) {
928
- return;
929
- }
930
- this.isRunning = true;
931
- this.runtime.logger.info({ universeId: this.config.universeId }, "Roblox agent manager started");
932
- if (this.config.pollInterval > 0) {
933
- this.startPolling();
934
- }
935
- }
936
- async stop() {
937
- this.isRunning = false;
938
- this.stopPolling();
939
- this.runtime.logger.info("Roblox agent manager stopped");
940
- }
941
- startPolling() {
942
- if (this.pollTimer) {
943
- return;
944
- }
945
- const pollIntervalMs = this.config.pollInterval * 1000;
946
- this.pollTimer = setInterval(() => {
947
- this.poll().catch((error) => {
948
- this.runtime.logger.error({ error }, "Error during Roblox polling");
949
- });
950
- }, pollIntervalMs);
951
- this.runtime.logger.debug({ intervalSeconds: this.config.pollInterval }, "Roblox polling started");
952
- }
953
- stopPolling() {
954
- if (this.pollTimer) {
955
- clearInterval(this.pollTimer);
956
- this.pollTimer = null;
957
- this.runtime.logger.debug("Roblox polling stopped");
958
- }
959
- }
960
- async poll() {}
961
- async sendMessage(content, targetPlayerIds) {
962
- await this.client.sendAgentMessage({
963
- topic: this.config.messagingTopic,
964
- data: {
965
- type: "agent_message",
966
- content,
967
- targetPlayerIds,
968
- timestamp: Date.now()
969
- },
970
- sender: {
971
- agentId: this.runtime.agentId,
972
- agentName: this.runtime.character.name
973
- }
974
- });
975
- }
976
- async executeAction(actionName4, parameters, targetPlayerIds) {
977
- await this.client.sendAgentMessage({
978
- topic: this.config.messagingTopic,
979
- data: {
980
- type: "agent_action",
981
- action: actionName4,
982
- parameters,
983
- targetPlayerIds,
984
- timestamp: Date.now()
985
- },
986
- sender: {
987
- agentId: this.runtime.agentId,
988
- agentName: this.runtime.character.name
989
- }
990
- });
991
- }
992
- }
993
-
994
- class RobloxService extends Service {
995
- static instance;
996
- managers = new Map;
997
- static serviceType = ROBLOX_SERVICE_NAME;
998
- description = "Roblox integration service for game communication";
999
- capabilityDescription = "The agent can communicate with Roblox games and players";
1000
- static getInstance() {
1001
- if (!RobloxService.instance) {
1002
- RobloxService.instance = new RobloxService;
1003
- }
1004
- return RobloxService.instance;
1005
- }
1006
- async initialize(runtime) {
1007
- await RobloxService.start(runtime);
1008
- }
1009
- static async start(runtime) {
1010
- const service = RobloxService.getInstance();
1011
- let manager = service.managers.get(runtime.agentId);
1012
- if (manager) {
1013
- runtime.logger.warn({ agentId: runtime.agentId }, "Roblox service already started");
1014
- return service;
1015
- }
1016
- if (!hasRobloxEnabled(runtime)) {
1017
- runtime.logger.debug({ agentId: runtime.agentId }, "Roblox service not enabled - missing API key or Universe ID");
1018
- return service;
1019
- }
1020
- const robloxConfig = validateRobloxConfig(runtime);
1021
- manager = new RobloxAgentManager(runtime, robloxConfig);
1022
- service.managers.set(runtime.agentId, manager);
1023
- await manager.start();
1024
- runtime.logger.success({ agentId: runtime.agentId, universeId: robloxConfig.universeId }, "Roblox service started");
1025
- return service;
1026
- }
1027
- static async stop(runtime) {
1028
- const service = RobloxService.getInstance();
1029
- const manager = service.managers.get(runtime.agentId);
1030
- if (manager) {
1031
- await manager.stop();
1032
- service.managers.delete(runtime.agentId);
1033
- runtime.logger.info({ agentId: runtime.agentId }, "Roblox service stopped");
1034
- } else {
1035
- runtime.logger.debug({ agentId: runtime.agentId }, "Roblox service not running");
1036
- }
1037
- }
1038
- async stop() {
1039
- for (const manager of Array.from(this.managers.values())) {
1040
- const agentId = manager.runtime.agentId;
1041
- manager.runtime.logger.debug("Stopping Roblox service");
1042
- try {
1043
- await RobloxService.stop(manager.runtime);
1044
- } catch (error) {
1045
- manager.runtime.logger.error({ agentId, error }, "Error stopping Roblox service");
1046
- }
1047
- }
1048
- }
1049
- getManager(agentId) {
1050
- return this.managers.get(agentId);
1051
- }
1052
- getClient(agentId) {
1053
- return this.managers.get(agentId)?.client;
1054
- }
1055
- async sendMessage(agentId, content, targetPlayerIds) {
1056
- const manager = this.managers.get(agentId);
1057
- if (!manager) {
1058
- throw new Error(`No Roblox manager found for agent ${agentId}`);
1059
- }
1060
- await manager.sendMessage(content, targetPlayerIds);
1061
- }
1062
- async executeAction(agentId, actionName4, parameters, targetPlayerIds) {
1063
- const manager = this.managers.get(agentId);
1064
- if (!manager) {
1065
- throw new Error(`No Roblox manager found for agent ${agentId}`);
1066
- }
1067
- await manager.executeAction(actionName4, parameters, targetPlayerIds);
1068
- }
1069
- async healthCheck() {
1070
- const managerStatuses = {};
1071
- let overallHealthy = true;
1072
- for (const [agentId, manager] of Array.from(this.managers.entries())) {
1073
- try {
1074
- const experienceInfo = await manager.client.getExperienceInfo();
1075
- managerStatuses[agentId] = {
1076
- status: "healthy",
1077
- universeId: manager.config.universeId,
1078
- experienceName: experienceInfo.name,
1079
- playing: experienceInfo.playing
1080
- };
1081
- } catch (error) {
1082
- managerStatuses[agentId] = {
1083
- status: "unhealthy",
1084
- error: error instanceof Error ? error.message : "Unknown error"
1085
- };
1086
- overallHealthy = false;
1087
- }
1088
- }
1089
- return {
1090
- healthy: overallHealthy,
1091
- details: {
1092
- activeManagers: this.managers.size,
1093
- managerStatuses
1094
- }
1095
- };
1096
- }
1097
- getActiveManagers() {
1098
- return new Map(this.managers);
1099
- }
1100
- }
1101
-
1102
- // index.ts
1103
- var robloxPlugin = {
1104
- name: "roblox",
1105
- description: "Roblox game integration plugin for sending and receiving messages",
1106
- services: [RobloxService],
1107
- actions: robloxActions,
1108
- providers: robloxProviders,
1109
- tests: [new RobloxTestSuite],
1110
- init: async (_config, runtime) => {
1111
- const apiKey = runtime.getSetting("ROBLOX_API_KEY");
1112
- const universeId = runtime.getSetting("ROBLOX_UNIVERSE_ID");
1113
- if (!apiKey || apiKey.trim() === "") {
1114
- runtime.logger.warn("ROBLOX_API_KEY not provided");
1115
- return;
1116
- }
1117
- if (!universeId || universeId.trim() === "") {
1118
- runtime.logger.warn("ROBLOX_UNIVERSE_ID not provided");
1119
- return;
1120
- }
1121
- runtime.logger.info({ universeId }, "Roblox plugin initialized");
1122
- }
1123
- };
1124
- var typescript_default = robloxPlugin;
1125
- export {
1126
- robloxPlugin,
1127
- typescript_default as default,
1128
- RobloxService,
1129
- RobloxClient,
1130
- RobloxApiError
1131
- };
1132
-
1133
- //# debugId=740C50B5F8DE5EDA64756E2164756E21