@elizaos/server 1.0.12 → 1.0.14
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.d.ts +8 -0
- package/dist/index.js +532 -589
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -4,7 +4,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __getProtoOf = Object.getPrototypeOf;
|
|
6
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var
|
|
7
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
|
+
}) : x)(function(x) {
|
|
10
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
|
+
});
|
|
13
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
8
14
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
15
|
};
|
|
10
16
|
var __copyProps = (to, from, except, desc) => {
|
|
@@ -381,13 +387,11 @@ var import_cors2 = __toESM(require_lib(), 1);
|
|
|
381
387
|
import {
|
|
382
388
|
logger as logger29
|
|
383
389
|
} from "@elizaos/core";
|
|
384
|
-
import bodyParser2 from "body-parser";
|
|
385
390
|
import express30 from "express";
|
|
386
|
-
import fileUpload2 from "express-fileupload";
|
|
387
391
|
import helmet2 from "helmet";
|
|
388
|
-
import * as
|
|
392
|
+
import * as fs9 from "fs";
|
|
389
393
|
import http from "http";
|
|
390
|
-
import
|
|
394
|
+
import path9, { basename, dirname, extname, join } from "path";
|
|
391
395
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
392
396
|
|
|
393
397
|
// src/api/index.ts
|
|
@@ -499,7 +503,7 @@ function createAgentCrudRouter(agents, serverInstance) {
|
|
|
499
503
|
});
|
|
500
504
|
router.post("/", async (req, res) => {
|
|
501
505
|
logger.debug("[AGENT CREATE] Creating new agent");
|
|
502
|
-
const { characterPath, characterJson } = req.body;
|
|
506
|
+
const { characterPath, characterJson, agent } = req.body;
|
|
503
507
|
if (!db) {
|
|
504
508
|
return sendError(res, 500, "DB_ERROR", "Database not available");
|
|
505
509
|
}
|
|
@@ -511,6 +515,9 @@ function createAgentCrudRouter(agents, serverInstance) {
|
|
|
511
515
|
} else if (characterPath) {
|
|
512
516
|
logger.debug(`[AGENT CREATE] Loading character from path: ${characterPath}`);
|
|
513
517
|
character = await serverInstance?.loadCharacterTryPath(characterPath);
|
|
518
|
+
} else if (agent) {
|
|
519
|
+
logger.debug("[AGENT CREATE] Parsing character from agent object");
|
|
520
|
+
character = await serverInstance?.jsonToCharacter(agent);
|
|
514
521
|
} else {
|
|
515
522
|
throw new Error("No character configuration provided");
|
|
516
523
|
}
|
|
@@ -524,12 +531,12 @@ function createAgentCrudRouter(agents, serverInstance) {
|
|
|
524
531
|
}
|
|
525
532
|
const ensureAgentExists = async (character2) => {
|
|
526
533
|
const agentId = stringToUuid(character2.name);
|
|
527
|
-
let
|
|
528
|
-
if (!
|
|
534
|
+
let agent2 = await db.getAgent(agentId);
|
|
535
|
+
if (!agent2) {
|
|
529
536
|
await db.createAgent({ ...character2, id: agentId });
|
|
530
|
-
|
|
537
|
+
agent2 = await db.getAgent(agentId);
|
|
531
538
|
}
|
|
532
|
-
return
|
|
539
|
+
return agent2;
|
|
533
540
|
};
|
|
534
541
|
const newAgent = await ensureAgentExists(character);
|
|
535
542
|
if (!newAgent) {
|
|
@@ -1183,6 +1190,30 @@ function createAgentMemoryRouter(agents) {
|
|
|
1183
1190
|
);
|
|
1184
1191
|
}
|
|
1185
1192
|
});
|
|
1193
|
+
router.delete("/:agentId/memories/:memoryId", async (req, res) => {
|
|
1194
|
+
try {
|
|
1195
|
+
const agentId = validateUuid6(req.params.agentId);
|
|
1196
|
+
const memoryId = validateUuid6(req.params.memoryId);
|
|
1197
|
+
if (!agentId || !memoryId) {
|
|
1198
|
+
return sendError(res, 400, "INVALID_ID", "Invalid agent ID or memory ID format");
|
|
1199
|
+
}
|
|
1200
|
+
const runtime = agents.get(agentId);
|
|
1201
|
+
if (!runtime) {
|
|
1202
|
+
return sendError(res, 404, "NOT_FOUND", "Agent not found");
|
|
1203
|
+
}
|
|
1204
|
+
await runtime.deleteMemory(memoryId);
|
|
1205
|
+
sendSuccess(res, { message: "Memory deleted successfully" });
|
|
1206
|
+
} catch (error) {
|
|
1207
|
+
logger6.error(`[DELETE MEMORY] Error deleting memory ${req.params.memoryId}:`, error);
|
|
1208
|
+
sendError(
|
|
1209
|
+
res,
|
|
1210
|
+
500,
|
|
1211
|
+
"DELETE_ERROR",
|
|
1212
|
+
"Error deleting memory",
|
|
1213
|
+
error instanceof Error ? error.message : String(error)
|
|
1214
|
+
);
|
|
1215
|
+
}
|
|
1216
|
+
});
|
|
1186
1217
|
return router;
|
|
1187
1218
|
}
|
|
1188
1219
|
|
|
@@ -1683,189 +1714,16 @@ import {
|
|
|
1683
1714
|
composePromptFromState,
|
|
1684
1715
|
ModelType,
|
|
1685
1716
|
ChannelType as ChannelType2,
|
|
1686
|
-
logger as
|
|
1687
|
-
validateUuid as
|
|
1717
|
+
logger as logger12,
|
|
1718
|
+
validateUuid as validateUuid12
|
|
1688
1719
|
} from "@elizaos/core";
|
|
1689
1720
|
import express11 from "express";
|
|
1690
1721
|
|
|
1691
|
-
// src/upload.ts
|
|
1692
|
-
import fs2 from "fs";
|
|
1693
|
-
import path2 from "path";
|
|
1694
|
-
import fileUpload from "express-fileupload";
|
|
1695
|
-
import { validateUuid as validateUuid10, logger as logger11 } from "@elizaos/core";
|
|
1696
|
-
|
|
1697
|
-
// src/api/shared/file-utils.ts
|
|
1698
|
-
import fs from "fs";
|
|
1699
|
-
import path from "path";
|
|
1700
|
-
import { logger as logger10 } from "@elizaos/core";
|
|
1701
|
-
function createSecureUploadDir(id, type) {
|
|
1702
|
-
if (id.includes("..") || id.includes("/") || id.includes("\\") || id.includes("\0")) {
|
|
1703
|
-
throw new Error(`Invalid ${type.slice(0, -1)} ID: contains illegal characters`);
|
|
1704
|
-
}
|
|
1705
|
-
const basePath = path.resolve(process.cwd(), ".eliza", "data", "uploads", type);
|
|
1706
|
-
const targetPath = path.join(basePath, id);
|
|
1707
|
-
if (!targetPath.startsWith(basePath)) {
|
|
1708
|
-
throw new Error(`Invalid ${type.slice(0, -1)} ID: path traversal detected`);
|
|
1709
|
-
}
|
|
1710
|
-
return targetPath;
|
|
1711
|
-
}
|
|
1712
|
-
function sanitizeFilename(filename) {
|
|
1713
|
-
let sanitized = filename.replace(/[\0\/\\:*?"<>|]/g, "_");
|
|
1714
|
-
sanitized = sanitized.replace(/^[.\s]+/, "");
|
|
1715
|
-
if (sanitized.length > 255) {
|
|
1716
|
-
const ext = path.extname(sanitized);
|
|
1717
|
-
const name = path.basename(sanitized, ext);
|
|
1718
|
-
sanitized = name.substring(0, 255 - ext.length) + ext;
|
|
1719
|
-
}
|
|
1720
|
-
if (!sanitized || sanitized.trim() === "") {
|
|
1721
|
-
sanitized = "file";
|
|
1722
|
-
}
|
|
1723
|
-
return sanitized;
|
|
1724
|
-
}
|
|
1725
|
-
var cleanupFile = (filePath) => {
|
|
1726
|
-
if (!filePath) return;
|
|
1727
|
-
try {
|
|
1728
|
-
const resolvedPath = path.resolve(filePath);
|
|
1729
|
-
const normalizedPath = path.normalize(resolvedPath);
|
|
1730
|
-
if (normalizedPath.includes("..") || !normalizedPath.startsWith(process.cwd())) {
|
|
1731
|
-
logger10.warn(`[SECURITY] Potentially unsafe file path blocked: ${filePath}`);
|
|
1732
|
-
return;
|
|
1733
|
-
}
|
|
1734
|
-
if (fs.existsSync(normalizedPath)) {
|
|
1735
|
-
fs.unlinkSync(normalizedPath);
|
|
1736
|
-
logger10.debug(`[FILE] Successfully cleaned up file: ${normalizedPath}`);
|
|
1737
|
-
}
|
|
1738
|
-
} catch (error) {
|
|
1739
|
-
logger10.error(`Error cleaning up file ${filePath}:`, error);
|
|
1740
|
-
}
|
|
1741
|
-
};
|
|
1742
|
-
var cleanupUploadedFile = (file) => {
|
|
1743
|
-
if (file.tempFilePath) {
|
|
1744
|
-
cleanupFile(file.tempFilePath);
|
|
1745
|
-
}
|
|
1746
|
-
};
|
|
1747
|
-
|
|
1748
|
-
// src/api/shared/constants.ts
|
|
1749
|
-
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
1750
|
-
var MAX_FILE_SIZE_DISPLAY = "50MB";
|
|
1751
|
-
var ALLOWED_AUDIO_MIME_TYPES = [
|
|
1752
|
-
"audio/mpeg",
|
|
1753
|
-
"audio/mp3",
|
|
1754
|
-
"audio/wav",
|
|
1755
|
-
"audio/ogg",
|
|
1756
|
-
"audio/webm",
|
|
1757
|
-
"audio/mp4",
|
|
1758
|
-
"audio/aac",
|
|
1759
|
-
"audio/flac",
|
|
1760
|
-
"audio/x-wav",
|
|
1761
|
-
"audio/wave"
|
|
1762
|
-
];
|
|
1763
|
-
var ALLOWED_MEDIA_MIME_TYPES = [
|
|
1764
|
-
...ALLOWED_AUDIO_MIME_TYPES,
|
|
1765
|
-
"image/jpeg",
|
|
1766
|
-
"image/png",
|
|
1767
|
-
"image/gif",
|
|
1768
|
-
"image/webp",
|
|
1769
|
-
"video/mp4",
|
|
1770
|
-
"video/webm",
|
|
1771
|
-
"application/pdf",
|
|
1772
|
-
"text/plain"
|
|
1773
|
-
];
|
|
1774
|
-
|
|
1775
|
-
// src/upload.ts
|
|
1776
|
-
function generateSecureFilename(originalName) {
|
|
1777
|
-
const uniqueSuffix = `${Date.now()}-${Math.round(Math.random() * 1e9)}`;
|
|
1778
|
-
const sanitizedName = sanitizeFilename(originalName);
|
|
1779
|
-
return `${uniqueSuffix}-${sanitizedName}`;
|
|
1780
|
-
}
|
|
1781
|
-
function ensureUploadDir(id, type) {
|
|
1782
|
-
if (!validateUuid10(id)) {
|
|
1783
|
-
throw new Error(`Invalid ${type.slice(0, -1)} ID format`);
|
|
1784
|
-
}
|
|
1785
|
-
const uploadDir = createSecureUploadDir(id, type);
|
|
1786
|
-
if (!fs2.existsSync(uploadDir)) {
|
|
1787
|
-
fs2.mkdirSync(uploadDir, { recursive: true });
|
|
1788
|
-
}
|
|
1789
|
-
logger11.debug(`[UPLOAD] Secure ${type.slice(0, -1)} upload directory created: ${uploadDir}`);
|
|
1790
|
-
return uploadDir;
|
|
1791
|
-
}
|
|
1792
|
-
var agentAudioUpload = () => fileUpload({
|
|
1793
|
-
limits: {
|
|
1794
|
-
fileSize: MAX_FILE_SIZE,
|
|
1795
|
-
// 50MB max file size
|
|
1796
|
-
files: 1
|
|
1797
|
-
// Only allow 1 file per request
|
|
1798
|
-
},
|
|
1799
|
-
useTempFiles: true,
|
|
1800
|
-
tempFileDir: "/tmp/",
|
|
1801
|
-
parseNested: true,
|
|
1802
|
-
abortOnLimit: true,
|
|
1803
|
-
createParentPath: true,
|
|
1804
|
-
preserveExtension: true,
|
|
1805
|
-
safeFileNames: true,
|
|
1806
|
-
uploadTimeout: 6e4
|
|
1807
|
-
// 60 seconds timeout
|
|
1808
|
-
});
|
|
1809
|
-
var agentMediaUpload = () => fileUpload({
|
|
1810
|
-
limits: {
|
|
1811
|
-
fileSize: MAX_FILE_SIZE,
|
|
1812
|
-
// 50MB max file size
|
|
1813
|
-
files: 1
|
|
1814
|
-
// Only allow 1 file per request
|
|
1815
|
-
},
|
|
1816
|
-
useTempFiles: true,
|
|
1817
|
-
tempFileDir: "/tmp/",
|
|
1818
|
-
parseNested: true,
|
|
1819
|
-
abortOnLimit: true,
|
|
1820
|
-
createParentPath: true,
|
|
1821
|
-
preserveExtension: true,
|
|
1822
|
-
safeFileNames: true,
|
|
1823
|
-
uploadTimeout: 6e4
|
|
1824
|
-
// 60 seconds timeout
|
|
1825
|
-
});
|
|
1826
|
-
var channelUpload = () => fileUpload({
|
|
1827
|
-
limits: {
|
|
1828
|
-
fileSize: MAX_FILE_SIZE,
|
|
1829
|
-
// 50MB max file size
|
|
1830
|
-
files: 1
|
|
1831
|
-
// Only allow 1 file per request
|
|
1832
|
-
},
|
|
1833
|
-
useTempFiles: true,
|
|
1834
|
-
tempFileDir: "/tmp/",
|
|
1835
|
-
parseNested: true,
|
|
1836
|
-
abortOnLimit: true,
|
|
1837
|
-
createParentPath: true,
|
|
1838
|
-
preserveExtension: true,
|
|
1839
|
-
safeFileNames: true,
|
|
1840
|
-
uploadTimeout: 6e4
|
|
1841
|
-
// 60 seconds timeout
|
|
1842
|
-
});
|
|
1843
|
-
function validateAudioFile(file) {
|
|
1844
|
-
return ALLOWED_AUDIO_MIME_TYPES.includes(file.mimetype);
|
|
1845
|
-
}
|
|
1846
|
-
function validateMediaFile(file) {
|
|
1847
|
-
return ALLOWED_MEDIA_MIME_TYPES.includes(file.mimetype);
|
|
1848
|
-
}
|
|
1849
|
-
async function processUploadedFile(file, targetId, type) {
|
|
1850
|
-
try {
|
|
1851
|
-
const uploadDir = ensureUploadDir(targetId, type);
|
|
1852
|
-
const filename = generateSecureFilename(file.name);
|
|
1853
|
-
const finalPath = path2.join(uploadDir, filename);
|
|
1854
|
-
await file.mv(finalPath);
|
|
1855
|
-
const url = `/media/uploads/${type}/${targetId}/${filename}`;
|
|
1856
|
-
logger11.debug(`[UPLOAD] File processed successfully: ${filename}`);
|
|
1857
|
-
return { filename, path: finalPath, url };
|
|
1858
|
-
} catch (error) {
|
|
1859
|
-
logger11.error("[UPLOAD] Error processing uploaded file:", error);
|
|
1860
|
-
throw error;
|
|
1861
|
-
}
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
1722
|
// src/api/shared/middleware.ts
|
|
1865
|
-
import { validateUuid as
|
|
1723
|
+
import { validateUuid as validateUuid11, logger as logger11 } from "@elizaos/core";
|
|
1866
1724
|
|
|
1867
1725
|
// src/api/shared/validation.ts
|
|
1868
|
-
import { validateUuid as
|
|
1726
|
+
import { validateUuid as validateUuid10, logger as logger10 } from "@elizaos/core";
|
|
1869
1727
|
var getRuntime = (agents, agentId) => {
|
|
1870
1728
|
const runtime = agents.get(agentId);
|
|
1871
1729
|
if (!runtime) {
|
|
@@ -1889,7 +1747,7 @@ var securityMiddleware = () => {
|
|
|
1889
1747
|
const realIp = req.get("X-Real-IP");
|
|
1890
1748
|
const clientIp = forwarded || realIp || req.ip;
|
|
1891
1749
|
if (userAgent && (userAgent.includes("..") || userAgent.includes("<script"))) {
|
|
1892
|
-
|
|
1750
|
+
logger11.warn(`[SECURITY] Suspicious User-Agent from ${clientIp}: ${userAgent}`);
|
|
1893
1751
|
}
|
|
1894
1752
|
const url = req.originalUrl || req.url;
|
|
1895
1753
|
const queryString = JSON.stringify(req.query);
|
|
@@ -1915,12 +1773,12 @@ var securityMiddleware = () => {
|
|
|
1915
1773
|
}
|
|
1916
1774
|
for (const indicator of suspiciousIndicators) {
|
|
1917
1775
|
if (url.includes(indicator.pattern) || queryString.includes(indicator.pattern)) {
|
|
1918
|
-
|
|
1776
|
+
logger11.warn(`[SECURITY] ${indicator.name} detected from ${clientIp}: ${url}`);
|
|
1919
1777
|
break;
|
|
1920
1778
|
}
|
|
1921
1779
|
}
|
|
1922
1780
|
if (hasSqlPattern) {
|
|
1923
|
-
|
|
1781
|
+
logger11.warn(`[SECURITY] SQL injection pattern detected from ${clientIp}: ${url}`);
|
|
1924
1782
|
}
|
|
1925
1783
|
next();
|
|
1926
1784
|
};
|
|
@@ -1969,7 +1827,7 @@ var createApiRateLimit = () => {
|
|
|
1969
1827
|
// Disable the `X-RateLimit-*` headers
|
|
1970
1828
|
handler: (req, res) => {
|
|
1971
1829
|
const clientIp = req.ip || "unknown";
|
|
1972
|
-
|
|
1830
|
+
logger11.warn(`[SECURITY] Rate limit exceeded for IP: ${clientIp}`);
|
|
1973
1831
|
res.status(429).json({
|
|
1974
1832
|
success: false,
|
|
1975
1833
|
error: {
|
|
@@ -1997,7 +1855,7 @@ var createFileSystemRateLimit = () => {
|
|
|
1997
1855
|
legacyHeaders: false,
|
|
1998
1856
|
handler: (req, res) => {
|
|
1999
1857
|
const clientIp = req.ip || "unknown";
|
|
2000
|
-
|
|
1858
|
+
logger11.warn(
|
|
2001
1859
|
`[SECURITY] File system rate limit exceeded for IP: ${clientIp}, endpoint: ${req.path}`
|
|
2002
1860
|
);
|
|
2003
1861
|
res.status(429).json({
|
|
@@ -2027,7 +1885,7 @@ var createUploadRateLimit = () => {
|
|
|
2027
1885
|
legacyHeaders: false,
|
|
2028
1886
|
handler: (req, res) => {
|
|
2029
1887
|
const clientIp = req.ip || "unknown";
|
|
2030
|
-
|
|
1888
|
+
logger11.warn(
|
|
2031
1889
|
`[SECURITY] Upload rate limit exceeded for IP: ${clientIp}, endpoint: ${req.path}`
|
|
2032
1890
|
);
|
|
2033
1891
|
res.status(429).json({
|
|
@@ -2041,14 +1899,73 @@ var createUploadRateLimit = () => {
|
|
|
2041
1899
|
});
|
|
2042
1900
|
};
|
|
2043
1901
|
|
|
1902
|
+
// src/api/shared/constants.ts
|
|
1903
|
+
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
1904
|
+
var MAX_FILE_SIZE_DISPLAY = "50MB";
|
|
1905
|
+
var ALLOWED_AUDIO_MIME_TYPES = [
|
|
1906
|
+
"audio/mpeg",
|
|
1907
|
+
"audio/mp3",
|
|
1908
|
+
"audio/wav",
|
|
1909
|
+
"audio/ogg",
|
|
1910
|
+
"audio/webm",
|
|
1911
|
+
"audio/mp4",
|
|
1912
|
+
"audio/aac",
|
|
1913
|
+
"audio/flac",
|
|
1914
|
+
"audio/x-wav",
|
|
1915
|
+
"audio/wave"
|
|
1916
|
+
];
|
|
1917
|
+
var ALLOWED_MEDIA_MIME_TYPES = [
|
|
1918
|
+
...ALLOWED_AUDIO_MIME_TYPES,
|
|
1919
|
+
"image/jpeg",
|
|
1920
|
+
"image/png",
|
|
1921
|
+
"image/gif",
|
|
1922
|
+
"image/webp",
|
|
1923
|
+
"video/mp4",
|
|
1924
|
+
"video/webm",
|
|
1925
|
+
"application/pdf",
|
|
1926
|
+
"text/plain"
|
|
1927
|
+
];
|
|
1928
|
+
|
|
2044
1929
|
// src/api/messaging/channels.ts
|
|
1930
|
+
import multer from "multer";
|
|
1931
|
+
import fs from "fs";
|
|
1932
|
+
import path from "path";
|
|
2045
1933
|
var DEFAULT_SERVER_ID3 = "00000000-0000-0000-0000-000000000000";
|
|
1934
|
+
var channelStorage = multer.memoryStorage();
|
|
1935
|
+
var channelUploadMiddleware = multer({
|
|
1936
|
+
storage: channelStorage,
|
|
1937
|
+
limits: {
|
|
1938
|
+
fileSize: MAX_FILE_SIZE,
|
|
1939
|
+
files: 1
|
|
1940
|
+
},
|
|
1941
|
+
fileFilter: (req, file, cb) => {
|
|
1942
|
+
if (ALLOWED_MEDIA_MIME_TYPES.includes(file.mimetype)) {
|
|
1943
|
+
cb(null, true);
|
|
1944
|
+
} else {
|
|
1945
|
+
cb(new Error("Invalid file type"), false);
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
});
|
|
1949
|
+
async function saveChannelUploadedFile(file, channelId) {
|
|
1950
|
+
const uploadDir = path.join(process.cwd(), ".eliza/data/uploads/channels", channelId);
|
|
1951
|
+
if (!fs.existsSync(uploadDir)) {
|
|
1952
|
+
fs.mkdirSync(uploadDir, { recursive: true });
|
|
1953
|
+
}
|
|
1954
|
+
const timestamp = Date.now();
|
|
1955
|
+
const random = Math.round(Math.random() * 1e9);
|
|
1956
|
+
const ext = path.extname(file.originalname);
|
|
1957
|
+
const filename = `${timestamp}-${random}${ext}`;
|
|
1958
|
+
const filePath = path.join(uploadDir, filename);
|
|
1959
|
+
fs.writeFileSync(filePath, file.buffer);
|
|
1960
|
+
const url = `/media/uploads/channels/${channelId}/${filename}`;
|
|
1961
|
+
return { filename, url };
|
|
1962
|
+
}
|
|
2046
1963
|
function createChannelsRouter(agents, serverInstance) {
|
|
2047
1964
|
const router = express11.Router();
|
|
2048
1965
|
router.post(
|
|
2049
1966
|
"/central-channels/:channelId/messages",
|
|
2050
1967
|
async (req, res) => {
|
|
2051
|
-
const channelIdParam =
|
|
1968
|
+
const channelIdParam = validateUuid12(req.params.channelId);
|
|
2052
1969
|
const {
|
|
2053
1970
|
author_id,
|
|
2054
1971
|
// This is the GUI user's central ID
|
|
@@ -2063,40 +1980,40 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2063
1980
|
source_type
|
|
2064
1981
|
// Should be something like 'eliza_gui'
|
|
2065
1982
|
} = req.body;
|
|
2066
|
-
const isValidServerId = server_id === DEFAULT_SERVER_ID3 ||
|
|
2067
|
-
if (!channelIdParam || !
|
|
1983
|
+
const isValidServerId = server_id === DEFAULT_SERVER_ID3 || validateUuid12(server_id);
|
|
1984
|
+
if (!channelIdParam || !validateUuid12(author_id) || !content || !isValidServerId) {
|
|
2068
1985
|
return res.status(400).json({
|
|
2069
1986
|
success: false,
|
|
2070
1987
|
error: "Missing required fields: channelId, server_id, author_id, content"
|
|
2071
1988
|
});
|
|
2072
1989
|
}
|
|
2073
1990
|
try {
|
|
2074
|
-
|
|
1991
|
+
logger12.info(
|
|
2075
1992
|
`[Messages Router] Checking if channel ${channelIdParam} exists before creating message`
|
|
2076
1993
|
);
|
|
2077
1994
|
let channelExists = false;
|
|
2078
1995
|
try {
|
|
2079
1996
|
const existingChannel = await serverInstance.getChannelDetails(channelIdParam);
|
|
2080
1997
|
channelExists = !!existingChannel;
|
|
2081
|
-
|
|
1998
|
+
logger12.info(`[Messages Router] Channel ${channelIdParam} exists: ${channelExists}`);
|
|
2082
1999
|
} catch (error) {
|
|
2083
2000
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2084
|
-
|
|
2001
|
+
logger12.info(
|
|
2085
2002
|
`[Messages Router] Channel ${channelIdParam} does not exist, will create it. Error: ${errorMessage}`
|
|
2086
2003
|
);
|
|
2087
2004
|
}
|
|
2088
2005
|
if (!channelExists) {
|
|
2089
|
-
|
|
2006
|
+
logger12.info(
|
|
2090
2007
|
`[Messages Router] Auto-creating channel ${channelIdParam} with serverId ${server_id}`
|
|
2091
2008
|
);
|
|
2092
2009
|
try {
|
|
2093
2010
|
const servers = await serverInstance.getServers();
|
|
2094
2011
|
const serverExists = servers.some((s) => s.id === server_id);
|
|
2095
|
-
|
|
2012
|
+
logger12.info(
|
|
2096
2013
|
`[Messages Router] Server ${server_id} exists: ${serverExists}. Available servers: ${servers.map((s) => s.id).join(", ")}`
|
|
2097
2014
|
);
|
|
2098
2015
|
if (!serverExists) {
|
|
2099
|
-
|
|
2016
|
+
logger12.error(
|
|
2100
2017
|
`[Messages Router] Server ${server_id} does not exist, cannot create channel`
|
|
2101
2018
|
);
|
|
2102
2019
|
return res.status(500).json({ success: false, error: `Server ${server_id} does not exist` });
|
|
@@ -2117,38 +2034,38 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2117
2034
|
...metadata
|
|
2118
2035
|
}
|
|
2119
2036
|
};
|
|
2120
|
-
|
|
2037
|
+
logger12.info(
|
|
2121
2038
|
"[Messages Router] Creating channel with data:",
|
|
2122
2039
|
JSON.stringify(channelData, null, 2)
|
|
2123
2040
|
);
|
|
2124
2041
|
const participants = [author_id];
|
|
2125
2042
|
if (isDmChannel) {
|
|
2126
2043
|
const otherParticipant = metadata?.targetUserId || metadata?.recipientId;
|
|
2127
|
-
if (otherParticipant &&
|
|
2044
|
+
if (otherParticipant && validateUuid12(otherParticipant)) {
|
|
2128
2045
|
participants.push(otherParticipant);
|
|
2129
|
-
|
|
2046
|
+
logger12.info(
|
|
2130
2047
|
`[Messages Router] DM channel will include participants: ${participants.join(", ")}`
|
|
2131
2048
|
);
|
|
2132
2049
|
} else {
|
|
2133
|
-
|
|
2050
|
+
logger12.warn(
|
|
2134
2051
|
`[Messages Router] DM channel missing second participant, only adding author: ${author_id}`
|
|
2135
2052
|
);
|
|
2136
2053
|
}
|
|
2137
2054
|
}
|
|
2138
2055
|
await serverInstance.createChannel(channelData, participants);
|
|
2139
|
-
|
|
2056
|
+
logger12.info(
|
|
2140
2057
|
`[Messages Router] Auto-created ${isDmChannel ? ChannelType2.DM : ChannelType2.GROUP} channel ${channelIdParam} for message submission with ${participants.length} participants`
|
|
2141
2058
|
);
|
|
2142
2059
|
} catch (createError) {
|
|
2143
2060
|
const errorMessage = createError instanceof Error ? createError.message : String(createError);
|
|
2144
|
-
|
|
2061
|
+
logger12.error(
|
|
2145
2062
|
`[Messages Router] Failed to auto-create channel ${channelIdParam}:`,
|
|
2146
2063
|
createError
|
|
2147
2064
|
);
|
|
2148
2065
|
return res.status(500).json({ success: false, error: `Failed to create channel: ${errorMessage}` });
|
|
2149
2066
|
}
|
|
2150
2067
|
} else {
|
|
2151
|
-
|
|
2068
|
+
logger12.info(
|
|
2152
2069
|
`[Messages Router] Channel ${channelIdParam} already exists, proceeding with message creation`
|
|
2153
2070
|
);
|
|
2154
2071
|
}
|
|
@@ -2156,7 +2073,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2156
2073
|
channelId: channelIdParam,
|
|
2157
2074
|
authorId: author_id,
|
|
2158
2075
|
content,
|
|
2159
|
-
inReplyToRootMessageId: in_reply_to_message_id ?
|
|
2076
|
+
inReplyToRootMessageId: in_reply_to_message_id ? validateUuid12(in_reply_to_message_id) || void 0 : void 0,
|
|
2160
2077
|
rawMessage: raw_message,
|
|
2161
2078
|
metadata,
|
|
2162
2079
|
sourceType: source_type || "eliza_gui"
|
|
@@ -2182,7 +2099,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2182
2099
|
// Will be undefined here, which is fine
|
|
2183
2100
|
};
|
|
2184
2101
|
bus_default.emit("new_message", messageForBus);
|
|
2185
|
-
|
|
2102
|
+
logger12.info(
|
|
2186
2103
|
"[Messages Router /central-channels/:channelId/messages] GUI Message published to internal bus:",
|
|
2187
2104
|
messageForBus.id
|
|
2188
2105
|
);
|
|
@@ -2202,7 +2119,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2202
2119
|
}
|
|
2203
2120
|
res.status(201).json({ success: true, data: messageForBus });
|
|
2204
2121
|
} catch (error) {
|
|
2205
|
-
|
|
2122
|
+
logger12.error(
|
|
2206
2123
|
"[Messages Router /central-channels/:channelId/messages] Error processing GUI message:",
|
|
2207
2124
|
error
|
|
2208
2125
|
);
|
|
@@ -2213,7 +2130,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2213
2130
|
router.get(
|
|
2214
2131
|
"/central-channels/:channelId/messages",
|
|
2215
2132
|
async (req, res) => {
|
|
2216
|
-
const channelId =
|
|
2133
|
+
const channelId = validateUuid12(req.params.channelId);
|
|
2217
2134
|
const limit = req.query.limit ? Number.parseInt(req.query.limit, 10) : 50;
|
|
2218
2135
|
const before = req.query.before ? Number.parseInt(req.query.before, 10) : void 0;
|
|
2219
2136
|
const beforeDate = before ? new Date(before) : void 0;
|
|
@@ -2240,7 +2157,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2240
2157
|
});
|
|
2241
2158
|
res.json({ success: true, data: { messages: messagesForGui } });
|
|
2242
2159
|
} catch (error) {
|
|
2243
|
-
|
|
2160
|
+
logger12.error(
|
|
2244
2161
|
`[Messages Router /central-channels/:channelId/messages] Error fetching messages for channel ${channelId}:`,
|
|
2245
2162
|
error
|
|
2246
2163
|
);
|
|
@@ -2251,7 +2168,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2251
2168
|
router.get(
|
|
2252
2169
|
"/central-servers/:serverId/channels",
|
|
2253
2170
|
async (req, res) => {
|
|
2254
|
-
const serverId = req.params.serverId === DEFAULT_SERVER_ID3 ? DEFAULT_SERVER_ID3 :
|
|
2171
|
+
const serverId = req.params.serverId === DEFAULT_SERVER_ID3 ? DEFAULT_SERVER_ID3 : validateUuid12(req.params.serverId);
|
|
2255
2172
|
if (!serverId) {
|
|
2256
2173
|
return res.status(400).json({ success: false, error: "Invalid serverId" });
|
|
2257
2174
|
}
|
|
@@ -2259,7 +2176,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2259
2176
|
const channels = await serverInstance.getChannelsForServer(serverId);
|
|
2260
2177
|
res.json({ success: true, data: { channels } });
|
|
2261
2178
|
} catch (error) {
|
|
2262
|
-
|
|
2179
|
+
logger12.error(
|
|
2263
2180
|
`[Messages Router /central-servers/:serverId/channels] Error fetching channels for server ${serverId}:`,
|
|
2264
2181
|
error
|
|
2265
2182
|
);
|
|
@@ -2289,7 +2206,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2289
2206
|
error: "Missing required fields: type."
|
|
2290
2207
|
});
|
|
2291
2208
|
}
|
|
2292
|
-
if (!
|
|
2209
|
+
if (!validateUuid12(serverId)) {
|
|
2293
2210
|
return res.status(400).json({
|
|
2294
2211
|
success: false,
|
|
2295
2212
|
error: "Invalid serverId format"
|
|
@@ -2307,14 +2224,14 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2307
2224
|
});
|
|
2308
2225
|
res.status(201).json({ success: true, data: { channel } });
|
|
2309
2226
|
} catch (error) {
|
|
2310
|
-
|
|
2227
|
+
logger12.error("[Messages Router /channels] Error creating channel:", error);
|
|
2311
2228
|
res.status(500).json({ success: false, error: "Failed to create channel" });
|
|
2312
2229
|
}
|
|
2313
2230
|
});
|
|
2314
2231
|
router.get("/dm-channel", async (req, res) => {
|
|
2315
|
-
const targetUserId =
|
|
2316
|
-
const currentUserId =
|
|
2317
|
-
const providedDmServerId = req.query.dmServerId === DEFAULT_SERVER_ID3 ? DEFAULT_SERVER_ID3 :
|
|
2232
|
+
const targetUserId = validateUuid12(req.query.targetUserId);
|
|
2233
|
+
const currentUserId = validateUuid12(req.query.currentUserId);
|
|
2234
|
+
const providedDmServerId = req.query.dmServerId === DEFAULT_SERVER_ID3 ? DEFAULT_SERVER_ID3 : validateUuid12(req.query.dmServerId);
|
|
2318
2235
|
if (!targetUserId || !currentUserId) {
|
|
2319
2236
|
res.status(400).json({ success: false, error: "Missing targetUserId or currentUserId" });
|
|
2320
2237
|
return;
|
|
@@ -2330,7 +2247,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2330
2247
|
if (existingServer) {
|
|
2331
2248
|
dmServerIdToUse = providedDmServerId;
|
|
2332
2249
|
} else {
|
|
2333
|
-
|
|
2250
|
+
logger12.warn(
|
|
2334
2251
|
`Provided dmServerId ${providedDmServerId} not found, using default DM server logic.`
|
|
2335
2252
|
);
|
|
2336
2253
|
dmServerIdToUse = DEFAULT_SERVER_ID3;
|
|
@@ -2348,7 +2265,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2348
2265
|
stack: error.stack,
|
|
2349
2266
|
originalError: error
|
|
2350
2267
|
} : { message: String(error) };
|
|
2351
|
-
|
|
2268
|
+
logger12.error("Error finding/creating DM channel:", errorDetails);
|
|
2352
2269
|
res.status(500).json({ success: false, error: "Failed to find or create DM channel" });
|
|
2353
2270
|
}
|
|
2354
2271
|
});
|
|
@@ -2360,8 +2277,8 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2360
2277
|
server_id,
|
|
2361
2278
|
metadata
|
|
2362
2279
|
} = req.body;
|
|
2363
|
-
const isValidServerId = server_id === DEFAULT_SERVER_ID3 ||
|
|
2364
|
-
if (!name || !isValidServerId || !Array.isArray(participantCentralUserIds) || participantCentralUserIds.some((id) => !
|
|
2280
|
+
const isValidServerId = server_id === DEFAULT_SERVER_ID3 || validateUuid12(server_id);
|
|
2281
|
+
if (!name || !isValidServerId || !Array.isArray(participantCentralUserIds) || participantCentralUserIds.some((id) => !validateUuid12(id))) {
|
|
2365
2282
|
return res.status(400).json({
|
|
2366
2283
|
success: false,
|
|
2367
2284
|
error: 'Invalid payload. Required: name, server_id (UUID or "0"), participantCentralUserIds (array of UUIDs). Optional: type, metadata.'
|
|
@@ -2384,7 +2301,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2384
2301
|
res.status(201).json({ success: true, data: newChannel });
|
|
2385
2302
|
} catch (error) {
|
|
2386
2303
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2387
|
-
|
|
2304
|
+
logger12.error(
|
|
2388
2305
|
"[Messages Router /central-channels] Error creating group channel:",
|
|
2389
2306
|
errorMessage
|
|
2390
2307
|
);
|
|
@@ -2394,7 +2311,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2394
2311
|
router.get(
|
|
2395
2312
|
"/central-channels/:channelId/details",
|
|
2396
2313
|
async (req, res) => {
|
|
2397
|
-
const channelId =
|
|
2314
|
+
const channelId = validateUuid12(req.params.channelId);
|
|
2398
2315
|
if (!channelId) {
|
|
2399
2316
|
return res.status(400).json({ success: false, error: "Invalid channelId" });
|
|
2400
2317
|
}
|
|
@@ -2405,7 +2322,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2405
2322
|
}
|
|
2406
2323
|
res.json({ success: true, data: channelDetails });
|
|
2407
2324
|
} catch (error) {
|
|
2408
|
-
|
|
2325
|
+
logger12.error(`[Messages Router] Error fetching details for channel ${channelId}:`, error);
|
|
2409
2326
|
res.status(500).json({ success: false, error: "Failed to fetch channel details" });
|
|
2410
2327
|
}
|
|
2411
2328
|
}
|
|
@@ -2413,7 +2330,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2413
2330
|
router.get(
|
|
2414
2331
|
"/central-channels/:channelId/participants",
|
|
2415
2332
|
async (req, res) => {
|
|
2416
|
-
const channelId =
|
|
2333
|
+
const channelId = validateUuid12(req.params.channelId);
|
|
2417
2334
|
if (!channelId) {
|
|
2418
2335
|
return res.status(400).json({ success: false, error: "Invalid channelId" });
|
|
2419
2336
|
}
|
|
@@ -2421,7 +2338,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2421
2338
|
const participants = await serverInstance.getChannelParticipants(channelId);
|
|
2422
2339
|
res.json({ success: true, data: participants });
|
|
2423
2340
|
} catch (error) {
|
|
2424
|
-
|
|
2341
|
+
logger12.error(
|
|
2425
2342
|
`[Messages Router] Error fetching participants for channel ${channelId}:`,
|
|
2426
2343
|
error
|
|
2427
2344
|
);
|
|
@@ -2432,9 +2349,9 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2432
2349
|
router.post(
|
|
2433
2350
|
"/central-channels/:channelId/agents",
|
|
2434
2351
|
async (req, res) => {
|
|
2435
|
-
const channelId =
|
|
2352
|
+
const channelId = validateUuid12(req.params.channelId);
|
|
2436
2353
|
const { agentId } = req.body;
|
|
2437
|
-
if (!channelId || !
|
|
2354
|
+
if (!channelId || !validateUuid12(agentId)) {
|
|
2438
2355
|
return res.status(400).json({
|
|
2439
2356
|
success: false,
|
|
2440
2357
|
error: "Invalid channelId or agentId format"
|
|
@@ -2449,7 +2366,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2449
2366
|
});
|
|
2450
2367
|
}
|
|
2451
2368
|
await serverInstance.addParticipantsToChannel(channelId, [agentId]);
|
|
2452
|
-
|
|
2369
|
+
logger12.info(`[Messages Router] Added agent ${agentId} to channel ${channelId}`);
|
|
2453
2370
|
res.status(201).json({
|
|
2454
2371
|
success: true,
|
|
2455
2372
|
data: {
|
|
@@ -2459,7 +2376,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2459
2376
|
}
|
|
2460
2377
|
});
|
|
2461
2378
|
} catch (error) {
|
|
2462
|
-
|
|
2379
|
+
logger12.error(
|
|
2463
2380
|
`[Messages Router] Error adding agent ${agentId} to channel ${channelId}:`,
|
|
2464
2381
|
error
|
|
2465
2382
|
);
|
|
@@ -2474,8 +2391,8 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2474
2391
|
router.delete(
|
|
2475
2392
|
"/central-channels/:channelId/agents/:agentId",
|
|
2476
2393
|
async (req, res) => {
|
|
2477
|
-
const channelId =
|
|
2478
|
-
const agentId =
|
|
2394
|
+
const channelId = validateUuid12(req.params.channelId);
|
|
2395
|
+
const agentId = validateUuid12(req.params.agentId);
|
|
2479
2396
|
if (!channelId || !agentId) {
|
|
2480
2397
|
return res.status(400).json({
|
|
2481
2398
|
success: false,
|
|
@@ -2501,7 +2418,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2501
2418
|
await serverInstance.updateChannel(channelId, {
|
|
2502
2419
|
participantCentralUserIds: updatedParticipants
|
|
2503
2420
|
});
|
|
2504
|
-
|
|
2421
|
+
logger12.info(`[Messages Router] Removed agent ${agentId} from channel ${channelId}`);
|
|
2505
2422
|
res.status(200).json({
|
|
2506
2423
|
success: true,
|
|
2507
2424
|
data: {
|
|
@@ -2511,7 +2428,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2511
2428
|
}
|
|
2512
2429
|
});
|
|
2513
2430
|
} catch (error) {
|
|
2514
|
-
|
|
2431
|
+
logger12.error(
|
|
2515
2432
|
`[Messages Router] Error removing agent ${agentId} from channel ${channelId}:`,
|
|
2516
2433
|
error
|
|
2517
2434
|
);
|
|
@@ -2526,7 +2443,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2526
2443
|
router.get(
|
|
2527
2444
|
"/central-channels/:channelId/agents",
|
|
2528
2445
|
async (req, res) => {
|
|
2529
|
-
const channelId =
|
|
2446
|
+
const channelId = validateUuid12(req.params.channelId);
|
|
2530
2447
|
if (!channelId) {
|
|
2531
2448
|
return res.status(400).json({
|
|
2532
2449
|
success: false,
|
|
@@ -2545,7 +2462,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2545
2462
|
}
|
|
2546
2463
|
});
|
|
2547
2464
|
} catch (error) {
|
|
2548
|
-
|
|
2465
|
+
logger12.error(`[Messages Router] Error fetching agents for channel ${channelId}:`, error);
|
|
2549
2466
|
res.status(500).json({
|
|
2550
2467
|
success: false,
|
|
2551
2468
|
error: "Failed to fetch channel agents"
|
|
@@ -2556,20 +2473,20 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2556
2473
|
router.delete(
|
|
2557
2474
|
"/central-channels/:channelId/messages/:messageId",
|
|
2558
2475
|
async (req, res) => {
|
|
2559
|
-
const channelId =
|
|
2560
|
-
const messageId =
|
|
2476
|
+
const channelId = validateUuid12(req.params.channelId);
|
|
2477
|
+
const messageId = validateUuid12(req.params.messageId);
|
|
2561
2478
|
if (!channelId || !messageId) {
|
|
2562
2479
|
return res.status(400).json({ success: false, error: "Invalid channelId or messageId" });
|
|
2563
2480
|
}
|
|
2564
2481
|
try {
|
|
2565
2482
|
await serverInstance.deleteMessage(messageId);
|
|
2566
|
-
|
|
2483
|
+
logger12.info(`[Messages Router] Deleted message ${messageId} from central database`);
|
|
2567
2484
|
const deletedMessagePayload = {
|
|
2568
2485
|
messageId,
|
|
2569
2486
|
channelId
|
|
2570
2487
|
};
|
|
2571
2488
|
bus_default.emit("message_deleted", deletedMessagePayload);
|
|
2572
|
-
|
|
2489
|
+
logger12.info(
|
|
2573
2490
|
`[Messages Router] Emitted message_deleted event to internal bus for message ${messageId}`
|
|
2574
2491
|
);
|
|
2575
2492
|
if (serverInstance.socketIO) {
|
|
@@ -2580,7 +2497,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2580
2497
|
}
|
|
2581
2498
|
res.status(204).send();
|
|
2582
2499
|
} catch (error) {
|
|
2583
|
-
|
|
2500
|
+
logger12.error(
|
|
2584
2501
|
`[Messages Router] Error deleting message ${messageId} from channel ${channelId}:`,
|
|
2585
2502
|
error
|
|
2586
2503
|
);
|
|
@@ -2591,7 +2508,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2591
2508
|
router.delete(
|
|
2592
2509
|
"/central-channels/:channelId/messages",
|
|
2593
2510
|
async (req, res) => {
|
|
2594
|
-
const channelId =
|
|
2511
|
+
const channelId = validateUuid12(req.params.channelId);
|
|
2595
2512
|
if (!channelId) {
|
|
2596
2513
|
return res.status(400).json({ success: false, error: "Invalid channelId" });
|
|
2597
2514
|
}
|
|
@@ -2601,7 +2518,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2601
2518
|
channelId
|
|
2602
2519
|
};
|
|
2603
2520
|
bus_default.emit("channel_cleared", channelClearedPayload);
|
|
2604
|
-
|
|
2521
|
+
logger12.info(
|
|
2605
2522
|
`[Messages Router] Emitted channel_cleared event to internal bus for channel ${channelId}`
|
|
2606
2523
|
);
|
|
2607
2524
|
if (serverInstance.socketIO) {
|
|
@@ -2611,7 +2528,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2611
2528
|
}
|
|
2612
2529
|
res.status(204).send();
|
|
2613
2530
|
} catch (error) {
|
|
2614
|
-
|
|
2531
|
+
logger12.error(`[Messages Router] Error clearing messages for channel ${channelId}:`, error);
|
|
2615
2532
|
res.status(500).json({ success: false, error: "Failed to clear messages" });
|
|
2616
2533
|
}
|
|
2617
2534
|
}
|
|
@@ -2619,7 +2536,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2619
2536
|
router.patch(
|
|
2620
2537
|
"/central-channels/:channelId",
|
|
2621
2538
|
async (req, res) => {
|
|
2622
|
-
const channelId =
|
|
2539
|
+
const channelId = validateUuid12(req.params.channelId);
|
|
2623
2540
|
if (!channelId) {
|
|
2624
2541
|
return res.status(400).json({ success: false, error: "Invalid channelId" });
|
|
2625
2542
|
}
|
|
@@ -2638,7 +2555,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2638
2555
|
}
|
|
2639
2556
|
res.json({ success: true, data: updatedChannel });
|
|
2640
2557
|
} catch (error) {
|
|
2641
|
-
|
|
2558
|
+
logger12.error(`[Messages Router] Error updating channel ${channelId}:`, error);
|
|
2642
2559
|
res.status(500).json({ success: false, error: "Failed to update channel" });
|
|
2643
2560
|
}
|
|
2644
2561
|
}
|
|
@@ -2646,7 +2563,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2646
2563
|
router.delete(
|
|
2647
2564
|
"/central-channels/:channelId",
|
|
2648
2565
|
async (req, res) => {
|
|
2649
|
-
const channelId =
|
|
2566
|
+
const channelId = validateUuid12(req.params.channelId);
|
|
2650
2567
|
if (!channelId) {
|
|
2651
2568
|
return res.status(400).json({ success: false, error: "Invalid channelId" });
|
|
2652
2569
|
}
|
|
@@ -2654,14 +2571,14 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2654
2571
|
const messages = await serverInstance.getMessagesForChannel(channelId);
|
|
2655
2572
|
const messageCount = messages.length;
|
|
2656
2573
|
await serverInstance.deleteChannel(channelId);
|
|
2657
|
-
|
|
2574
|
+
logger12.info(
|
|
2658
2575
|
`[Messages Router] Deleted channel ${channelId} with ${messageCount} messages from central database`
|
|
2659
2576
|
);
|
|
2660
2577
|
const channelClearedPayload = {
|
|
2661
2578
|
channelId
|
|
2662
2579
|
};
|
|
2663
2580
|
bus_default.emit("channel_cleared", channelClearedPayload);
|
|
2664
|
-
|
|
2581
|
+
logger12.info(
|
|
2665
2582
|
`[Messages Router] Emitted channel_cleared event to internal bus for deleted channel ${channelId}`
|
|
2666
2583
|
);
|
|
2667
2584
|
if (serverInstance.socketIO) {
|
|
@@ -2671,7 +2588,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2671
2588
|
}
|
|
2672
2589
|
res.status(204).send();
|
|
2673
2590
|
} catch (error) {
|
|
2674
|
-
|
|
2591
|
+
logger12.error(`[Messages Router] Error deleting channel ${channelId}:`, error);
|
|
2675
2592
|
res.status(500).json({ success: false, error: "Failed to delete channel" });
|
|
2676
2593
|
}
|
|
2677
2594
|
}
|
|
@@ -2680,44 +2597,24 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2680
2597
|
"/channels/:channelId/upload-media",
|
|
2681
2598
|
createUploadRateLimit(),
|
|
2682
2599
|
createFileSystemRateLimit(),
|
|
2683
|
-
|
|
2600
|
+
channelUploadMiddleware.single("file"),
|
|
2684
2601
|
async (req, res) => {
|
|
2685
|
-
const channelId =
|
|
2602
|
+
const channelId = validateUuid12(req.params.channelId);
|
|
2686
2603
|
if (!channelId) {
|
|
2687
2604
|
res.status(400).json({ success: false, error: "Invalid channelId format" });
|
|
2688
2605
|
return;
|
|
2689
2606
|
}
|
|
2690
|
-
|
|
2691
|
-
if (req.files && !Array.isArray(req.files)) {
|
|
2692
|
-
mediaFile = req.files.file;
|
|
2693
|
-
} else if (Array.isArray(req.files) && req.files.length > 0) {
|
|
2694
|
-
mediaFile = req.files[0];
|
|
2695
|
-
} else {
|
|
2696
|
-
res.status(400).json({ success: false, error: "No media file provided" });
|
|
2697
|
-
return;
|
|
2698
|
-
}
|
|
2699
|
-
if (!mediaFile) {
|
|
2607
|
+
if (!req.file) {
|
|
2700
2608
|
res.status(400).json({ success: false, error: "No media file provided" });
|
|
2701
2609
|
return;
|
|
2702
2610
|
}
|
|
2703
2611
|
try {
|
|
2704
|
-
if (!
|
|
2705
|
-
cleanupUploadedFile(mediaFile);
|
|
2706
|
-
res.status(400).json({ success: false, error: `Invalid file type: ${mediaFile.mimetype}` });
|
|
2707
|
-
return;
|
|
2708
|
-
}
|
|
2709
|
-
if (!mediaFile.name || mediaFile.name.includes("..") || mediaFile.name.includes("/")) {
|
|
2710
|
-
cleanupUploadedFile(mediaFile);
|
|
2612
|
+
if (!req.file.originalname || req.file.originalname.includes("..") || req.file.originalname.includes("/")) {
|
|
2711
2613
|
res.status(400).json({ success: false, error: "Invalid filename detected" });
|
|
2712
2614
|
return;
|
|
2713
2615
|
}
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
res.status(400).json({ success: false, error: "File too large" });
|
|
2717
|
-
return;
|
|
2718
|
-
}
|
|
2719
|
-
const result = await processUploadedFile(mediaFile, channelId, "channels");
|
|
2720
|
-
logger14.info(
|
|
2616
|
+
const result = await saveChannelUploadedFile(req.file, channelId);
|
|
2617
|
+
logger12.info(
|
|
2721
2618
|
`[MessagesRouter /upload-media] Secure file uploaded for channel ${channelId}: ${result.filename}. URL: ${result.url}`
|
|
2722
2619
|
);
|
|
2723
2620
|
res.json({
|
|
@@ -2725,21 +2622,18 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2725
2622
|
data: {
|
|
2726
2623
|
url: result.url,
|
|
2727
2624
|
// Relative URL, client prepends server origin
|
|
2728
|
-
type:
|
|
2625
|
+
type: req.file.mimetype,
|
|
2729
2626
|
filename: result.filename,
|
|
2730
|
-
originalName:
|
|
2731
|
-
size:
|
|
2627
|
+
originalName: req.file.originalname,
|
|
2628
|
+
size: req.file.size
|
|
2732
2629
|
}
|
|
2733
2630
|
});
|
|
2734
2631
|
} catch (error) {
|
|
2735
2632
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2736
|
-
|
|
2633
|
+
logger12.error(
|
|
2737
2634
|
`[MessagesRouter /upload-media] Error processing upload for channel ${channelId}: ${errorMessage}`,
|
|
2738
2635
|
error
|
|
2739
2636
|
);
|
|
2740
|
-
if (mediaFile) {
|
|
2741
|
-
cleanupUploadedFile(mediaFile);
|
|
2742
|
-
}
|
|
2743
2637
|
res.status(500).json({ success: false, error: "Failed to process media upload" });
|
|
2744
2638
|
}
|
|
2745
2639
|
}
|
|
@@ -2747,7 +2641,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2747
2641
|
router.post(
|
|
2748
2642
|
"/central-channels/:channelId/generate-title",
|
|
2749
2643
|
async (req, res) => {
|
|
2750
|
-
const channelId =
|
|
2644
|
+
const channelId = validateUuid12(req.params.channelId);
|
|
2751
2645
|
const { agentId } = req.body;
|
|
2752
2646
|
if (!channelId) {
|
|
2753
2647
|
return res.status(400).json({
|
|
@@ -2755,7 +2649,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2755
2649
|
error: "Invalid channel ID format"
|
|
2756
2650
|
});
|
|
2757
2651
|
}
|
|
2758
|
-
if (!agentId || !
|
|
2652
|
+
if (!agentId || !validateUuid12(agentId)) {
|
|
2759
2653
|
return res.status(400).json({
|
|
2760
2654
|
success: false,
|
|
2761
2655
|
error: "Valid agent ID is required"
|
|
@@ -2769,7 +2663,7 @@ function createChannelsRouter(agents, serverInstance) {
|
|
|
2769
2663
|
error: "Agent not found or not active"
|
|
2770
2664
|
});
|
|
2771
2665
|
}
|
|
2772
|
-
|
|
2666
|
+
logger12.info(`[CHANNEL SUMMARIZE] Summarizing channel ${channelId}`);
|
|
2773
2667
|
const limit = req.query.limit ? Number.parseInt(req.query.limit, 10) : 50;
|
|
2774
2668
|
const before = req.query.before ? Number.parseInt(req.query.before, 10) : void 0;
|
|
2775
2669
|
const beforeDate = before ? new Date(before) : void 0;
|
|
@@ -2823,22 +2717,22 @@ Respond with just the title, nothing else.
|
|
|
2823
2717
|
// Keep titles short
|
|
2824
2718
|
});
|
|
2825
2719
|
if (!newTitle || newTitle.trim().length === 0) {
|
|
2826
|
-
|
|
2720
|
+
logger12.warn(`[ChatTitleEvaluator] Failed to generate title for room ${channelId}`);
|
|
2827
2721
|
return;
|
|
2828
2722
|
}
|
|
2829
2723
|
const cleanTitle = newTitle.trim().replace(/^["']|["']$/g, "");
|
|
2830
|
-
|
|
2724
|
+
logger12.info(`[ChatTitleEvaluator] Generated title: "${cleanTitle}" for room ${channelId}`);
|
|
2831
2725
|
const result = {
|
|
2832
2726
|
title: cleanTitle,
|
|
2833
2727
|
channelId
|
|
2834
2728
|
};
|
|
2835
|
-
|
|
2729
|
+
logger12.success(`[CHANNEL SUMMARIZE] Successfully summarized channel ${channelId}`);
|
|
2836
2730
|
res.json({
|
|
2837
2731
|
success: true,
|
|
2838
2732
|
data: result
|
|
2839
2733
|
});
|
|
2840
2734
|
} catch (error) {
|
|
2841
|
-
|
|
2735
|
+
logger12.error("[CHANNEL SUMMARIZE] Error summarizing channel:", error);
|
|
2842
2736
|
res.status(500).json({
|
|
2843
2737
|
success: false,
|
|
2844
2738
|
error: "Failed to summarize channel",
|
|
@@ -2866,58 +2760,74 @@ function messagingRouter(agents, serverInstance) {
|
|
|
2866
2760
|
import express15 from "express";
|
|
2867
2761
|
|
|
2868
2762
|
// src/api/media/agents.ts
|
|
2869
|
-
import { validateUuid as
|
|
2763
|
+
import { validateUuid as validateUuid13, logger as logger13, getContentTypeFromMimeType } from "@elizaos/core";
|
|
2870
2764
|
import express13 from "express";
|
|
2765
|
+
import multer2 from "multer";
|
|
2766
|
+
import fs2 from "fs";
|
|
2767
|
+
import path2 from "path";
|
|
2768
|
+
var storage = multer2.memoryStorage();
|
|
2769
|
+
var upload = multer2({
|
|
2770
|
+
storage,
|
|
2771
|
+
limits: {
|
|
2772
|
+
fileSize: MAX_FILE_SIZE,
|
|
2773
|
+
files: 1
|
|
2774
|
+
},
|
|
2775
|
+
fileFilter: (req, file, cb) => {
|
|
2776
|
+
if (ALLOWED_MEDIA_MIME_TYPES.includes(file.mimetype)) {
|
|
2777
|
+
cb(null, true);
|
|
2778
|
+
} else {
|
|
2779
|
+
cb(new Error("Invalid file type"), false);
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
});
|
|
2783
|
+
async function saveUploadedFile(file, agentId) {
|
|
2784
|
+
const uploadDir = path2.join(process.cwd(), ".eliza/data/uploads/agents", agentId);
|
|
2785
|
+
if (!fs2.existsSync(uploadDir)) {
|
|
2786
|
+
fs2.mkdirSync(uploadDir, { recursive: true });
|
|
2787
|
+
}
|
|
2788
|
+
const timestamp = Date.now();
|
|
2789
|
+
const random = Math.round(Math.random() * 1e9);
|
|
2790
|
+
const ext = path2.extname(file.originalname);
|
|
2791
|
+
const filename = `${timestamp}-${random}${ext}`;
|
|
2792
|
+
const filePath = path2.join(uploadDir, filename);
|
|
2793
|
+
fs2.writeFileSync(filePath, file.buffer);
|
|
2794
|
+
const url = `/media/uploads/agents/${agentId}/${filename}`;
|
|
2795
|
+
return { filename, url };
|
|
2796
|
+
}
|
|
2871
2797
|
function createAgentMediaRouter() {
|
|
2872
2798
|
const router = express13.Router();
|
|
2873
|
-
router.post("/:agentId/upload-media",
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
const agentId = validateUuid14(agentMediaReq.params.agentId);
|
|
2799
|
+
router.post("/:agentId/upload-media", upload.single("file"), async (req, res) => {
|
|
2800
|
+
logger13.debug("[MEDIA UPLOAD] Processing media upload with multer");
|
|
2801
|
+
const agentId = validateUuid13(req.params.agentId);
|
|
2877
2802
|
if (!agentId) {
|
|
2878
2803
|
return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
|
|
2879
2804
|
}
|
|
2880
|
-
|
|
2881
|
-
if (agentMediaReq.files && !Array.isArray(agentMediaReq.files)) {
|
|
2882
|
-
mediaFile = agentMediaReq.files.file;
|
|
2883
|
-
} else if (Array.isArray(agentMediaReq.files) && agentMediaReq.files.length > 0) {
|
|
2884
|
-
mediaFile = agentMediaReq.files[0];
|
|
2885
|
-
} else {
|
|
2886
|
-
return sendError(res, 400, "INVALID_REQUEST", "No media file provided");
|
|
2887
|
-
}
|
|
2888
|
-
if (!mediaFile) {
|
|
2805
|
+
if (!req.file) {
|
|
2889
2806
|
return sendError(res, 400, "INVALID_REQUEST", "No media file provided");
|
|
2890
2807
|
}
|
|
2891
|
-
const
|
|
2892
|
-
if (!validateMediaFile(mediaFile)) {
|
|
2893
|
-
cleanupUploadedFile(mediaFile);
|
|
2894
|
-
return sendError(res, 400, "INVALID_FILE_TYPE", "Unsupported media file type");
|
|
2895
|
-
}
|
|
2896
|
-
const mediaType = getContentTypeFromMimeType(mimetype);
|
|
2808
|
+
const mediaType = getContentTypeFromMimeType(req.file.mimetype);
|
|
2897
2809
|
if (!mediaType) {
|
|
2898
|
-
cleanupUploadedFile(mediaFile);
|
|
2899
2810
|
return sendError(
|
|
2900
2811
|
res,
|
|
2901
2812
|
400,
|
|
2902
2813
|
"UNSUPPORTED_MEDIA_TYPE",
|
|
2903
|
-
`Unsupported media MIME type: ${mimetype}`
|
|
2814
|
+
`Unsupported media MIME type: ${req.file.mimetype}`
|
|
2904
2815
|
);
|
|
2905
2816
|
}
|
|
2906
2817
|
try {
|
|
2907
|
-
const result = await
|
|
2908
|
-
|
|
2818
|
+
const result = await saveUploadedFile(req.file, agentId);
|
|
2819
|
+
logger13.info(
|
|
2909
2820
|
`[MEDIA UPLOAD] Successfully uploaded ${mediaType}: ${result.filename}. URL: ${result.url}`
|
|
2910
2821
|
);
|
|
2911
2822
|
sendSuccess(res, {
|
|
2912
2823
|
url: result.url,
|
|
2913
2824
|
type: mediaType,
|
|
2914
2825
|
filename: result.filename,
|
|
2915
|
-
originalName:
|
|
2916
|
-
size:
|
|
2826
|
+
originalName: req.file.originalname,
|
|
2827
|
+
size: req.file.size
|
|
2917
2828
|
});
|
|
2918
2829
|
} catch (error) {
|
|
2919
|
-
|
|
2920
|
-
cleanupUploadedFile(mediaFile);
|
|
2830
|
+
logger13.error(`[MEDIA UPLOAD] Error processing upload: ${error}`);
|
|
2921
2831
|
sendError(
|
|
2922
2832
|
res,
|
|
2923
2833
|
500,
|
|
@@ -2931,9 +2841,41 @@ function createAgentMediaRouter() {
|
|
|
2931
2841
|
}
|
|
2932
2842
|
|
|
2933
2843
|
// src/api/media/channels.ts
|
|
2934
|
-
import { validateUuid as
|
|
2844
|
+
import { validateUuid as validateUuid14, logger as logger14 } from "@elizaos/core";
|
|
2935
2845
|
import express14 from "express";
|
|
2936
2846
|
import rateLimit2 from "express-rate-limit";
|
|
2847
|
+
import multer3 from "multer";
|
|
2848
|
+
import fs3 from "fs";
|
|
2849
|
+
import path3 from "path";
|
|
2850
|
+
var storage2 = multer3.memoryStorage();
|
|
2851
|
+
var upload2 = multer3({
|
|
2852
|
+
storage: storage2,
|
|
2853
|
+
limits: {
|
|
2854
|
+
fileSize: MAX_FILE_SIZE,
|
|
2855
|
+
files: 1
|
|
2856
|
+
},
|
|
2857
|
+
fileFilter: (req, file, cb) => {
|
|
2858
|
+
if (ALLOWED_MEDIA_MIME_TYPES.includes(file.mimetype)) {
|
|
2859
|
+
cb(null, true);
|
|
2860
|
+
} else {
|
|
2861
|
+
cb(new Error("Invalid file type"), false);
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
});
|
|
2865
|
+
async function saveUploadedFile2(file, channelId) {
|
|
2866
|
+
const uploadDir = path3.join(process.cwd(), ".eliza/data/uploads/channels", channelId);
|
|
2867
|
+
if (!fs3.existsSync(uploadDir)) {
|
|
2868
|
+
fs3.mkdirSync(uploadDir, { recursive: true });
|
|
2869
|
+
}
|
|
2870
|
+
const timestamp = Date.now();
|
|
2871
|
+
const random = Math.round(Math.random() * 1e9);
|
|
2872
|
+
const ext = path3.extname(file.originalname);
|
|
2873
|
+
const filename = `${timestamp}-${random}${ext}`;
|
|
2874
|
+
const filePath = path3.join(uploadDir, filename);
|
|
2875
|
+
fs3.writeFileSync(filePath, file.buffer);
|
|
2876
|
+
const url = `/media/uploads/channels/${channelId}/${filename}`;
|
|
2877
|
+
return { filename, url };
|
|
2878
|
+
}
|
|
2937
2879
|
function createChannelMediaRouter() {
|
|
2938
2880
|
const router = express14.Router();
|
|
2939
2881
|
const uploadMediaRateLimiter = rateLimit2({
|
|
@@ -2947,35 +2889,20 @@ function createChannelMediaRouter() {
|
|
|
2947
2889
|
"/:channelId/upload-media",
|
|
2948
2890
|
uploadMediaRateLimiter,
|
|
2949
2891
|
// Apply rate limiter
|
|
2950
|
-
|
|
2892
|
+
upload2.single("file"),
|
|
2951
2893
|
async (req, res) => {
|
|
2952
|
-
const
|
|
2953
|
-
const channelId = validateUuid15(channelMediaReq.params.channelId);
|
|
2894
|
+
const channelId = validateUuid14(req.params.channelId);
|
|
2954
2895
|
if (!channelId) {
|
|
2955
2896
|
res.status(400).json({ success: false, error: "Invalid channelId format" });
|
|
2956
2897
|
return;
|
|
2957
2898
|
}
|
|
2958
|
-
|
|
2959
|
-
if (channelMediaReq.files && !Array.isArray(channelMediaReq.files)) {
|
|
2960
|
-
mediaFile = channelMediaReq.files.file;
|
|
2961
|
-
} else if (Array.isArray(channelMediaReq.files) && channelMediaReq.files.length > 0) {
|
|
2962
|
-
mediaFile = channelMediaReq.files[0];
|
|
2963
|
-
} else {
|
|
2899
|
+
if (!req.file) {
|
|
2964
2900
|
res.status(400).json({ success: false, error: "No media file provided" });
|
|
2965
2901
|
return;
|
|
2966
2902
|
}
|
|
2967
|
-
if (!mediaFile) {
|
|
2968
|
-
res.status(400).json({ success: false, error: "No media file provided" });
|
|
2969
|
-
return;
|
|
2970
|
-
}
|
|
2971
|
-
if (!validateMediaFile(mediaFile)) {
|
|
2972
|
-
cleanupUploadedFile(mediaFile);
|
|
2973
|
-
res.status(400).json({ success: false, error: `Invalid file type: ${mediaFile.mimetype}` });
|
|
2974
|
-
return;
|
|
2975
|
-
}
|
|
2976
2903
|
try {
|
|
2977
|
-
const result = await
|
|
2978
|
-
|
|
2904
|
+
const result = await saveUploadedFile2(req.file, channelId);
|
|
2905
|
+
logger14.info(
|
|
2979
2906
|
`[Channel Media Upload] File uploaded for channel ${channelId}: ${result.filename}. URL: ${result.url}`
|
|
2980
2907
|
);
|
|
2981
2908
|
res.json({
|
|
@@ -2983,18 +2910,17 @@ function createChannelMediaRouter() {
|
|
|
2983
2910
|
data: {
|
|
2984
2911
|
url: result.url,
|
|
2985
2912
|
// Relative URL, client prepends server origin
|
|
2986
|
-
type:
|
|
2913
|
+
type: req.file.mimetype,
|
|
2987
2914
|
filename: result.filename,
|
|
2988
|
-
originalName:
|
|
2989
|
-
size:
|
|
2915
|
+
originalName: req.file.originalname,
|
|
2916
|
+
size: req.file.size
|
|
2990
2917
|
}
|
|
2991
2918
|
});
|
|
2992
2919
|
} catch (error) {
|
|
2993
|
-
|
|
2920
|
+
logger14.error(
|
|
2994
2921
|
`[Channel Media Upload] Error processing upload for channel ${channelId}: ${error.message}`,
|
|
2995
2922
|
error
|
|
2996
2923
|
);
|
|
2997
|
-
cleanupUploadedFile(mediaFile);
|
|
2998
2924
|
res.status(500).json({ success: false, error: "Failed to process media upload" });
|
|
2999
2925
|
}
|
|
3000
2926
|
}
|
|
@@ -3016,6 +2942,40 @@ import express17 from "express";
|
|
|
3016
2942
|
// src/api/memory/groups.ts
|
|
3017
2943
|
import { validateUuid as validateUuid16, logger as logger17, createUniqueUuid as createUniqueUuid4, ChannelType as ChannelType3 } from "@elizaos/core";
|
|
3018
2944
|
import express16 from "express";
|
|
2945
|
+
|
|
2946
|
+
// src/api/shared/file-utils.ts
|
|
2947
|
+
import fs4 from "fs";
|
|
2948
|
+
import path4 from "path";
|
|
2949
|
+
import { logger as logger15 } from "@elizaos/core";
|
|
2950
|
+
var cleanupUploadedFile = (file) => {
|
|
2951
|
+
logger15.debug(`[FILE] Multer file ${file.originalname} in memory, no cleanup needed`);
|
|
2952
|
+
};
|
|
2953
|
+
|
|
2954
|
+
// src/upload.ts
|
|
2955
|
+
import fs5 from "fs";
|
|
2956
|
+
import path5 from "path";
|
|
2957
|
+
import multer4 from "multer";
|
|
2958
|
+
import { validateUuid as validateUuid15, logger as logger16 } from "@elizaos/core";
|
|
2959
|
+
var storage3 = multer4.memoryStorage();
|
|
2960
|
+
var agentAudioUpload = () => multer4({
|
|
2961
|
+
storage: storage3,
|
|
2962
|
+
limits: {
|
|
2963
|
+
fileSize: MAX_FILE_SIZE,
|
|
2964
|
+
files: 1
|
|
2965
|
+
},
|
|
2966
|
+
fileFilter: (req, file, cb) => {
|
|
2967
|
+
if (ALLOWED_AUDIO_MIME_TYPES.includes(file.mimetype)) {
|
|
2968
|
+
cb(null, true);
|
|
2969
|
+
} else {
|
|
2970
|
+
cb(new Error("Invalid audio file type"), false);
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
});
|
|
2974
|
+
function validateAudioFile(file) {
|
|
2975
|
+
return ALLOWED_AUDIO_MIME_TYPES.includes(file.mimetype);
|
|
2976
|
+
}
|
|
2977
|
+
|
|
2978
|
+
// src/api/memory/groups.ts
|
|
3019
2979
|
function createGroupMemoryRouter(agents, serverInstance) {
|
|
3020
2980
|
const router = express16.Router();
|
|
3021
2981
|
const db = serverInstance?.database;
|
|
@@ -3147,184 +3107,110 @@ import express21 from "express";
|
|
|
3147
3107
|
// src/api/audio/processing.ts
|
|
3148
3108
|
import { logger as logger18, ModelType as ModelType2, validateUuid as validateUuid17 } from "@elizaos/core";
|
|
3149
3109
|
import express18 from "express";
|
|
3150
|
-
import
|
|
3110
|
+
import fs6 from "fs";
|
|
3151
3111
|
import os from "os";
|
|
3152
|
-
import
|
|
3153
|
-
function validateSecureFilePath(filePath) {
|
|
3154
|
-
if (!filePath) {
|
|
3155
|
-
throw new Error("File path is required");
|
|
3156
|
-
}
|
|
3157
|
-
const resolvedPath = path3.resolve(filePath);
|
|
3158
|
-
const normalizedPath = path3.normalize(resolvedPath);
|
|
3159
|
-
if (normalizedPath.includes("..") || normalizedPath !== resolvedPath) {
|
|
3160
|
-
throw new Error("Invalid file path: path traversal detected");
|
|
3161
|
-
}
|
|
3162
|
-
const allowedBasePaths = [process.cwd(), os.tmpdir(), os.homedir()];
|
|
3163
|
-
const isPathAllowed = allowedBasePaths.some(
|
|
3164
|
-
(basePath) => normalizedPath.startsWith(path3.resolve(basePath))
|
|
3165
|
-
);
|
|
3166
|
-
if (!isPathAllowed) {
|
|
3167
|
-
throw new Error("Invalid file path: path outside allowed directories");
|
|
3168
|
-
}
|
|
3169
|
-
try {
|
|
3170
|
-
const stats = fs3.statSync(normalizedPath);
|
|
3171
|
-
if (!stats.isFile()) {
|
|
3172
|
-
throw new Error("Path does not point to a regular file");
|
|
3173
|
-
}
|
|
3174
|
-
} catch (error) {
|
|
3175
|
-
throw new Error(`File access error: ${error instanceof Error ? error.message : String(error)}`);
|
|
3176
|
-
}
|
|
3177
|
-
return normalizedPath;
|
|
3178
|
-
}
|
|
3179
|
-
function getUploadedFile(req) {
|
|
3180
|
-
if (req.files && !Array.isArray(req.files)) {
|
|
3181
|
-
return req.files.file;
|
|
3182
|
-
} else if (Array.isArray(req.files) && req.files.length > 0) {
|
|
3183
|
-
return req.files[0];
|
|
3184
|
-
}
|
|
3185
|
-
return null;
|
|
3186
|
-
}
|
|
3112
|
+
import path6 from "path";
|
|
3187
3113
|
function createAudioProcessingRouter(agents) {
|
|
3188
3114
|
const router = express18.Router();
|
|
3189
3115
|
router.use(createUploadRateLimit());
|
|
3190
3116
|
router.use(createFileSystemRateLimit());
|
|
3191
|
-
router.post(
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3117
|
+
router.post("/:agentId/audio-messages", agentAudioUpload().single("file"), async (req, res) => {
|
|
3118
|
+
const audioReq = req;
|
|
3119
|
+
logger18.debug("[AUDIO MESSAGE] Processing audio message");
|
|
3120
|
+
const agentId = validateUuid17(req.params.agentId);
|
|
3121
|
+
if (!agentId) {
|
|
3122
|
+
return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
|
|
3123
|
+
}
|
|
3124
|
+
const audioFile = audioReq.file;
|
|
3125
|
+
if (!audioFile) {
|
|
3126
|
+
return sendError(res, 400, "INVALID_REQUEST", "No audio file provided");
|
|
3127
|
+
}
|
|
3128
|
+
const runtime = agents.get(agentId);
|
|
3129
|
+
if (!runtime) {
|
|
3130
|
+
cleanupUploadedFile(audioFile);
|
|
3131
|
+
return sendError(res, 404, "NOT_FOUND", "Agent not found");
|
|
3132
|
+
}
|
|
3133
|
+
try {
|
|
3134
|
+
if (!validateAudioFile(audioFile)) {
|
|
3208
3135
|
cleanupUploadedFile(audioFile);
|
|
3209
|
-
return sendError(res,
|
|
3136
|
+
return sendError(res, 400, "INVALID_FILE_TYPE", "Invalid audio file type");
|
|
3210
3137
|
}
|
|
3211
|
-
|
|
3212
|
-
if (!validateAudioFile(audioFile)) {
|
|
3213
|
-
cleanupUploadedFile(audioFile);
|
|
3214
|
-
return sendError(res, 400, "INVALID_FILE_TYPE", "Invalid audio file type");
|
|
3215
|
-
}
|
|
3216
|
-
let securePath;
|
|
3217
|
-
try {
|
|
3218
|
-
const filePath = audioFile.tempFilePath || "";
|
|
3219
|
-
securePath = validateSecureFilePath(filePath);
|
|
3220
|
-
} catch (pathError) {
|
|
3221
|
-
cleanupUploadedFile(audioFile);
|
|
3222
|
-
return sendError(
|
|
3223
|
-
res,
|
|
3224
|
-
403,
|
|
3225
|
-
"INVALID_PATH",
|
|
3226
|
-
`Invalid file path: ${pathError instanceof Error ? pathError.message : String(pathError)}`
|
|
3227
|
-
);
|
|
3228
|
-
}
|
|
3229
|
-
const stats = await fs3.promises.stat(securePath);
|
|
3230
|
-
if (stats.size > MAX_FILE_SIZE) {
|
|
3231
|
-
cleanupUploadedFile(audioFile);
|
|
3232
|
-
return sendError(
|
|
3233
|
-
res,
|
|
3234
|
-
413,
|
|
3235
|
-
"FILE_TOO_LARGE",
|
|
3236
|
-
`Audio file too large (max ${MAX_FILE_SIZE_DISPLAY})`
|
|
3237
|
-
);
|
|
3238
|
-
}
|
|
3239
|
-
const audioBuffer = await fs3.promises.readFile(securePath);
|
|
3240
|
-
const transcription = await runtime.useModel(ModelType2.TRANSCRIPTION, audioBuffer);
|
|
3241
|
-
logger18.info(`[AUDIO MESSAGE] Transcription for agent ${agentId}: ${transcription}`);
|
|
3138
|
+
if (audioFile.size > MAX_FILE_SIZE) {
|
|
3242
3139
|
cleanupUploadedFile(audioFile);
|
|
3243
|
-
|
|
3244
|
-
} catch (error) {
|
|
3245
|
-
logger18.error("[AUDIO MESSAGE] Error processing audio:", error);
|
|
3246
|
-
cleanupUploadedFile(audioFile);
|
|
3247
|
-
sendError(
|
|
3140
|
+
return sendError(
|
|
3248
3141
|
res,
|
|
3249
|
-
|
|
3250
|
-
"
|
|
3251
|
-
|
|
3252
|
-
error instanceof Error ? error.message : String(error)
|
|
3142
|
+
413,
|
|
3143
|
+
"FILE_TOO_LARGE",
|
|
3144
|
+
`Audio file too large (max ${MAX_FILE_SIZE_DISPLAY})`
|
|
3253
3145
|
);
|
|
3254
3146
|
}
|
|
3147
|
+
const transcription = await runtime.useModel(ModelType2.TRANSCRIPTION, audioFile.buffer);
|
|
3148
|
+
logger18.info(`[AUDIO MESSAGE] Transcription for agent ${agentId}: ${transcription}`);
|
|
3149
|
+
cleanupUploadedFile(audioFile);
|
|
3150
|
+
sendSuccess(res, { transcription, message: "Audio transcribed, further processing TBD." });
|
|
3151
|
+
} catch (error) {
|
|
3152
|
+
logger18.error("[AUDIO MESSAGE] Error processing audio:", error);
|
|
3153
|
+
cleanupUploadedFile(audioFile);
|
|
3154
|
+
sendError(
|
|
3155
|
+
res,
|
|
3156
|
+
500,
|
|
3157
|
+
"PROCESSING_ERROR",
|
|
3158
|
+
"Error processing audio message",
|
|
3159
|
+
error instanceof Error ? error.message : String(error)
|
|
3160
|
+
);
|
|
3255
3161
|
}
|
|
3256
|
-
);
|
|
3257
|
-
router.post(
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3162
|
+
});
|
|
3163
|
+
router.post("/:agentId/transcriptions", agentAudioUpload().single("file"), async (req, res) => {
|
|
3164
|
+
const audioReq = req;
|
|
3165
|
+
logger18.debug("[TRANSCRIPTION] Request to transcribe audio");
|
|
3166
|
+
const agentId = validateUuid17(req.params.agentId);
|
|
3167
|
+
if (!agentId) {
|
|
3168
|
+
return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
|
|
3169
|
+
}
|
|
3170
|
+
const audioFile = audioReq.file;
|
|
3171
|
+
if (!audioFile) {
|
|
3172
|
+
return sendError(res, 400, "INVALID_REQUEST", "No audio file provided");
|
|
3173
|
+
}
|
|
3174
|
+
const runtime = agents.get(agentId);
|
|
3175
|
+
if (!runtime) {
|
|
3176
|
+
cleanupUploadedFile(audioFile);
|
|
3177
|
+
return sendError(res, 404, "NOT_FOUND", "Agent not found");
|
|
3178
|
+
}
|
|
3179
|
+
try {
|
|
3180
|
+
logger18.debug("[TRANSCRIPTION] Reading audio file");
|
|
3181
|
+
if (!validateAudioFile(audioFile)) {
|
|
3274
3182
|
cleanupUploadedFile(audioFile);
|
|
3275
|
-
return sendError(res,
|
|
3183
|
+
return sendError(res, 400, "INVALID_FILE_TYPE", "Invalid audio file type");
|
|
3276
3184
|
}
|
|
3277
|
-
|
|
3278
|
-
logger18.debug("[TRANSCRIPTION] Reading audio file");
|
|
3279
|
-
if (!validateAudioFile(audioFile)) {
|
|
3280
|
-
cleanupUploadedFile(audioFile);
|
|
3281
|
-
return sendError(res, 400, "INVALID_FILE_TYPE", "Invalid audio file type");
|
|
3282
|
-
}
|
|
3283
|
-
let securePath;
|
|
3284
|
-
try {
|
|
3285
|
-
const filePath = audioFile.tempFilePath || "";
|
|
3286
|
-
securePath = validateSecureFilePath(filePath);
|
|
3287
|
-
} catch (pathError) {
|
|
3288
|
-
cleanupUploadedFile(audioFile);
|
|
3289
|
-
return sendError(
|
|
3290
|
-
res,
|
|
3291
|
-
403,
|
|
3292
|
-
"INVALID_PATH",
|
|
3293
|
-
`Invalid file path: ${pathError instanceof Error ? pathError.message : String(pathError)}`
|
|
3294
|
-
);
|
|
3295
|
-
}
|
|
3296
|
-
const stats = await fs3.promises.stat(securePath);
|
|
3297
|
-
if (stats.size > MAX_FILE_SIZE) {
|
|
3298
|
-
cleanupUploadedFile(audioFile);
|
|
3299
|
-
return sendError(
|
|
3300
|
-
res,
|
|
3301
|
-
413,
|
|
3302
|
-
"FILE_TOO_LARGE",
|
|
3303
|
-
`Audio file too large (max ${MAX_FILE_SIZE_DISPLAY})`
|
|
3304
|
-
);
|
|
3305
|
-
}
|
|
3306
|
-
const audioBuffer = await fs3.promises.readFile(securePath);
|
|
3307
|
-
logger18.debug("[TRANSCRIPTION] Transcribing audio");
|
|
3308
|
-
const transcription = await runtime.useModel(ModelType2.TRANSCRIPTION, audioBuffer);
|
|
3185
|
+
if (audioFile.size > MAX_FILE_SIZE) {
|
|
3309
3186
|
cleanupUploadedFile(audioFile);
|
|
3310
|
-
|
|
3311
|
-
return sendError(res, 500, "PROCESSING_ERROR", "Failed to transcribe audio");
|
|
3312
|
-
}
|
|
3313
|
-
logger18.success("[TRANSCRIPTION] Successfully transcribed audio");
|
|
3314
|
-
sendSuccess(res, { text: transcription });
|
|
3315
|
-
} catch (error) {
|
|
3316
|
-
logger18.error("[TRANSCRIPTION] Error transcribing audio:", error);
|
|
3317
|
-
cleanupUploadedFile(audioFile);
|
|
3318
|
-
sendError(
|
|
3187
|
+
return sendError(
|
|
3319
3188
|
res,
|
|
3320
|
-
|
|
3321
|
-
"
|
|
3322
|
-
|
|
3323
|
-
error instanceof Error ? error.message : String(error)
|
|
3189
|
+
413,
|
|
3190
|
+
"FILE_TOO_LARGE",
|
|
3191
|
+
`Audio file too large (max ${MAX_FILE_SIZE_DISPLAY})`
|
|
3324
3192
|
);
|
|
3325
3193
|
}
|
|
3194
|
+
logger18.debug("[TRANSCRIPTION] Transcribing audio");
|
|
3195
|
+
const transcription = await runtime.useModel(ModelType2.TRANSCRIPTION, audioFile.buffer);
|
|
3196
|
+
cleanupUploadedFile(audioFile);
|
|
3197
|
+
if (!transcription) {
|
|
3198
|
+
return sendError(res, 500, "PROCESSING_ERROR", "Failed to transcribe audio");
|
|
3199
|
+
}
|
|
3200
|
+
logger18.success("[TRANSCRIPTION] Successfully transcribed audio");
|
|
3201
|
+
sendSuccess(res, { text: transcription });
|
|
3202
|
+
} catch (error) {
|
|
3203
|
+
logger18.error("[TRANSCRIPTION] Error transcribing audio:", error);
|
|
3204
|
+
cleanupUploadedFile(audioFile);
|
|
3205
|
+
sendError(
|
|
3206
|
+
res,
|
|
3207
|
+
500,
|
|
3208
|
+
"PROCESSING_ERROR",
|
|
3209
|
+
"Error transcribing audio",
|
|
3210
|
+
error instanceof Error ? error.message : String(error)
|
|
3211
|
+
);
|
|
3326
3212
|
}
|
|
3327
|
-
);
|
|
3213
|
+
});
|
|
3328
3214
|
return router;
|
|
3329
3215
|
}
|
|
3330
3216
|
|
|
@@ -3821,15 +3707,15 @@ import express28 from "express";
|
|
|
3821
3707
|
import { logger as logger23 } from "@elizaos/core";
|
|
3822
3708
|
import express27 from "express";
|
|
3823
3709
|
import { existsSync, writeFileSync } from "fs";
|
|
3824
|
-
import
|
|
3710
|
+
import path7 from "path";
|
|
3825
3711
|
import dotenv from "dotenv";
|
|
3826
|
-
import
|
|
3712
|
+
import fs7 from "fs/promises";
|
|
3827
3713
|
async function parseEnvFile(filePath) {
|
|
3828
3714
|
try {
|
|
3829
3715
|
if (!existsSync(filePath)) {
|
|
3830
3716
|
return {};
|
|
3831
3717
|
}
|
|
3832
|
-
const content = await
|
|
3718
|
+
const content = await fs7.readFile(filePath, "utf-8");
|
|
3833
3719
|
if (content.trim() === "") {
|
|
3834
3720
|
return {};
|
|
3835
3721
|
}
|
|
@@ -3849,17 +3735,17 @@ function getLocalEnvPath() {
|
|
|
3849
3735
|
function resolveEnvFile(startDir = process.cwd()) {
|
|
3850
3736
|
let currentDir = startDir;
|
|
3851
3737
|
while (true) {
|
|
3852
|
-
const candidate =
|
|
3738
|
+
const candidate = path7.join(currentDir, ".env");
|
|
3853
3739
|
if (existsSync(candidate)) {
|
|
3854
3740
|
return candidate;
|
|
3855
3741
|
}
|
|
3856
|
-
const parentDir =
|
|
3742
|
+
const parentDir = path7.dirname(currentDir);
|
|
3857
3743
|
if (parentDir === currentDir) {
|
|
3858
3744
|
break;
|
|
3859
3745
|
}
|
|
3860
3746
|
currentDir = parentDir;
|
|
3861
3747
|
}
|
|
3862
|
-
return
|
|
3748
|
+
return path7.join(startDir, ".env");
|
|
3863
3749
|
}
|
|
3864
3750
|
function createEnvironmentRouter() {
|
|
3865
3751
|
const router = express27.Router();
|
|
@@ -4610,6 +4496,7 @@ function createApiRouter(agents, serverInstance) {
|
|
|
4610
4496
|
);
|
|
4611
4497
|
router.use(createApiRateLimit());
|
|
4612
4498
|
router.use(securityMiddleware());
|
|
4499
|
+
router.use("/media", mediaRouter());
|
|
4613
4500
|
router.use(validateContentTypeMiddleware());
|
|
4614
4501
|
router.use(
|
|
4615
4502
|
bodyParser.json({
|
|
@@ -4629,7 +4516,6 @@ function createApiRouter(agents, serverInstance) {
|
|
|
4629
4516
|
);
|
|
4630
4517
|
router.use("/agents", agentsRouter(agents, serverInstance));
|
|
4631
4518
|
router.use("/messaging", messagingRouter(agents, serverInstance));
|
|
4632
|
-
router.use("/media", mediaRouter());
|
|
4633
4519
|
router.use("/memory", memoryRouter(agents, serverInstance));
|
|
4634
4520
|
router.use("/audio", audioRouter(agents));
|
|
4635
4521
|
router.use("/server", runtimeRouter(agents, serverInstance));
|
|
@@ -5033,7 +4919,14 @@ var MessageBusService = class _MessageBusService extends Service {
|
|
|
5033
4919
|
await this.runtime.emitEvent(EventType2.MESSAGE_RECEIVED, {
|
|
5034
4920
|
runtime: this.runtime,
|
|
5035
4921
|
message: agentMemory,
|
|
5036
|
-
callback: callbackForCentralBus
|
|
4922
|
+
callback: callbackForCentralBus,
|
|
4923
|
+
onComplete: async () => {
|
|
4924
|
+
const room = await this.runtime.getRoom(agentRoomId);
|
|
4925
|
+
const world = await this.runtime.getWorld(agentWorldId);
|
|
4926
|
+
const channelId = room?.channelId;
|
|
4927
|
+
const serverId = world?.serverId;
|
|
4928
|
+
await this.notifyMessageComplete(channelId, serverId);
|
|
4929
|
+
}
|
|
5037
4930
|
});
|
|
5038
4931
|
} catch (error) {
|
|
5039
4932
|
logger27.error(
|
|
@@ -5110,7 +5003,6 @@ var MessageBusService = class _MessageBusService extends Service {
|
|
|
5110
5003
|
logger27.error(
|
|
5111
5004
|
`[${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.`
|
|
5112
5005
|
);
|
|
5113
|
-
await this.notifyMessageComplete(channelId, serverId);
|
|
5114
5006
|
return;
|
|
5115
5007
|
}
|
|
5116
5008
|
const shouldSkip = content.actions?.includes("IGNORE") || !content.text || content.text.trim() === "";
|
|
@@ -5118,7 +5010,6 @@ var MessageBusService = class _MessageBusService extends Service {
|
|
|
5118
5010
|
logger27.info(
|
|
5119
5011
|
`[${this.runtime.character.name}] MessageBusService: Skipping response (reason: ${content.actions?.includes("IGNORE") ? "IGNORE action" : "No text"})`
|
|
5120
5012
|
);
|
|
5121
|
-
await this.notifyMessageComplete(channelId, serverId);
|
|
5122
5013
|
return;
|
|
5123
5014
|
}
|
|
5124
5015
|
let centralInReplyToRootMessageId = void 0;
|
|
@@ -5263,8 +5154,8 @@ var messageBusConnectorPlugin = {
|
|
|
5263
5154
|
};
|
|
5264
5155
|
|
|
5265
5156
|
// src/loader.ts
|
|
5266
|
-
import
|
|
5267
|
-
import
|
|
5157
|
+
import fs8 from "fs";
|
|
5158
|
+
import path8 from "path";
|
|
5268
5159
|
import { fileURLToPath } from "url";
|
|
5269
5160
|
import {
|
|
5270
5161
|
logger as logger28,
|
|
@@ -5272,10 +5163,10 @@ import {
|
|
|
5272
5163
|
validateCharacter
|
|
5273
5164
|
} from "@elizaos/core";
|
|
5274
5165
|
var __filename = fileURLToPath(import.meta.url);
|
|
5275
|
-
var __dirname =
|
|
5166
|
+
var __dirname = path8.dirname(__filename);
|
|
5276
5167
|
function tryLoadFile(filePath) {
|
|
5277
5168
|
try {
|
|
5278
|
-
return
|
|
5169
|
+
return fs8.readFileSync(filePath, "utf8");
|
|
5279
5170
|
} catch (e) {
|
|
5280
5171
|
throw new Error(`Error loading file ${filePath}: ${e}`);
|
|
5281
5172
|
}
|
|
@@ -5372,36 +5263,36 @@ async function loadCharacter(filePath) {
|
|
|
5372
5263
|
}
|
|
5373
5264
|
return jsonToCharacter(parseResult.data);
|
|
5374
5265
|
}
|
|
5375
|
-
function handleCharacterLoadError(
|
|
5266
|
+
function handleCharacterLoadError(path10, error) {
|
|
5376
5267
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
5377
5268
|
if (errorMsg.includes("ENOENT") || errorMsg.includes("no such file")) {
|
|
5378
|
-
logger28.error(`Character file not found: ${
|
|
5269
|
+
logger28.error(`Character file not found: ${path10}`);
|
|
5379
5270
|
throw new Error(
|
|
5380
|
-
`Character '${
|
|
5271
|
+
`Character '${path10}' not found. Please check if the file exists and the path is correct.`
|
|
5381
5272
|
);
|
|
5382
5273
|
} else if (errorMsg.includes("Character validation failed")) {
|
|
5383
|
-
logger28.error(`Character validation failed for: ${
|
|
5384
|
-
throw new Error(`Character file '${
|
|
5274
|
+
logger28.error(`Character validation failed for: ${path10}`);
|
|
5275
|
+
throw new Error(`Character file '${path10}' contains invalid character data. ${errorMsg}`);
|
|
5385
5276
|
} else if (errorMsg.includes("JSON")) {
|
|
5386
|
-
logger28.error(`JSON parsing error in character file: ${
|
|
5387
|
-
throw new Error(`Character file '${
|
|
5277
|
+
logger28.error(`JSON parsing error in character file: ${path10}`);
|
|
5278
|
+
throw new Error(`Character file '${path10}' has malformed JSON. Please check the file content.`);
|
|
5388
5279
|
} else if (errorMsg.includes("Invalid JSON")) {
|
|
5389
|
-
logger28.error(`Invalid JSON in character file: ${
|
|
5280
|
+
logger28.error(`Invalid JSON in character file: ${path10}`);
|
|
5390
5281
|
throw new Error(
|
|
5391
|
-
`Character file '${
|
|
5282
|
+
`Character file '${path10}' has invalid JSON format. Please check the file content.`
|
|
5392
5283
|
);
|
|
5393
5284
|
} else {
|
|
5394
|
-
logger28.error(`Error loading character from ${
|
|
5395
|
-
throw new Error(`Failed to load character '${
|
|
5285
|
+
logger28.error(`Error loading character from ${path10}: ${errorMsg}`);
|
|
5286
|
+
throw new Error(`Failed to load character '${path10}': ${errorMsg}`);
|
|
5396
5287
|
}
|
|
5397
5288
|
}
|
|
5398
|
-
async function safeLoadCharacter(
|
|
5289
|
+
async function safeLoadCharacter(path10) {
|
|
5399
5290
|
try {
|
|
5400
|
-
const character = await loadCharacter(
|
|
5401
|
-
logger28.info(`Successfully loaded character from: ${
|
|
5291
|
+
const character = await loadCharacter(path10);
|
|
5292
|
+
logger28.info(`Successfully loaded character from: ${path10}`);
|
|
5402
5293
|
return character;
|
|
5403
5294
|
} catch (e) {
|
|
5404
|
-
return handleCharacterLoadError(
|
|
5295
|
+
return handleCharacterLoadError(path10, e);
|
|
5405
5296
|
}
|
|
5406
5297
|
}
|
|
5407
5298
|
async function loadCharacterTryPath(characterPath) {
|
|
@@ -5421,27 +5312,27 @@ async function loadCharacterTryPath(characterPath) {
|
|
|
5421
5312
|
const jsonPath = hasJsonExtension ? characterPath : `${characterPath}.json`;
|
|
5422
5313
|
const basePathsToTry = [
|
|
5423
5314
|
basePath,
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5315
|
+
path8.resolve(process.cwd(), basePath),
|
|
5316
|
+
path8.resolve(process.cwd(), "..", "..", basePath),
|
|
5317
|
+
path8.resolve(process.cwd(), "..", "..", "..", basePath),
|
|
5318
|
+
path8.resolve(process.cwd(), "agent", basePath),
|
|
5319
|
+
path8.resolve(__dirname, basePath),
|
|
5320
|
+
path8.resolve(__dirname, "characters", path8.basename(basePath)),
|
|
5321
|
+
path8.resolve(__dirname, "../characters", path8.basename(basePath)),
|
|
5322
|
+
path8.resolve(__dirname, "../../characters", path8.basename(basePath)),
|
|
5323
|
+
path8.resolve(__dirname, "../../../characters", path8.basename(basePath))
|
|
5433
5324
|
];
|
|
5434
5325
|
const jsonPathsToTry = hasJsonExtension ? [] : [
|
|
5435
5326
|
jsonPath,
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5327
|
+
path8.resolve(process.cwd(), jsonPath),
|
|
5328
|
+
path8.resolve(process.cwd(), "..", "..", jsonPath),
|
|
5329
|
+
path8.resolve(process.cwd(), "..", "..", "..", jsonPath),
|
|
5330
|
+
path8.resolve(process.cwd(), "agent", jsonPath),
|
|
5331
|
+
path8.resolve(__dirname, jsonPath),
|
|
5332
|
+
path8.resolve(__dirname, "characters", path8.basename(jsonPath)),
|
|
5333
|
+
path8.resolve(__dirname, "../characters", path8.basename(jsonPath)),
|
|
5334
|
+
path8.resolve(__dirname, "../../characters", path8.basename(jsonPath)),
|
|
5335
|
+
path8.resolve(__dirname, "../../../characters", path8.basename(jsonPath))
|
|
5445
5336
|
];
|
|
5446
5337
|
const pathsToTry = Array.from(/* @__PURE__ */ new Set([...basePathsToTry, ...jsonPathsToTry]));
|
|
5447
5338
|
let lastError = null;
|
|
@@ -5466,11 +5357,11 @@ function commaSeparatedStringToArray(commaSeparated) {
|
|
|
5466
5357
|
}
|
|
5467
5358
|
async function readCharactersFromStorage(characterPaths) {
|
|
5468
5359
|
try {
|
|
5469
|
-
const uploadDir =
|
|
5470
|
-
await
|
|
5471
|
-
const fileNames = await
|
|
5360
|
+
const uploadDir = path8.join(process.cwd(), ".eliza", "data", "characters");
|
|
5361
|
+
await fs8.promises.mkdir(uploadDir, { recursive: true });
|
|
5362
|
+
const fileNames = await fs8.promises.readdir(uploadDir);
|
|
5472
5363
|
for (const fileName of fileNames) {
|
|
5473
|
-
characterPaths.push(
|
|
5364
|
+
characterPaths.push(path8.join(uploadDir, fileName));
|
|
5474
5365
|
}
|
|
5475
5366
|
} catch (err) {
|
|
5476
5367
|
logger28.error(`Error reading directory: ${err.message}`);
|
|
@@ -5526,11 +5417,11 @@ function expandTildePath(filepath) {
|
|
|
5526
5417
|
if (filepath === "~") {
|
|
5527
5418
|
return process.cwd();
|
|
5528
5419
|
} else if (filepath.startsWith("~/")) {
|
|
5529
|
-
return
|
|
5420
|
+
return path9.join(process.cwd(), filepath.slice(2));
|
|
5530
5421
|
} else if (filepath.startsWith("~~")) {
|
|
5531
5422
|
return filepath;
|
|
5532
5423
|
} else {
|
|
5533
|
-
return
|
|
5424
|
+
return path9.join(process.cwd(), filepath.slice(1));
|
|
5534
5425
|
}
|
|
5535
5426
|
}
|
|
5536
5427
|
return filepath;
|
|
@@ -5540,11 +5431,11 @@ function resolvePgliteDir(dir, fallbackDir) {
|
|
|
5540
5431
|
if (existsSync3(envPath)) {
|
|
5541
5432
|
dotenv2.config({ path: envPath });
|
|
5542
5433
|
}
|
|
5543
|
-
const base = dir ?? process.env.PGLITE_DATA_DIR ?? fallbackDir ??
|
|
5434
|
+
const base = dir ?? process.env.PGLITE_DATA_DIR ?? fallbackDir ?? path9.join(process.cwd(), ".eliza", ".elizadb");
|
|
5544
5435
|
const resolved = expandTildePath(base);
|
|
5545
|
-
const legacyPath =
|
|
5436
|
+
const legacyPath = path9.join(process.cwd(), ".elizadb");
|
|
5546
5437
|
if (resolved === legacyPath) {
|
|
5547
|
-
const newPath =
|
|
5438
|
+
const newPath = path9.join(process.cwd(), ".eliza", ".elizadb");
|
|
5548
5439
|
process.env.PGLITE_DATA_DIR = newPath;
|
|
5549
5440
|
return newPath;
|
|
5550
5441
|
}
|
|
@@ -5580,6 +5471,46 @@ var AgentServer = class {
|
|
|
5580
5471
|
throw error;
|
|
5581
5472
|
}
|
|
5582
5473
|
}
|
|
5474
|
+
/**
|
|
5475
|
+
* Dynamically resolves the client path based on the installation context.
|
|
5476
|
+
* Handles both development and production scenarios.
|
|
5477
|
+
*
|
|
5478
|
+
* @returns {string} The resolved path to the client dist directory
|
|
5479
|
+
* @throws {Error} If no valid client path can be found
|
|
5480
|
+
*/
|
|
5481
|
+
resolveClientPath() {
|
|
5482
|
+
try {
|
|
5483
|
+
const cliPackageJson = __require.resolve("@elizaos/cli/package.json");
|
|
5484
|
+
const cliDir = path9.dirname(cliPackageJson);
|
|
5485
|
+
const cliDistPath = path9.join(cliDir, "dist");
|
|
5486
|
+
if (fs9.existsSync(path9.join(cliDistPath, "index.html"))) {
|
|
5487
|
+
logger29.debug(`[CLIENT PATH] Resolved client path from npm package: ${cliDistPath}`);
|
|
5488
|
+
return cliDistPath;
|
|
5489
|
+
}
|
|
5490
|
+
} catch (e) {
|
|
5491
|
+
logger29.debug("[CLIENT PATH] Could not resolve @elizaos/cli package, trying other methods");
|
|
5492
|
+
}
|
|
5493
|
+
const relativePath = path9.resolve(__dirname2, "../../cli/dist");
|
|
5494
|
+
if (fs9.existsSync(path9.join(relativePath, "index.html"))) {
|
|
5495
|
+
logger29.debug(`[CLIENT PATH] Resolved client path from relative path: ${relativePath}`);
|
|
5496
|
+
return relativePath;
|
|
5497
|
+
}
|
|
5498
|
+
const cwdPath = path9.join(process.cwd(), "dist");
|
|
5499
|
+
if (fs9.existsSync(path9.join(cwdPath, "index.html"))) {
|
|
5500
|
+
logger29.debug(`[CLIENT PATH] Resolved client path from current directory: ${cwdPath}`);
|
|
5501
|
+
return cwdPath;
|
|
5502
|
+
}
|
|
5503
|
+
if (process.env.ELIZA_CLIENT_PATH) {
|
|
5504
|
+
const envPath = path9.resolve(process.env.ELIZA_CLIENT_PATH);
|
|
5505
|
+
if (fs9.existsSync(path9.join(envPath, "index.html"))) {
|
|
5506
|
+
logger29.debug(`[CLIENT PATH] Resolved client path from environment variable: ${envPath}`);
|
|
5507
|
+
return envPath;
|
|
5508
|
+
}
|
|
5509
|
+
}
|
|
5510
|
+
throw new Error(
|
|
5511
|
+
"Unable to locate client files. Please ensure @elizaos/cli is properly installed."
|
|
5512
|
+
);
|
|
5513
|
+
}
|
|
5583
5514
|
/**
|
|
5584
5515
|
* Initializes the database and server.
|
|
5585
5516
|
*
|
|
@@ -5784,26 +5715,10 @@ var AgentServer = class {
|
|
|
5784
5715
|
})
|
|
5785
5716
|
);
|
|
5786
5717
|
this.app.use(
|
|
5787
|
-
|
|
5718
|
+
express30.json({
|
|
5788
5719
|
limit: process.env.EXPRESS_MAX_PAYLOAD || "100kb"
|
|
5789
5720
|
})
|
|
5790
5721
|
);
|
|
5791
|
-
this.app.use(
|
|
5792
|
-
fileUpload2({
|
|
5793
|
-
useTempFiles: true,
|
|
5794
|
-
tempFileDir: "/tmp/",
|
|
5795
|
-
createParentPath: true,
|
|
5796
|
-
preserveExtension: true,
|
|
5797
|
-
safeFileNames: true,
|
|
5798
|
-
limits: {
|
|
5799
|
-
fileSize: 50 * 1024 * 1024
|
|
5800
|
-
// 50MB default limit
|
|
5801
|
-
},
|
|
5802
|
-
abortOnLimit: true,
|
|
5803
|
-
uploadTimeout: 6e4
|
|
5804
|
-
// 60 seconds
|
|
5805
|
-
})
|
|
5806
|
-
);
|
|
5807
5722
|
const serverAuthToken = process.env.ELIZA_SERVER_AUTH_TOKEN;
|
|
5808
5723
|
if (serverAuthToken) {
|
|
5809
5724
|
logger29.info("Server authentication enabled. Requires X-API-KEY header for /api routes.");
|
|
@@ -5815,10 +5730,10 @@ var AgentServer = class {
|
|
|
5815
5730
|
"Server authentication is disabled. Set ELIZA_SERVER_AUTH_TOKEN environment variable to enable."
|
|
5816
5731
|
);
|
|
5817
5732
|
}
|
|
5818
|
-
const uploadsBasePath =
|
|
5819
|
-
const generatedBasePath =
|
|
5820
|
-
|
|
5821
|
-
|
|
5733
|
+
const uploadsBasePath = path9.join(process.cwd(), ".eliza", "data", "uploads", "agents");
|
|
5734
|
+
const generatedBasePath = path9.join(process.cwd(), ".eliza", "data", "generated");
|
|
5735
|
+
fs9.mkdirSync(uploadsBasePath, { recursive: true });
|
|
5736
|
+
fs9.mkdirSync(generatedBasePath, { recursive: true });
|
|
5822
5737
|
this.app.get(
|
|
5823
5738
|
"/media/uploads/agents/:agentId/:filename",
|
|
5824
5739
|
// @ts-expect-error - this is a valid express route
|
|
@@ -5835,7 +5750,7 @@ var AgentServer = class {
|
|
|
5835
5750
|
if (!filePath.startsWith(agentUploadsPath)) {
|
|
5836
5751
|
return res.status(403).json({ error: "Access denied" });
|
|
5837
5752
|
}
|
|
5838
|
-
if (!
|
|
5753
|
+
if (!fs9.existsSync(filePath)) {
|
|
5839
5754
|
return res.status(404).json({ error: "File does not exist!!!!!!!" });
|
|
5840
5755
|
}
|
|
5841
5756
|
res.sendFile(sanitizedFilename, { root: agentUploadsPath }, (err) => {
|
|
@@ -5939,8 +5854,14 @@ var AgentServer = class {
|
|
|
5939
5854
|
}
|
|
5940
5855
|
}
|
|
5941
5856
|
};
|
|
5942
|
-
|
|
5943
|
-
|
|
5857
|
+
try {
|
|
5858
|
+
const clientPath = this.resolveClientPath();
|
|
5859
|
+
this.app.use(express30.static(clientPath, staticOptions));
|
|
5860
|
+
logger29.info(`[STATIC] Serving client files from: ${clientPath}`);
|
|
5861
|
+
} catch (error) {
|
|
5862
|
+
logger29.error("[STATIC] Failed to resolve client path:", error);
|
|
5863
|
+
logger29.warn("[STATIC] Client UI will not be available. API endpoints will still work.");
|
|
5864
|
+
}
|
|
5944
5865
|
const pluginRouteHandler = createPluginRouteHandler(this.agents);
|
|
5945
5866
|
this.app.use(pluginRouteHandler);
|
|
5946
5867
|
const apiRouter = createApiRouter(this.agents, this);
|
|
@@ -5982,8 +5903,30 @@ var AgentServer = class {
|
|
|
5982
5903
|
res.setHeader("Content-Type", "application/javascript");
|
|
5983
5904
|
return res.status(404).send(`// JavaScript module not found: ${req.path}`);
|
|
5984
5905
|
}
|
|
5985
|
-
|
|
5986
|
-
|
|
5906
|
+
try {
|
|
5907
|
+
const cliDistPath = this.resolveClientPath();
|
|
5908
|
+
res.sendFile(path9.join(cliDistPath, "index.html"), (err) => {
|
|
5909
|
+
if (err && !res.headersSent) {
|
|
5910
|
+
logger29.error("[STATIC] Failed to serve index.html:", err);
|
|
5911
|
+
res.status(404).json({
|
|
5912
|
+
success: false,
|
|
5913
|
+
error: {
|
|
5914
|
+
message: "Client UI not available. Please ensure @elizaos/cli is properly installed.",
|
|
5915
|
+
code: 404
|
|
5916
|
+
}
|
|
5917
|
+
});
|
|
5918
|
+
}
|
|
5919
|
+
});
|
|
5920
|
+
} catch (error) {
|
|
5921
|
+
logger29.error("[STATIC] Failed to resolve client path for fallback route:", error);
|
|
5922
|
+
res.status(404).json({
|
|
5923
|
+
success: false,
|
|
5924
|
+
error: {
|
|
5925
|
+
message: "Client UI not available. API endpoints are still accessible at /api/*",
|
|
5926
|
+
code: 404
|
|
5927
|
+
}
|
|
5928
|
+
});
|
|
5929
|
+
}
|
|
5987
5930
|
});
|
|
5988
5931
|
this.server = http.createServer(this.app);
|
|
5989
5932
|
this.socketIO = setupSocketIO(this.server, this.agents, this);
|