@elizaos/server 1.0.11 → 1.0.13
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/dist/index.js +653 -769
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -381,13 +381,11 @@ var import_cors2 = __toESM(require_lib(), 1);
|
|
|
381
381
|
import {
|
|
382
382
|
logger as logger29
|
|
383
383
|
} from "@elizaos/core";
|
|
384
|
-
import bodyParser2 from "body-parser";
|
|
385
384
|
import express30 from "express";
|
|
386
|
-
import fileUpload2 from "express-fileupload";
|
|
387
385
|
import helmet2 from "helmet";
|
|
388
|
-
import * as
|
|
386
|
+
import * as fs9 from "fs";
|
|
389
387
|
import http from "http";
|
|
390
|
-
import
|
|
388
|
+
import path9, { basename, dirname, extname, join } from "path";
|
|
391
389
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
392
390
|
|
|
393
391
|
// src/api/index.ts
|
|
@@ -400,7 +398,7 @@ import { match } from "path-to-regexp";
|
|
|
400
398
|
import { Server as SocketIOServer } from "socket.io";
|
|
401
399
|
|
|
402
400
|
// src/api/agents/index.ts
|
|
403
|
-
import
|
|
401
|
+
import express8 from "express";
|
|
404
402
|
|
|
405
403
|
// src/api/agents/crud.ts
|
|
406
404
|
import {
|
|
@@ -499,7 +497,7 @@ function createAgentCrudRouter(agents, serverInstance) {
|
|
|
499
497
|
});
|
|
500
498
|
router.post("/", async (req, res) => {
|
|
501
499
|
logger.debug("[AGENT CREATE] Creating new agent");
|
|
502
|
-
const { characterPath, characterJson } = req.body;
|
|
500
|
+
const { characterPath, characterJson, agent } = req.body;
|
|
503
501
|
if (!db) {
|
|
504
502
|
return sendError(res, 500, "DB_ERROR", "Database not available");
|
|
505
503
|
}
|
|
@@ -511,6 +509,9 @@ function createAgentCrudRouter(agents, serverInstance) {
|
|
|
511
509
|
} else if (characterPath) {
|
|
512
510
|
logger.debug(`[AGENT CREATE] Loading character from path: ${characterPath}`);
|
|
513
511
|
character = await serverInstance?.loadCharacterTryPath(characterPath);
|
|
512
|
+
} else if (agent) {
|
|
513
|
+
logger.debug("[AGENT CREATE] Parsing character from agent object");
|
|
514
|
+
character = await serverInstance?.jsonToCharacter(agent);
|
|
514
515
|
} else {
|
|
515
516
|
throw new Error("No character configuration provided");
|
|
516
517
|
}
|
|
@@ -524,12 +525,12 @@ function createAgentCrudRouter(agents, serverInstance) {
|
|
|
524
525
|
}
|
|
525
526
|
const ensureAgentExists = async (character2) => {
|
|
526
527
|
const agentId = stringToUuid(character2.name);
|
|
527
|
-
let
|
|
528
|
-
if (!
|
|
528
|
+
let agent2 = await db.getAgent(agentId);
|
|
529
|
+
if (!agent2) {
|
|
529
530
|
await db.createAgent({ ...character2, id: agentId });
|
|
530
|
-
|
|
531
|
+
agent2 = await db.getAgent(agentId);
|
|
531
532
|
}
|
|
532
|
-
return
|
|
533
|
+
return agent2;
|
|
533
534
|
};
|
|
534
535
|
const newAgent = await ensureAgentExists(character);
|
|
535
536
|
if (!newAgent) {
|
|
@@ -1183,27 +1184,197 @@ function createAgentMemoryRouter(agents) {
|
|
|
1183
1184
|
);
|
|
1184
1185
|
}
|
|
1185
1186
|
});
|
|
1187
|
+
router.delete("/:agentId/memories/:memoryId", async (req, res) => {
|
|
1188
|
+
try {
|
|
1189
|
+
const agentId = validateUuid6(req.params.agentId);
|
|
1190
|
+
const memoryId = validateUuid6(req.params.memoryId);
|
|
1191
|
+
if (!agentId || !memoryId) {
|
|
1192
|
+
return sendError(res, 400, "INVALID_ID", "Invalid agent ID or memory ID format");
|
|
1193
|
+
}
|
|
1194
|
+
const runtime = agents.get(agentId);
|
|
1195
|
+
if (!runtime) {
|
|
1196
|
+
return sendError(res, 404, "NOT_FOUND", "Agent not found");
|
|
1197
|
+
}
|
|
1198
|
+
await runtime.deleteMemory(memoryId);
|
|
1199
|
+
sendSuccess(res, { message: "Memory deleted successfully" });
|
|
1200
|
+
} catch (error) {
|
|
1201
|
+
logger6.error(`[DELETE MEMORY] Error deleting memory ${req.params.memoryId}:`, error);
|
|
1202
|
+
sendError(
|
|
1203
|
+
res,
|
|
1204
|
+
500,
|
|
1205
|
+
"DELETE_ERROR",
|
|
1206
|
+
"Error deleting memory",
|
|
1207
|
+
error instanceof Error ? error.message : String(error)
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
});
|
|
1211
|
+
return router;
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
// src/api/memory/rooms.ts
|
|
1215
|
+
import { validateUuid as validateUuid7, logger as logger7, createUniqueUuid as createUniqueUuid3, ChannelType } from "@elizaos/core";
|
|
1216
|
+
import express7 from "express";
|
|
1217
|
+
function createRoomManagementRouter(agents) {
|
|
1218
|
+
const router = express7.Router();
|
|
1219
|
+
router.post("/:agentId/rooms", async (req, res) => {
|
|
1220
|
+
const agentId = validateUuid7(req.params.agentId);
|
|
1221
|
+
if (!agentId) {
|
|
1222
|
+
return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
|
|
1223
|
+
}
|
|
1224
|
+
const runtime = agents.get(agentId);
|
|
1225
|
+
if (!runtime) {
|
|
1226
|
+
return sendError(res, 404, "NOT_FOUND", "Agent not found");
|
|
1227
|
+
}
|
|
1228
|
+
try {
|
|
1229
|
+
const { name, type = ChannelType.DM, source = "client", worldId, metadata } = req.body;
|
|
1230
|
+
if (!name) {
|
|
1231
|
+
return sendError(res, 400, "MISSING_PARAM", "Room name is required");
|
|
1232
|
+
}
|
|
1233
|
+
const roomId = createUniqueUuid3(runtime, `room-${Date.now()}`);
|
|
1234
|
+
const serverId = req.body.serverId || `server-${Date.now()}`;
|
|
1235
|
+
let resolvedWorldId = worldId;
|
|
1236
|
+
if (!resolvedWorldId) {
|
|
1237
|
+
const worldName = `World for ${name}`;
|
|
1238
|
+
resolvedWorldId = createUniqueUuid3(runtime, `world-${Date.now()}`);
|
|
1239
|
+
await runtime.ensureWorldExists({
|
|
1240
|
+
id: resolvedWorldId,
|
|
1241
|
+
name: worldName,
|
|
1242
|
+
agentId: runtime.agentId,
|
|
1243
|
+
serverId,
|
|
1244
|
+
metadata
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
await runtime.ensureRoomExists({
|
|
1248
|
+
id: roomId,
|
|
1249
|
+
name,
|
|
1250
|
+
source,
|
|
1251
|
+
type,
|
|
1252
|
+
channelId: roomId,
|
|
1253
|
+
serverId,
|
|
1254
|
+
worldId: resolvedWorldId,
|
|
1255
|
+
metadata
|
|
1256
|
+
});
|
|
1257
|
+
await runtime.addParticipant(runtime.agentId, roomId);
|
|
1258
|
+
await runtime.ensureParticipantInRoom(runtime.agentId, roomId);
|
|
1259
|
+
await runtime.setParticipantUserState(roomId, runtime.agentId, "FOLLOWED");
|
|
1260
|
+
sendSuccess(
|
|
1261
|
+
res,
|
|
1262
|
+
{
|
|
1263
|
+
id: roomId,
|
|
1264
|
+
name,
|
|
1265
|
+
agentId,
|
|
1266
|
+
createdAt: Date.now(),
|
|
1267
|
+
source,
|
|
1268
|
+
type,
|
|
1269
|
+
worldId: resolvedWorldId,
|
|
1270
|
+
serverId,
|
|
1271
|
+
metadata
|
|
1272
|
+
},
|
|
1273
|
+
201
|
|
1274
|
+
);
|
|
1275
|
+
} catch (error) {
|
|
1276
|
+
logger7.error(`[ROOM CREATE] Error creating room for agent ${agentId}:`, error);
|
|
1277
|
+
sendError(
|
|
1278
|
+
res,
|
|
1279
|
+
500,
|
|
1280
|
+
"CREATE_ERROR",
|
|
1281
|
+
"Failed to create room",
|
|
1282
|
+
error instanceof Error ? error.message : String(error)
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1285
|
+
});
|
|
1286
|
+
router.get("/:agentId/rooms", async (req, res) => {
|
|
1287
|
+
const agentId = validateUuid7(req.params.agentId);
|
|
1288
|
+
if (!agentId) {
|
|
1289
|
+
return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
|
|
1290
|
+
}
|
|
1291
|
+
const runtime = agents.get(agentId);
|
|
1292
|
+
if (!runtime) {
|
|
1293
|
+
return sendError(res, 404, "NOT_FOUND", "Agent not found");
|
|
1294
|
+
}
|
|
1295
|
+
try {
|
|
1296
|
+
const worlds = await runtime.getAllWorlds();
|
|
1297
|
+
const participantRoomIds = await runtime.getRoomsForParticipant(agentId);
|
|
1298
|
+
const agentRooms = [];
|
|
1299
|
+
for (const world of worlds) {
|
|
1300
|
+
const worldRooms = await runtime.getRooms(world.id);
|
|
1301
|
+
for (const room of worldRooms) {
|
|
1302
|
+
if (participantRoomIds.includes(room.id)) {
|
|
1303
|
+
agentRooms.push({
|
|
1304
|
+
...room
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
sendSuccess(res, { rooms: agentRooms });
|
|
1310
|
+
} catch (error) {
|
|
1311
|
+
logger7.error(`[ROOMS LIST] Error retrieving rooms for agent ${agentId}:`, error);
|
|
1312
|
+
sendError(
|
|
1313
|
+
res,
|
|
1314
|
+
500,
|
|
1315
|
+
"RETRIEVAL_ERROR",
|
|
1316
|
+
"Failed to retrieve agent rooms",
|
|
1317
|
+
error instanceof Error ? error.message : String(error)
|
|
1318
|
+
);
|
|
1319
|
+
}
|
|
1320
|
+
});
|
|
1321
|
+
router.get("/:agentId/rooms/:roomId", async (req, res) => {
|
|
1322
|
+
const agentId = validateUuid7(req.params.agentId);
|
|
1323
|
+
const roomId = validateUuid7(req.params.roomId);
|
|
1324
|
+
if (!agentId || !roomId) {
|
|
1325
|
+
return sendError(res, 400, "INVALID_ID", "Invalid agent ID or room ID format");
|
|
1326
|
+
}
|
|
1327
|
+
const runtime = agents.get(agentId);
|
|
1328
|
+
if (!runtime) {
|
|
1329
|
+
return sendError(res, 404, "NOT_FOUND", "Agent not found");
|
|
1330
|
+
}
|
|
1331
|
+
try {
|
|
1332
|
+
const room = await runtime.getRoom(roomId);
|
|
1333
|
+
if (!room) {
|
|
1334
|
+
return sendError(res, 404, "NOT_FOUND", "Room not found");
|
|
1335
|
+
}
|
|
1336
|
+
let worldName;
|
|
1337
|
+
if (room.worldId) {
|
|
1338
|
+
const world = await runtime.getWorld(room.worldId);
|
|
1339
|
+
worldName = world?.name;
|
|
1340
|
+
}
|
|
1341
|
+
sendSuccess(res, {
|
|
1342
|
+
...room,
|
|
1343
|
+
...worldName && { worldName }
|
|
1344
|
+
});
|
|
1345
|
+
} catch (error) {
|
|
1346
|
+
logger7.error(`[ROOM DETAILS] Error retrieving room ${roomId} for agent ${agentId}:`, error);
|
|
1347
|
+
sendError(
|
|
1348
|
+
res,
|
|
1349
|
+
500,
|
|
1350
|
+
"RETRIEVAL_ERROR",
|
|
1351
|
+
"Failed to retrieve room details",
|
|
1352
|
+
error instanceof Error ? error.message : String(error)
|
|
1353
|
+
);
|
|
1354
|
+
}
|
|
1355
|
+
});
|
|
1186
1356
|
return router;
|
|
1187
1357
|
}
|
|
1188
1358
|
|
|
1189
1359
|
// src/api/agents/index.ts
|
|
1190
1360
|
function agentsRouter(agents, serverInstance) {
|
|
1191
|
-
const router =
|
|
1361
|
+
const router = express8.Router();
|
|
1192
1362
|
router.use("/", createAgentCrudRouter(agents, serverInstance));
|
|
1193
1363
|
router.use("/", createAgentLifecycleRouter(agents, serverInstance));
|
|
1194
1364
|
router.use("/", createAgentWorldsRouter(agents));
|
|
1195
1365
|
router.use("/", createAgentPanelsRouter(agents));
|
|
1196
1366
|
router.use("/", createAgentLogsRouter(agents));
|
|
1197
|
-
router.use("/", createAgentMemoryRouter(agents
|
|
1367
|
+
router.use("/", createAgentMemoryRouter(agents));
|
|
1368
|
+
router.use("/", createRoomManagementRouter(agents));
|
|
1198
1369
|
return router;
|
|
1199
1370
|
}
|
|
1200
1371
|
|
|
1201
1372
|
// src/api/messaging/index.ts
|
|
1202
|
-
import
|
|
1373
|
+
import express12 from "express";
|
|
1203
1374
|
|
|
1204
1375
|
// src/api/messaging/core.ts
|
|
1205
|
-
import { logger as
|
|
1206
|
-
import
|
|
1376
|
+
import { logger as logger8, validateUuid as validateUuid8 } from "@elizaos/core";
|
|
1377
|
+
import express9 from "express";
|
|
1207
1378
|
|
|
1208
1379
|
// src/bus.ts
|
|
1209
1380
|
import EventEmitter from "events";
|
|
@@ -1216,7 +1387,7 @@ var bus_default = internalMessageBus;
|
|
|
1216
1387
|
// src/api/messaging/core.ts
|
|
1217
1388
|
var DEFAULT_SERVER_ID = "00000000-0000-0000-0000-000000000000";
|
|
1218
1389
|
function createMessagingCoreRouter(serverInstance) {
|
|
1219
|
-
const router =
|
|
1390
|
+
const router = express9.Router();
|
|
1220
1391
|
router.post("/submit", async (req, res) => {
|
|
1221
1392
|
const {
|
|
1222
1393
|
channel_id,
|
|
@@ -1232,14 +1403,14 @@ function createMessagingCoreRouter(serverInstance) {
|
|
|
1232
1403
|
metadata
|
|
1233
1404
|
// Should include agent_name if author_id is agent's runtime.agentId
|
|
1234
1405
|
} = req.body;
|
|
1235
|
-
const isValidServerId = server_id === DEFAULT_SERVER_ID ||
|
|
1236
|
-
if (!
|
|
1406
|
+
const isValidServerId = server_id === DEFAULT_SERVER_ID || validateUuid8(server_id);
|
|
1407
|
+
if (!validateUuid8(channel_id) || !validateUuid8(author_id) || !content || !isValidServerId || !source_type || !raw_message) {
|
|
1237
1408
|
return res.status(400).json({
|
|
1238
1409
|
success: false,
|
|
1239
1410
|
error: "Missing required fields: channel_id, server_id, author_id, content, source_type, raw_message"
|
|
1240
1411
|
});
|
|
1241
1412
|
}
|
|
1242
|
-
if (in_reply_to_message_id && !
|
|
1413
|
+
if (in_reply_to_message_id && !validateUuid8(in_reply_to_message_id)) {
|
|
1243
1414
|
return res.status(400).json({
|
|
1244
1415
|
success: false,
|
|
1245
1416
|
error: "Invalid in_reply_to_message_id format"
|
|
@@ -1247,12 +1418,12 @@ function createMessagingCoreRouter(serverInstance) {
|
|
|
1247
1418
|
}
|
|
1248
1419
|
try {
|
|
1249
1420
|
const newRootMessageData = {
|
|
1250
|
-
channelId:
|
|
1251
|
-
authorId:
|
|
1421
|
+
channelId: validateUuid8(channel_id),
|
|
1422
|
+
authorId: validateUuid8(author_id),
|
|
1252
1423
|
content,
|
|
1253
1424
|
rawMessage: raw_message,
|
|
1254
1425
|
sourceType: source_type || "agent_response",
|
|
1255
|
-
inReplyToRootMessageId: in_reply_to_message_id ?
|
|
1426
|
+
inReplyToRootMessageId: in_reply_to_message_id ? validateUuid8(in_reply_to_message_id) || void 0 : void 0,
|
|
1256
1427
|
metadata
|
|
1257
1428
|
};
|
|
1258
1429
|
const createdMessage = await serverInstance.createMessage(newRootMessageData);
|
|
@@ -1277,13 +1448,13 @@ function createMessagingCoreRouter(serverInstance) {
|
|
|
1277
1448
|
}
|
|
1278
1449
|
res.status(201).json({ success: true, data: createdMessage });
|
|
1279
1450
|
} catch (error) {
|
|
1280
|
-
|
|
1451
|
+
logger8.error("[Messages Router /submit] Error submitting agent message:", error);
|
|
1281
1452
|
res.status(500).json({ success: false, error: "Failed to submit agent message" });
|
|
1282
1453
|
}
|
|
1283
1454
|
});
|
|
1284
1455
|
router.post("/complete", async (req, res) => {
|
|
1285
1456
|
const { channel_id, server_id } = req.body;
|
|
1286
|
-
if (!
|
|
1457
|
+
if (!validateUuid8(channel_id) || !validateUuid8(server_id)) {
|
|
1287
1458
|
return res.status(400).json({
|
|
1288
1459
|
success: false,
|
|
1289
1460
|
error: "Missing or invalid fields: channel_id, server_id"
|
|
@@ -1298,7 +1469,7 @@ function createMessagingCoreRouter(serverInstance) {
|
|
|
1298
1469
|
}
|
|
1299
1470
|
res.status(200).json({ success: true, message: "Completion event emitted" });
|
|
1300
1471
|
} catch (error) {
|
|
1301
|
-
|
|
1472
|
+
logger8.error("[Messages Router /notify-complete] Error notifying message complete:", error);
|
|
1302
1473
|
res.status(500).json({ success: false, error: "Failed to notify message completion" });
|
|
1303
1474
|
}
|
|
1304
1475
|
});
|
|
@@ -1317,7 +1488,7 @@ function createMessagingCoreRouter(serverInstance) {
|
|
|
1317
1488
|
sourceId: messagePayload.source_id,
|
|
1318
1489
|
// Original platform message ID
|
|
1319
1490
|
sourceType: messagePayload.source_type,
|
|
1320
|
-
inReplyToRootMessageId: messagePayload.in_reply_to_message_id ?
|
|
1491
|
+
inReplyToRootMessageId: messagePayload.in_reply_to_message_id ? validateUuid8(messagePayload.in_reply_to_message_id) || void 0 : void 0,
|
|
1321
1492
|
metadata: messagePayload.metadata
|
|
1322
1493
|
};
|
|
1323
1494
|
const createdRootMessage = await serverInstance.createMessage(messageToCreate);
|
|
@@ -1339,7 +1510,7 @@ function createMessagingCoreRouter(serverInstance) {
|
|
|
1339
1510
|
metadata: createdRootMessage.metadata
|
|
1340
1511
|
};
|
|
1341
1512
|
bus_default.emit("new_message", messageForBus);
|
|
1342
|
-
|
|
1513
|
+
logger8.info(
|
|
1343
1514
|
"[Messages Router /ingest-external] Published to internal message bus:",
|
|
1344
1515
|
createdRootMessage.id
|
|
1345
1516
|
);
|
|
@@ -1362,7 +1533,7 @@ function createMessagingCoreRouter(serverInstance) {
|
|
|
1362
1533
|
data: { messageId: createdRootMessage.id }
|
|
1363
1534
|
});
|
|
1364
1535
|
} catch (error) {
|
|
1365
|
-
|
|
1536
|
+
logger8.error("[Messages Router /ingest-external] Error ingesting external message:", error);
|
|
1366
1537
|
res.status(500).json({ success: false, error: "Failed to ingest message" });
|
|
1367
1538
|
}
|
|
1368
1539
|
});
|
|
@@ -1370,17 +1541,17 @@ function createMessagingCoreRouter(serverInstance) {
|
|
|
1370
1541
|
}
|
|
1371
1542
|
|
|
1372
1543
|
// src/api/messaging/servers.ts
|
|
1373
|
-
import { logger as
|
|
1374
|
-
import
|
|
1544
|
+
import { logger as logger9, validateUuid as validateUuid9 } from "@elizaos/core";
|
|
1545
|
+
import express10 from "express";
|
|
1375
1546
|
var DEFAULT_SERVER_ID2 = "00000000-0000-0000-0000-000000000000";
|
|
1376
1547
|
function createServersRouter(serverInstance) {
|
|
1377
|
-
const router =
|
|
1548
|
+
const router = express10.Router();
|
|
1378
1549
|
router.get("/central-servers", async (_req, res) => {
|
|
1379
1550
|
try {
|
|
1380
1551
|
const servers = await serverInstance.getServers();
|
|
1381
1552
|
res.json({ success: true, data: { servers } });
|
|
1382
1553
|
} catch (error) {
|
|
1383
|
-
|
|
1554
|
+
logger9.error("[Messages Router /central-servers] Error fetching servers:", error);
|
|
1384
1555
|
res.status(500).json({ success: false, error: "Failed to fetch servers" });
|
|
1385
1556
|
}
|
|
1386
1557
|
});
|
|
@@ -1401,16 +1572,16 @@ function createServersRouter(serverInstance) {
|
|
|
1401
1572
|
});
|
|
1402
1573
|
res.status(201).json({ success: true, data: { server } });
|
|
1403
1574
|
} catch (error) {
|
|
1404
|
-
|
|
1575
|
+
logger9.error("[Messages Router /servers] Error creating server:", error);
|
|
1405
1576
|
res.status(500).json({ success: false, error: "Failed to create server" });
|
|
1406
1577
|
}
|
|
1407
1578
|
});
|
|
1408
1579
|
router.post(
|
|
1409
1580
|
"/servers/:serverId/agents",
|
|
1410
1581
|
async (req, res) => {
|
|
1411
|
-
const serverId = req.params.serverId === DEFAULT_SERVER_ID2 ? DEFAULT_SERVER_ID2 :
|
|
1582
|
+
const serverId = req.params.serverId === DEFAULT_SERVER_ID2 ? DEFAULT_SERVER_ID2 : validateUuid9(req.params.serverId);
|
|
1412
1583
|
const { agentId } = req.body;
|
|
1413
|
-
if (!serverId || !
|
|
1584
|
+
if (!serverId || !validateUuid9(agentId)) {
|
|
1414
1585
|
return res.status(400).json({
|
|
1415
1586
|
success: false,
|
|
1416
1587
|
error: "Invalid serverId or agentId format"
|
|
@@ -1433,7 +1604,7 @@ function createServersRouter(serverInstance) {
|
|
|
1433
1604
|
}
|
|
1434
1605
|
});
|
|
1435
1606
|
} catch (error) {
|
|
1436
|
-
|
|
1607
|
+
logger9.error(
|
|
1437
1608
|
`[MessagesRouter] Error adding agent ${agentId} to server ${serverId}:`,
|
|
1438
1609
|
error
|
|
1439
1610
|
);
|
|
@@ -1444,8 +1615,8 @@ function createServersRouter(serverInstance) {
|
|
|
1444
1615
|
router.delete(
|
|
1445
1616
|
"/servers/:serverId/agents/:agentId",
|
|
1446
1617
|
async (req, res) => {
|
|
1447
|
-
const serverId = req.params.serverId === DEFAULT_SERVER_ID2 ? DEFAULT_SERVER_ID2 :
|
|
1448
|
-
const agentId =
|
|
1618
|
+
const serverId = req.params.serverId === DEFAULT_SERVER_ID2 ? DEFAULT_SERVER_ID2 : validateUuid9(req.params.serverId);
|
|
1619
|
+
const agentId = validateUuid9(req.params.agentId);
|
|
1449
1620
|
if (!serverId || !agentId) {
|
|
1450
1621
|
return res.status(400).json({
|
|
1451
1622
|
success: false,
|
|
@@ -1469,7 +1640,7 @@ function createServersRouter(serverInstance) {
|
|
|
1469
1640
|
}
|
|
1470
1641
|
});
|
|
1471
1642
|
} catch (error) {
|
|
1472
|
-
|
|
1643
|
+
logger9.error(
|
|
1473
1644
|
`[MessagesRouter] Error removing agent ${agentId} from server ${serverId}:`,
|
|
1474
1645
|
error
|
|
1475
1646
|
);
|
|
@@ -1480,7 +1651,7 @@ function createServersRouter(serverInstance) {
|
|
|
1480
1651
|
router.get(
|
|
1481
1652
|
"/servers/:serverId/agents",
|
|
1482
1653
|
async (req, res) => {
|
|
1483
|
-
const serverId = req.params.serverId === DEFAULT_SERVER_ID2 ? DEFAULT_SERVER_ID2 :
|
|
1654
|
+
const serverId = req.params.serverId === DEFAULT_SERVER_ID2 ? DEFAULT_SERVER_ID2 : validateUuid9(req.params.serverId);
|
|
1484
1655
|
if (!serverId) {
|
|
1485
1656
|
return res.status(400).json({
|
|
1486
1657
|
success: false,
|
|
@@ -1498,7 +1669,7 @@ function createServersRouter(serverInstance) {
|
|
|
1498
1669
|
}
|
|
1499
1670
|
});
|
|
1500
1671
|
} catch (error) {
|
|
1501
|
-
|
|
1672
|
+
logger9.error(`[MessagesRouter] Error fetching agents for server ${serverId}:`, error);
|
|
1502
1673
|
res.status(500).json({ success: false, error: "Failed to fetch server agents" });
|
|
1503
1674
|
}
|
|
1504
1675
|
}
|
|
@@ -1506,7 +1677,7 @@ function createServersRouter(serverInstance) {
|
|
|
1506
1677
|
router.get(
|
|
1507
1678
|
"/agents/:agentId/servers",
|
|
1508
1679
|
async (req, res) => {
|
|
1509
|
-
const agentId =
|
|
1680
|
+
const agentId = validateUuid9(req.params.agentId);
|
|
1510
1681
|
if (!agentId) {
|
|
1511
1682
|
return res.status(400).json({
|
|
1512
1683
|
success: false,
|
|
@@ -1524,7 +1695,7 @@ function createServersRouter(serverInstance) {
|
|
|
1524
1695
|
}
|
|
1525
1696
|
});
|
|
1526
1697
|
} catch (error) {
|
|
1527
|
-
|
|
1698
|
+
logger9.error(`[MessagesRouter] Error fetching servers for agent ${agentId}:`, error);
|
|
1528
1699
|
res.status(500).json({ success: false, error: "Failed to fetch agent servers" });
|
|
1529
1700
|
}
|
|
1530
1701
|
}
|
|
@@ -1536,190 +1707,17 @@ function createServersRouter(serverInstance) {
|
|
|
1536
1707
|
import {
|
|
1537
1708
|
composePromptFromState,
|
|
1538
1709
|
ModelType,
|
|
1539
|
-
ChannelType,
|
|
1540
|
-
logger as
|
|
1710
|
+
ChannelType as ChannelType2,
|
|
1711
|
+
logger as logger12,
|
|
1541
1712
|
validateUuid as validateUuid12
|
|
1542
1713
|
} from "@elizaos/core";
|
|
1543
|
-
import
|
|
1544
|
-
|
|
1545
|
-
// src/upload.ts
|
|
1546
|
-
import fs2 from "fs";
|
|
1547
|
-
import path2 from "path";
|
|
1548
|
-
import fileUpload from "express-fileupload";
|
|
1549
|
-
import { validateUuid as validateUuid9, logger as logger10 } from "@elizaos/core";
|
|
1550
|
-
|
|
1551
|
-
// src/api/shared/file-utils.ts
|
|
1552
|
-
import fs from "fs";
|
|
1553
|
-
import path from "path";
|
|
1554
|
-
import { logger as logger9 } from "@elizaos/core";
|
|
1555
|
-
function createSecureUploadDir(id, type) {
|
|
1556
|
-
if (id.includes("..") || id.includes("/") || id.includes("\\") || id.includes("\0")) {
|
|
1557
|
-
throw new Error(`Invalid ${type.slice(0, -1)} ID: contains illegal characters`);
|
|
1558
|
-
}
|
|
1559
|
-
const basePath = path.resolve(process.cwd(), ".eliza", "data", "uploads", type);
|
|
1560
|
-
const targetPath = path.join(basePath, id);
|
|
1561
|
-
if (!targetPath.startsWith(basePath)) {
|
|
1562
|
-
throw new Error(`Invalid ${type.slice(0, -1)} ID: path traversal detected`);
|
|
1563
|
-
}
|
|
1564
|
-
return targetPath;
|
|
1565
|
-
}
|
|
1566
|
-
function sanitizeFilename(filename) {
|
|
1567
|
-
let sanitized = filename.replace(/[\0\/\\:*?"<>|]/g, "_");
|
|
1568
|
-
sanitized = sanitized.replace(/^[.\s]+/, "");
|
|
1569
|
-
if (sanitized.length > 255) {
|
|
1570
|
-
const ext = path.extname(sanitized);
|
|
1571
|
-
const name = path.basename(sanitized, ext);
|
|
1572
|
-
sanitized = name.substring(0, 255 - ext.length) + ext;
|
|
1573
|
-
}
|
|
1574
|
-
if (!sanitized || sanitized.trim() === "") {
|
|
1575
|
-
sanitized = "file";
|
|
1576
|
-
}
|
|
1577
|
-
return sanitized;
|
|
1578
|
-
}
|
|
1579
|
-
var cleanupFile = (filePath) => {
|
|
1580
|
-
if (!filePath) return;
|
|
1581
|
-
try {
|
|
1582
|
-
const resolvedPath = path.resolve(filePath);
|
|
1583
|
-
const normalizedPath = path.normalize(resolvedPath);
|
|
1584
|
-
if (normalizedPath.includes("..") || !normalizedPath.startsWith(process.cwd())) {
|
|
1585
|
-
logger9.warn(`[SECURITY] Potentially unsafe file path blocked: ${filePath}`);
|
|
1586
|
-
return;
|
|
1587
|
-
}
|
|
1588
|
-
if (fs.existsSync(normalizedPath)) {
|
|
1589
|
-
fs.unlinkSync(normalizedPath);
|
|
1590
|
-
logger9.debug(`[FILE] Successfully cleaned up file: ${normalizedPath}`);
|
|
1591
|
-
}
|
|
1592
|
-
} catch (error) {
|
|
1593
|
-
logger9.error(`Error cleaning up file ${filePath}:`, error);
|
|
1594
|
-
}
|
|
1595
|
-
};
|
|
1596
|
-
var cleanupUploadedFile = (file) => {
|
|
1597
|
-
if (file.tempFilePath) {
|
|
1598
|
-
cleanupFile(file.tempFilePath);
|
|
1599
|
-
}
|
|
1600
|
-
};
|
|
1601
|
-
|
|
1602
|
-
// src/api/shared/constants.ts
|
|
1603
|
-
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
1604
|
-
var MAX_FILE_SIZE_DISPLAY = "50MB";
|
|
1605
|
-
var ALLOWED_AUDIO_MIME_TYPES = [
|
|
1606
|
-
"audio/mpeg",
|
|
1607
|
-
"audio/mp3",
|
|
1608
|
-
"audio/wav",
|
|
1609
|
-
"audio/ogg",
|
|
1610
|
-
"audio/webm",
|
|
1611
|
-
"audio/mp4",
|
|
1612
|
-
"audio/aac",
|
|
1613
|
-
"audio/flac",
|
|
1614
|
-
"audio/x-wav",
|
|
1615
|
-
"audio/wave"
|
|
1616
|
-
];
|
|
1617
|
-
var ALLOWED_MEDIA_MIME_TYPES = [
|
|
1618
|
-
...ALLOWED_AUDIO_MIME_TYPES,
|
|
1619
|
-
"image/jpeg",
|
|
1620
|
-
"image/png",
|
|
1621
|
-
"image/gif",
|
|
1622
|
-
"image/webp",
|
|
1623
|
-
"video/mp4",
|
|
1624
|
-
"video/webm",
|
|
1625
|
-
"application/pdf",
|
|
1626
|
-
"text/plain"
|
|
1627
|
-
];
|
|
1628
|
-
|
|
1629
|
-
// src/upload.ts
|
|
1630
|
-
function generateSecureFilename(originalName) {
|
|
1631
|
-
const uniqueSuffix = `${Date.now()}-${Math.round(Math.random() * 1e9)}`;
|
|
1632
|
-
const sanitizedName = sanitizeFilename(originalName);
|
|
1633
|
-
return `${uniqueSuffix}-${sanitizedName}`;
|
|
1634
|
-
}
|
|
1635
|
-
function ensureUploadDir(id, type) {
|
|
1636
|
-
if (!validateUuid9(id)) {
|
|
1637
|
-
throw new Error(`Invalid ${type.slice(0, -1)} ID format`);
|
|
1638
|
-
}
|
|
1639
|
-
const uploadDir = createSecureUploadDir(id, type);
|
|
1640
|
-
if (!fs2.existsSync(uploadDir)) {
|
|
1641
|
-
fs2.mkdirSync(uploadDir, { recursive: true });
|
|
1642
|
-
}
|
|
1643
|
-
logger10.debug(`[UPLOAD] Secure ${type.slice(0, -1)} upload directory created: ${uploadDir}`);
|
|
1644
|
-
return uploadDir;
|
|
1645
|
-
}
|
|
1646
|
-
var agentAudioUpload = () => fileUpload({
|
|
1647
|
-
limits: {
|
|
1648
|
-
fileSize: MAX_FILE_SIZE,
|
|
1649
|
-
// 50MB max file size
|
|
1650
|
-
files: 1
|
|
1651
|
-
// Only allow 1 file per request
|
|
1652
|
-
},
|
|
1653
|
-
useTempFiles: true,
|
|
1654
|
-
tempFileDir: "/tmp/",
|
|
1655
|
-
parseNested: true,
|
|
1656
|
-
abortOnLimit: true,
|
|
1657
|
-
createParentPath: true,
|
|
1658
|
-
preserveExtension: true,
|
|
1659
|
-
safeFileNames: true,
|
|
1660
|
-
uploadTimeout: 6e4
|
|
1661
|
-
// 60 seconds timeout
|
|
1662
|
-
});
|
|
1663
|
-
var agentMediaUpload = () => fileUpload({
|
|
1664
|
-
limits: {
|
|
1665
|
-
fileSize: MAX_FILE_SIZE,
|
|
1666
|
-
// 50MB max file size
|
|
1667
|
-
files: 1
|
|
1668
|
-
// Only allow 1 file per request
|
|
1669
|
-
},
|
|
1670
|
-
useTempFiles: true,
|
|
1671
|
-
tempFileDir: "/tmp/",
|
|
1672
|
-
parseNested: true,
|
|
1673
|
-
abortOnLimit: true,
|
|
1674
|
-
createParentPath: true,
|
|
1675
|
-
preserveExtension: true,
|
|
1676
|
-
safeFileNames: true,
|
|
1677
|
-
uploadTimeout: 6e4
|
|
1678
|
-
// 60 seconds timeout
|
|
1679
|
-
});
|
|
1680
|
-
var channelUpload = () => fileUpload({
|
|
1681
|
-
limits: {
|
|
1682
|
-
fileSize: MAX_FILE_SIZE,
|
|
1683
|
-
// 50MB max file size
|
|
1684
|
-
files: 1
|
|
1685
|
-
// Only allow 1 file per request
|
|
1686
|
-
},
|
|
1687
|
-
useTempFiles: true,
|
|
1688
|
-
tempFileDir: "/tmp/",
|
|
1689
|
-
parseNested: true,
|
|
1690
|
-
abortOnLimit: true,
|
|
1691
|
-
createParentPath: true,
|
|
1692
|
-
preserveExtension: true,
|
|
1693
|
-
safeFileNames: true,
|
|
1694
|
-
uploadTimeout: 6e4
|
|
1695
|
-
// 60 seconds timeout
|
|
1696
|
-
});
|
|
1697
|
-
function validateAudioFile(file) {
|
|
1698
|
-
return ALLOWED_AUDIO_MIME_TYPES.includes(file.mimetype);
|
|
1699
|
-
}
|
|
1700
|
-
function validateMediaFile(file) {
|
|
1701
|
-
return ALLOWED_MEDIA_MIME_TYPES.includes(file.mimetype);
|
|
1702
|
-
}
|
|
1703
|
-
async function processUploadedFile(file, targetId, type) {
|
|
1704
|
-
try {
|
|
1705
|
-
const uploadDir = ensureUploadDir(targetId, type);
|
|
1706
|
-
const filename = generateSecureFilename(file.name);
|
|
1707
|
-
const finalPath = path2.join(uploadDir, filename);
|
|
1708
|
-
await file.mv(finalPath);
|
|
1709
|
-
const url = `/media/uploads/${type}/${targetId}/${filename}`;
|
|
1710
|
-
logger10.debug(`[UPLOAD] File processed successfully: ${filename}`);
|
|
1711
|
-
return { filename, path: finalPath, url };
|
|
1712
|
-
} catch (error) {
|
|
1713
|
-
logger10.error("[UPLOAD] Error processing uploaded file:", error);
|
|
1714
|
-
throw error;
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1714
|
+
import express11 from "express";
|
|
1717
1715
|
|
|
1718
1716
|
// src/api/shared/middleware.ts
|
|
1719
|
-
import { validateUuid as validateUuid11, logger as
|
|
1717
|
+
import { validateUuid as validateUuid11, logger as logger11 } from "@elizaos/core";
|
|
1720
1718
|
|
|
1721
1719
|
// src/api/shared/validation.ts
|
|
1722
|
-
import { validateUuid as validateUuid10, logger as
|
|
1720
|
+
import { validateUuid as validateUuid10, logger as logger10 } from "@elizaos/core";
|
|
1723
1721
|
var getRuntime = (agents, agentId) => {
|
|
1724
1722
|
const runtime = agents.get(agentId);
|
|
1725
1723
|
if (!runtime) {
|
|
@@ -1743,7 +1741,7 @@ var securityMiddleware = () => {
|
|
|
1743
1741
|
const realIp = req.get("X-Real-IP");
|
|
1744
1742
|
const clientIp = forwarded || realIp || req.ip;
|
|
1745
1743
|
if (userAgent && (userAgent.includes("..") || userAgent.includes("<script"))) {
|
|
1746
|
-
|
|
1744
|
+
logger11.warn(`[SECURITY] Suspicious User-Agent from ${clientIp}: ${userAgent}`);
|
|
1747
1745
|
}
|
|
1748
1746
|
const url = req.originalUrl || req.url;
|
|
1749
1747
|
const queryString = JSON.stringify(req.query);
|
|
@@ -1769,12 +1767,12 @@ var securityMiddleware = () => {
|
|
|
1769
1767
|
}
|
|
1770
1768
|
for (const indicator of suspiciousIndicators) {
|
|
1771
1769
|
if (url.includes(indicator.pattern) || queryString.includes(indicator.pattern)) {
|
|
1772
|
-
|
|
1770
|
+
logger11.warn(`[SECURITY] ${indicator.name} detected from ${clientIp}: ${url}`);
|
|
1773
1771
|
break;
|
|
1774
1772
|
}
|
|
1775
1773
|
}
|
|
1776
1774
|
if (hasSqlPattern) {
|
|
1777
|
-
|
|
1775
|
+
logger11.warn(`[SECURITY] SQL injection pattern detected from ${clientIp}: ${url}`);
|
|
1778
1776
|
}
|
|
1779
1777
|
next();
|
|
1780
1778
|
};
|
|
@@ -1823,7 +1821,7 @@ var createApiRateLimit = () => {
|
|
|
1823
1821
|
// Disable the `X-RateLimit-*` headers
|
|
1824
1822
|
handler: (req, res) => {
|
|
1825
1823
|
const clientIp = req.ip || "unknown";
|
|
1826
|
-
|
|
1824
|
+
logger11.warn(`[SECURITY] Rate limit exceeded for IP: ${clientIp}`);
|
|
1827
1825
|
res.status(429).json({
|
|
1828
1826
|
success: false,
|
|
1829
1827
|
error: {
|
|
@@ -1851,7 +1849,7 @@ var createFileSystemRateLimit = () => {
|
|
|
1851
1849
|
legacyHeaders: false,
|
|
1852
1850
|
handler: (req, res) => {
|
|
1853
1851
|
const clientIp = req.ip || "unknown";
|
|
1854
|
-
|
|
1852
|
+
logger11.warn(
|
|
1855
1853
|
`[SECURITY] File system rate limit exceeded for IP: ${clientIp}, endpoint: ${req.path}`
|
|
1856
1854
|
);
|
|
1857
1855
|
res.status(429).json({
|
|
@@ -1881,7 +1879,7 @@ var createUploadRateLimit = () => {
|
|
|
1881
1879
|
legacyHeaders: false,
|
|
1882
1880
|
handler: (req, res) => {
|
|
1883
1881
|
const clientIp = req.ip || "unknown";
|
|
1884
|
-
|
|
1882
|
+
logger11.warn(
|
|
1885
1883
|
`[SECURITY] Upload rate limit exceeded for IP: ${clientIp}, endpoint: ${req.path}`
|
|
1886
1884
|
);
|
|
1887
1885
|
res.status(429).json({
|
|
@@ -1895,10 +1893,69 @@ var createUploadRateLimit = () => {
|
|
|
1895
1893
|
});
|
|
1896
1894
|
};
|
|
1897
1895
|
|
|
1896
|
+
// src/api/shared/constants.ts
|
|
1897
|
+
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
1898
|
+
var MAX_FILE_SIZE_DISPLAY = "50MB";
|
|
1899
|
+
var ALLOWED_AUDIO_MIME_TYPES = [
|
|
1900
|
+
"audio/mpeg",
|
|
1901
|
+
"audio/mp3",
|
|
1902
|
+
"audio/wav",
|
|
1903
|
+
"audio/ogg",
|
|
1904
|
+
"audio/webm",
|
|
1905
|
+
"audio/mp4",
|
|
1906
|
+
"audio/aac",
|
|
1907
|
+
"audio/flac",
|
|
1908
|
+
"audio/x-wav",
|
|
1909
|
+
"audio/wave"
|
|
1910
|
+
];
|
|
1911
|
+
var ALLOWED_MEDIA_MIME_TYPES = [
|
|
1912
|
+
...ALLOWED_AUDIO_MIME_TYPES,
|
|
1913
|
+
"image/jpeg",
|
|
1914
|
+
"image/png",
|
|
1915
|
+
"image/gif",
|
|
1916
|
+
"image/webp",
|
|
1917
|
+
"video/mp4",
|
|
1918
|
+
"video/webm",
|
|
1919
|
+
"application/pdf",
|
|
1920
|
+
"text/plain"
|
|
1921
|
+
];
|
|
1922
|
+
|
|
1898
1923
|
// src/api/messaging/channels.ts
|
|
1924
|
+
import multer from "multer";
|
|
1925
|
+
import fs from "fs";
|
|
1926
|
+
import path from "path";
|
|
1899
1927
|
var DEFAULT_SERVER_ID3 = "00000000-0000-0000-0000-000000000000";
|
|
1928
|
+
var channelStorage = multer.memoryStorage();
|
|
1929
|
+
var channelUploadMiddleware = multer({
|
|
1930
|
+
storage: channelStorage,
|
|
1931
|
+
limits: {
|
|
1932
|
+
fileSize: MAX_FILE_SIZE,
|
|
1933
|
+
files: 1
|
|
1934
|
+
},
|
|
1935
|
+
fileFilter: (req, file, cb) => {
|
|
1936
|
+
if (ALLOWED_MEDIA_MIME_TYPES.includes(file.mimetype)) {
|
|
1937
|
+
cb(null, true);
|
|
1938
|
+
} else {
|
|
1939
|
+
cb(new Error("Invalid file type"), false);
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
});
|
|
1943
|
+
async function saveChannelUploadedFile(file, channelId) {
|
|
1944
|
+
const uploadDir = path.join(process.cwd(), ".eliza/data/uploads/channels", channelId);
|
|
1945
|
+
if (!fs.existsSync(uploadDir)) {
|
|
1946
|
+
fs.mkdirSync(uploadDir, { recursive: true });
|
|
1947
|
+
}
|
|
1948
|
+
const timestamp = Date.now();
|
|
1949
|
+
const random = Math.round(Math.random() * 1e9);
|
|
1950
|
+
const ext = path.extname(file.originalname);
|
|
1951
|
+
const filename = `${timestamp}-${random}${ext}`;
|
|
1952
|
+
const filePath = path.join(uploadDir, filename);
|
|
1953
|
+
fs.writeFileSync(filePath, file.buffer);
|
|
1954
|
+
const url = `/media/uploads/channels/${channelId}/${filename}`;
|
|
1955
|
+
return { filename, url };
|
|
1956
|
+
}
|
|
1900
1957
|
function createChannelsRouter(agents, serverInstance) {
|
|
1901
|
-
const router =
|
|
1958
|
+
const router = express11.Router();
|
|
1902
1959
|
router.post(
|
|
1903
1960
|
"/central-channels/:channelId/messages",
|
|
1904
1961
|
async (req, res) => {
|
|
@@ -1925,53 +1982,53 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
1925
1982
|
});
|
|
1926
1983
|
}
|
|
1927
1984
|
try {
|
|
1928
|
-
|
|
1985
|
+
logger12.info(
|
|
1929
1986
|
`[Messages Router] Checking if channel ${channelIdParam} exists before creating message`
|
|
1930
1987
|
);
|
|
1931
1988
|
let channelExists = false;
|
|
1932
1989
|
try {
|
|
1933
1990
|
const existingChannel = await serverInstance.getChannelDetails(channelIdParam);
|
|
1934
1991
|
channelExists = !!existingChannel;
|
|
1935
|
-
|
|
1992
|
+
logger12.info(`[Messages Router] Channel ${channelIdParam} exists: ${channelExists}`);
|
|
1936
1993
|
} catch (error) {
|
|
1937
1994
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1938
|
-
|
|
1995
|
+
logger12.info(
|
|
1939
1996
|
`[Messages Router] Channel ${channelIdParam} does not exist, will create it. Error: ${errorMessage}`
|
|
1940
1997
|
);
|
|
1941
1998
|
}
|
|
1942
1999
|
if (!channelExists) {
|
|
1943
|
-
|
|
2000
|
+
logger12.info(
|
|
1944
2001
|
`[Messages Router] Auto-creating channel ${channelIdParam} with serverId ${server_id}`
|
|
1945
2002
|
);
|
|
1946
2003
|
try {
|
|
1947
2004
|
const servers = await serverInstance.getServers();
|
|
1948
2005
|
const serverExists = servers.some((s) => s.id === server_id);
|
|
1949
|
-
|
|
2006
|
+
logger12.info(
|
|
1950
2007
|
`[Messages Router] Server ${server_id} exists: ${serverExists}. Available servers: ${servers.map((s) => s.id).join(", ")}`
|
|
1951
2008
|
);
|
|
1952
2009
|
if (!serverExists) {
|
|
1953
|
-
|
|
2010
|
+
logger12.error(
|
|
1954
2011
|
`[Messages Router] Server ${server_id} does not exist, cannot create channel`
|
|
1955
2012
|
);
|
|
1956
2013
|
return res.status(500).json({ success: false, error: `Server ${server_id} does not exist` });
|
|
1957
2014
|
}
|
|
1958
|
-
const isDmChannel = metadata?.isDm || metadata?.channelType ===
|
|
2015
|
+
const isDmChannel = metadata?.isDm || metadata?.channelType === ChannelType2.DM || metadata?.channel_type === ChannelType2.DM;
|
|
1959
2016
|
const channelData = {
|
|
1960
2017
|
id: channelIdParam,
|
|
1961
2018
|
// Use the specific channel ID from the URL
|
|
1962
2019
|
messageServerId: server_id,
|
|
1963
2020
|
name: isDmChannel ? `DM ${channelIdParam.substring(0, 8)}` : `Chat ${channelIdParam.substring(0, 8)}`,
|
|
1964
|
-
type: isDmChannel ?
|
|
2021
|
+
type: isDmChannel ? ChannelType2.DM : ChannelType2.GROUP,
|
|
1965
2022
|
sourceType: "auto_created",
|
|
1966
2023
|
metadata: {
|
|
1967
2024
|
created_by: "gui_auto_creation",
|
|
1968
2025
|
created_for_user: author_id,
|
|
1969
2026
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1970
|
-
channel_type: isDmChannel ?
|
|
2027
|
+
channel_type: isDmChannel ? ChannelType2.DM : ChannelType2.GROUP,
|
|
1971
2028
|
...metadata
|
|
1972
2029
|
}
|
|
1973
2030
|
};
|
|
1974
|
-
|
|
2031
|
+
logger12.info(
|
|
1975
2032
|
"[Messages Router] Creating channel with data:",
|
|
1976
2033
|
JSON.stringify(channelData, null, 2)
|
|
1977
2034
|
);
|
|
@@ -1980,29 +2037,29 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
1980
2037
|
const otherParticipant = metadata?.targetUserId || metadata?.recipientId;
|
|
1981
2038
|
if (otherParticipant && validateUuid12(otherParticipant)) {
|
|
1982
2039
|
participants.push(otherParticipant);
|
|
1983
|
-
|
|
2040
|
+
logger12.info(
|
|
1984
2041
|
`[Messages Router] DM channel will include participants: ${participants.join(", ")}`
|
|
1985
2042
|
);
|
|
1986
2043
|
} else {
|
|
1987
|
-
|
|
2044
|
+
logger12.warn(
|
|
1988
2045
|
`[Messages Router] DM channel missing second participant, only adding author: ${author_id}`
|
|
1989
2046
|
);
|
|
1990
2047
|
}
|
|
1991
2048
|
}
|
|
1992
2049
|
await serverInstance.createChannel(channelData, participants);
|
|
1993
|
-
|
|
1994
|
-
`[Messages Router] Auto-created ${isDmChannel ?
|
|
2050
|
+
logger12.info(
|
|
2051
|
+
`[Messages Router] Auto-created ${isDmChannel ? ChannelType2.DM : ChannelType2.GROUP} channel ${channelIdParam} for message submission with ${participants.length} participants`
|
|
1995
2052
|
);
|
|
1996
2053
|
} catch (createError) {
|
|
1997
2054
|
const errorMessage = createError instanceof Error ? createError.message : String(createError);
|
|
1998
|
-
|
|
2055
|
+
logger12.error(
|
|
1999
2056
|
`[Messages Router] Failed to auto-create channel ${channelIdParam}:`,
|
|
2000
2057
|
createError
|
|
2001
2058
|
);
|
|
2002
2059
|
return res.status(500).json({ success: false, error: `Failed to create channel: ${errorMessage}` });
|
|
2003
2060
|
}
|
|
2004
2061
|
} else {
|
|
2005
|
-
|
|
2062
|
+
logger12.info(
|
|
2006
2063
|
`[Messages Router] Channel ${channelIdParam} already exists, proceeding with message creation`
|
|
2007
2064
|
);
|
|
2008
2065
|
}
|
|
@@ -2036,7 +2093,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2036
2093
|
// Will be undefined here, which is fine
|
|
2037
2094
|
};
|
|
2038
2095
|
bus_default.emit("new_message", messageForBus);
|
|
2039
|
-
|
|
2096
|
+
logger12.info(
|
|
2040
2097
|
"[Messages Router /central-channels/:channelId/messages] GUI Message published to internal bus:",
|
|
2041
2098
|
messageForBus.id
|
|
2042
2099
|
);
|
|
@@ -2056,7 +2113,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2056
2113
|
}
|
|
2057
2114
|
res.status(201).json({ success: true, data: messageForBus });
|
|
2058
2115
|
} catch (error) {
|
|
2059
|
-
|
|
2116
|
+
logger12.error(
|
|
2060
2117
|
"[Messages Router /central-channels/:channelId/messages] Error processing GUI message:",
|
|
2061
2118
|
error
|
|
2062
2119
|
);
|
|
@@ -2094,7 +2151,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2094
2151
|
});
|
|
2095
2152
|
res.json({ success: true, data: { messages: messagesForGui } });
|
|
2096
2153
|
} catch (error) {
|
|
2097
|
-
|
|
2154
|
+
logger12.error(
|
|
2098
2155
|
`[Messages Router /central-channels/:channelId/messages] Error fetching messages for channel ${channelId}:`,
|
|
2099
2156
|
error
|
|
2100
2157
|
);
|
|
@@ -2113,7 +2170,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2113
2170
|
const channels = await serverInstance.getChannelsForServer(serverId);
|
|
2114
2171
|
res.json({ success: true, data: { channels } });
|
|
2115
2172
|
} catch (error) {
|
|
2116
|
-
|
|
2173
|
+
logger12.error(
|
|
2117
2174
|
`[Messages Router /central-servers/:serverId/channels] Error fetching channels for server ${serverId}:`,
|
|
2118
2175
|
error
|
|
2119
2176
|
);
|
|
@@ -2122,22 +2179,36 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2122
2179
|
}
|
|
2123
2180
|
);
|
|
2124
2181
|
router.post("/channels", async (req, res) => {
|
|
2125
|
-
const
|
|
2126
|
-
|
|
2182
|
+
const serverId = req.body.serverId;
|
|
2183
|
+
const { name, type, sourceType, sourceId, metadata } = req.body;
|
|
2184
|
+
const topic = req.body.topic ?? req.body.description;
|
|
2185
|
+
if (!serverId) {
|
|
2127
2186
|
return res.status(400).json({
|
|
2128
2187
|
success: false,
|
|
2129
|
-
error: "Missing required fields:
|
|
2188
|
+
error: "Missing required fields: serverId."
|
|
2130
2189
|
});
|
|
2131
2190
|
}
|
|
2132
|
-
if (!
|
|
2191
|
+
if (!name) {
|
|
2133
2192
|
return res.status(400).json({
|
|
2134
2193
|
success: false,
|
|
2135
|
-
error: "
|
|
2194
|
+
error: "Missing required fields: name."
|
|
2195
|
+
});
|
|
2196
|
+
}
|
|
2197
|
+
if (!type) {
|
|
2198
|
+
return res.status(400).json({
|
|
2199
|
+
success: false,
|
|
2200
|
+
error: "Missing required fields: type."
|
|
2201
|
+
});
|
|
2202
|
+
}
|
|
2203
|
+
if (!validateUuid12(serverId)) {
|
|
2204
|
+
return res.status(400).json({
|
|
2205
|
+
success: false,
|
|
2206
|
+
error: "Invalid serverId format"
|
|
2136
2207
|
});
|
|
2137
2208
|
}
|
|
2138
2209
|
try {
|
|
2139
2210
|
const channel = await serverInstance.createChannel({
|
|
2140
|
-
messageServerId,
|
|
2211
|
+
messageServerId: serverId,
|
|
2141
2212
|
name,
|
|
2142
2213
|
type,
|
|
2143
2214
|
sourceType,
|
|
@@ -2147,7 +2218,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2147
2218
|
});
|
|
2148
2219
|
res.status(201).json({ success: true, data: { channel } });
|
|
2149
2220
|
} catch (error) {
|
|
2150
|
-
|
|
2221
|
+
logger12.error("[Messages Router /channels] Error creating channel:", error);
|
|
2151
2222
|
res.status(500).json({ success: false, error: "Failed to create channel" });
|
|
2152
2223
|
}
|
|
2153
2224
|
});
|
|
@@ -2170,7 +2241,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2170
2241
|
if (existingServer) {
|
|
2171
2242
|
dmServerIdToUse = providedDmServerId;
|
|
2172
2243
|
} else {
|
|
2173
|
-
|
|
2244
|
+
logger12.warn(
|
|
2174
2245
|
`Provided dmServerId ${providedDmServerId} not found, using default DM server logic.`
|
|
2175
2246
|
);
|
|
2176
2247
|
dmServerIdToUse = DEFAULT_SERVER_ID3;
|
|
@@ -2188,7 +2259,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2188
2259
|
stack: error.stack,
|
|
2189
2260
|
originalError: error
|
|
2190
2261
|
} : { message: String(error) };
|
|
2191
|
-
|
|
2262
|
+
logger12.error("Error finding/creating DM channel:", errorDetails);
|
|
2192
2263
|
res.status(500).json({ success: false, error: "Failed to find or create DM channel" });
|
|
2193
2264
|
}
|
|
2194
2265
|
});
|
|
@@ -2196,7 +2267,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2196
2267
|
const {
|
|
2197
2268
|
name,
|
|
2198
2269
|
participantCentralUserIds,
|
|
2199
|
-
type =
|
|
2270
|
+
type = ChannelType2.GROUP,
|
|
2200
2271
|
server_id,
|
|
2201
2272
|
metadata
|
|
2202
2273
|
} = req.body;
|
|
@@ -2224,7 +2295,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2224
2295
|
res.status(201).json({ success: true, data: newChannel });
|
|
2225
2296
|
} catch (error) {
|
|
2226
2297
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2227
|
-
|
|
2298
|
+
logger12.error(
|
|
2228
2299
|
"[Messages Router /central-channels] Error creating group channel:",
|
|
2229
2300
|
errorMessage
|
|
2230
2301
|
);
|
|
@@ -2245,7 +2316,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2245
2316
|
}
|
|
2246
2317
|
res.json({ success: true, data: channelDetails });
|
|
2247
2318
|
} catch (error) {
|
|
2248
|
-
|
|
2319
|
+
logger12.error(`[Messages Router] Error fetching details for channel ${channelId}:`, error);
|
|
2249
2320
|
res.status(500).json({ success: false, error: "Failed to fetch channel details" });
|
|
2250
2321
|
}
|
|
2251
2322
|
}
|
|
@@ -2261,7 +2332,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2261
2332
|
const participants = await serverInstance.getChannelParticipants(channelId);
|
|
2262
2333
|
res.json({ success: true, data: participants });
|
|
2263
2334
|
} catch (error) {
|
|
2264
|
-
|
|
2335
|
+
logger12.error(
|
|
2265
2336
|
`[Messages Router] Error fetching participants for channel ${channelId}:`,
|
|
2266
2337
|
error
|
|
2267
2338
|
);
|
|
@@ -2289,7 +2360,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2289
2360
|
});
|
|
2290
2361
|
}
|
|
2291
2362
|
await serverInstance.addParticipantsToChannel(channelId, [agentId]);
|
|
2292
|
-
|
|
2363
|
+
logger12.info(`[Messages Router] Added agent ${agentId} to channel ${channelId}`);
|
|
2293
2364
|
res.status(201).json({
|
|
2294
2365
|
success: true,
|
|
2295
2366
|
data: {
|
|
@@ -2299,7 +2370,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2299
2370
|
}
|
|
2300
2371
|
});
|
|
2301
2372
|
} catch (error) {
|
|
2302
|
-
|
|
2373
|
+
logger12.error(
|
|
2303
2374
|
`[Messages Router] Error adding agent ${agentId} to channel ${channelId}:`,
|
|
2304
2375
|
error
|
|
2305
2376
|
);
|
|
@@ -2341,7 +2412,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2341
2412
|
await serverInstance.updateChannel(channelId, {
|
|
2342
2413
|
participantCentralUserIds: updatedParticipants
|
|
2343
2414
|
});
|
|
2344
|
-
|
|
2415
|
+
logger12.info(`[Messages Router] Removed agent ${agentId} from channel ${channelId}`);
|
|
2345
2416
|
res.status(200).json({
|
|
2346
2417
|
success: true,
|
|
2347
2418
|
data: {
|
|
@@ -2351,7 +2422,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2351
2422
|
}
|
|
2352
2423
|
});
|
|
2353
2424
|
} catch (error) {
|
|
2354
|
-
|
|
2425
|
+
logger12.error(
|
|
2355
2426
|
`[Messages Router] Error removing agent ${agentId} from channel ${channelId}:`,
|
|
2356
2427
|
error
|
|
2357
2428
|
);
|
|
@@ -2385,7 +2456,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2385
2456
|
}
|
|
2386
2457
|
});
|
|
2387
2458
|
} catch (error) {
|
|
2388
|
-
|
|
2459
|
+
logger12.error(`[Messages Router] Error fetching agents for channel ${channelId}:`, error);
|
|
2389
2460
|
res.status(500).json({
|
|
2390
2461
|
success: false,
|
|
2391
2462
|
error: "Failed to fetch channel agents"
|
|
@@ -2403,13 +2474,13 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2403
2474
|
}
|
|
2404
2475
|
try {
|
|
2405
2476
|
await serverInstance.deleteMessage(messageId);
|
|
2406
|
-
|
|
2477
|
+
logger12.info(`[Messages Router] Deleted message ${messageId} from central database`);
|
|
2407
2478
|
const deletedMessagePayload = {
|
|
2408
2479
|
messageId,
|
|
2409
2480
|
channelId
|
|
2410
2481
|
};
|
|
2411
2482
|
bus_default.emit("message_deleted", deletedMessagePayload);
|
|
2412
|
-
|
|
2483
|
+
logger12.info(
|
|
2413
2484
|
`[Messages Router] Emitted message_deleted event to internal bus for message ${messageId}`
|
|
2414
2485
|
);
|
|
2415
2486
|
if (serverInstance.socketIO) {
|
|
@@ -2420,7 +2491,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2420
2491
|
}
|
|
2421
2492
|
res.status(204).send();
|
|
2422
2493
|
} catch (error) {
|
|
2423
|
-
|
|
2494
|
+
logger12.error(
|
|
2424
2495
|
`[Messages Router] Error deleting message ${messageId} from channel ${channelId}:`,
|
|
2425
2496
|
error
|
|
2426
2497
|
);
|
|
@@ -2441,7 +2512,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2441
2512
|
channelId
|
|
2442
2513
|
};
|
|
2443
2514
|
bus_default.emit("channel_cleared", channelClearedPayload);
|
|
2444
|
-
|
|
2515
|
+
logger12.info(
|
|
2445
2516
|
`[Messages Router] Emitted channel_cleared event to internal bus for channel ${channelId}`
|
|
2446
2517
|
);
|
|
2447
2518
|
if (serverInstance.socketIO) {
|
|
@@ -2451,7 +2522,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2451
2522
|
}
|
|
2452
2523
|
res.status(204).send();
|
|
2453
2524
|
} catch (error) {
|
|
2454
|
-
|
|
2525
|
+
logger12.error(`[Messages Router] Error clearing messages for channel ${channelId}:`, error);
|
|
2455
2526
|
res.status(500).json({ success: false, error: "Failed to clear messages" });
|
|
2456
2527
|
}
|
|
2457
2528
|
}
|
|
@@ -2478,7 +2549,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2478
2549
|
}
|
|
2479
2550
|
res.json({ success: true, data: updatedChannel });
|
|
2480
2551
|
} catch (error) {
|
|
2481
|
-
|
|
2552
|
+
logger12.error(`[Messages Router] Error updating channel ${channelId}:`, error);
|
|
2482
2553
|
res.status(500).json({ success: false, error: "Failed to update channel" });
|
|
2483
2554
|
}
|
|
2484
2555
|
}
|
|
@@ -2494,14 +2565,14 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2494
2565
|
const messages = await serverInstance.getMessagesForChannel(channelId);
|
|
2495
2566
|
const messageCount = messages.length;
|
|
2496
2567
|
await serverInstance.deleteChannel(channelId);
|
|
2497
|
-
|
|
2568
|
+
logger12.info(
|
|
2498
2569
|
`[Messages Router] Deleted channel ${channelId} with ${messageCount} messages from central database`
|
|
2499
2570
|
);
|
|
2500
2571
|
const channelClearedPayload = {
|
|
2501
2572
|
channelId
|
|
2502
2573
|
};
|
|
2503
2574
|
bus_default.emit("channel_cleared", channelClearedPayload);
|
|
2504
|
-
|
|
2575
|
+
logger12.info(
|
|
2505
2576
|
`[Messages Router] Emitted channel_cleared event to internal bus for deleted channel ${channelId}`
|
|
2506
2577
|
);
|
|
2507
2578
|
if (serverInstance.socketIO) {
|
|
@@ -2511,7 +2582,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2511
2582
|
}
|
|
2512
2583
|
res.status(204).send();
|
|
2513
2584
|
} catch (error) {
|
|
2514
|
-
|
|
2585
|
+
logger12.error(`[Messages Router] Error deleting channel ${channelId}:`, error);
|
|
2515
2586
|
res.status(500).json({ success: false, error: "Failed to delete channel" });
|
|
2516
2587
|
}
|
|
2517
2588
|
}
|
|
@@ -2520,44 +2591,24 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2520
2591
|
"/channels/:channelId/upload-media",
|
|
2521
2592
|
createUploadRateLimit(),
|
|
2522
2593
|
createFileSystemRateLimit(),
|
|
2523
|
-
|
|
2594
|
+
channelUploadMiddleware.single("file"),
|
|
2524
2595
|
async (req, res) => {
|
|
2525
2596
|
const channelId = validateUuid12(req.params.channelId);
|
|
2526
2597
|
if (!channelId) {
|
|
2527
2598
|
res.status(400).json({ success: false, error: "Invalid channelId format" });
|
|
2528
2599
|
return;
|
|
2529
2600
|
}
|
|
2530
|
-
|
|
2531
|
-
if (req.files && !Array.isArray(req.files)) {
|
|
2532
|
-
mediaFile = req.files.file;
|
|
2533
|
-
} else if (Array.isArray(req.files) && req.files.length > 0) {
|
|
2534
|
-
mediaFile = req.files[0];
|
|
2535
|
-
} else {
|
|
2536
|
-
res.status(400).json({ success: false, error: "No media file provided" });
|
|
2537
|
-
return;
|
|
2538
|
-
}
|
|
2539
|
-
if (!mediaFile) {
|
|
2601
|
+
if (!req.file) {
|
|
2540
2602
|
res.status(400).json({ success: false, error: "No media file provided" });
|
|
2541
2603
|
return;
|
|
2542
2604
|
}
|
|
2543
2605
|
try {
|
|
2544
|
-
if (!
|
|
2545
|
-
cleanupUploadedFile(mediaFile);
|
|
2546
|
-
res.status(400).json({ success: false, error: `Invalid file type: ${mediaFile.mimetype}` });
|
|
2547
|
-
return;
|
|
2548
|
-
}
|
|
2549
|
-
if (!mediaFile.name || mediaFile.name.includes("..") || mediaFile.name.includes("/")) {
|
|
2550
|
-
cleanupUploadedFile(mediaFile);
|
|
2606
|
+
if (!req.file.originalname || req.file.originalname.includes("..") || req.file.originalname.includes("/")) {
|
|
2551
2607
|
res.status(400).json({ success: false, error: "Invalid filename detected" });
|
|
2552
2608
|
return;
|
|
2553
2609
|
}
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
res.status(400).json({ success: false, error: "File too large" });
|
|
2557
|
-
return;
|
|
2558
|
-
}
|
|
2559
|
-
const result = await processUploadedFile(mediaFile, channelId, "channels");
|
|
2560
|
-
logger13.info(
|
|
2610
|
+
const result = await saveChannelUploadedFile(req.file, channelId);
|
|
2611
|
+
logger12.info(
|
|
2561
2612
|
`[MessagesRouter /upload-media] Secure file uploaded for channel ${channelId}: ${result.filename}. URL: ${result.url}`
|
|
2562
2613
|
);
|
|
2563
2614
|
res.json({
|
|
@@ -2565,21 +2616,18 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2565
2616
|
data: {
|
|
2566
2617
|
url: result.url,
|
|
2567
2618
|
// Relative URL, client prepends server origin
|
|
2568
|
-
type:
|
|
2619
|
+
type: req.file.mimetype,
|
|
2569
2620
|
filename: result.filename,
|
|
2570
|
-
originalName:
|
|
2571
|
-
size:
|
|
2621
|
+
originalName: req.file.originalname,
|
|
2622
|
+
size: req.file.size
|
|
2572
2623
|
}
|
|
2573
2624
|
});
|
|
2574
2625
|
} catch (error) {
|
|
2575
2626
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2576
|
-
|
|
2627
|
+
logger12.error(
|
|
2577
2628
|
`[MessagesRouter /upload-media] Error processing upload for channel ${channelId}: ${errorMessage}`,
|
|
2578
2629
|
error
|
|
2579
2630
|
);
|
|
2580
|
-
if (mediaFile) {
|
|
2581
|
-
cleanupUploadedFile(mediaFile);
|
|
2582
|
-
}
|
|
2583
2631
|
res.status(500).json({ success: false, error: "Failed to process media upload" });
|
|
2584
2632
|
}
|
|
2585
2633
|
}
|
|
@@ -2609,7 +2657,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2609
2657
|
error: "Agent not found or not active"
|
|
2610
2658
|
});
|
|
2611
2659
|
}
|
|
2612
|
-
|
|
2660
|
+
logger12.info(`[CHANNEL SUMMARIZE] Summarizing channel ${channelId}`);
|
|
2613
2661
|
const limit = req.query.limit ? Number.parseInt(req.query.limit, 10) : 50;
|
|
2614
2662
|
const before = req.query.before ? Number.parseInt(req.query.before, 10) : void 0;
|
|
2615
2663
|
const beforeDate = before ? new Date(before) : void 0;
|
|
@@ -2663,22 +2711,22 @@ Respond with just the title, nothing else.
|
|
|
2663
2711
|
// Keep titles short
|
|
2664
2712
|
});
|
|
2665
2713
|
if (!newTitle || newTitle.trim().length === 0) {
|
|
2666
|
-
|
|
2714
|
+
logger12.warn(`[ChatTitleEvaluator] Failed to generate title for room ${channelId}`);
|
|
2667
2715
|
return;
|
|
2668
2716
|
}
|
|
2669
2717
|
const cleanTitle = newTitle.trim().replace(/^["']|["']$/g, "");
|
|
2670
|
-
|
|
2718
|
+
logger12.info(`[ChatTitleEvaluator] Generated title: "${cleanTitle}" for room ${channelId}`);
|
|
2671
2719
|
const result = {
|
|
2672
2720
|
title: cleanTitle,
|
|
2673
2721
|
channelId
|
|
2674
2722
|
};
|
|
2675
|
-
|
|
2723
|
+
logger12.success(`[CHANNEL SUMMARIZE] Successfully summarized channel ${channelId}`);
|
|
2676
2724
|
res.json({
|
|
2677
2725
|
success: true,
|
|
2678
2726
|
data: result
|
|
2679
2727
|
});
|
|
2680
2728
|
} catch (error) {
|
|
2681
|
-
|
|
2729
|
+
logger12.error("[CHANNEL SUMMARIZE] Error summarizing channel:", error);
|
|
2682
2730
|
res.status(500).json({
|
|
2683
2731
|
success: false,
|
|
2684
2732
|
error: "Failed to summarize channel",
|
|
@@ -2692,7 +2740,7 @@ Respond with just the title, nothing else.
|
|
|
2692
2740
|
|
|
2693
2741
|
// src/api/messaging/index.ts
|
|
2694
2742
|
function messagingRouter(agents, serverInstance) {
|
|
2695
|
-
const router =
|
|
2743
|
+
const router = express12.Router();
|
|
2696
2744
|
if (!serverInstance) {
|
|
2697
2745
|
throw new Error("ServerInstance is required for messaging router");
|
|
2698
2746
|
}
|
|
@@ -2703,61 +2751,77 @@ function messagingRouter(agents, serverInstance) {
|
|
|
2703
2751
|
}
|
|
2704
2752
|
|
|
2705
2753
|
// src/api/media/index.ts
|
|
2706
|
-
import
|
|
2754
|
+
import express15 from "express";
|
|
2707
2755
|
|
|
2708
2756
|
// src/api/media/agents.ts
|
|
2709
|
-
import { validateUuid as validateUuid13, logger as
|
|
2710
|
-
import
|
|
2757
|
+
import { validateUuid as validateUuid13, logger as logger13, getContentTypeFromMimeType } from "@elizaos/core";
|
|
2758
|
+
import express13 from "express";
|
|
2759
|
+
import multer2 from "multer";
|
|
2760
|
+
import fs2 from "fs";
|
|
2761
|
+
import path2 from "path";
|
|
2762
|
+
var storage = multer2.memoryStorage();
|
|
2763
|
+
var upload = multer2({
|
|
2764
|
+
storage,
|
|
2765
|
+
limits: {
|
|
2766
|
+
fileSize: MAX_FILE_SIZE,
|
|
2767
|
+
files: 1
|
|
2768
|
+
},
|
|
2769
|
+
fileFilter: (req, file, cb) => {
|
|
2770
|
+
if (ALLOWED_MEDIA_MIME_TYPES.includes(file.mimetype)) {
|
|
2771
|
+
cb(null, true);
|
|
2772
|
+
} else {
|
|
2773
|
+
cb(new Error("Invalid file type"), false);
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
});
|
|
2777
|
+
async function saveUploadedFile(file, agentId) {
|
|
2778
|
+
const uploadDir = path2.join(process.cwd(), ".eliza/data/uploads/agents", agentId);
|
|
2779
|
+
if (!fs2.existsSync(uploadDir)) {
|
|
2780
|
+
fs2.mkdirSync(uploadDir, { recursive: true });
|
|
2781
|
+
}
|
|
2782
|
+
const timestamp = Date.now();
|
|
2783
|
+
const random = Math.round(Math.random() * 1e9);
|
|
2784
|
+
const ext = path2.extname(file.originalname);
|
|
2785
|
+
const filename = `${timestamp}-${random}${ext}`;
|
|
2786
|
+
const filePath = path2.join(uploadDir, filename);
|
|
2787
|
+
fs2.writeFileSync(filePath, file.buffer);
|
|
2788
|
+
const url = `/media/uploads/agents/${agentId}/${filename}`;
|
|
2789
|
+
return { filename, url };
|
|
2790
|
+
}
|
|
2711
2791
|
function createAgentMediaRouter() {
|
|
2712
|
-
const router =
|
|
2713
|
-
router.post("/:agentId/upload-media",
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
const agentId = validateUuid13(agentMediaReq.params.agentId);
|
|
2792
|
+
const router = express13.Router();
|
|
2793
|
+
router.post("/:agentId/upload-media", upload.single("file"), async (req, res) => {
|
|
2794
|
+
logger13.debug("[MEDIA UPLOAD] Processing media upload with multer");
|
|
2795
|
+
const agentId = validateUuid13(req.params.agentId);
|
|
2717
2796
|
if (!agentId) {
|
|
2718
2797
|
return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
|
|
2719
2798
|
}
|
|
2720
|
-
|
|
2721
|
-
if (agentMediaReq.files && !Array.isArray(agentMediaReq.files)) {
|
|
2722
|
-
mediaFile = agentMediaReq.files.file;
|
|
2723
|
-
} else if (Array.isArray(agentMediaReq.files) && agentMediaReq.files.length > 0) {
|
|
2724
|
-
mediaFile = agentMediaReq.files[0];
|
|
2725
|
-
} else {
|
|
2726
|
-
return sendError(res, 400, "INVALID_REQUEST", "No media file provided");
|
|
2727
|
-
}
|
|
2728
|
-
if (!mediaFile) {
|
|
2799
|
+
if (!req.file) {
|
|
2729
2800
|
return sendError(res, 400, "INVALID_REQUEST", "No media file provided");
|
|
2730
2801
|
}
|
|
2731
|
-
const
|
|
2732
|
-
if (!validateMediaFile(mediaFile)) {
|
|
2733
|
-
cleanupUploadedFile(mediaFile);
|
|
2734
|
-
return sendError(res, 400, "INVALID_FILE_TYPE", "Unsupported media file type");
|
|
2735
|
-
}
|
|
2736
|
-
const mediaType = getContentTypeFromMimeType(mimetype);
|
|
2802
|
+
const mediaType = getContentTypeFromMimeType(req.file.mimetype);
|
|
2737
2803
|
if (!mediaType) {
|
|
2738
|
-
cleanupUploadedFile(mediaFile);
|
|
2739
2804
|
return sendError(
|
|
2740
2805
|
res,
|
|
2741
2806
|
400,
|
|
2742
2807
|
"UNSUPPORTED_MEDIA_TYPE",
|
|
2743
|
-
`Unsupported media MIME type: ${mimetype}`
|
|
2808
|
+
`Unsupported media MIME type: ${req.file.mimetype}`
|
|
2744
2809
|
);
|
|
2745
2810
|
}
|
|
2746
2811
|
try {
|
|
2747
|
-
const result = await
|
|
2748
|
-
|
|
2812
|
+
const result = await saveUploadedFile(req.file, agentId);
|
|
2813
|
+
logger13.info(
|
|
2749
2814
|
`[MEDIA UPLOAD] Successfully uploaded ${mediaType}: ${result.filename}. URL: ${result.url}`
|
|
2750
2815
|
);
|
|
2751
2816
|
sendSuccess(res, {
|
|
2752
2817
|
url: result.url,
|
|
2753
2818
|
type: mediaType,
|
|
2754
2819
|
filename: result.filename,
|
|
2755
|
-
originalName:
|
|
2756
|
-
size:
|
|
2820
|
+
originalName: req.file.originalname,
|
|
2821
|
+
size: req.file.size
|
|
2757
2822
|
});
|
|
2758
2823
|
} catch (error) {
|
|
2759
|
-
|
|
2760
|
-
cleanupUploadedFile(mediaFile);
|
|
2824
|
+
logger13.error(`[MEDIA UPLOAD] Error processing upload: ${error}`);
|
|
2761
2825
|
sendError(
|
|
2762
2826
|
res,
|
|
2763
2827
|
500,
|
|
@@ -2771,11 +2835,43 @@ function createAgentMediaRouter() {
|
|
|
2771
2835
|
}
|
|
2772
2836
|
|
|
2773
2837
|
// src/api/media/channels.ts
|
|
2774
|
-
import { validateUuid as validateUuid14, logger as
|
|
2775
|
-
import
|
|
2838
|
+
import { validateUuid as validateUuid14, logger as logger14 } from "@elizaos/core";
|
|
2839
|
+
import express14 from "express";
|
|
2776
2840
|
import rateLimit2 from "express-rate-limit";
|
|
2841
|
+
import multer3 from "multer";
|
|
2842
|
+
import fs3 from "fs";
|
|
2843
|
+
import path3 from "path";
|
|
2844
|
+
var storage2 = multer3.memoryStorage();
|
|
2845
|
+
var upload2 = multer3({
|
|
2846
|
+
storage: storage2,
|
|
2847
|
+
limits: {
|
|
2848
|
+
fileSize: MAX_FILE_SIZE,
|
|
2849
|
+
files: 1
|
|
2850
|
+
},
|
|
2851
|
+
fileFilter: (req, file, cb) => {
|
|
2852
|
+
if (ALLOWED_MEDIA_MIME_TYPES.includes(file.mimetype)) {
|
|
2853
|
+
cb(null, true);
|
|
2854
|
+
} else {
|
|
2855
|
+
cb(new Error("Invalid file type"), false);
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2858
|
+
});
|
|
2859
|
+
async function saveUploadedFile2(file, channelId) {
|
|
2860
|
+
const uploadDir = path3.join(process.cwd(), ".eliza/data/uploads/channels", channelId);
|
|
2861
|
+
if (!fs3.existsSync(uploadDir)) {
|
|
2862
|
+
fs3.mkdirSync(uploadDir, { recursive: true });
|
|
2863
|
+
}
|
|
2864
|
+
const timestamp = Date.now();
|
|
2865
|
+
const random = Math.round(Math.random() * 1e9);
|
|
2866
|
+
const ext = path3.extname(file.originalname);
|
|
2867
|
+
const filename = `${timestamp}-${random}${ext}`;
|
|
2868
|
+
const filePath = path3.join(uploadDir, filename);
|
|
2869
|
+
fs3.writeFileSync(filePath, file.buffer);
|
|
2870
|
+
const url = `/media/uploads/channels/${channelId}/${filename}`;
|
|
2871
|
+
return { filename, url };
|
|
2872
|
+
}
|
|
2777
2873
|
function createChannelMediaRouter() {
|
|
2778
|
-
const router =
|
|
2874
|
+
const router = express14.Router();
|
|
2779
2875
|
const uploadMediaRateLimiter = rateLimit2({
|
|
2780
2876
|
windowMs: 15 * 60 * 1e3,
|
|
2781
2877
|
// 15 minutes
|
|
@@ -2787,35 +2883,20 @@ function createChannelMediaRouter() {
|
|
|
2787
2883
|
"/:channelId/upload-media",
|
|
2788
2884
|
uploadMediaRateLimiter,
|
|
2789
2885
|
// Apply rate limiter
|
|
2790
|
-
|
|
2886
|
+
upload2.single("file"),
|
|
2791
2887
|
async (req, res) => {
|
|
2792
|
-
const
|
|
2793
|
-
const channelId = validateUuid14(channelMediaReq.params.channelId);
|
|
2888
|
+
const channelId = validateUuid14(req.params.channelId);
|
|
2794
2889
|
if (!channelId) {
|
|
2795
2890
|
res.status(400).json({ success: false, error: "Invalid channelId format" });
|
|
2796
2891
|
return;
|
|
2797
2892
|
}
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
mediaFile = channelMediaReq.files.file;
|
|
2801
|
-
} else if (Array.isArray(channelMediaReq.files) && channelMediaReq.files.length > 0) {
|
|
2802
|
-
mediaFile = channelMediaReq.files[0];
|
|
2803
|
-
} else {
|
|
2804
|
-
res.status(400).json({ success: false, error: "No media file provided" });
|
|
2805
|
-
return;
|
|
2806
|
-
}
|
|
2807
|
-
if (!mediaFile) {
|
|
2808
|
-
res.status(400).json({ success: false, error: "No media file provided" });
|
|
2809
|
-
return;
|
|
2810
|
-
}
|
|
2811
|
-
if (!validateMediaFile(mediaFile)) {
|
|
2812
|
-
cleanupUploadedFile(mediaFile);
|
|
2813
|
-
res.status(400).json({ success: false, error: `Invalid file type: ${mediaFile.mimetype}` });
|
|
2893
|
+
if (!req.file) {
|
|
2894
|
+
res.status(400).json({ success: false, error: "No media file provided" });
|
|
2814
2895
|
return;
|
|
2815
2896
|
}
|
|
2816
2897
|
try {
|
|
2817
|
-
const result = await
|
|
2818
|
-
|
|
2898
|
+
const result = await saveUploadedFile2(req.file, channelId);
|
|
2899
|
+
logger14.info(
|
|
2819
2900
|
`[Channel Media Upload] File uploaded for channel ${channelId}: ${result.filename}. URL: ${result.url}`
|
|
2820
2901
|
);
|
|
2821
2902
|
res.json({
|
|
@@ -2823,18 +2904,17 @@ function createChannelMediaRouter() {
|
|
|
2823
2904
|
data: {
|
|
2824
2905
|
url: result.url,
|
|
2825
2906
|
// Relative URL, client prepends server origin
|
|
2826
|
-
type:
|
|
2907
|
+
type: req.file.mimetype,
|
|
2827
2908
|
filename: result.filename,
|
|
2828
|
-
originalName:
|
|
2829
|
-
size:
|
|
2909
|
+
originalName: req.file.originalname,
|
|
2910
|
+
size: req.file.size
|
|
2830
2911
|
}
|
|
2831
2912
|
});
|
|
2832
2913
|
} catch (error) {
|
|
2833
|
-
|
|
2914
|
+
logger14.error(
|
|
2834
2915
|
`[Channel Media Upload] Error processing upload for channel ${channelId}: ${error.message}`,
|
|
2835
2916
|
error
|
|
2836
2917
|
);
|
|
2837
|
-
cleanupUploadedFile(mediaFile);
|
|
2838
2918
|
res.status(500).json({ success: false, error: "Failed to process media upload" });
|
|
2839
2919
|
}
|
|
2840
2920
|
}
|
|
@@ -2844,7 +2924,7 @@ function createChannelMediaRouter() {
|
|
|
2844
2924
|
|
|
2845
2925
|
// src/api/media/index.ts
|
|
2846
2926
|
function mediaRouter() {
|
|
2847
|
-
const router =
|
|
2927
|
+
const router = express15.Router();
|
|
2848
2928
|
router.use("/agents", createAgentMediaRouter());
|
|
2849
2929
|
router.use("/channels", createChannelMediaRouter());
|
|
2850
2930
|
return router;
|
|
@@ -2854,13 +2934,47 @@ function mediaRouter() {
|
|
|
2854
2934
|
import express17 from "express";
|
|
2855
2935
|
|
|
2856
2936
|
// src/api/memory/groups.ts
|
|
2857
|
-
import { validateUuid as
|
|
2858
|
-
import
|
|
2937
|
+
import { validateUuid as validateUuid16, logger as logger17, createUniqueUuid as createUniqueUuid4, ChannelType as ChannelType3 } from "@elizaos/core";
|
|
2938
|
+
import express16 from "express";
|
|
2939
|
+
|
|
2940
|
+
// src/api/shared/file-utils.ts
|
|
2941
|
+
import fs4 from "fs";
|
|
2942
|
+
import path4 from "path";
|
|
2943
|
+
import { logger as logger15 } from "@elizaos/core";
|
|
2944
|
+
var cleanupUploadedFile = (file) => {
|
|
2945
|
+
logger15.debug(`[FILE] Multer file ${file.originalname} in memory, no cleanup needed`);
|
|
2946
|
+
};
|
|
2947
|
+
|
|
2948
|
+
// src/upload.ts
|
|
2949
|
+
import fs5 from "fs";
|
|
2950
|
+
import path5 from "path";
|
|
2951
|
+
import multer4 from "multer";
|
|
2952
|
+
import { validateUuid as validateUuid15, logger as logger16 } from "@elizaos/core";
|
|
2953
|
+
var storage3 = multer4.memoryStorage();
|
|
2954
|
+
var agentAudioUpload = () => multer4({
|
|
2955
|
+
storage: storage3,
|
|
2956
|
+
limits: {
|
|
2957
|
+
fileSize: MAX_FILE_SIZE,
|
|
2958
|
+
files: 1
|
|
2959
|
+
},
|
|
2960
|
+
fileFilter: (req, file, cb) => {
|
|
2961
|
+
if (ALLOWED_AUDIO_MIME_TYPES.includes(file.mimetype)) {
|
|
2962
|
+
cb(null, true);
|
|
2963
|
+
} else {
|
|
2964
|
+
cb(new Error("Invalid audio file type"), false);
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
});
|
|
2968
|
+
function validateAudioFile(file) {
|
|
2969
|
+
return ALLOWED_AUDIO_MIME_TYPES.includes(file.mimetype);
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
// src/api/memory/groups.ts
|
|
2859
2973
|
function createGroupMemoryRouter(agents, serverInstance) {
|
|
2860
|
-
const router =
|
|
2974
|
+
const router = express16.Router();
|
|
2861
2975
|
const db = serverInstance?.database;
|
|
2862
2976
|
router.post("/groups/:serverId", async (req, res) => {
|
|
2863
|
-
const serverId =
|
|
2977
|
+
const serverId = validateUuid16(req.params.serverId);
|
|
2864
2978
|
const { name, worldId, source, metadata, agentIds = [] } = req.body;
|
|
2865
2979
|
if (!Array.isArray(agentIds) || agentIds.length === 0) {
|
|
2866
2980
|
return sendError(res, 400, "BAD_REQUEST", "agentIds must be a non-empty array");
|
|
@@ -2870,7 +2984,7 @@ function createGroupMemoryRouter(agents, serverInstance) {
|
|
|
2870
2984
|
for (const agentId of agentIds) {
|
|
2871
2985
|
try {
|
|
2872
2986
|
const runtime = getRuntime(agents, agentId);
|
|
2873
|
-
const roomId =
|
|
2987
|
+
const roomId = createUniqueUuid4(runtime, serverId);
|
|
2874
2988
|
const roomName = name || `Chat ${(/* @__PURE__ */ new Date()).toLocaleString()}`;
|
|
2875
2989
|
await runtime.ensureWorldExists({
|
|
2876
2990
|
id: worldId,
|
|
@@ -2882,7 +2996,7 @@ function createGroupMemoryRouter(agents, serverInstance) {
|
|
|
2882
2996
|
id: roomId,
|
|
2883
2997
|
name: roomName,
|
|
2884
2998
|
source,
|
|
2885
|
-
type:
|
|
2999
|
+
type: ChannelType3.API,
|
|
2886
3000
|
worldId,
|
|
2887
3001
|
serverId,
|
|
2888
3002
|
metadata,
|
|
@@ -2896,10 +3010,10 @@ function createGroupMemoryRouter(agents, serverInstance) {
|
|
|
2896
3010
|
name: roomName,
|
|
2897
3011
|
source: "client",
|
|
2898
3012
|
worldId,
|
|
2899
|
-
type:
|
|
3013
|
+
type: ChannelType3.API
|
|
2900
3014
|
});
|
|
2901
3015
|
} catch (error) {
|
|
2902
|
-
|
|
3016
|
+
logger17.error(`[ROOM CREATE] Error creating room for agent ${agentId}:`, error);
|
|
2903
3017
|
errors.push({
|
|
2904
3018
|
agentId,
|
|
2905
3019
|
code: error instanceof Error && error.message === "Agent not found" ? "NOT_FOUND" : "CREATE_ERROR",
|
|
@@ -2922,7 +3036,7 @@ function createGroupMemoryRouter(agents, serverInstance) {
|
|
|
2922
3036
|
});
|
|
2923
3037
|
});
|
|
2924
3038
|
router.delete("/groups/:serverId", async (req, res) => {
|
|
2925
|
-
const worldId =
|
|
3039
|
+
const worldId = validateUuid16(req.params.serverId);
|
|
2926
3040
|
if (!worldId) {
|
|
2927
3041
|
return sendError(res, 400, "INVALID_ID", "Invalid serverId (worldId) format");
|
|
2928
3042
|
}
|
|
@@ -2933,7 +3047,7 @@ function createGroupMemoryRouter(agents, serverInstance) {
|
|
|
2933
3047
|
await db.deleteRoomsByWorldId(worldId);
|
|
2934
3048
|
res.status(204).send();
|
|
2935
3049
|
} catch (error) {
|
|
2936
|
-
|
|
3050
|
+
logger17.error("[GROUP DELETE] Error deleting group:", error);
|
|
2937
3051
|
sendError(
|
|
2938
3052
|
res,
|
|
2939
3053
|
500,
|
|
@@ -2944,7 +3058,7 @@ function createGroupMemoryRouter(agents, serverInstance) {
|
|
|
2944
3058
|
}
|
|
2945
3059
|
});
|
|
2946
3060
|
router.delete("/groups/:serverId/memories", async (req, res) => {
|
|
2947
|
-
const worldId =
|
|
3061
|
+
const worldId = validateUuid16(req.params.serverId);
|
|
2948
3062
|
if (!worldId) {
|
|
2949
3063
|
return sendError(res, 400, "INVALID_ID", "Invalid serverId (worldId) format");
|
|
2950
3064
|
}
|
|
@@ -2959,7 +3073,7 @@ function createGroupMemoryRouter(agents, serverInstance) {
|
|
|
2959
3073
|
}
|
|
2960
3074
|
res.status(204).send();
|
|
2961
3075
|
} catch (error) {
|
|
2962
|
-
|
|
3076
|
+
logger17.error("[GROUP MEMORIES DELETE] Error clearing memories:", error);
|
|
2963
3077
|
sendError(
|
|
2964
3078
|
res,
|
|
2965
3079
|
500,
|
|
@@ -2972,144 +3086,121 @@ function createGroupMemoryRouter(agents, serverInstance) {
|
|
|
2972
3086
|
return router;
|
|
2973
3087
|
}
|
|
2974
3088
|
|
|
2975
|
-
// src/api/memory/
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
router.
|
|
2981
|
-
|
|
3089
|
+
// src/api/memory/index.ts
|
|
3090
|
+
function memoryRouter(agents, serverInstance) {
|
|
3091
|
+
const router = express17.Router();
|
|
3092
|
+
router.use("/", createAgentMemoryRouter(agents));
|
|
3093
|
+
router.use("/", createGroupMemoryRouter(agents, serverInstance));
|
|
3094
|
+
router.use("/", createRoomManagementRouter(agents));
|
|
3095
|
+
return router;
|
|
3096
|
+
}
|
|
3097
|
+
|
|
3098
|
+
// src/api/audio/index.ts
|
|
3099
|
+
import express21 from "express";
|
|
3100
|
+
|
|
3101
|
+
// src/api/audio/processing.ts
|
|
3102
|
+
import { logger as logger18, ModelType as ModelType2, validateUuid as validateUuid17 } from "@elizaos/core";
|
|
3103
|
+
import express18 from "express";
|
|
3104
|
+
import fs6 from "fs";
|
|
3105
|
+
import os from "os";
|
|
3106
|
+
import path6 from "path";
|
|
3107
|
+
function createAudioProcessingRouter(agents) {
|
|
3108
|
+
const router = express18.Router();
|
|
3109
|
+
router.use(createUploadRateLimit());
|
|
3110
|
+
router.use(createFileSystemRateLimit());
|
|
3111
|
+
router.post("/:agentId/audio-messages", agentAudioUpload().single("file"), async (req, res) => {
|
|
3112
|
+
const audioReq = req;
|
|
3113
|
+
logger18.debug("[AUDIO MESSAGE] Processing audio message");
|
|
3114
|
+
const agentId = validateUuid17(req.params.agentId);
|
|
2982
3115
|
if (!agentId) {
|
|
2983
3116
|
return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
|
|
2984
3117
|
}
|
|
3118
|
+
const audioFile = audioReq.file;
|
|
3119
|
+
if (!audioFile) {
|
|
3120
|
+
return sendError(res, 400, "INVALID_REQUEST", "No audio file provided");
|
|
3121
|
+
}
|
|
2985
3122
|
const runtime = agents.get(agentId);
|
|
2986
3123
|
if (!runtime) {
|
|
3124
|
+
cleanupUploadedFile(audioFile);
|
|
2987
3125
|
return sendError(res, 404, "NOT_FOUND", "Agent not found");
|
|
2988
3126
|
}
|
|
2989
3127
|
try {
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
return sendError(res, 400, "
|
|
3128
|
+
if (!validateAudioFile(audioFile)) {
|
|
3129
|
+
cleanupUploadedFile(audioFile);
|
|
3130
|
+
return sendError(res, 400, "INVALID_FILE_TYPE", "Invalid audio file type");
|
|
2993
3131
|
}
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
name: worldName,
|
|
3003
|
-
agentId: runtime.agentId,
|
|
3004
|
-
serverId,
|
|
3005
|
-
metadata
|
|
3006
|
-
});
|
|
3132
|
+
if (audioFile.size > MAX_FILE_SIZE) {
|
|
3133
|
+
cleanupUploadedFile(audioFile);
|
|
3134
|
+
return sendError(
|
|
3135
|
+
res,
|
|
3136
|
+
413,
|
|
3137
|
+
"FILE_TOO_LARGE",
|
|
3138
|
+
`Audio file too large (max ${MAX_FILE_SIZE_DISPLAY})`
|
|
3139
|
+
);
|
|
3007
3140
|
}
|
|
3008
|
-
await runtime.
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
type,
|
|
3013
|
-
channelId: roomId,
|
|
3014
|
-
serverId,
|
|
3015
|
-
worldId: resolvedWorldId,
|
|
3016
|
-
metadata
|
|
3017
|
-
});
|
|
3018
|
-
await runtime.addParticipant(runtime.agentId, roomId);
|
|
3019
|
-
await runtime.ensureParticipantInRoom(runtime.agentId, roomId);
|
|
3020
|
-
await runtime.setParticipantUserState(roomId, runtime.agentId, "FOLLOWED");
|
|
3021
|
-
sendSuccess(
|
|
3022
|
-
res,
|
|
3023
|
-
{
|
|
3024
|
-
id: roomId,
|
|
3025
|
-
name,
|
|
3026
|
-
agentId,
|
|
3027
|
-
createdAt: Date.now(),
|
|
3028
|
-
source,
|
|
3029
|
-
type,
|
|
3030
|
-
worldId: resolvedWorldId,
|
|
3031
|
-
serverId,
|
|
3032
|
-
metadata
|
|
3033
|
-
},
|
|
3034
|
-
201
|
|
3035
|
-
);
|
|
3141
|
+
const transcription = await runtime.useModel(ModelType2.TRANSCRIPTION, audioFile.buffer);
|
|
3142
|
+
logger18.info(`[AUDIO MESSAGE] Transcription for agent ${agentId}: ${transcription}`);
|
|
3143
|
+
cleanupUploadedFile(audioFile);
|
|
3144
|
+
sendSuccess(res, { transcription, message: "Audio transcribed, further processing TBD." });
|
|
3036
3145
|
} catch (error) {
|
|
3037
|
-
|
|
3146
|
+
logger18.error("[AUDIO MESSAGE] Error processing audio:", error);
|
|
3147
|
+
cleanupUploadedFile(audioFile);
|
|
3038
3148
|
sendError(
|
|
3039
3149
|
res,
|
|
3040
3150
|
500,
|
|
3041
|
-
"
|
|
3042
|
-
"
|
|
3151
|
+
"PROCESSING_ERROR",
|
|
3152
|
+
"Error processing audio message",
|
|
3043
3153
|
error instanceof Error ? error.message : String(error)
|
|
3044
3154
|
);
|
|
3045
3155
|
}
|
|
3046
3156
|
});
|
|
3047
|
-
router.
|
|
3048
|
-
const
|
|
3157
|
+
router.post("/:agentId/transcriptions", agentAudioUpload().single("file"), async (req, res) => {
|
|
3158
|
+
const audioReq = req;
|
|
3159
|
+
logger18.debug("[TRANSCRIPTION] Request to transcribe audio");
|
|
3160
|
+
const agentId = validateUuid17(req.params.agentId);
|
|
3049
3161
|
if (!agentId) {
|
|
3050
3162
|
return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
|
|
3051
3163
|
}
|
|
3052
|
-
const
|
|
3053
|
-
if (!
|
|
3054
|
-
return sendError(res,
|
|
3055
|
-
}
|
|
3056
|
-
try {
|
|
3057
|
-
const worlds = await runtime.getAllWorlds();
|
|
3058
|
-
const participantRoomIds = await runtime.getRoomsForParticipant(agentId);
|
|
3059
|
-
const agentRooms = [];
|
|
3060
|
-
for (const world of worlds) {
|
|
3061
|
-
const worldRooms = await runtime.getRooms(world.id);
|
|
3062
|
-
for (const room of worldRooms) {
|
|
3063
|
-
if (participantRoomIds.includes(room.id)) {
|
|
3064
|
-
agentRooms.push({
|
|
3065
|
-
...room
|
|
3066
|
-
});
|
|
3067
|
-
}
|
|
3068
|
-
}
|
|
3069
|
-
}
|
|
3070
|
-
sendSuccess(res, { rooms: agentRooms });
|
|
3071
|
-
} catch (error) {
|
|
3072
|
-
logger17.error(`[ROOMS LIST] Error retrieving rooms for agent ${agentId}:`, error);
|
|
3073
|
-
sendError(
|
|
3074
|
-
res,
|
|
3075
|
-
500,
|
|
3076
|
-
"RETRIEVAL_ERROR",
|
|
3077
|
-
"Failed to retrieve agent rooms",
|
|
3078
|
-
error instanceof Error ? error.message : String(error)
|
|
3079
|
-
);
|
|
3080
|
-
}
|
|
3081
|
-
});
|
|
3082
|
-
router.get("/:agentId/rooms/:roomId", async (req, res) => {
|
|
3083
|
-
const agentId = validateUuid16(req.params.agentId);
|
|
3084
|
-
const roomId = validateUuid16(req.params.roomId);
|
|
3085
|
-
if (!agentId || !roomId) {
|
|
3086
|
-
return sendError(res, 400, "INVALID_ID", "Invalid agent ID or room ID format");
|
|
3164
|
+
const audioFile = audioReq.file;
|
|
3165
|
+
if (!audioFile) {
|
|
3166
|
+
return sendError(res, 400, "INVALID_REQUEST", "No audio file provided");
|
|
3087
3167
|
}
|
|
3088
3168
|
const runtime = agents.get(agentId);
|
|
3089
3169
|
if (!runtime) {
|
|
3170
|
+
cleanupUploadedFile(audioFile);
|
|
3090
3171
|
return sendError(res, 404, "NOT_FOUND", "Agent not found");
|
|
3091
3172
|
}
|
|
3092
3173
|
try {
|
|
3093
|
-
|
|
3094
|
-
if (!
|
|
3095
|
-
|
|
3174
|
+
logger18.debug("[TRANSCRIPTION] Reading audio file");
|
|
3175
|
+
if (!validateAudioFile(audioFile)) {
|
|
3176
|
+
cleanupUploadedFile(audioFile);
|
|
3177
|
+
return sendError(res, 400, "INVALID_FILE_TYPE", "Invalid audio file type");
|
|
3096
3178
|
}
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3179
|
+
if (audioFile.size > MAX_FILE_SIZE) {
|
|
3180
|
+
cleanupUploadedFile(audioFile);
|
|
3181
|
+
return sendError(
|
|
3182
|
+
res,
|
|
3183
|
+
413,
|
|
3184
|
+
"FILE_TOO_LARGE",
|
|
3185
|
+
`Audio file too large (max ${MAX_FILE_SIZE_DISPLAY})`
|
|
3186
|
+
);
|
|
3101
3187
|
}
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3188
|
+
logger18.debug("[TRANSCRIPTION] Transcribing audio");
|
|
3189
|
+
const transcription = await runtime.useModel(ModelType2.TRANSCRIPTION, audioFile.buffer);
|
|
3190
|
+
cleanupUploadedFile(audioFile);
|
|
3191
|
+
if (!transcription) {
|
|
3192
|
+
return sendError(res, 500, "PROCESSING_ERROR", "Failed to transcribe audio");
|
|
3193
|
+
}
|
|
3194
|
+
logger18.success("[TRANSCRIPTION] Successfully transcribed audio");
|
|
3195
|
+
sendSuccess(res, { text: transcription });
|
|
3106
3196
|
} catch (error) {
|
|
3107
|
-
|
|
3197
|
+
logger18.error("[TRANSCRIPTION] Error transcribing audio:", error);
|
|
3198
|
+
cleanupUploadedFile(audioFile);
|
|
3108
3199
|
sendError(
|
|
3109
3200
|
res,
|
|
3110
3201
|
500,
|
|
3111
|
-
"
|
|
3112
|
-
"
|
|
3202
|
+
"PROCESSING_ERROR",
|
|
3203
|
+
"Error transcribing audio",
|
|
3113
3204
|
error instanceof Error ? error.message : String(error)
|
|
3114
3205
|
);
|
|
3115
3206
|
}
|
|
@@ -3117,202 +3208,6 @@ function createRoomManagementRouter(agents) {
|
|
|
3117
3208
|
return router;
|
|
3118
3209
|
}
|
|
3119
3210
|
|
|
3120
|
-
// src/api/memory/index.ts
|
|
3121
|
-
function memoryRouter(agents, serverInstance) {
|
|
3122
|
-
const router = express17.Router();
|
|
3123
|
-
router.use("/", createAgentMemoryRouter(agents));
|
|
3124
|
-
router.use("/", createGroupMemoryRouter(agents, serverInstance));
|
|
3125
|
-
router.use("/", createRoomManagementRouter(agents));
|
|
3126
|
-
return router;
|
|
3127
|
-
}
|
|
3128
|
-
|
|
3129
|
-
// src/api/audio/index.ts
|
|
3130
|
-
import express21 from "express";
|
|
3131
|
-
|
|
3132
|
-
// src/api/audio/processing.ts
|
|
3133
|
-
import { logger as logger18, ModelType as ModelType2, validateUuid as validateUuid17 } from "@elizaos/core";
|
|
3134
|
-
import express18 from "express";
|
|
3135
|
-
import fs3 from "fs";
|
|
3136
|
-
import os from "os";
|
|
3137
|
-
import path3 from "path";
|
|
3138
|
-
function validateSecureFilePath(filePath) {
|
|
3139
|
-
if (!filePath) {
|
|
3140
|
-
throw new Error("File path is required");
|
|
3141
|
-
}
|
|
3142
|
-
const resolvedPath = path3.resolve(filePath);
|
|
3143
|
-
const normalizedPath = path3.normalize(resolvedPath);
|
|
3144
|
-
if (normalizedPath.includes("..") || normalizedPath !== resolvedPath) {
|
|
3145
|
-
throw new Error("Invalid file path: path traversal detected");
|
|
3146
|
-
}
|
|
3147
|
-
const allowedBasePaths = [process.cwd(), os.tmpdir(), os.homedir()];
|
|
3148
|
-
const isPathAllowed = allowedBasePaths.some(
|
|
3149
|
-
(basePath) => normalizedPath.startsWith(path3.resolve(basePath))
|
|
3150
|
-
);
|
|
3151
|
-
if (!isPathAllowed) {
|
|
3152
|
-
throw new Error("Invalid file path: path outside allowed directories");
|
|
3153
|
-
}
|
|
3154
|
-
try {
|
|
3155
|
-
const stats = fs3.statSync(normalizedPath);
|
|
3156
|
-
if (!stats.isFile()) {
|
|
3157
|
-
throw new Error("Path does not point to a regular file");
|
|
3158
|
-
}
|
|
3159
|
-
} catch (error) {
|
|
3160
|
-
throw new Error(`File access error: ${error instanceof Error ? error.message : String(error)}`);
|
|
3161
|
-
}
|
|
3162
|
-
return normalizedPath;
|
|
3163
|
-
}
|
|
3164
|
-
function getUploadedFile(req) {
|
|
3165
|
-
if (req.files && !Array.isArray(req.files)) {
|
|
3166
|
-
return req.files.file;
|
|
3167
|
-
} else if (Array.isArray(req.files) && req.files.length > 0) {
|
|
3168
|
-
return req.files[0];
|
|
3169
|
-
}
|
|
3170
|
-
return null;
|
|
3171
|
-
}
|
|
3172
|
-
function createAudioProcessingRouter(agents) {
|
|
3173
|
-
const router = express18.Router();
|
|
3174
|
-
router.use(createUploadRateLimit());
|
|
3175
|
-
router.use(createFileSystemRateLimit());
|
|
3176
|
-
router.post(
|
|
3177
|
-
"/:agentId/audio-messages",
|
|
3178
|
-
agentAudioUpload(),
|
|
3179
|
-
// Use agentAudioUpload
|
|
3180
|
-
async (req, res) => {
|
|
3181
|
-
const audioReq = req;
|
|
3182
|
-
logger18.debug("[AUDIO MESSAGE] Processing audio message");
|
|
3183
|
-
const agentId = validateUuid17(req.params.agentId);
|
|
3184
|
-
if (!agentId) {
|
|
3185
|
-
return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
|
|
3186
|
-
}
|
|
3187
|
-
const audioFile = getUploadedFile(audioReq);
|
|
3188
|
-
if (!audioFile) {
|
|
3189
|
-
return sendError(res, 400, "INVALID_REQUEST", "No audio file provided");
|
|
3190
|
-
}
|
|
3191
|
-
const runtime = agents.get(agentId);
|
|
3192
|
-
if (!runtime) {
|
|
3193
|
-
cleanupUploadedFile(audioFile);
|
|
3194
|
-
return sendError(res, 404, "NOT_FOUND", "Agent not found");
|
|
3195
|
-
}
|
|
3196
|
-
try {
|
|
3197
|
-
if (!validateAudioFile(audioFile)) {
|
|
3198
|
-
cleanupUploadedFile(audioFile);
|
|
3199
|
-
return sendError(res, 400, "INVALID_FILE_TYPE", "Invalid audio file type");
|
|
3200
|
-
}
|
|
3201
|
-
let securePath;
|
|
3202
|
-
try {
|
|
3203
|
-
const filePath = audioFile.tempFilePath || "";
|
|
3204
|
-
securePath = validateSecureFilePath(filePath);
|
|
3205
|
-
} catch (pathError) {
|
|
3206
|
-
cleanupUploadedFile(audioFile);
|
|
3207
|
-
return sendError(
|
|
3208
|
-
res,
|
|
3209
|
-
403,
|
|
3210
|
-
"INVALID_PATH",
|
|
3211
|
-
`Invalid file path: ${pathError instanceof Error ? pathError.message : String(pathError)}`
|
|
3212
|
-
);
|
|
3213
|
-
}
|
|
3214
|
-
const stats = await fs3.promises.stat(securePath);
|
|
3215
|
-
if (stats.size > MAX_FILE_SIZE) {
|
|
3216
|
-
cleanupUploadedFile(audioFile);
|
|
3217
|
-
return sendError(
|
|
3218
|
-
res,
|
|
3219
|
-
413,
|
|
3220
|
-
"FILE_TOO_LARGE",
|
|
3221
|
-
`Audio file too large (max ${MAX_FILE_SIZE_DISPLAY})`
|
|
3222
|
-
);
|
|
3223
|
-
}
|
|
3224
|
-
const audioBuffer = await fs3.promises.readFile(securePath);
|
|
3225
|
-
const transcription = await runtime.useModel(ModelType2.TRANSCRIPTION, audioBuffer);
|
|
3226
|
-
logger18.info(`[AUDIO MESSAGE] Transcription for agent ${agentId}: ${transcription}`);
|
|
3227
|
-
cleanupUploadedFile(audioFile);
|
|
3228
|
-
sendSuccess(res, { transcription, message: "Audio transcribed, further processing TBD." });
|
|
3229
|
-
} catch (error) {
|
|
3230
|
-
logger18.error("[AUDIO MESSAGE] Error processing audio:", error);
|
|
3231
|
-
cleanupUploadedFile(audioFile);
|
|
3232
|
-
sendError(
|
|
3233
|
-
res,
|
|
3234
|
-
500,
|
|
3235
|
-
"PROCESSING_ERROR",
|
|
3236
|
-
"Error processing audio message",
|
|
3237
|
-
error instanceof Error ? error.message : String(error)
|
|
3238
|
-
);
|
|
3239
|
-
}
|
|
3240
|
-
}
|
|
3241
|
-
);
|
|
3242
|
-
router.post(
|
|
3243
|
-
"/:agentId/transcriptions",
|
|
3244
|
-
agentAudioUpload(),
|
|
3245
|
-
// Use agentAudioUpload
|
|
3246
|
-
async (req, res) => {
|
|
3247
|
-
const audioReq = req;
|
|
3248
|
-
logger18.debug("[TRANSCRIPTION] Request to transcribe audio");
|
|
3249
|
-
const agentId = validateUuid17(req.params.agentId);
|
|
3250
|
-
if (!agentId) {
|
|
3251
|
-
return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
|
|
3252
|
-
}
|
|
3253
|
-
const audioFile = getUploadedFile(audioReq);
|
|
3254
|
-
if (!audioFile) {
|
|
3255
|
-
return sendError(res, 400, "INVALID_REQUEST", "No audio file provided");
|
|
3256
|
-
}
|
|
3257
|
-
const runtime = agents.get(agentId);
|
|
3258
|
-
if (!runtime) {
|
|
3259
|
-
cleanupUploadedFile(audioFile);
|
|
3260
|
-
return sendError(res, 404, "NOT_FOUND", "Agent not found");
|
|
3261
|
-
}
|
|
3262
|
-
try {
|
|
3263
|
-
logger18.debug("[TRANSCRIPTION] Reading audio file");
|
|
3264
|
-
if (!validateAudioFile(audioFile)) {
|
|
3265
|
-
cleanupUploadedFile(audioFile);
|
|
3266
|
-
return sendError(res, 400, "INVALID_FILE_TYPE", "Invalid audio file type");
|
|
3267
|
-
}
|
|
3268
|
-
let securePath;
|
|
3269
|
-
try {
|
|
3270
|
-
const filePath = audioFile.tempFilePath || "";
|
|
3271
|
-
securePath = validateSecureFilePath(filePath);
|
|
3272
|
-
} catch (pathError) {
|
|
3273
|
-
cleanupUploadedFile(audioFile);
|
|
3274
|
-
return sendError(
|
|
3275
|
-
res,
|
|
3276
|
-
403,
|
|
3277
|
-
"INVALID_PATH",
|
|
3278
|
-
`Invalid file path: ${pathError instanceof Error ? pathError.message : String(pathError)}`
|
|
3279
|
-
);
|
|
3280
|
-
}
|
|
3281
|
-
const stats = await fs3.promises.stat(securePath);
|
|
3282
|
-
if (stats.size > MAX_FILE_SIZE) {
|
|
3283
|
-
cleanupUploadedFile(audioFile);
|
|
3284
|
-
return sendError(
|
|
3285
|
-
res,
|
|
3286
|
-
413,
|
|
3287
|
-
"FILE_TOO_LARGE",
|
|
3288
|
-
`Audio file too large (max ${MAX_FILE_SIZE_DISPLAY})`
|
|
3289
|
-
);
|
|
3290
|
-
}
|
|
3291
|
-
const audioBuffer = await fs3.promises.readFile(securePath);
|
|
3292
|
-
logger18.debug("[TRANSCRIPTION] Transcribing audio");
|
|
3293
|
-
const transcription = await runtime.useModel(ModelType2.TRANSCRIPTION, audioBuffer);
|
|
3294
|
-
cleanupUploadedFile(audioFile);
|
|
3295
|
-
if (!transcription) {
|
|
3296
|
-
return sendError(res, 500, "PROCESSING_ERROR", "Failed to transcribe audio");
|
|
3297
|
-
}
|
|
3298
|
-
logger18.success("[TRANSCRIPTION] Successfully transcribed audio");
|
|
3299
|
-
sendSuccess(res, { text: transcription });
|
|
3300
|
-
} catch (error) {
|
|
3301
|
-
logger18.error("[TRANSCRIPTION] Error transcribing audio:", error);
|
|
3302
|
-
cleanupUploadedFile(audioFile);
|
|
3303
|
-
sendError(
|
|
3304
|
-
res,
|
|
3305
|
-
500,
|
|
3306
|
-
"PROCESSING_ERROR",
|
|
3307
|
-
"Error transcribing audio",
|
|
3308
|
-
error instanceof Error ? error.message : String(error)
|
|
3309
|
-
);
|
|
3310
|
-
}
|
|
3311
|
-
}
|
|
3312
|
-
);
|
|
3313
|
-
return router;
|
|
3314
|
-
}
|
|
3315
|
-
|
|
3316
3211
|
// src/api/audio/synthesis.ts
|
|
3317
3212
|
import { validateUuid as validateUuid18, logger as logger19, ModelType as ModelType3 } from "@elizaos/core";
|
|
3318
3213
|
import express19 from "express";
|
|
@@ -3806,15 +3701,15 @@ import express28 from "express";
|
|
|
3806
3701
|
import { logger as logger23 } from "@elizaos/core";
|
|
3807
3702
|
import express27 from "express";
|
|
3808
3703
|
import { existsSync, writeFileSync } from "fs";
|
|
3809
|
-
import
|
|
3704
|
+
import path7 from "path";
|
|
3810
3705
|
import dotenv from "dotenv";
|
|
3811
|
-
import
|
|
3706
|
+
import fs7 from "fs/promises";
|
|
3812
3707
|
async function parseEnvFile(filePath) {
|
|
3813
3708
|
try {
|
|
3814
3709
|
if (!existsSync(filePath)) {
|
|
3815
3710
|
return {};
|
|
3816
3711
|
}
|
|
3817
|
-
const content = await
|
|
3712
|
+
const content = await fs7.readFile(filePath, "utf-8");
|
|
3818
3713
|
if (content.trim() === "") {
|
|
3819
3714
|
return {};
|
|
3820
3715
|
}
|
|
@@ -3834,17 +3729,17 @@ function getLocalEnvPath() {
|
|
|
3834
3729
|
function resolveEnvFile(startDir = process.cwd()) {
|
|
3835
3730
|
let currentDir = startDir;
|
|
3836
3731
|
while (true) {
|
|
3837
|
-
const candidate =
|
|
3732
|
+
const candidate = path7.join(currentDir, ".env");
|
|
3838
3733
|
if (existsSync(candidate)) {
|
|
3839
3734
|
return candidate;
|
|
3840
3735
|
}
|
|
3841
|
-
const parentDir =
|
|
3736
|
+
const parentDir = path7.dirname(currentDir);
|
|
3842
3737
|
if (parentDir === currentDir) {
|
|
3843
3738
|
break;
|
|
3844
3739
|
}
|
|
3845
3740
|
currentDir = parentDir;
|
|
3846
3741
|
}
|
|
3847
|
-
return
|
|
3742
|
+
return path7.join(startDir, ".env");
|
|
3848
3743
|
}
|
|
3849
3744
|
function createEnvironmentRouter() {
|
|
3850
3745
|
const router = express27.Router();
|
|
@@ -4595,6 +4490,7 @@ function createApiRouter(agents, serverInstance) {
|
|
|
4595
4490
|
);
|
|
4596
4491
|
router.use(createApiRateLimit());
|
|
4597
4492
|
router.use(securityMiddleware());
|
|
4493
|
+
router.use("/media", mediaRouter());
|
|
4598
4494
|
router.use(validateContentTypeMiddleware());
|
|
4599
4495
|
router.use(
|
|
4600
4496
|
bodyParser.json({
|
|
@@ -4614,7 +4510,6 @@ function createApiRouter(agents, serverInstance) {
|
|
|
4614
4510
|
);
|
|
4615
4511
|
router.use("/agents", agentsRouter(agents, serverInstance));
|
|
4616
4512
|
router.use("/messaging", messagingRouter(agents, serverInstance));
|
|
4617
|
-
router.use("/media", mediaRouter());
|
|
4618
4513
|
router.use("/memory", memoryRouter(agents, serverInstance));
|
|
4619
4514
|
router.use("/audio", audioRouter(agents));
|
|
4620
4515
|
router.use("/server", runtimeRouter(agents, serverInstance));
|
|
@@ -5018,7 +4913,14 @@ var MessageBusService = class _MessageBusService extends Service {
|
|
|
5018
4913
|
await this.runtime.emitEvent(EventType2.MESSAGE_RECEIVED, {
|
|
5019
4914
|
runtime: this.runtime,
|
|
5020
4915
|
message: agentMemory,
|
|
5021
|
-
callback: callbackForCentralBus
|
|
4916
|
+
callback: callbackForCentralBus,
|
|
4917
|
+
onComplete: async () => {
|
|
4918
|
+
const room = await this.runtime.getRoom(agentRoomId);
|
|
4919
|
+
const world = await this.runtime.getWorld(agentWorldId);
|
|
4920
|
+
const channelId = room?.channelId;
|
|
4921
|
+
const serverId = world?.serverId;
|
|
4922
|
+
await this.notifyMessageComplete(channelId, serverId);
|
|
4923
|
+
}
|
|
5022
4924
|
});
|
|
5023
4925
|
} catch (error) {
|
|
5024
4926
|
logger27.error(
|
|
@@ -5095,7 +4997,6 @@ var MessageBusService = class _MessageBusService extends Service {
|
|
|
5095
4997
|
logger27.error(
|
|
5096
4998
|
`[${this.runtime.character.name}] MessageBusService: Cannot map agent room/world to central IDs for response. AgentRoomID: ${agentRoomId}, AgentWorldID: ${agentWorldId}. Room or World object missing, or channelId/serverId not found on them.`
|
|
5097
4999
|
);
|
|
5098
|
-
await this.notifyMessageComplete(channelId, serverId);
|
|
5099
5000
|
return;
|
|
5100
5001
|
}
|
|
5101
5002
|
const shouldSkip = content.actions?.includes("IGNORE") || !content.text || content.text.trim() === "";
|
|
@@ -5103,7 +5004,6 @@ var MessageBusService = class _MessageBusService extends Service {
|
|
|
5103
5004
|
logger27.info(
|
|
5104
5005
|
`[${this.runtime.character.name}] MessageBusService: Skipping response (reason: ${content.actions?.includes("IGNORE") ? "IGNORE action" : "No text"})`
|
|
5105
5006
|
);
|
|
5106
|
-
await this.notifyMessageComplete(channelId, serverId);
|
|
5107
5007
|
return;
|
|
5108
5008
|
}
|
|
5109
5009
|
let centralInReplyToRootMessageId = void 0;
|
|
@@ -5248,8 +5148,8 @@ var messageBusConnectorPlugin = {
|
|
|
5248
5148
|
};
|
|
5249
5149
|
|
|
5250
5150
|
// src/loader.ts
|
|
5251
|
-
import
|
|
5252
|
-
import
|
|
5151
|
+
import fs8 from "fs";
|
|
5152
|
+
import path8 from "path";
|
|
5253
5153
|
import { fileURLToPath } from "url";
|
|
5254
5154
|
import {
|
|
5255
5155
|
logger as logger28,
|
|
@@ -5257,10 +5157,10 @@ import {
|
|
|
5257
5157
|
validateCharacter
|
|
5258
5158
|
} from "@elizaos/core";
|
|
5259
5159
|
var __filename = fileURLToPath(import.meta.url);
|
|
5260
|
-
var __dirname =
|
|
5160
|
+
var __dirname = path8.dirname(__filename);
|
|
5261
5161
|
function tryLoadFile(filePath) {
|
|
5262
5162
|
try {
|
|
5263
|
-
return
|
|
5163
|
+
return fs8.readFileSync(filePath, "utf8");
|
|
5264
5164
|
} catch (e) {
|
|
5265
5165
|
throw new Error(`Error loading file ${filePath}: ${e}`);
|
|
5266
5166
|
}
|
|
@@ -5357,36 +5257,36 @@ async function loadCharacter(filePath) {
|
|
|
5357
5257
|
}
|
|
5358
5258
|
return jsonToCharacter(parseResult.data);
|
|
5359
5259
|
}
|
|
5360
|
-
function handleCharacterLoadError(
|
|
5260
|
+
function handleCharacterLoadError(path10, error) {
|
|
5361
5261
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
5362
5262
|
if (errorMsg.includes("ENOENT") || errorMsg.includes("no such file")) {
|
|
5363
|
-
logger28.error(`Character file not found: ${
|
|
5263
|
+
logger28.error(`Character file not found: ${path10}`);
|
|
5364
5264
|
throw new Error(
|
|
5365
|
-
`Character '${
|
|
5265
|
+
`Character '${path10}' not found. Please check if the file exists and the path is correct.`
|
|
5366
5266
|
);
|
|
5367
5267
|
} else if (errorMsg.includes("Character validation failed")) {
|
|
5368
|
-
logger28.error(`Character validation failed for: ${
|
|
5369
|
-
throw new Error(`Character file '${
|
|
5268
|
+
logger28.error(`Character validation failed for: ${path10}`);
|
|
5269
|
+
throw new Error(`Character file '${path10}' contains invalid character data. ${errorMsg}`);
|
|
5370
5270
|
} else if (errorMsg.includes("JSON")) {
|
|
5371
|
-
logger28.error(`JSON parsing error in character file: ${
|
|
5372
|
-
throw new Error(`Character file '${
|
|
5271
|
+
logger28.error(`JSON parsing error in character file: ${path10}`);
|
|
5272
|
+
throw new Error(`Character file '${path10}' has malformed JSON. Please check the file content.`);
|
|
5373
5273
|
} else if (errorMsg.includes("Invalid JSON")) {
|
|
5374
|
-
logger28.error(`Invalid JSON in character file: ${
|
|
5274
|
+
logger28.error(`Invalid JSON in character file: ${path10}`);
|
|
5375
5275
|
throw new Error(
|
|
5376
|
-
`Character file '${
|
|
5276
|
+
`Character file '${path10}' has invalid JSON format. Please check the file content.`
|
|
5377
5277
|
);
|
|
5378
5278
|
} else {
|
|
5379
|
-
logger28.error(`Error loading character from ${
|
|
5380
|
-
throw new Error(`Failed to load character '${
|
|
5279
|
+
logger28.error(`Error loading character from ${path10}: ${errorMsg}`);
|
|
5280
|
+
throw new Error(`Failed to load character '${path10}': ${errorMsg}`);
|
|
5381
5281
|
}
|
|
5382
5282
|
}
|
|
5383
|
-
async function safeLoadCharacter(
|
|
5283
|
+
async function safeLoadCharacter(path10) {
|
|
5384
5284
|
try {
|
|
5385
|
-
const character = await loadCharacter(
|
|
5386
|
-
logger28.info(`Successfully loaded character from: ${
|
|
5285
|
+
const character = await loadCharacter(path10);
|
|
5286
|
+
logger28.info(`Successfully loaded character from: ${path10}`);
|
|
5387
5287
|
return character;
|
|
5388
5288
|
} catch (e) {
|
|
5389
|
-
return handleCharacterLoadError(
|
|
5289
|
+
return handleCharacterLoadError(path10, e);
|
|
5390
5290
|
}
|
|
5391
5291
|
}
|
|
5392
5292
|
async function loadCharacterTryPath(characterPath) {
|
|
@@ -5406,27 +5306,27 @@ async function loadCharacterTryPath(characterPath) {
|
|
|
5406
5306
|
const jsonPath = hasJsonExtension ? characterPath : `${characterPath}.json`;
|
|
5407
5307
|
const basePathsToTry = [
|
|
5408
5308
|
basePath,
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5309
|
+
path8.resolve(process.cwd(), basePath),
|
|
5310
|
+
path8.resolve(process.cwd(), "..", "..", basePath),
|
|
5311
|
+
path8.resolve(process.cwd(), "..", "..", "..", basePath),
|
|
5312
|
+
path8.resolve(process.cwd(), "agent", basePath),
|
|
5313
|
+
path8.resolve(__dirname, basePath),
|
|
5314
|
+
path8.resolve(__dirname, "characters", path8.basename(basePath)),
|
|
5315
|
+
path8.resolve(__dirname, "../characters", path8.basename(basePath)),
|
|
5316
|
+
path8.resolve(__dirname, "../../characters", path8.basename(basePath)),
|
|
5317
|
+
path8.resolve(__dirname, "../../../characters", path8.basename(basePath))
|
|
5418
5318
|
];
|
|
5419
5319
|
const jsonPathsToTry = hasJsonExtension ? [] : [
|
|
5420
5320
|
jsonPath,
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5321
|
+
path8.resolve(process.cwd(), jsonPath),
|
|
5322
|
+
path8.resolve(process.cwd(), "..", "..", jsonPath),
|
|
5323
|
+
path8.resolve(process.cwd(), "..", "..", "..", jsonPath),
|
|
5324
|
+
path8.resolve(process.cwd(), "agent", jsonPath),
|
|
5325
|
+
path8.resolve(__dirname, jsonPath),
|
|
5326
|
+
path8.resolve(__dirname, "characters", path8.basename(jsonPath)),
|
|
5327
|
+
path8.resolve(__dirname, "../characters", path8.basename(jsonPath)),
|
|
5328
|
+
path8.resolve(__dirname, "../../characters", path8.basename(jsonPath)),
|
|
5329
|
+
path8.resolve(__dirname, "../../../characters", path8.basename(jsonPath))
|
|
5430
5330
|
];
|
|
5431
5331
|
const pathsToTry = Array.from(/* @__PURE__ */ new Set([...basePathsToTry, ...jsonPathsToTry]));
|
|
5432
5332
|
let lastError = null;
|
|
@@ -5451,11 +5351,11 @@ function commaSeparatedStringToArray(commaSeparated) {
|
|
|
5451
5351
|
}
|
|
5452
5352
|
async function readCharactersFromStorage(characterPaths) {
|
|
5453
5353
|
try {
|
|
5454
|
-
const uploadDir =
|
|
5455
|
-
await
|
|
5456
|
-
const fileNames = await
|
|
5354
|
+
const uploadDir = path8.join(process.cwd(), ".eliza", "data", "characters");
|
|
5355
|
+
await fs8.promises.mkdir(uploadDir, { recursive: true });
|
|
5356
|
+
const fileNames = await fs8.promises.readdir(uploadDir);
|
|
5457
5357
|
for (const fileName of fileNames) {
|
|
5458
|
-
characterPaths.push(
|
|
5358
|
+
characterPaths.push(path8.join(uploadDir, fileName));
|
|
5459
5359
|
}
|
|
5460
5360
|
} catch (err) {
|
|
5461
5361
|
logger28.error(`Error reading directory: ${err.message}`);
|
|
@@ -5511,11 +5411,11 @@ function expandTildePath(filepath) {
|
|
|
5511
5411
|
if (filepath === "~") {
|
|
5512
5412
|
return process.cwd();
|
|
5513
5413
|
} else if (filepath.startsWith("~/")) {
|
|
5514
|
-
return
|
|
5414
|
+
return path9.join(process.cwd(), filepath.slice(2));
|
|
5515
5415
|
} else if (filepath.startsWith("~~")) {
|
|
5516
5416
|
return filepath;
|
|
5517
5417
|
} else {
|
|
5518
|
-
return
|
|
5418
|
+
return path9.join(process.cwd(), filepath.slice(1));
|
|
5519
5419
|
}
|
|
5520
5420
|
}
|
|
5521
5421
|
return filepath;
|
|
@@ -5525,11 +5425,11 @@ function resolvePgliteDir(dir, fallbackDir) {
|
|
|
5525
5425
|
if (existsSync3(envPath)) {
|
|
5526
5426
|
dotenv2.config({ path: envPath });
|
|
5527
5427
|
}
|
|
5528
|
-
const base = dir ?? process.env.PGLITE_DATA_DIR ?? fallbackDir ??
|
|
5428
|
+
const base = dir ?? process.env.PGLITE_DATA_DIR ?? fallbackDir ?? path9.join(process.cwd(), ".eliza", ".elizadb");
|
|
5529
5429
|
const resolved = expandTildePath(base);
|
|
5530
|
-
const legacyPath =
|
|
5430
|
+
const legacyPath = path9.join(process.cwd(), ".elizadb");
|
|
5531
5431
|
if (resolved === legacyPath) {
|
|
5532
|
-
const newPath =
|
|
5432
|
+
const newPath = path9.join(process.cwd(), ".eliza", ".elizadb");
|
|
5533
5433
|
process.env.PGLITE_DATA_DIR = newPath;
|
|
5534
5434
|
return newPath;
|
|
5535
5435
|
}
|
|
@@ -5769,26 +5669,10 @@ var AgentServer = class {
|
|
|
5769
5669
|
})
|
|
5770
5670
|
);
|
|
5771
5671
|
this.app.use(
|
|
5772
|
-
|
|
5672
|
+
express30.json({
|
|
5773
5673
|
limit: process.env.EXPRESS_MAX_PAYLOAD || "100kb"
|
|
5774
5674
|
})
|
|
5775
5675
|
);
|
|
5776
|
-
this.app.use(
|
|
5777
|
-
fileUpload2({
|
|
5778
|
-
useTempFiles: true,
|
|
5779
|
-
tempFileDir: "/tmp/",
|
|
5780
|
-
createParentPath: true,
|
|
5781
|
-
preserveExtension: true,
|
|
5782
|
-
safeFileNames: true,
|
|
5783
|
-
limits: {
|
|
5784
|
-
fileSize: 50 * 1024 * 1024
|
|
5785
|
-
// 50MB default limit
|
|
5786
|
-
},
|
|
5787
|
-
abortOnLimit: true,
|
|
5788
|
-
uploadTimeout: 6e4
|
|
5789
|
-
// 60 seconds
|
|
5790
|
-
})
|
|
5791
|
-
);
|
|
5792
5676
|
const serverAuthToken = process.env.ELIZA_SERVER_AUTH_TOKEN;
|
|
5793
5677
|
if (serverAuthToken) {
|
|
5794
5678
|
logger29.info("Server authentication enabled. Requires X-API-KEY header for /api routes.");
|
|
@@ -5800,10 +5684,10 @@ var AgentServer = class {
|
|
|
5800
5684
|
"Server authentication is disabled. Set ELIZA_SERVER_AUTH_TOKEN environment variable to enable."
|
|
5801
5685
|
);
|
|
5802
5686
|
}
|
|
5803
|
-
const uploadsBasePath =
|
|
5804
|
-
const generatedBasePath =
|
|
5805
|
-
|
|
5806
|
-
|
|
5687
|
+
const uploadsBasePath = path9.join(process.cwd(), ".eliza", "data", "uploads", "agents");
|
|
5688
|
+
const generatedBasePath = path9.join(process.cwd(), ".eliza", "data", "generated");
|
|
5689
|
+
fs9.mkdirSync(uploadsBasePath, { recursive: true });
|
|
5690
|
+
fs9.mkdirSync(generatedBasePath, { recursive: true });
|
|
5807
5691
|
this.app.get(
|
|
5808
5692
|
"/media/uploads/agents/:agentId/:filename",
|
|
5809
5693
|
// @ts-expect-error - this is a valid express route
|
|
@@ -5820,7 +5704,7 @@ var AgentServer = class {
|
|
|
5820
5704
|
if (!filePath.startsWith(agentUploadsPath)) {
|
|
5821
5705
|
return res.status(403).json({ error: "Access denied" });
|
|
5822
5706
|
}
|
|
5823
|
-
if (!
|
|
5707
|
+
if (!fs9.existsSync(filePath)) {
|
|
5824
5708
|
return res.status(404).json({ error: "File does not exist!!!!!!!" });
|
|
5825
5709
|
}
|
|
5826
5710
|
res.sendFile(sanitizedFilename, { root: agentUploadsPath }, (err) => {
|
|
@@ -5924,7 +5808,7 @@ var AgentServer = class {
|
|
|
5924
5808
|
}
|
|
5925
5809
|
}
|
|
5926
5810
|
};
|
|
5927
|
-
const clientPath =
|
|
5811
|
+
const clientPath = path9.resolve(__dirname2, "../../cli/dist");
|
|
5928
5812
|
this.app.use(express30.static(clientPath, staticOptions));
|
|
5929
5813
|
const pluginRouteHandler = createPluginRouteHandler(this.agents);
|
|
5930
5814
|
this.app.use(pluginRouteHandler);
|
|
@@ -5938,7 +5822,7 @@ var AgentServer = class {
|
|
|
5938
5822
|
next();
|
|
5939
5823
|
},
|
|
5940
5824
|
apiRouter,
|
|
5941
|
-
(err, req, res) => {
|
|
5825
|
+
(err, req, res, _next) => {
|
|
5942
5826
|
logger29.error(`API error: ${req.method} ${req.path}`, err);
|
|
5943
5827
|
res.status(500).json({
|
|
5944
5828
|
success: false,
|
|
@@ -5967,8 +5851,8 @@ var AgentServer = class {
|
|
|
5967
5851
|
res.setHeader("Content-Type", "application/javascript");
|
|
5968
5852
|
return res.status(404).send(`// JavaScript module not found: ${req.path}`);
|
|
5969
5853
|
}
|
|
5970
|
-
const cliDistPath =
|
|
5971
|
-
res.sendFile(
|
|
5854
|
+
const cliDistPath = path9.resolve(__dirname2, "../../cli/dist");
|
|
5855
|
+
res.sendFile(path9.join(cliDistPath, "index.html"));
|
|
5972
5856
|
});
|
|
5973
5857
|
this.server = http.createServer(this.app);
|
|
5974
5858
|
this.socketIO = setupSocketIO(this.server, this.agents, this);
|