@elizaos/server 1.0.12 → 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 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 fs6 from "fs";
386
+ import * as fs9 from "fs";
389
387
  import http from "http";
390
- import path6, { basename, dirname, extname, join } from "path";
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
@@ -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 agent = await db.getAgent(agentId);
528
- if (!agent) {
528
+ let agent2 = await db.getAgent(agentId);
529
+ if (!agent2) {
529
530
  await db.createAgent({ ...character2, id: agentId });
530
- agent = await db.getAgent(agentId);
531
+ agent2 = await db.getAgent(agentId);
531
532
  }
532
- return agent;
533
+ return agent2;
533
534
  };
534
535
  const newAgent = await ensureAgentExists(character);
535
536
  if (!newAgent) {
@@ -1183,6 +1184,30 @@ 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
+ });
1186
1211
  return router;
1187
1212
  }
1188
1213
 
@@ -1683,189 +1708,16 @@ import {
1683
1708
  composePromptFromState,
1684
1709
  ModelType,
1685
1710
  ChannelType as ChannelType2,
1686
- logger as logger14,
1687
- validateUuid as validateUuid13
1711
+ logger as logger12,
1712
+ validateUuid as validateUuid12
1688
1713
  } from "@elizaos/core";
1689
1714
  import express11 from "express";
1690
1715
 
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
1716
  // src/api/shared/middleware.ts
1865
- import { validateUuid as validateUuid12, logger as logger13 } from "@elizaos/core";
1717
+ import { validateUuid as validateUuid11, logger as logger11 } from "@elizaos/core";
1866
1718
 
1867
1719
  // src/api/shared/validation.ts
1868
- import { validateUuid as validateUuid11, logger as logger12 } from "@elizaos/core";
1720
+ import { validateUuid as validateUuid10, logger as logger10 } from "@elizaos/core";
1869
1721
  var getRuntime = (agents, agentId) => {
1870
1722
  const runtime = agents.get(agentId);
1871
1723
  if (!runtime) {
@@ -1889,7 +1741,7 @@ var securityMiddleware = () => {
1889
1741
  const realIp = req.get("X-Real-IP");
1890
1742
  const clientIp = forwarded || realIp || req.ip;
1891
1743
  if (userAgent && (userAgent.includes("..") || userAgent.includes("<script"))) {
1892
- logger13.warn(`[SECURITY] Suspicious User-Agent from ${clientIp}: ${userAgent}`);
1744
+ logger11.warn(`[SECURITY] Suspicious User-Agent from ${clientIp}: ${userAgent}`);
1893
1745
  }
1894
1746
  const url = req.originalUrl || req.url;
1895
1747
  const queryString = JSON.stringify(req.query);
@@ -1915,12 +1767,12 @@ var securityMiddleware = () => {
1915
1767
  }
1916
1768
  for (const indicator of suspiciousIndicators) {
1917
1769
  if (url.includes(indicator.pattern) || queryString.includes(indicator.pattern)) {
1918
- logger13.warn(`[SECURITY] ${indicator.name} detected from ${clientIp}: ${url}`);
1770
+ logger11.warn(`[SECURITY] ${indicator.name} detected from ${clientIp}: ${url}`);
1919
1771
  break;
1920
1772
  }
1921
1773
  }
1922
1774
  if (hasSqlPattern) {
1923
- logger13.warn(`[SECURITY] SQL injection pattern detected from ${clientIp}: ${url}`);
1775
+ logger11.warn(`[SECURITY] SQL injection pattern detected from ${clientIp}: ${url}`);
1924
1776
  }
1925
1777
  next();
1926
1778
  };
@@ -1969,7 +1821,7 @@ var createApiRateLimit = () => {
1969
1821
  // Disable the `X-RateLimit-*` headers
1970
1822
  handler: (req, res) => {
1971
1823
  const clientIp = req.ip || "unknown";
1972
- logger13.warn(`[SECURITY] Rate limit exceeded for IP: ${clientIp}`);
1824
+ logger11.warn(`[SECURITY] Rate limit exceeded for IP: ${clientIp}`);
1973
1825
  res.status(429).json({
1974
1826
  success: false,
1975
1827
  error: {
@@ -1997,7 +1849,7 @@ var createFileSystemRateLimit = () => {
1997
1849
  legacyHeaders: false,
1998
1850
  handler: (req, res) => {
1999
1851
  const clientIp = req.ip || "unknown";
2000
- logger13.warn(
1852
+ logger11.warn(
2001
1853
  `[SECURITY] File system rate limit exceeded for IP: ${clientIp}, endpoint: ${req.path}`
2002
1854
  );
2003
1855
  res.status(429).json({
@@ -2027,7 +1879,7 @@ var createUploadRateLimit = () => {
2027
1879
  legacyHeaders: false,
2028
1880
  handler: (req, res) => {
2029
1881
  const clientIp = req.ip || "unknown";
2030
- logger13.warn(
1882
+ logger11.warn(
2031
1883
  `[SECURITY] Upload rate limit exceeded for IP: ${clientIp}, endpoint: ${req.path}`
2032
1884
  );
2033
1885
  res.status(429).json({
@@ -2041,14 +1893,73 @@ var createUploadRateLimit = () => {
2041
1893
  });
2042
1894
  };
2043
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
+
2044
1923
  // src/api/messaging/channels.ts
1924
+ import multer from "multer";
1925
+ import fs from "fs";
1926
+ import path from "path";
2045
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
+ }
2046
1957
  function createChannelsRouter(agents, serverInstance) {
2047
1958
  const router = express11.Router();
2048
1959
  router.post(
2049
1960
  "/central-channels/:channelId/messages",
2050
1961
  async (req, res) => {
2051
- const channelIdParam = validateUuid13(req.params.channelId);
1962
+ const channelIdParam = validateUuid12(req.params.channelId);
2052
1963
  const {
2053
1964
  author_id,
2054
1965
  // This is the GUI user's central ID
@@ -2063,40 +1974,40 @@ function createChannelsRouter(agents, serverInstance) {
2063
1974
  source_type
2064
1975
  // Should be something like 'eliza_gui'
2065
1976
  } = req.body;
2066
- const isValidServerId = server_id === DEFAULT_SERVER_ID3 || validateUuid13(server_id);
2067
- if (!channelIdParam || !validateUuid13(author_id) || !content || !isValidServerId) {
1977
+ const isValidServerId = server_id === DEFAULT_SERVER_ID3 || validateUuid12(server_id);
1978
+ if (!channelIdParam || !validateUuid12(author_id) || !content || !isValidServerId) {
2068
1979
  return res.status(400).json({
2069
1980
  success: false,
2070
1981
  error: "Missing required fields: channelId, server_id, author_id, content"
2071
1982
  });
2072
1983
  }
2073
1984
  try {
2074
- logger14.info(
1985
+ logger12.info(
2075
1986
  `[Messages Router] Checking if channel ${channelIdParam} exists before creating message`
2076
1987
  );
2077
1988
  let channelExists = false;
2078
1989
  try {
2079
1990
  const existingChannel = await serverInstance.getChannelDetails(channelIdParam);
2080
1991
  channelExists = !!existingChannel;
2081
- logger14.info(`[Messages Router] Channel ${channelIdParam} exists: ${channelExists}`);
1992
+ logger12.info(`[Messages Router] Channel ${channelIdParam} exists: ${channelExists}`);
2082
1993
  } catch (error) {
2083
1994
  const errorMessage = error instanceof Error ? error.message : String(error);
2084
- logger14.info(
1995
+ logger12.info(
2085
1996
  `[Messages Router] Channel ${channelIdParam} does not exist, will create it. Error: ${errorMessage}`
2086
1997
  );
2087
1998
  }
2088
1999
  if (!channelExists) {
2089
- logger14.info(
2000
+ logger12.info(
2090
2001
  `[Messages Router] Auto-creating channel ${channelIdParam} with serverId ${server_id}`
2091
2002
  );
2092
2003
  try {
2093
2004
  const servers = await serverInstance.getServers();
2094
2005
  const serverExists = servers.some((s) => s.id === server_id);
2095
- logger14.info(
2006
+ logger12.info(
2096
2007
  `[Messages Router] Server ${server_id} exists: ${serverExists}. Available servers: ${servers.map((s) => s.id).join(", ")}`
2097
2008
  );
2098
2009
  if (!serverExists) {
2099
- logger14.error(
2010
+ logger12.error(
2100
2011
  `[Messages Router] Server ${server_id} does not exist, cannot create channel`
2101
2012
  );
2102
2013
  return res.status(500).json({ success: false, error: `Server ${server_id} does not exist` });
@@ -2117,38 +2028,38 @@ function createChannelsRouter(agents, serverInstance) {
2117
2028
  ...metadata
2118
2029
  }
2119
2030
  };
2120
- logger14.info(
2031
+ logger12.info(
2121
2032
  "[Messages Router] Creating channel with data:",
2122
2033
  JSON.stringify(channelData, null, 2)
2123
2034
  );
2124
2035
  const participants = [author_id];
2125
2036
  if (isDmChannel) {
2126
2037
  const otherParticipant = metadata?.targetUserId || metadata?.recipientId;
2127
- if (otherParticipant && validateUuid13(otherParticipant)) {
2038
+ if (otherParticipant && validateUuid12(otherParticipant)) {
2128
2039
  participants.push(otherParticipant);
2129
- logger14.info(
2040
+ logger12.info(
2130
2041
  `[Messages Router] DM channel will include participants: ${participants.join(", ")}`
2131
2042
  );
2132
2043
  } else {
2133
- logger14.warn(
2044
+ logger12.warn(
2134
2045
  `[Messages Router] DM channel missing second participant, only adding author: ${author_id}`
2135
2046
  );
2136
2047
  }
2137
2048
  }
2138
2049
  await serverInstance.createChannel(channelData, participants);
2139
- logger14.info(
2050
+ logger12.info(
2140
2051
  `[Messages Router] Auto-created ${isDmChannel ? ChannelType2.DM : ChannelType2.GROUP} channel ${channelIdParam} for message submission with ${participants.length} participants`
2141
2052
  );
2142
2053
  } catch (createError) {
2143
2054
  const errorMessage = createError instanceof Error ? createError.message : String(createError);
2144
- logger14.error(
2055
+ logger12.error(
2145
2056
  `[Messages Router] Failed to auto-create channel ${channelIdParam}:`,
2146
2057
  createError
2147
2058
  );
2148
2059
  return res.status(500).json({ success: false, error: `Failed to create channel: ${errorMessage}` });
2149
2060
  }
2150
2061
  } else {
2151
- logger14.info(
2062
+ logger12.info(
2152
2063
  `[Messages Router] Channel ${channelIdParam} already exists, proceeding with message creation`
2153
2064
  );
2154
2065
  }
@@ -2156,7 +2067,7 @@ function createChannelsRouter(agents, serverInstance) {
2156
2067
  channelId: channelIdParam,
2157
2068
  authorId: author_id,
2158
2069
  content,
2159
- inReplyToRootMessageId: in_reply_to_message_id ? validateUuid13(in_reply_to_message_id) || void 0 : void 0,
2070
+ inReplyToRootMessageId: in_reply_to_message_id ? validateUuid12(in_reply_to_message_id) || void 0 : void 0,
2160
2071
  rawMessage: raw_message,
2161
2072
  metadata,
2162
2073
  sourceType: source_type || "eliza_gui"
@@ -2182,7 +2093,7 @@ function createChannelsRouter(agents, serverInstance) {
2182
2093
  // Will be undefined here, which is fine
2183
2094
  };
2184
2095
  bus_default.emit("new_message", messageForBus);
2185
- logger14.info(
2096
+ logger12.info(
2186
2097
  "[Messages Router /central-channels/:channelId/messages] GUI Message published to internal bus:",
2187
2098
  messageForBus.id
2188
2099
  );
@@ -2202,7 +2113,7 @@ function createChannelsRouter(agents, serverInstance) {
2202
2113
  }
2203
2114
  res.status(201).json({ success: true, data: messageForBus });
2204
2115
  } catch (error) {
2205
- logger14.error(
2116
+ logger12.error(
2206
2117
  "[Messages Router /central-channels/:channelId/messages] Error processing GUI message:",
2207
2118
  error
2208
2119
  );
@@ -2213,7 +2124,7 @@ function createChannelsRouter(agents, serverInstance) {
2213
2124
  router.get(
2214
2125
  "/central-channels/:channelId/messages",
2215
2126
  async (req, res) => {
2216
- const channelId = validateUuid13(req.params.channelId);
2127
+ const channelId = validateUuid12(req.params.channelId);
2217
2128
  const limit = req.query.limit ? Number.parseInt(req.query.limit, 10) : 50;
2218
2129
  const before = req.query.before ? Number.parseInt(req.query.before, 10) : void 0;
2219
2130
  const beforeDate = before ? new Date(before) : void 0;
@@ -2240,7 +2151,7 @@ function createChannelsRouter(agents, serverInstance) {
2240
2151
  });
2241
2152
  res.json({ success: true, data: { messages: messagesForGui } });
2242
2153
  } catch (error) {
2243
- logger14.error(
2154
+ logger12.error(
2244
2155
  `[Messages Router /central-channels/:channelId/messages] Error fetching messages for channel ${channelId}:`,
2245
2156
  error
2246
2157
  );
@@ -2251,7 +2162,7 @@ function createChannelsRouter(agents, serverInstance) {
2251
2162
  router.get(
2252
2163
  "/central-servers/:serverId/channels",
2253
2164
  async (req, res) => {
2254
- const serverId = req.params.serverId === DEFAULT_SERVER_ID3 ? DEFAULT_SERVER_ID3 : validateUuid13(req.params.serverId);
2165
+ const serverId = req.params.serverId === DEFAULT_SERVER_ID3 ? DEFAULT_SERVER_ID3 : validateUuid12(req.params.serverId);
2255
2166
  if (!serverId) {
2256
2167
  return res.status(400).json({ success: false, error: "Invalid serverId" });
2257
2168
  }
@@ -2259,7 +2170,7 @@ function createChannelsRouter(agents, serverInstance) {
2259
2170
  const channels = await serverInstance.getChannelsForServer(serverId);
2260
2171
  res.json({ success: true, data: { channels } });
2261
2172
  } catch (error) {
2262
- logger14.error(
2173
+ logger12.error(
2263
2174
  `[Messages Router /central-servers/:serverId/channels] Error fetching channels for server ${serverId}:`,
2264
2175
  error
2265
2176
  );
@@ -2289,7 +2200,7 @@ function createChannelsRouter(agents, serverInstance) {
2289
2200
  error: "Missing required fields: type."
2290
2201
  });
2291
2202
  }
2292
- if (!validateUuid13(serverId)) {
2203
+ if (!validateUuid12(serverId)) {
2293
2204
  return res.status(400).json({
2294
2205
  success: false,
2295
2206
  error: "Invalid serverId format"
@@ -2307,14 +2218,14 @@ function createChannelsRouter(agents, serverInstance) {
2307
2218
  });
2308
2219
  res.status(201).json({ success: true, data: { channel } });
2309
2220
  } catch (error) {
2310
- logger14.error("[Messages Router /channels] Error creating channel:", error);
2221
+ logger12.error("[Messages Router /channels] Error creating channel:", error);
2311
2222
  res.status(500).json({ success: false, error: "Failed to create channel" });
2312
2223
  }
2313
2224
  });
2314
2225
  router.get("/dm-channel", async (req, res) => {
2315
- const targetUserId = validateUuid13(req.query.targetUserId);
2316
- const currentUserId = validateUuid13(req.query.currentUserId);
2317
- const providedDmServerId = req.query.dmServerId === DEFAULT_SERVER_ID3 ? DEFAULT_SERVER_ID3 : validateUuid13(req.query.dmServerId);
2226
+ const targetUserId = validateUuid12(req.query.targetUserId);
2227
+ const currentUserId = validateUuid12(req.query.currentUserId);
2228
+ const providedDmServerId = req.query.dmServerId === DEFAULT_SERVER_ID3 ? DEFAULT_SERVER_ID3 : validateUuid12(req.query.dmServerId);
2318
2229
  if (!targetUserId || !currentUserId) {
2319
2230
  res.status(400).json({ success: false, error: "Missing targetUserId or currentUserId" });
2320
2231
  return;
@@ -2330,7 +2241,7 @@ function createChannelsRouter(agents, serverInstance) {
2330
2241
  if (existingServer) {
2331
2242
  dmServerIdToUse = providedDmServerId;
2332
2243
  } else {
2333
- logger14.warn(
2244
+ logger12.warn(
2334
2245
  `Provided dmServerId ${providedDmServerId} not found, using default DM server logic.`
2335
2246
  );
2336
2247
  dmServerIdToUse = DEFAULT_SERVER_ID3;
@@ -2348,7 +2259,7 @@ function createChannelsRouter(agents, serverInstance) {
2348
2259
  stack: error.stack,
2349
2260
  originalError: error
2350
2261
  } : { message: String(error) };
2351
- logger14.error("Error finding/creating DM channel:", errorDetails);
2262
+ logger12.error("Error finding/creating DM channel:", errorDetails);
2352
2263
  res.status(500).json({ success: false, error: "Failed to find or create DM channel" });
2353
2264
  }
2354
2265
  });
@@ -2360,8 +2271,8 @@ function createChannelsRouter(agents, serverInstance) {
2360
2271
  server_id,
2361
2272
  metadata
2362
2273
  } = req.body;
2363
- const isValidServerId = server_id === DEFAULT_SERVER_ID3 || validateUuid13(server_id);
2364
- if (!name || !isValidServerId || !Array.isArray(participantCentralUserIds) || participantCentralUserIds.some((id) => !validateUuid13(id))) {
2274
+ const isValidServerId = server_id === DEFAULT_SERVER_ID3 || validateUuid12(server_id);
2275
+ if (!name || !isValidServerId || !Array.isArray(participantCentralUserIds) || participantCentralUserIds.some((id) => !validateUuid12(id))) {
2365
2276
  return res.status(400).json({
2366
2277
  success: false,
2367
2278
  error: 'Invalid payload. Required: name, server_id (UUID or "0"), participantCentralUserIds (array of UUIDs). Optional: type, metadata.'
@@ -2384,7 +2295,7 @@ function createChannelsRouter(agents, serverInstance) {
2384
2295
  res.status(201).json({ success: true, data: newChannel });
2385
2296
  } catch (error) {
2386
2297
  const errorMessage = error instanceof Error ? error.message : String(error);
2387
- logger14.error(
2298
+ logger12.error(
2388
2299
  "[Messages Router /central-channels] Error creating group channel:",
2389
2300
  errorMessage
2390
2301
  );
@@ -2394,7 +2305,7 @@ function createChannelsRouter(agents, serverInstance) {
2394
2305
  router.get(
2395
2306
  "/central-channels/:channelId/details",
2396
2307
  async (req, res) => {
2397
- const channelId = validateUuid13(req.params.channelId);
2308
+ const channelId = validateUuid12(req.params.channelId);
2398
2309
  if (!channelId) {
2399
2310
  return res.status(400).json({ success: false, error: "Invalid channelId" });
2400
2311
  }
@@ -2405,7 +2316,7 @@ function createChannelsRouter(agents, serverInstance) {
2405
2316
  }
2406
2317
  res.json({ success: true, data: channelDetails });
2407
2318
  } catch (error) {
2408
- logger14.error(`[Messages Router] Error fetching details for channel ${channelId}:`, error);
2319
+ logger12.error(`[Messages Router] Error fetching details for channel ${channelId}:`, error);
2409
2320
  res.status(500).json({ success: false, error: "Failed to fetch channel details" });
2410
2321
  }
2411
2322
  }
@@ -2413,7 +2324,7 @@ function createChannelsRouter(agents, serverInstance) {
2413
2324
  router.get(
2414
2325
  "/central-channels/:channelId/participants",
2415
2326
  async (req, res) => {
2416
- const channelId = validateUuid13(req.params.channelId);
2327
+ const channelId = validateUuid12(req.params.channelId);
2417
2328
  if (!channelId) {
2418
2329
  return res.status(400).json({ success: false, error: "Invalid channelId" });
2419
2330
  }
@@ -2421,7 +2332,7 @@ function createChannelsRouter(agents, serverInstance) {
2421
2332
  const participants = await serverInstance.getChannelParticipants(channelId);
2422
2333
  res.json({ success: true, data: participants });
2423
2334
  } catch (error) {
2424
- logger14.error(
2335
+ logger12.error(
2425
2336
  `[Messages Router] Error fetching participants for channel ${channelId}:`,
2426
2337
  error
2427
2338
  );
@@ -2432,9 +2343,9 @@ function createChannelsRouter(agents, serverInstance) {
2432
2343
  router.post(
2433
2344
  "/central-channels/:channelId/agents",
2434
2345
  async (req, res) => {
2435
- const channelId = validateUuid13(req.params.channelId);
2346
+ const channelId = validateUuid12(req.params.channelId);
2436
2347
  const { agentId } = req.body;
2437
- if (!channelId || !validateUuid13(agentId)) {
2348
+ if (!channelId || !validateUuid12(agentId)) {
2438
2349
  return res.status(400).json({
2439
2350
  success: false,
2440
2351
  error: "Invalid channelId or agentId format"
@@ -2449,7 +2360,7 @@ function createChannelsRouter(agents, serverInstance) {
2449
2360
  });
2450
2361
  }
2451
2362
  await serverInstance.addParticipantsToChannel(channelId, [agentId]);
2452
- logger14.info(`[Messages Router] Added agent ${agentId} to channel ${channelId}`);
2363
+ logger12.info(`[Messages Router] Added agent ${agentId} to channel ${channelId}`);
2453
2364
  res.status(201).json({
2454
2365
  success: true,
2455
2366
  data: {
@@ -2459,7 +2370,7 @@ function createChannelsRouter(agents, serverInstance) {
2459
2370
  }
2460
2371
  });
2461
2372
  } catch (error) {
2462
- logger14.error(
2373
+ logger12.error(
2463
2374
  `[Messages Router] Error adding agent ${agentId} to channel ${channelId}:`,
2464
2375
  error
2465
2376
  );
@@ -2474,8 +2385,8 @@ function createChannelsRouter(agents, serverInstance) {
2474
2385
  router.delete(
2475
2386
  "/central-channels/:channelId/agents/:agentId",
2476
2387
  async (req, res) => {
2477
- const channelId = validateUuid13(req.params.channelId);
2478
- const agentId = validateUuid13(req.params.agentId);
2388
+ const channelId = validateUuid12(req.params.channelId);
2389
+ const agentId = validateUuid12(req.params.agentId);
2479
2390
  if (!channelId || !agentId) {
2480
2391
  return res.status(400).json({
2481
2392
  success: false,
@@ -2501,7 +2412,7 @@ function createChannelsRouter(agents, serverInstance) {
2501
2412
  await serverInstance.updateChannel(channelId, {
2502
2413
  participantCentralUserIds: updatedParticipants
2503
2414
  });
2504
- logger14.info(`[Messages Router] Removed agent ${agentId} from channel ${channelId}`);
2415
+ logger12.info(`[Messages Router] Removed agent ${agentId} from channel ${channelId}`);
2505
2416
  res.status(200).json({
2506
2417
  success: true,
2507
2418
  data: {
@@ -2511,7 +2422,7 @@ function createChannelsRouter(agents, serverInstance) {
2511
2422
  }
2512
2423
  });
2513
2424
  } catch (error) {
2514
- logger14.error(
2425
+ logger12.error(
2515
2426
  `[Messages Router] Error removing agent ${agentId} from channel ${channelId}:`,
2516
2427
  error
2517
2428
  );
@@ -2526,7 +2437,7 @@ function createChannelsRouter(agents, serverInstance) {
2526
2437
  router.get(
2527
2438
  "/central-channels/:channelId/agents",
2528
2439
  async (req, res) => {
2529
- const channelId = validateUuid13(req.params.channelId);
2440
+ const channelId = validateUuid12(req.params.channelId);
2530
2441
  if (!channelId) {
2531
2442
  return res.status(400).json({
2532
2443
  success: false,
@@ -2545,7 +2456,7 @@ function createChannelsRouter(agents, serverInstance) {
2545
2456
  }
2546
2457
  });
2547
2458
  } catch (error) {
2548
- logger14.error(`[Messages Router] Error fetching agents for channel ${channelId}:`, error);
2459
+ logger12.error(`[Messages Router] Error fetching agents for channel ${channelId}:`, error);
2549
2460
  res.status(500).json({
2550
2461
  success: false,
2551
2462
  error: "Failed to fetch channel agents"
@@ -2556,20 +2467,20 @@ function createChannelsRouter(agents, serverInstance) {
2556
2467
  router.delete(
2557
2468
  "/central-channels/:channelId/messages/:messageId",
2558
2469
  async (req, res) => {
2559
- const channelId = validateUuid13(req.params.channelId);
2560
- const messageId = validateUuid13(req.params.messageId);
2470
+ const channelId = validateUuid12(req.params.channelId);
2471
+ const messageId = validateUuid12(req.params.messageId);
2561
2472
  if (!channelId || !messageId) {
2562
2473
  return res.status(400).json({ success: false, error: "Invalid channelId or messageId" });
2563
2474
  }
2564
2475
  try {
2565
2476
  await serverInstance.deleteMessage(messageId);
2566
- logger14.info(`[Messages Router] Deleted message ${messageId} from central database`);
2477
+ logger12.info(`[Messages Router] Deleted message ${messageId} from central database`);
2567
2478
  const deletedMessagePayload = {
2568
2479
  messageId,
2569
2480
  channelId
2570
2481
  };
2571
2482
  bus_default.emit("message_deleted", deletedMessagePayload);
2572
- logger14.info(
2483
+ logger12.info(
2573
2484
  `[Messages Router] Emitted message_deleted event to internal bus for message ${messageId}`
2574
2485
  );
2575
2486
  if (serverInstance.socketIO) {
@@ -2580,7 +2491,7 @@ function createChannelsRouter(agents, serverInstance) {
2580
2491
  }
2581
2492
  res.status(204).send();
2582
2493
  } catch (error) {
2583
- logger14.error(
2494
+ logger12.error(
2584
2495
  `[Messages Router] Error deleting message ${messageId} from channel ${channelId}:`,
2585
2496
  error
2586
2497
  );
@@ -2591,7 +2502,7 @@ function createChannelsRouter(agents, serverInstance) {
2591
2502
  router.delete(
2592
2503
  "/central-channels/:channelId/messages",
2593
2504
  async (req, res) => {
2594
- const channelId = validateUuid13(req.params.channelId);
2505
+ const channelId = validateUuid12(req.params.channelId);
2595
2506
  if (!channelId) {
2596
2507
  return res.status(400).json({ success: false, error: "Invalid channelId" });
2597
2508
  }
@@ -2601,7 +2512,7 @@ function createChannelsRouter(agents, serverInstance) {
2601
2512
  channelId
2602
2513
  };
2603
2514
  bus_default.emit("channel_cleared", channelClearedPayload);
2604
- logger14.info(
2515
+ logger12.info(
2605
2516
  `[Messages Router] Emitted channel_cleared event to internal bus for channel ${channelId}`
2606
2517
  );
2607
2518
  if (serverInstance.socketIO) {
@@ -2611,7 +2522,7 @@ function createChannelsRouter(agents, serverInstance) {
2611
2522
  }
2612
2523
  res.status(204).send();
2613
2524
  } catch (error) {
2614
- logger14.error(`[Messages Router] Error clearing messages for channel ${channelId}:`, error);
2525
+ logger12.error(`[Messages Router] Error clearing messages for channel ${channelId}:`, error);
2615
2526
  res.status(500).json({ success: false, error: "Failed to clear messages" });
2616
2527
  }
2617
2528
  }
@@ -2619,7 +2530,7 @@ function createChannelsRouter(agents, serverInstance) {
2619
2530
  router.patch(
2620
2531
  "/central-channels/:channelId",
2621
2532
  async (req, res) => {
2622
- const channelId = validateUuid13(req.params.channelId);
2533
+ const channelId = validateUuid12(req.params.channelId);
2623
2534
  if (!channelId) {
2624
2535
  return res.status(400).json({ success: false, error: "Invalid channelId" });
2625
2536
  }
@@ -2638,7 +2549,7 @@ function createChannelsRouter(agents, serverInstance) {
2638
2549
  }
2639
2550
  res.json({ success: true, data: updatedChannel });
2640
2551
  } catch (error) {
2641
- logger14.error(`[Messages Router] Error updating channel ${channelId}:`, error);
2552
+ logger12.error(`[Messages Router] Error updating channel ${channelId}:`, error);
2642
2553
  res.status(500).json({ success: false, error: "Failed to update channel" });
2643
2554
  }
2644
2555
  }
@@ -2646,7 +2557,7 @@ function createChannelsRouter(agents, serverInstance) {
2646
2557
  router.delete(
2647
2558
  "/central-channels/:channelId",
2648
2559
  async (req, res) => {
2649
- const channelId = validateUuid13(req.params.channelId);
2560
+ const channelId = validateUuid12(req.params.channelId);
2650
2561
  if (!channelId) {
2651
2562
  return res.status(400).json({ success: false, error: "Invalid channelId" });
2652
2563
  }
@@ -2654,14 +2565,14 @@ function createChannelsRouter(agents, serverInstance) {
2654
2565
  const messages = await serverInstance.getMessagesForChannel(channelId);
2655
2566
  const messageCount = messages.length;
2656
2567
  await serverInstance.deleteChannel(channelId);
2657
- logger14.info(
2568
+ logger12.info(
2658
2569
  `[Messages Router] Deleted channel ${channelId} with ${messageCount} messages from central database`
2659
2570
  );
2660
2571
  const channelClearedPayload = {
2661
2572
  channelId
2662
2573
  };
2663
2574
  bus_default.emit("channel_cleared", channelClearedPayload);
2664
- logger14.info(
2575
+ logger12.info(
2665
2576
  `[Messages Router] Emitted channel_cleared event to internal bus for deleted channel ${channelId}`
2666
2577
  );
2667
2578
  if (serverInstance.socketIO) {
@@ -2671,7 +2582,7 @@ function createChannelsRouter(agents, serverInstance) {
2671
2582
  }
2672
2583
  res.status(204).send();
2673
2584
  } catch (error) {
2674
- logger14.error(`[Messages Router] Error deleting channel ${channelId}:`, error);
2585
+ logger12.error(`[Messages Router] Error deleting channel ${channelId}:`, error);
2675
2586
  res.status(500).json({ success: false, error: "Failed to delete channel" });
2676
2587
  }
2677
2588
  }
@@ -2680,44 +2591,24 @@ function createChannelsRouter(agents, serverInstance) {
2680
2591
  "/channels/:channelId/upload-media",
2681
2592
  createUploadRateLimit(),
2682
2593
  createFileSystemRateLimit(),
2683
- channelUpload(),
2594
+ channelUploadMiddleware.single("file"),
2684
2595
  async (req, res) => {
2685
- const channelId = validateUuid13(req.params.channelId);
2596
+ const channelId = validateUuid12(req.params.channelId);
2686
2597
  if (!channelId) {
2687
2598
  res.status(400).json({ success: false, error: "Invalid channelId format" });
2688
2599
  return;
2689
2600
  }
2690
- let mediaFile;
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) {
2601
+ if (!req.file) {
2700
2602
  res.status(400).json({ success: false, error: "No media file provided" });
2701
2603
  return;
2702
2604
  }
2703
2605
  try {
2704
- if (!validateMediaFile(mediaFile)) {
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);
2606
+ if (!req.file.originalname || req.file.originalname.includes("..") || req.file.originalname.includes("/")) {
2711
2607
  res.status(400).json({ success: false, error: "Invalid filename detected" });
2712
2608
  return;
2713
2609
  }
2714
- if (mediaFile.size > MAX_FILE_SIZE) {
2715
- cleanupUploadedFile(mediaFile);
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(
2610
+ const result = await saveChannelUploadedFile(req.file, channelId);
2611
+ logger12.info(
2721
2612
  `[MessagesRouter /upload-media] Secure file uploaded for channel ${channelId}: ${result.filename}. URL: ${result.url}`
2722
2613
  );
2723
2614
  res.json({
@@ -2725,21 +2616,18 @@ function createChannelsRouter(agents, serverInstance) {
2725
2616
  data: {
2726
2617
  url: result.url,
2727
2618
  // Relative URL, client prepends server origin
2728
- type: mediaFile.mimetype,
2619
+ type: req.file.mimetype,
2729
2620
  filename: result.filename,
2730
- originalName: mediaFile.name,
2731
- size: mediaFile.size
2621
+ originalName: req.file.originalname,
2622
+ size: req.file.size
2732
2623
  }
2733
2624
  });
2734
2625
  } catch (error) {
2735
2626
  const errorMessage = error instanceof Error ? error.message : String(error);
2736
- logger14.error(
2627
+ logger12.error(
2737
2628
  `[MessagesRouter /upload-media] Error processing upload for channel ${channelId}: ${errorMessage}`,
2738
2629
  error
2739
2630
  );
2740
- if (mediaFile) {
2741
- cleanupUploadedFile(mediaFile);
2742
- }
2743
2631
  res.status(500).json({ success: false, error: "Failed to process media upload" });
2744
2632
  }
2745
2633
  }
@@ -2747,7 +2635,7 @@ function createChannelsRouter(agents, serverInstance) {
2747
2635
  router.post(
2748
2636
  "/central-channels/:channelId/generate-title",
2749
2637
  async (req, res) => {
2750
- const channelId = validateUuid13(req.params.channelId);
2638
+ const channelId = validateUuid12(req.params.channelId);
2751
2639
  const { agentId } = req.body;
2752
2640
  if (!channelId) {
2753
2641
  return res.status(400).json({
@@ -2755,7 +2643,7 @@ function createChannelsRouter(agents, serverInstance) {
2755
2643
  error: "Invalid channel ID format"
2756
2644
  });
2757
2645
  }
2758
- if (!agentId || !validateUuid13(agentId)) {
2646
+ if (!agentId || !validateUuid12(agentId)) {
2759
2647
  return res.status(400).json({
2760
2648
  success: false,
2761
2649
  error: "Valid agent ID is required"
@@ -2769,7 +2657,7 @@ function createChannelsRouter(agents, serverInstance) {
2769
2657
  error: "Agent not found or not active"
2770
2658
  });
2771
2659
  }
2772
- logger14.info(`[CHANNEL SUMMARIZE] Summarizing channel ${channelId}`);
2660
+ logger12.info(`[CHANNEL SUMMARIZE] Summarizing channel ${channelId}`);
2773
2661
  const limit = req.query.limit ? Number.parseInt(req.query.limit, 10) : 50;
2774
2662
  const before = req.query.before ? Number.parseInt(req.query.before, 10) : void 0;
2775
2663
  const beforeDate = before ? new Date(before) : void 0;
@@ -2823,22 +2711,22 @@ Respond with just the title, nothing else.
2823
2711
  // Keep titles short
2824
2712
  });
2825
2713
  if (!newTitle || newTitle.trim().length === 0) {
2826
- logger14.warn(`[ChatTitleEvaluator] Failed to generate title for room ${channelId}`);
2714
+ logger12.warn(`[ChatTitleEvaluator] Failed to generate title for room ${channelId}`);
2827
2715
  return;
2828
2716
  }
2829
2717
  const cleanTitle = newTitle.trim().replace(/^["']|["']$/g, "");
2830
- logger14.info(`[ChatTitleEvaluator] Generated title: "${cleanTitle}" for room ${channelId}`);
2718
+ logger12.info(`[ChatTitleEvaluator] Generated title: "${cleanTitle}" for room ${channelId}`);
2831
2719
  const result = {
2832
2720
  title: cleanTitle,
2833
2721
  channelId
2834
2722
  };
2835
- logger14.success(`[CHANNEL SUMMARIZE] Successfully summarized channel ${channelId}`);
2723
+ logger12.success(`[CHANNEL SUMMARIZE] Successfully summarized channel ${channelId}`);
2836
2724
  res.json({
2837
2725
  success: true,
2838
2726
  data: result
2839
2727
  });
2840
2728
  } catch (error) {
2841
- logger14.error("[CHANNEL SUMMARIZE] Error summarizing channel:", error);
2729
+ logger12.error("[CHANNEL SUMMARIZE] Error summarizing channel:", error);
2842
2730
  res.status(500).json({
2843
2731
  success: false,
2844
2732
  error: "Failed to summarize channel",
@@ -2866,58 +2754,74 @@ function messagingRouter(agents, serverInstance) {
2866
2754
  import express15 from "express";
2867
2755
 
2868
2756
  // src/api/media/agents.ts
2869
- import { validateUuid as validateUuid14, logger as logger15, getContentTypeFromMimeType } from "@elizaos/core";
2757
+ import { validateUuid as validateUuid13, logger as logger13, getContentTypeFromMimeType } from "@elizaos/core";
2870
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
+ }
2871
2791
  function createAgentMediaRouter() {
2872
2792
  const router = express13.Router();
2873
- router.post("/:agentId/upload-media", agentMediaUpload(), async (req, res) => {
2874
- const agentMediaReq = req;
2875
- logger15.debug("[MEDIA UPLOAD] Processing media upload");
2876
- const agentId = validateUuid14(agentMediaReq.params.agentId);
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);
2877
2796
  if (!agentId) {
2878
2797
  return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
2879
2798
  }
2880
- let mediaFile;
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) {
2799
+ if (!req.file) {
2889
2800
  return sendError(res, 400, "INVALID_REQUEST", "No media file provided");
2890
2801
  }
2891
- const mimetype = mediaFile.mimetype;
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);
2802
+ const mediaType = getContentTypeFromMimeType(req.file.mimetype);
2897
2803
  if (!mediaType) {
2898
- cleanupUploadedFile(mediaFile);
2899
2804
  return sendError(
2900
2805
  res,
2901
2806
  400,
2902
2807
  "UNSUPPORTED_MEDIA_TYPE",
2903
- `Unsupported media MIME type: ${mimetype}`
2808
+ `Unsupported media MIME type: ${req.file.mimetype}`
2904
2809
  );
2905
2810
  }
2906
2811
  try {
2907
- const result = await processUploadedFile(mediaFile, agentId, "agents");
2908
- logger15.info(
2812
+ const result = await saveUploadedFile(req.file, agentId);
2813
+ logger13.info(
2909
2814
  `[MEDIA UPLOAD] Successfully uploaded ${mediaType}: ${result.filename}. URL: ${result.url}`
2910
2815
  );
2911
2816
  sendSuccess(res, {
2912
2817
  url: result.url,
2913
2818
  type: mediaType,
2914
2819
  filename: result.filename,
2915
- originalName: mediaFile.name,
2916
- size: mediaFile.size
2820
+ originalName: req.file.originalname,
2821
+ size: req.file.size
2917
2822
  });
2918
2823
  } catch (error) {
2919
- logger15.error(`[MEDIA UPLOAD] Error processing upload: ${error}`);
2920
- cleanupUploadedFile(mediaFile);
2824
+ logger13.error(`[MEDIA UPLOAD] Error processing upload: ${error}`);
2921
2825
  sendError(
2922
2826
  res,
2923
2827
  500,
@@ -2931,9 +2835,41 @@ function createAgentMediaRouter() {
2931
2835
  }
2932
2836
 
2933
2837
  // src/api/media/channels.ts
2934
- import { validateUuid as validateUuid15, logger as logger16 } from "@elizaos/core";
2838
+ import { validateUuid as validateUuid14, logger as logger14 } from "@elizaos/core";
2935
2839
  import express14 from "express";
2936
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
+ }
2937
2873
  function createChannelMediaRouter() {
2938
2874
  const router = express14.Router();
2939
2875
  const uploadMediaRateLimiter = rateLimit2({
@@ -2947,35 +2883,20 @@ function createChannelMediaRouter() {
2947
2883
  "/:channelId/upload-media",
2948
2884
  uploadMediaRateLimiter,
2949
2885
  // Apply rate limiter
2950
- channelUpload(),
2886
+ upload2.single("file"),
2951
2887
  async (req, res) => {
2952
- const channelMediaReq = req;
2953
- const channelId = validateUuid15(channelMediaReq.params.channelId);
2888
+ const channelId = validateUuid14(req.params.channelId);
2954
2889
  if (!channelId) {
2955
2890
  res.status(400).json({ success: false, error: "Invalid channelId format" });
2956
2891
  return;
2957
2892
  }
2958
- let mediaFile;
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 {
2964
- res.status(400).json({ success: false, error: "No media file provided" });
2965
- return;
2966
- }
2967
- if (!mediaFile) {
2893
+ if (!req.file) {
2968
2894
  res.status(400).json({ success: false, error: "No media file provided" });
2969
2895
  return;
2970
2896
  }
2971
- if (!validateMediaFile(mediaFile)) {
2972
- cleanupUploadedFile(mediaFile);
2973
- res.status(400).json({ success: false, error: `Invalid file type: ${mediaFile.mimetype}` });
2974
- return;
2975
- }
2976
2897
  try {
2977
- const result = await processUploadedFile(mediaFile, channelId, "channels");
2978
- logger16.info(
2898
+ const result = await saveUploadedFile2(req.file, channelId);
2899
+ logger14.info(
2979
2900
  `[Channel Media Upload] File uploaded for channel ${channelId}: ${result.filename}. URL: ${result.url}`
2980
2901
  );
2981
2902
  res.json({
@@ -2983,18 +2904,17 @@ function createChannelMediaRouter() {
2983
2904
  data: {
2984
2905
  url: result.url,
2985
2906
  // Relative URL, client prepends server origin
2986
- type: mediaFile.mimetype,
2907
+ type: req.file.mimetype,
2987
2908
  filename: result.filename,
2988
- originalName: mediaFile.name,
2989
- size: mediaFile.size
2909
+ originalName: req.file.originalname,
2910
+ size: req.file.size
2990
2911
  }
2991
2912
  });
2992
2913
  } catch (error) {
2993
- logger16.error(
2914
+ logger14.error(
2994
2915
  `[Channel Media Upload] Error processing upload for channel ${channelId}: ${error.message}`,
2995
2916
  error
2996
2917
  );
2997
- cleanupUploadedFile(mediaFile);
2998
2918
  res.status(500).json({ success: false, error: "Failed to process media upload" });
2999
2919
  }
3000
2920
  }
@@ -3016,6 +2936,40 @@ import express17 from "express";
3016
2936
  // src/api/memory/groups.ts
3017
2937
  import { validateUuid as validateUuid16, logger as logger17, createUniqueUuid as createUniqueUuid4, ChannelType as ChannelType3 } from "@elizaos/core";
3018
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
3019
2973
  function createGroupMemoryRouter(agents, serverInstance) {
3020
2974
  const router = express16.Router();
3021
2975
  const db = serverInstance?.database;
@@ -3147,184 +3101,110 @@ import express21 from "express";
3147
3101
  // src/api/audio/processing.ts
3148
3102
  import { logger as logger18, ModelType as ModelType2, validateUuid as validateUuid17 } from "@elizaos/core";
3149
3103
  import express18 from "express";
3150
- import fs3 from "fs";
3104
+ import fs6 from "fs";
3151
3105
  import os from "os";
3152
- import path3 from "path";
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
- }
3106
+ import path6 from "path";
3187
3107
  function createAudioProcessingRouter(agents) {
3188
3108
  const router = express18.Router();
3189
3109
  router.use(createUploadRateLimit());
3190
3110
  router.use(createFileSystemRateLimit());
3191
- router.post(
3192
- "/:agentId/audio-messages",
3193
- agentAudioUpload(),
3194
- // Use agentAudioUpload
3195
- async (req, res) => {
3196
- const audioReq = req;
3197
- logger18.debug("[AUDIO MESSAGE] Processing audio message");
3198
- const agentId = validateUuid17(req.params.agentId);
3199
- if (!agentId) {
3200
- return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
3201
- }
3202
- const audioFile = getUploadedFile(audioReq);
3203
- if (!audioFile) {
3204
- return sendError(res, 400, "INVALID_REQUEST", "No audio file provided");
3205
- }
3206
- const runtime = agents.get(agentId);
3207
- if (!runtime) {
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);
3115
+ if (!agentId) {
3116
+ return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
3117
+ }
3118
+ const audioFile = audioReq.file;
3119
+ if (!audioFile) {
3120
+ return sendError(res, 400, "INVALID_REQUEST", "No audio file provided");
3121
+ }
3122
+ const runtime = agents.get(agentId);
3123
+ if (!runtime) {
3124
+ cleanupUploadedFile(audioFile);
3125
+ return sendError(res, 404, "NOT_FOUND", "Agent not found");
3126
+ }
3127
+ try {
3128
+ if (!validateAudioFile(audioFile)) {
3208
3129
  cleanupUploadedFile(audioFile);
3209
- return sendError(res, 404, "NOT_FOUND", "Agent not found");
3130
+ return sendError(res, 400, "INVALID_FILE_TYPE", "Invalid audio file type");
3210
3131
  }
3211
- try {
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}`);
3132
+ if (audioFile.size > MAX_FILE_SIZE) {
3242
3133
  cleanupUploadedFile(audioFile);
3243
- sendSuccess(res, { transcription, message: "Audio transcribed, further processing TBD." });
3244
- } catch (error) {
3245
- logger18.error("[AUDIO MESSAGE] Error processing audio:", error);
3246
- cleanupUploadedFile(audioFile);
3247
- sendError(
3134
+ return sendError(
3248
3135
  res,
3249
- 500,
3250
- "PROCESSING_ERROR",
3251
- "Error processing audio message",
3252
- error instanceof Error ? error.message : String(error)
3136
+ 413,
3137
+ "FILE_TOO_LARGE",
3138
+ `Audio file too large (max ${MAX_FILE_SIZE_DISPLAY})`
3253
3139
  );
3254
3140
  }
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." });
3145
+ } catch (error) {
3146
+ logger18.error("[AUDIO MESSAGE] Error processing audio:", error);
3147
+ cleanupUploadedFile(audioFile);
3148
+ sendError(
3149
+ res,
3150
+ 500,
3151
+ "PROCESSING_ERROR",
3152
+ "Error processing audio message",
3153
+ error instanceof Error ? error.message : String(error)
3154
+ );
3255
3155
  }
3256
- );
3257
- router.post(
3258
- "/:agentId/transcriptions",
3259
- agentAudioUpload(),
3260
- // Use agentAudioUpload
3261
- async (req, res) => {
3262
- const audioReq = req;
3263
- logger18.debug("[TRANSCRIPTION] Request to transcribe audio");
3264
- const agentId = validateUuid17(req.params.agentId);
3265
- if (!agentId) {
3266
- return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
3267
- }
3268
- const audioFile = getUploadedFile(audioReq);
3269
- if (!audioFile) {
3270
- return sendError(res, 400, "INVALID_REQUEST", "No audio file provided");
3271
- }
3272
- const runtime = agents.get(agentId);
3273
- if (!runtime) {
3156
+ });
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);
3161
+ if (!agentId) {
3162
+ return sendError(res, 400, "INVALID_ID", "Invalid agent ID format");
3163
+ }
3164
+ const audioFile = audioReq.file;
3165
+ if (!audioFile) {
3166
+ return sendError(res, 400, "INVALID_REQUEST", "No audio file provided");
3167
+ }
3168
+ const runtime = agents.get(agentId);
3169
+ if (!runtime) {
3170
+ cleanupUploadedFile(audioFile);
3171
+ return sendError(res, 404, "NOT_FOUND", "Agent not found");
3172
+ }
3173
+ try {
3174
+ logger18.debug("[TRANSCRIPTION] Reading audio file");
3175
+ if (!validateAudioFile(audioFile)) {
3274
3176
  cleanupUploadedFile(audioFile);
3275
- return sendError(res, 404, "NOT_FOUND", "Agent not found");
3177
+ return sendError(res, 400, "INVALID_FILE_TYPE", "Invalid audio file type");
3276
3178
  }
3277
- try {
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);
3179
+ if (audioFile.size > MAX_FILE_SIZE) {
3309
3180
  cleanupUploadedFile(audioFile);
3310
- if (!transcription) {
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(
3181
+ return sendError(
3319
3182
  res,
3320
- 500,
3321
- "PROCESSING_ERROR",
3322
- "Error transcribing audio",
3323
- error instanceof Error ? error.message : String(error)
3183
+ 413,
3184
+ "FILE_TOO_LARGE",
3185
+ `Audio file too large (max ${MAX_FILE_SIZE_DISPLAY})`
3324
3186
  );
3325
3187
  }
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 });
3196
+ } catch (error) {
3197
+ logger18.error("[TRANSCRIPTION] Error transcribing audio:", error);
3198
+ cleanupUploadedFile(audioFile);
3199
+ sendError(
3200
+ res,
3201
+ 500,
3202
+ "PROCESSING_ERROR",
3203
+ "Error transcribing audio",
3204
+ error instanceof Error ? error.message : String(error)
3205
+ );
3326
3206
  }
3327
- );
3207
+ });
3328
3208
  return router;
3329
3209
  }
3330
3210
 
@@ -3821,15 +3701,15 @@ import express28 from "express";
3821
3701
  import { logger as logger23 } from "@elizaos/core";
3822
3702
  import express27 from "express";
3823
3703
  import { existsSync, writeFileSync } from "fs";
3824
- import path4 from "path";
3704
+ import path7 from "path";
3825
3705
  import dotenv from "dotenv";
3826
- import fs4 from "fs/promises";
3706
+ import fs7 from "fs/promises";
3827
3707
  async function parseEnvFile(filePath) {
3828
3708
  try {
3829
3709
  if (!existsSync(filePath)) {
3830
3710
  return {};
3831
3711
  }
3832
- const content = await fs4.readFile(filePath, "utf-8");
3712
+ const content = await fs7.readFile(filePath, "utf-8");
3833
3713
  if (content.trim() === "") {
3834
3714
  return {};
3835
3715
  }
@@ -3849,17 +3729,17 @@ function getLocalEnvPath() {
3849
3729
  function resolveEnvFile(startDir = process.cwd()) {
3850
3730
  let currentDir = startDir;
3851
3731
  while (true) {
3852
- const candidate = path4.join(currentDir, ".env");
3732
+ const candidate = path7.join(currentDir, ".env");
3853
3733
  if (existsSync(candidate)) {
3854
3734
  return candidate;
3855
3735
  }
3856
- const parentDir = path4.dirname(currentDir);
3736
+ const parentDir = path7.dirname(currentDir);
3857
3737
  if (parentDir === currentDir) {
3858
3738
  break;
3859
3739
  }
3860
3740
  currentDir = parentDir;
3861
3741
  }
3862
- return path4.join(startDir, ".env");
3742
+ return path7.join(startDir, ".env");
3863
3743
  }
3864
3744
  function createEnvironmentRouter() {
3865
3745
  const router = express27.Router();
@@ -4610,6 +4490,7 @@ function createApiRouter(agents, serverInstance) {
4610
4490
  );
4611
4491
  router.use(createApiRateLimit());
4612
4492
  router.use(securityMiddleware());
4493
+ router.use("/media", mediaRouter());
4613
4494
  router.use(validateContentTypeMiddleware());
4614
4495
  router.use(
4615
4496
  bodyParser.json({
@@ -4629,7 +4510,6 @@ function createApiRouter(agents, serverInstance) {
4629
4510
  );
4630
4511
  router.use("/agents", agentsRouter(agents, serverInstance));
4631
4512
  router.use("/messaging", messagingRouter(agents, serverInstance));
4632
- router.use("/media", mediaRouter());
4633
4513
  router.use("/memory", memoryRouter(agents, serverInstance));
4634
4514
  router.use("/audio", audioRouter(agents));
4635
4515
  router.use("/server", runtimeRouter(agents, serverInstance));
@@ -5033,7 +4913,14 @@ var MessageBusService = class _MessageBusService extends Service {
5033
4913
  await this.runtime.emitEvent(EventType2.MESSAGE_RECEIVED, {
5034
4914
  runtime: this.runtime,
5035
4915
  message: agentMemory,
5036
- 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
+ }
5037
4924
  });
5038
4925
  } catch (error) {
5039
4926
  logger27.error(
@@ -5110,7 +4997,6 @@ var MessageBusService = class _MessageBusService extends Service {
5110
4997
  logger27.error(
5111
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.`
5112
4999
  );
5113
- await this.notifyMessageComplete(channelId, serverId);
5114
5000
  return;
5115
5001
  }
5116
5002
  const shouldSkip = content.actions?.includes("IGNORE") || !content.text || content.text.trim() === "";
@@ -5118,7 +5004,6 @@ var MessageBusService = class _MessageBusService extends Service {
5118
5004
  logger27.info(
5119
5005
  `[${this.runtime.character.name}] MessageBusService: Skipping response (reason: ${content.actions?.includes("IGNORE") ? "IGNORE action" : "No text"})`
5120
5006
  );
5121
- await this.notifyMessageComplete(channelId, serverId);
5122
5007
  return;
5123
5008
  }
5124
5009
  let centralInReplyToRootMessageId = void 0;
@@ -5263,8 +5148,8 @@ var messageBusConnectorPlugin = {
5263
5148
  };
5264
5149
 
5265
5150
  // src/loader.ts
5266
- import fs5 from "fs";
5267
- import path5 from "path";
5151
+ import fs8 from "fs";
5152
+ import path8 from "path";
5268
5153
  import { fileURLToPath } from "url";
5269
5154
  import {
5270
5155
  logger as logger28,
@@ -5272,10 +5157,10 @@ import {
5272
5157
  validateCharacter
5273
5158
  } from "@elizaos/core";
5274
5159
  var __filename = fileURLToPath(import.meta.url);
5275
- var __dirname = path5.dirname(__filename);
5160
+ var __dirname = path8.dirname(__filename);
5276
5161
  function tryLoadFile(filePath) {
5277
5162
  try {
5278
- return fs5.readFileSync(filePath, "utf8");
5163
+ return fs8.readFileSync(filePath, "utf8");
5279
5164
  } catch (e) {
5280
5165
  throw new Error(`Error loading file ${filePath}: ${e}`);
5281
5166
  }
@@ -5372,36 +5257,36 @@ async function loadCharacter(filePath) {
5372
5257
  }
5373
5258
  return jsonToCharacter(parseResult.data);
5374
5259
  }
5375
- function handleCharacterLoadError(path7, error) {
5260
+ function handleCharacterLoadError(path10, error) {
5376
5261
  const errorMsg = error instanceof Error ? error.message : String(error);
5377
5262
  if (errorMsg.includes("ENOENT") || errorMsg.includes("no such file")) {
5378
- logger28.error(`Character file not found: ${path7}`);
5263
+ logger28.error(`Character file not found: ${path10}`);
5379
5264
  throw new Error(
5380
- `Character '${path7}' not found. Please check if the file exists and the path is correct.`
5265
+ `Character '${path10}' not found. Please check if the file exists and the path is correct.`
5381
5266
  );
5382
5267
  } else if (errorMsg.includes("Character validation failed")) {
5383
- logger28.error(`Character validation failed for: ${path7}`);
5384
- throw new Error(`Character file '${path7}' contains invalid character data. ${errorMsg}`);
5268
+ logger28.error(`Character validation failed for: ${path10}`);
5269
+ throw new Error(`Character file '${path10}' contains invalid character data. ${errorMsg}`);
5385
5270
  } else if (errorMsg.includes("JSON")) {
5386
- logger28.error(`JSON parsing error in character file: ${path7}`);
5387
- throw new Error(`Character file '${path7}' has malformed JSON. Please check the file content.`);
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.`);
5388
5273
  } else if (errorMsg.includes("Invalid JSON")) {
5389
- logger28.error(`Invalid JSON in character file: ${path7}`);
5274
+ logger28.error(`Invalid JSON in character file: ${path10}`);
5390
5275
  throw new Error(
5391
- `Character file '${path7}' has invalid JSON format. Please check the file content.`
5276
+ `Character file '${path10}' has invalid JSON format. Please check the file content.`
5392
5277
  );
5393
5278
  } else {
5394
- logger28.error(`Error loading character from ${path7}: ${errorMsg}`);
5395
- throw new Error(`Failed to load character '${path7}': ${errorMsg}`);
5279
+ logger28.error(`Error loading character from ${path10}: ${errorMsg}`);
5280
+ throw new Error(`Failed to load character '${path10}': ${errorMsg}`);
5396
5281
  }
5397
5282
  }
5398
- async function safeLoadCharacter(path7) {
5283
+ async function safeLoadCharacter(path10) {
5399
5284
  try {
5400
- const character = await loadCharacter(path7);
5401
- logger28.info(`Successfully loaded character from: ${path7}`);
5285
+ const character = await loadCharacter(path10);
5286
+ logger28.info(`Successfully loaded character from: ${path10}`);
5402
5287
  return character;
5403
5288
  } catch (e) {
5404
- return handleCharacterLoadError(path7, e);
5289
+ return handleCharacterLoadError(path10, e);
5405
5290
  }
5406
5291
  }
5407
5292
  async function loadCharacterTryPath(characterPath) {
@@ -5421,27 +5306,27 @@ async function loadCharacterTryPath(characterPath) {
5421
5306
  const jsonPath = hasJsonExtension ? characterPath : `${characterPath}.json`;
5422
5307
  const basePathsToTry = [
5423
5308
  basePath,
5424
- path5.resolve(process.cwd(), basePath),
5425
- path5.resolve(process.cwd(), "..", "..", basePath),
5426
- path5.resolve(process.cwd(), "..", "..", "..", basePath),
5427
- path5.resolve(process.cwd(), "agent", basePath),
5428
- path5.resolve(__dirname, basePath),
5429
- path5.resolve(__dirname, "characters", path5.basename(basePath)),
5430
- path5.resolve(__dirname, "../characters", path5.basename(basePath)),
5431
- path5.resolve(__dirname, "../../characters", path5.basename(basePath)),
5432
- path5.resolve(__dirname, "../../../characters", path5.basename(basePath))
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))
5433
5318
  ];
5434
5319
  const jsonPathsToTry = hasJsonExtension ? [] : [
5435
5320
  jsonPath,
5436
- path5.resolve(process.cwd(), jsonPath),
5437
- path5.resolve(process.cwd(), "..", "..", jsonPath),
5438
- path5.resolve(process.cwd(), "..", "..", "..", jsonPath),
5439
- path5.resolve(process.cwd(), "agent", jsonPath),
5440
- path5.resolve(__dirname, jsonPath),
5441
- path5.resolve(__dirname, "characters", path5.basename(jsonPath)),
5442
- path5.resolve(__dirname, "../characters", path5.basename(jsonPath)),
5443
- path5.resolve(__dirname, "../../characters", path5.basename(jsonPath)),
5444
- path5.resolve(__dirname, "../../../characters", path5.basename(jsonPath))
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))
5445
5330
  ];
5446
5331
  const pathsToTry = Array.from(/* @__PURE__ */ new Set([...basePathsToTry, ...jsonPathsToTry]));
5447
5332
  let lastError = null;
@@ -5466,11 +5351,11 @@ function commaSeparatedStringToArray(commaSeparated) {
5466
5351
  }
5467
5352
  async function readCharactersFromStorage(characterPaths) {
5468
5353
  try {
5469
- const uploadDir = path5.join(process.cwd(), ".eliza", "data", "characters");
5470
- await fs5.promises.mkdir(uploadDir, { recursive: true });
5471
- const fileNames = await fs5.promises.readdir(uploadDir);
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);
5472
5357
  for (const fileName of fileNames) {
5473
- characterPaths.push(path5.join(uploadDir, fileName));
5358
+ characterPaths.push(path8.join(uploadDir, fileName));
5474
5359
  }
5475
5360
  } catch (err) {
5476
5361
  logger28.error(`Error reading directory: ${err.message}`);
@@ -5526,11 +5411,11 @@ function expandTildePath(filepath) {
5526
5411
  if (filepath === "~") {
5527
5412
  return process.cwd();
5528
5413
  } else if (filepath.startsWith("~/")) {
5529
- return path6.join(process.cwd(), filepath.slice(2));
5414
+ return path9.join(process.cwd(), filepath.slice(2));
5530
5415
  } else if (filepath.startsWith("~~")) {
5531
5416
  return filepath;
5532
5417
  } else {
5533
- return path6.join(process.cwd(), filepath.slice(1));
5418
+ return path9.join(process.cwd(), filepath.slice(1));
5534
5419
  }
5535
5420
  }
5536
5421
  return filepath;
@@ -5540,11 +5425,11 @@ function resolvePgliteDir(dir, fallbackDir) {
5540
5425
  if (existsSync3(envPath)) {
5541
5426
  dotenv2.config({ path: envPath });
5542
5427
  }
5543
- const base = dir ?? process.env.PGLITE_DATA_DIR ?? fallbackDir ?? path6.join(process.cwd(), ".eliza", ".elizadb");
5428
+ const base = dir ?? process.env.PGLITE_DATA_DIR ?? fallbackDir ?? path9.join(process.cwd(), ".eliza", ".elizadb");
5544
5429
  const resolved = expandTildePath(base);
5545
- const legacyPath = path6.join(process.cwd(), ".elizadb");
5430
+ const legacyPath = path9.join(process.cwd(), ".elizadb");
5546
5431
  if (resolved === legacyPath) {
5547
- const newPath = path6.join(process.cwd(), ".eliza", ".elizadb");
5432
+ const newPath = path9.join(process.cwd(), ".eliza", ".elizadb");
5548
5433
  process.env.PGLITE_DATA_DIR = newPath;
5549
5434
  return newPath;
5550
5435
  }
@@ -5784,26 +5669,10 @@ var AgentServer = class {
5784
5669
  })
5785
5670
  );
5786
5671
  this.app.use(
5787
- bodyParser2.json({
5672
+ express30.json({
5788
5673
  limit: process.env.EXPRESS_MAX_PAYLOAD || "100kb"
5789
5674
  })
5790
5675
  );
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
5676
  const serverAuthToken = process.env.ELIZA_SERVER_AUTH_TOKEN;
5808
5677
  if (serverAuthToken) {
5809
5678
  logger29.info("Server authentication enabled. Requires X-API-KEY header for /api routes.");
@@ -5815,10 +5684,10 @@ var AgentServer = class {
5815
5684
  "Server authentication is disabled. Set ELIZA_SERVER_AUTH_TOKEN environment variable to enable."
5816
5685
  );
5817
5686
  }
5818
- const uploadsBasePath = path6.join(process.cwd(), ".eliza", "data", "uploads", "agents");
5819
- const generatedBasePath = path6.join(process.cwd(), ".eliza", "data", "generated");
5820
- fs6.mkdirSync(uploadsBasePath, { recursive: true });
5821
- fs6.mkdirSync(generatedBasePath, { recursive: true });
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 });
5822
5691
  this.app.get(
5823
5692
  "/media/uploads/agents/:agentId/:filename",
5824
5693
  // @ts-expect-error - this is a valid express route
@@ -5835,7 +5704,7 @@ var AgentServer = class {
5835
5704
  if (!filePath.startsWith(agentUploadsPath)) {
5836
5705
  return res.status(403).json({ error: "Access denied" });
5837
5706
  }
5838
- if (!fs6.existsSync(filePath)) {
5707
+ if (!fs9.existsSync(filePath)) {
5839
5708
  return res.status(404).json({ error: "File does not exist!!!!!!!" });
5840
5709
  }
5841
5710
  res.sendFile(sanitizedFilename, { root: agentUploadsPath }, (err) => {
@@ -5939,7 +5808,7 @@ var AgentServer = class {
5939
5808
  }
5940
5809
  }
5941
5810
  };
5942
- const clientPath = path6.resolve(__dirname2, "../../cli/dist");
5811
+ const clientPath = path9.resolve(__dirname2, "../../cli/dist");
5943
5812
  this.app.use(express30.static(clientPath, staticOptions));
5944
5813
  const pluginRouteHandler = createPluginRouteHandler(this.agents);
5945
5814
  this.app.use(pluginRouteHandler);
@@ -5982,8 +5851,8 @@ var AgentServer = class {
5982
5851
  res.setHeader("Content-Type", "application/javascript");
5983
5852
  return res.status(404).send(`// JavaScript module not found: ${req.path}`);
5984
5853
  }
5985
- const cliDistPath = path6.resolve(__dirname2, "../../cli/dist");
5986
- res.sendFile(path6.join(cliDistPath, "index.html"));
5854
+ const cliDistPath = path9.resolve(__dirname2, "../../cli/dist");
5855
+ res.sendFile(path9.join(cliDistPath, "index.html"));
5987
5856
  });
5988
5857
  this.server = http.createServer(this.app);
5989
5858
  this.socketIO = setupSocketIO(this.server, this.agents, this);