@elizaos/core 1.6.2-alpha.24 → 1.6.2-alpha.26

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.
@@ -10018,10 +10018,7 @@ function findEnvFile() {
10018
10018
  }
10019
10019
  const fs = __require("node:fs");
10020
10020
  const path = __require("node:path");
10021
- const possiblePaths = [
10022
- path.join(process.cwd(), ".env"),
10023
- path.join(process.cwd(), ".env.local")
10024
- ];
10021
+ const possiblePaths = [path.join(process.cwd(), ".env"), path.join(process.cwd(), ".env.local")];
10025
10022
  for (const envPath of possiblePaths) {
10026
10023
  if (fs.existsSync(envPath)) {
10027
10024
  return envPath;
@@ -25192,6 +25189,7 @@ var ServiceType = {
25192
25189
  WALLET: "wallet",
25193
25190
  LP_POOL: "lp_pool",
25194
25191
  TOKEN_DATA: "token_data",
25192
+ MESSAGE_SERVICE: "message_service",
25195
25193
  MESSAGE: "message",
25196
25194
  POST: "post",
25197
25195
  UNKNOWN: "unknown"
@@ -43004,6 +43002,751 @@ var v4_default = v43;
43004
43002
  // src/runtime.ts
43005
43003
  init_environment();
43006
43004
 
43005
+ // src/services/default-message-service.ts
43006
+ var latestResponseIds = new Map;
43007
+
43008
+ class DefaultMessageService {
43009
+ async handleMessage(runtime, message, callback, options) {
43010
+ const opts = {
43011
+ maxRetries: options?.maxRetries ?? 3,
43012
+ timeoutDuration: options?.timeoutDuration ?? 60 * 60 * 1000,
43013
+ useMultiStep: options?.useMultiStep ?? parseBooleanFromText2(runtime.getSetting("USE_MULTI_STEP")),
43014
+ maxMultiStepIterations: options?.maxMultiStepIterations ?? parseInt(runtime.getSetting("MAX_MULTISTEP_ITERATIONS") || "6")
43015
+ };
43016
+ let timeoutId = undefined;
43017
+ const responseId = v4_default();
43018
+ try {
43019
+ runtime.logger.info(`[MessageService] Message received from ${message.entityId} in room ${message.roomId}`);
43020
+ if (!latestResponseIds.has(runtime.agentId)) {
43021
+ latestResponseIds.set(runtime.agentId, new Map);
43022
+ }
43023
+ const agentResponses = latestResponseIds.get(runtime.agentId);
43024
+ if (!agentResponses)
43025
+ throw new Error("Agent responses map not found");
43026
+ const previousResponseId = agentResponses.get(message.roomId);
43027
+ if (previousResponseId) {
43028
+ logger.warn(`[MessageService] Updating response ID for room ${message.roomId} from ${previousResponseId} to ${responseId}`);
43029
+ }
43030
+ agentResponses.set(message.roomId, responseId);
43031
+ const runId = runtime.startRun();
43032
+ const startTime = Date.now();
43033
+ await runtime.emitEvent("RUN_STARTED" /* RUN_STARTED */, {
43034
+ runtime,
43035
+ runId,
43036
+ messageId: message.id,
43037
+ roomId: message.roomId,
43038
+ entityId: message.entityId,
43039
+ startTime,
43040
+ status: "started",
43041
+ source: "messageHandler",
43042
+ metadata: message.content
43043
+ });
43044
+ const timeoutPromise = new Promise((_, reject) => {
43045
+ timeoutId = setTimeout(async () => {
43046
+ await runtime.emitEvent("RUN_TIMEOUT" /* RUN_TIMEOUT */, {
43047
+ runtime,
43048
+ runId,
43049
+ messageId: message.id,
43050
+ roomId: message.roomId,
43051
+ entityId: message.entityId,
43052
+ startTime,
43053
+ status: "timeout",
43054
+ endTime: Date.now(),
43055
+ duration: Date.now() - startTime,
43056
+ error: "Run exceeded timeout",
43057
+ source: "messageHandler"
43058
+ });
43059
+ reject(new Error("Run exceeded timeout"));
43060
+ }, opts.timeoutDuration);
43061
+ });
43062
+ const processingPromise = this.processMessage(runtime, message, callback, responseId, runId, startTime, opts);
43063
+ const result = await Promise.race([processingPromise, timeoutPromise]);
43064
+ clearTimeout(timeoutId);
43065
+ return result;
43066
+ } catch (error) {
43067
+ clearTimeout(timeoutId);
43068
+ runtime.logger.error({ error }, "[MessageService] Error in handleMessage:");
43069
+ throw error;
43070
+ }
43071
+ }
43072
+ async processMessage(runtime, message, callback, responseId, runId, startTime, opts) {
43073
+ try {
43074
+ const agentResponses = latestResponseIds.get(runtime.agentId);
43075
+ if (!agentResponses)
43076
+ throw new Error("Agent responses map not found");
43077
+ if (message.entityId === runtime.agentId) {
43078
+ runtime.logger.debug(`[MessageService] Skipping message from self (${runtime.agentId})`);
43079
+ await this.emitRunEnded(runtime, runId, message, startTime, "self");
43080
+ return {
43081
+ didRespond: false,
43082
+ responseContent: null,
43083
+ responseMessages: [],
43084
+ state: {},
43085
+ mode: "none"
43086
+ };
43087
+ }
43088
+ runtime.logger.debug(`[MessageService] Processing message: ${truncateToCompleteSentence(message.content.text || "", 50)}...`);
43089
+ runtime.logger.debug("[MessageService] Saving message to memory and queueing embeddings");
43090
+ let memoryToQueue;
43091
+ if (message.id) {
43092
+ const existingMemory = await runtime.getMemoryById(message.id);
43093
+ if (existingMemory) {
43094
+ runtime.logger.debug("[MessageService] Memory already exists, skipping creation");
43095
+ memoryToQueue = existingMemory;
43096
+ } else {
43097
+ const createdMemoryId = await runtime.createMemory(message, "messages");
43098
+ memoryToQueue = { ...message, id: createdMemoryId };
43099
+ }
43100
+ await runtime.queueEmbeddingGeneration(memoryToQueue, "high");
43101
+ } else {
43102
+ const memoryId = await runtime.createMemory(message, "messages");
43103
+ message.id = memoryId;
43104
+ memoryToQueue = { ...message, id: memoryId };
43105
+ await runtime.queueEmbeddingGeneration(memoryToQueue, "normal");
43106
+ }
43107
+ const agentUserState = await runtime.getParticipantUserState(message.roomId, runtime.agentId);
43108
+ const defLllmOff = parseBooleanFromText2(runtime.getSetting("BOOTSTRAP_DEFLLMOFF"));
43109
+ if (defLllmOff && agentUserState === null) {
43110
+ runtime.logger.debug("[MessageService] LLM is off by default");
43111
+ await this.emitRunEnded(runtime, runId, message, startTime, "off");
43112
+ return {
43113
+ didRespond: false,
43114
+ responseContent: null,
43115
+ responseMessages: [],
43116
+ state: {},
43117
+ mode: "none"
43118
+ };
43119
+ }
43120
+ if (agentUserState === "MUTED" && !message.content.text?.toLowerCase().includes(runtime.character.name.toLowerCase())) {
43121
+ runtime.logger.debug(`[MessageService] Ignoring muted room ${message.roomId}`);
43122
+ await this.emitRunEnded(runtime, runId, message, startTime, "muted");
43123
+ return {
43124
+ didRespond: false,
43125
+ responseContent: null,
43126
+ responseMessages: [],
43127
+ state: {},
43128
+ mode: "none"
43129
+ };
43130
+ }
43131
+ let state = await runtime.composeState(message, ["ANXIETY", "ENTITIES", "CHARACTER", "RECENT_MESSAGES", "ACTIONS"], true);
43132
+ const mentionContext = message.content.mentionContext;
43133
+ const room = await runtime.getRoom(message.roomId);
43134
+ if (message.content.attachments && message.content.attachments.length > 0) {
43135
+ message.content.attachments = await this.processAttachments(runtime, message.content.attachments);
43136
+ if (message.id) {
43137
+ await runtime.updateMemory({ id: message.id, content: message.content });
43138
+ }
43139
+ }
43140
+ const responseDecision = this.shouldRespond(runtime, message, room ?? undefined, mentionContext);
43141
+ runtime.logger.debug(`[MessageService] Response decision: ${JSON.stringify(responseDecision)}`);
43142
+ let shouldRespondToMessage = true;
43143
+ if (responseDecision.skipEvaluation) {
43144
+ runtime.logger.debug(`[MessageService] Skipping evaluation for ${runtime.character.name} (${responseDecision.reason})`);
43145
+ shouldRespondToMessage = responseDecision.shouldRespond;
43146
+ } else {
43147
+ const shouldRespondPrompt = composePromptFromState({
43148
+ state,
43149
+ template: runtime.character.templates?.shouldRespondTemplate || shouldRespondTemplate
43150
+ });
43151
+ runtime.logger.debug(`[MessageService] Using LLM evaluation for ${runtime.character.name} (${responseDecision.reason})`);
43152
+ const response = await runtime.useModel(ModelType.TEXT_SMALL, {
43153
+ prompt: shouldRespondPrompt
43154
+ });
43155
+ runtime.logger.debug(`[MessageService] LLM evaluation result:
43156
+ ${response}`);
43157
+ const responseObject = parseKeyValueXml(response);
43158
+ runtime.logger.debug({ responseObject }, "[MessageService] Parsed evaluation result:");
43159
+ const nonResponseActions = ["IGNORE", "NONE"];
43160
+ shouldRespondToMessage = responseObject?.action && !nonResponseActions.includes(responseObject.action.toUpperCase());
43161
+ }
43162
+ let responseContent = null;
43163
+ let responseMessages = [];
43164
+ let mode = "none";
43165
+ if (shouldRespondToMessage) {
43166
+ const result = opts.useMultiStep ? await this.runMultiStepCore(runtime, message, state, callback, opts) : await this.runSingleShotCore(runtime, message, state, opts);
43167
+ responseContent = result.responseContent;
43168
+ responseMessages = result.responseMessages;
43169
+ state = result.state;
43170
+ mode = result.mode;
43171
+ const currentResponseId = agentResponses.get(message.roomId);
43172
+ if (currentResponseId !== responseId) {
43173
+ runtime.logger.info(`Response discarded - newer message being processed for agent: ${runtime.agentId}, room: ${message.roomId}`);
43174
+ return {
43175
+ didRespond: false,
43176
+ responseContent: null,
43177
+ responseMessages: [],
43178
+ state,
43179
+ mode: "none"
43180
+ };
43181
+ }
43182
+ if (responseContent && message.id) {
43183
+ responseContent.inReplyTo = createUniqueUuid(runtime, message.id);
43184
+ }
43185
+ if (responseContent?.providers?.length && responseContent.providers.length > 0) {
43186
+ state = await runtime.composeState(message, responseContent.providers || []);
43187
+ }
43188
+ if (responseContent) {
43189
+ if (mode === "simple") {
43190
+ if (responseContent.providers && responseContent.providers.length > 0) {
43191
+ runtime.logger.debug({ providers: responseContent.providers }, "[MessageService] Simple response used providers");
43192
+ }
43193
+ if (callback) {
43194
+ await callback(responseContent);
43195
+ }
43196
+ } else if (mode === "actions") {
43197
+ await runtime.processActions(message, responseMessages, state, async (content) => {
43198
+ runtime.logger.debug({ content }, "action callback");
43199
+ responseContent.actionCallbacks = content;
43200
+ if (callback) {
43201
+ return callback(content);
43202
+ }
43203
+ return [];
43204
+ });
43205
+ }
43206
+ }
43207
+ } else {
43208
+ runtime.logger.debug("[MessageService] Agent decided not to respond (shouldRespond is false).");
43209
+ const currentResponseId = agentResponses.get(message.roomId);
43210
+ const keepResp = parseBooleanFromText2(runtime.getSetting("BOOTSTRAP_KEEP_RESP"));
43211
+ if (currentResponseId !== responseId && !keepResp) {
43212
+ runtime.logger.info(`Ignore response discarded - newer message being processed for agent: ${runtime.agentId}, room: ${message.roomId}`);
43213
+ await this.emitRunEnded(runtime, runId, message, startTime, "replaced");
43214
+ return {
43215
+ didRespond: false,
43216
+ responseContent: null,
43217
+ responseMessages: [],
43218
+ state,
43219
+ mode: "none"
43220
+ };
43221
+ }
43222
+ if (!message.id) {
43223
+ runtime.logger.error("[MessageService] Message ID is missing, cannot create ignore response.");
43224
+ await this.emitRunEnded(runtime, runId, message, startTime, "noMessageId");
43225
+ return {
43226
+ didRespond: false,
43227
+ responseContent: null,
43228
+ responseMessages: [],
43229
+ state,
43230
+ mode: "none"
43231
+ };
43232
+ }
43233
+ const ignoreContent = {
43234
+ thought: "Agent decided not to respond to this message.",
43235
+ actions: ["IGNORE"],
43236
+ simple: true,
43237
+ inReplyTo: createUniqueUuid(runtime, message.id)
43238
+ };
43239
+ if (callback) {
43240
+ await callback(ignoreContent);
43241
+ }
43242
+ const ignoreMemory = {
43243
+ id: asUUID(v4_default()),
43244
+ entityId: runtime.agentId,
43245
+ agentId: runtime.agentId,
43246
+ content: ignoreContent,
43247
+ roomId: message.roomId,
43248
+ createdAt: Date.now()
43249
+ };
43250
+ await runtime.createMemory(ignoreMemory, "messages");
43251
+ runtime.logger.debug("[MessageService] Saved ignore response to memory", `memoryId: ${ignoreMemory.id}`);
43252
+ }
43253
+ agentResponses.delete(message.roomId);
43254
+ if (agentResponses.size === 0) {
43255
+ latestResponseIds.delete(runtime.agentId);
43256
+ }
43257
+ await runtime.evaluate(message, state, shouldRespondToMessage, async (content) => {
43258
+ runtime.logger.debug({ content }, "evaluate callback");
43259
+ if (responseContent) {
43260
+ responseContent.evalCallbacks = content;
43261
+ }
43262
+ if (callback) {
43263
+ return callback(content);
43264
+ }
43265
+ return [];
43266
+ }, responseMessages);
43267
+ let entityName = "noname";
43268
+ if (message.metadata && "entityName" in message.metadata) {
43269
+ entityName = message.metadata.entityName;
43270
+ }
43271
+ const isDM = message.content?.channelType === "DM" /* DM */;
43272
+ let roomName = entityName;
43273
+ if (!isDM) {
43274
+ const roomDatas = await runtime.getRoomsByIds([message.roomId]);
43275
+ if (roomDatas?.length) {
43276
+ const roomData = roomDatas[0];
43277
+ if (roomData.name) {
43278
+ roomName = roomData.name;
43279
+ }
43280
+ if (roomData.worldId) {
43281
+ const worldData = await runtime.getWorld(roomData.worldId);
43282
+ if (worldData) {
43283
+ roomName = worldData.name + "-" + roomName;
43284
+ }
43285
+ }
43286
+ }
43287
+ }
43288
+ const date2 = new Date;
43289
+ const availableActions = state.data?.providers?.ACTIONS?.data?.actionsData?.map((a) => a.name) || [-1];
43290
+ const logData = {
43291
+ at: date2.toString(),
43292
+ timestamp: parseInt("" + date2.getTime() / 1000),
43293
+ messageId: message.id,
43294
+ userEntityId: message.entityId,
43295
+ input: message.content.text,
43296
+ thought: responseContent?.thought,
43297
+ simple: responseContent?.simple,
43298
+ availableActions,
43299
+ actions: responseContent?.actions,
43300
+ providers: responseContent?.providers,
43301
+ irt: responseContent?.inReplyTo,
43302
+ output: responseContent?.text,
43303
+ entityName,
43304
+ source: message.content.source,
43305
+ channelType: message.content.channelType,
43306
+ roomName
43307
+ };
43308
+ await runtime.emitEvent("RUN_ENDED" /* RUN_ENDED */, {
43309
+ runtime,
43310
+ runId,
43311
+ messageId: message.id,
43312
+ roomId: message.roomId,
43313
+ entityId: message.entityId,
43314
+ startTime,
43315
+ status: "completed",
43316
+ endTime: Date.now(),
43317
+ duration: Date.now() - startTime,
43318
+ source: "messageHandler",
43319
+ entityName,
43320
+ responseContent,
43321
+ metadata: logData
43322
+ });
43323
+ return {
43324
+ didRespond: shouldRespondToMessage,
43325
+ responseContent,
43326
+ responseMessages,
43327
+ state,
43328
+ mode
43329
+ };
43330
+ } catch (error) {
43331
+ console.error("error is", error);
43332
+ await runtime.emitEvent("RUN_ENDED" /* RUN_ENDED */, {
43333
+ runtime,
43334
+ runId,
43335
+ messageId: message.id,
43336
+ roomId: message.roomId,
43337
+ entityId: message.entityId,
43338
+ startTime,
43339
+ status: "error",
43340
+ endTime: Date.now(),
43341
+ duration: Date.now() - startTime,
43342
+ error: error.message,
43343
+ source: "messageHandler"
43344
+ });
43345
+ throw error;
43346
+ }
43347
+ }
43348
+ shouldRespond(runtime, message, room, mentionContext) {
43349
+ if (!room) {
43350
+ return { shouldRespond: false, skipEvaluation: true, reason: "no room context" };
43351
+ }
43352
+ function normalizeEnvList(value) {
43353
+ if (!value || typeof value !== "string")
43354
+ return [];
43355
+ const cleaned = value.trim().replace(/^\[|\]$/g, "");
43356
+ return cleaned.split(",").map((v) => v.trim()).filter(Boolean);
43357
+ }
43358
+ const alwaysRespondChannels = [
43359
+ "DM" /* DM */,
43360
+ "VOICE_DM" /* VOICE_DM */,
43361
+ "SELF" /* SELF */,
43362
+ "API" /* API */
43363
+ ];
43364
+ const alwaysRespondSources = ["client_chat"];
43365
+ const customChannels = normalizeEnvList(runtime.getSetting("ALWAYS_RESPOND_CHANNELS") || runtime.getSetting("SHOULD_RESPOND_BYPASS_TYPES"));
43366
+ const customSources = normalizeEnvList(runtime.getSetting("ALWAYS_RESPOND_SOURCES") || runtime.getSetting("SHOULD_RESPOND_BYPASS_SOURCES"));
43367
+ const respondChannels = new Set([...alwaysRespondChannels.map((t) => t.toString()), ...customChannels].map((s) => s.trim().toLowerCase()));
43368
+ const respondSources = [...alwaysRespondSources, ...customSources].map((s) => s.trim().toLowerCase());
43369
+ const roomType = room.type?.toString().toLowerCase();
43370
+ const sourceStr = message.content.source?.toLowerCase() || "";
43371
+ if (respondChannels.has(roomType)) {
43372
+ return { shouldRespond: true, skipEvaluation: true, reason: `private channel: ${roomType}` };
43373
+ }
43374
+ if (respondSources.some((pattern) => sourceStr.includes(pattern))) {
43375
+ return {
43376
+ shouldRespond: true,
43377
+ skipEvaluation: true,
43378
+ reason: `whitelisted source: ${sourceStr}`
43379
+ };
43380
+ }
43381
+ const hasPlatformMention = !!(mentionContext?.isMention || mentionContext?.isReply);
43382
+ if (hasPlatformMention) {
43383
+ const mentionType = mentionContext?.isMention ? "mention" : "reply";
43384
+ return { shouldRespond: true, skipEvaluation: true, reason: `platform ${mentionType}` };
43385
+ }
43386
+ return { shouldRespond: false, skipEvaluation: false, reason: "needs LLM evaluation" };
43387
+ }
43388
+ async processAttachments(runtime, attachments) {
43389
+ if (!attachments || attachments.length === 0) {
43390
+ return [];
43391
+ }
43392
+ runtime.logger.debug(`[MessageService] Processing ${attachments.length} attachment(s)`);
43393
+ const processedAttachments = [];
43394
+ for (const attachment of attachments) {
43395
+ try {
43396
+ const processedAttachment = { ...attachment };
43397
+ const isRemote = /^(http|https):\/\//.test(attachment.url);
43398
+ const url = isRemote ? attachment.url : getLocalServerUrl(attachment.url);
43399
+ if (attachment.contentType === "image" /* IMAGE */ && !attachment.description) {
43400
+ runtime.logger.debug(`[MessageService] Generating description for image: ${attachment.url}`);
43401
+ let imageUrl = url;
43402
+ if (!isRemote) {
43403
+ const res = await fetch(url);
43404
+ if (!res.ok)
43405
+ throw new Error(`Failed to fetch image: ${res.statusText}`);
43406
+ const arrayBuffer = await res.arrayBuffer();
43407
+ const buffer = Buffer.from(arrayBuffer);
43408
+ const contentType = res.headers.get("content-type") || "application/octet-stream";
43409
+ imageUrl = `data:${contentType};base64,${buffer.toString("base64")}`;
43410
+ }
43411
+ try {
43412
+ const response = await runtime.useModel(ModelType.IMAGE_DESCRIPTION, {
43413
+ prompt: imageDescriptionTemplate,
43414
+ imageUrl
43415
+ });
43416
+ if (typeof response === "string") {
43417
+ const parsedXml = parseKeyValueXml(response);
43418
+ if (parsedXml && (parsedXml.description || parsedXml.text)) {
43419
+ processedAttachment.description = parsedXml.description || "";
43420
+ processedAttachment.title = parsedXml.title || "Image";
43421
+ processedAttachment.text = parsedXml.text || parsedXml.description || "";
43422
+ runtime.logger.debug(`[MessageService] Generated description: ${processedAttachment.description?.substring(0, 100)}...`);
43423
+ } else {
43424
+ const responseStr = response;
43425
+ const titleMatch = responseStr.match(/<title>([^<]+)<\/title>/);
43426
+ const descMatch = responseStr.match(/<description>([^<]+)<\/description>/);
43427
+ const textMatch = responseStr.match(/<text>([^<]+)<\/text>/);
43428
+ if (titleMatch || descMatch || textMatch) {
43429
+ processedAttachment.title = titleMatch?.[1] || "Image";
43430
+ processedAttachment.description = descMatch?.[1] || "";
43431
+ processedAttachment.text = textMatch?.[1] || descMatch?.[1] || "";
43432
+ runtime.logger.debug(`[MessageService] Used fallback XML parsing - description: ${processedAttachment.description?.substring(0, 100)}...`);
43433
+ } else {
43434
+ runtime.logger.warn(`[MessageService] Failed to parse XML response for image description`);
43435
+ }
43436
+ }
43437
+ } else if (response && typeof response === "object" && "description" in response) {
43438
+ processedAttachment.description = response.description;
43439
+ processedAttachment.title = response.title || "Image";
43440
+ processedAttachment.text = response.description;
43441
+ runtime.logger.debug(`[MessageService] Generated description: ${processedAttachment.description?.substring(0, 100)}...`);
43442
+ } else {
43443
+ runtime.logger.warn(`[MessageService] Unexpected response format for image description`);
43444
+ }
43445
+ } catch (error) {
43446
+ runtime.logger.error({ error }, `[MessageService] Error generating image description:`);
43447
+ }
43448
+ } else if (attachment.contentType === "document" /* DOCUMENT */ && !attachment.text) {
43449
+ const res = await fetch(url);
43450
+ if (!res.ok)
43451
+ throw new Error(`Failed to fetch document: ${res.statusText}`);
43452
+ const contentType = res.headers.get("content-type") || "";
43453
+ const isPlainText = contentType.startsWith("text/plain");
43454
+ if (isPlainText) {
43455
+ runtime.logger.debug(`[MessageService] Processing plain text document: ${attachment.url}`);
43456
+ const textContent = await res.text();
43457
+ processedAttachment.text = textContent;
43458
+ processedAttachment.title = processedAttachment.title || "Text File";
43459
+ runtime.logger.debug(`[MessageService] Extracted text content (first 100 chars): ${processedAttachment.text?.substring(0, 100)}...`);
43460
+ } else {
43461
+ runtime.logger.warn(`[MessageService] Skipping non-plain-text document: ${contentType}`);
43462
+ }
43463
+ }
43464
+ processedAttachments.push(processedAttachment);
43465
+ } catch (error) {
43466
+ runtime.logger.error({ error, attachmentUrl: attachment.url }, `[MessageService] Failed to process attachment ${attachment.url}:`);
43467
+ processedAttachments.push(attachment);
43468
+ }
43469
+ }
43470
+ return processedAttachments;
43471
+ }
43472
+ async runSingleShotCore(runtime, message, state, opts) {
43473
+ state = await runtime.composeState(message, ["ACTIONS"]);
43474
+ if (!state.values?.actionNames) {
43475
+ runtime.logger.warn("actionNames data missing from state, even though it was requested");
43476
+ }
43477
+ const prompt = composePromptFromState({
43478
+ state,
43479
+ template: runtime.character.templates?.messageHandlerTemplate || messageHandlerTemplate
43480
+ });
43481
+ let responseContent = null;
43482
+ let retries = 0;
43483
+ while (retries < opts.maxRetries && (!responseContent?.thought || !responseContent?.actions)) {
43484
+ const response = await runtime.useModel(ModelType.TEXT_LARGE, { prompt });
43485
+ runtime.logger.debug({ response }, "[MessageService] *** Raw LLM Response ***");
43486
+ const parsedXml = parseKeyValueXml(response);
43487
+ runtime.logger.debug({ parsedXml }, "[MessageService] *** Parsed XML Content ***");
43488
+ if (parsedXml) {
43489
+ responseContent = {
43490
+ ...parsedXml,
43491
+ thought: parsedXml.thought || "",
43492
+ actions: parsedXml.actions || ["IGNORE"],
43493
+ providers: parsedXml.providers || [],
43494
+ text: parsedXml.text || "",
43495
+ simple: parsedXml.simple || false
43496
+ };
43497
+ } else {
43498
+ responseContent = null;
43499
+ }
43500
+ retries++;
43501
+ if (!responseContent?.thought || !responseContent?.actions) {
43502
+ runtime.logger.warn({ response, parsedXml, responseContent }, "[MessageService] *** Missing required fields (thought or actions), retrying... ***");
43503
+ }
43504
+ }
43505
+ if (!responseContent) {
43506
+ return { responseContent: null, responseMessages: [], state, mode: "none" };
43507
+ }
43508
+ if (responseContent.actions && responseContent.actions.length > 1) {
43509
+ const isIgnore = (a) => typeof a === "string" && a.toUpperCase() === "IGNORE";
43510
+ const hasIgnore = responseContent.actions.some(isIgnore);
43511
+ if (hasIgnore) {
43512
+ if (!responseContent.text || responseContent.text.trim() === "") {
43513
+ responseContent.actions = ["IGNORE"];
43514
+ } else {
43515
+ const filtered = responseContent.actions.filter((a) => !isIgnore(a));
43516
+ responseContent.actions = filtered.length ? filtered : ["REPLY"];
43517
+ }
43518
+ }
43519
+ }
43520
+ const isSimple = responseContent.actions?.length === 1 && typeof responseContent.actions[0] === "string" && responseContent.actions[0].toUpperCase() === "REPLY" && (!responseContent.providers || responseContent.providers.length === 0);
43521
+ responseContent.simple = isSimple;
43522
+ const responseMessages = [
43523
+ {
43524
+ id: asUUID(v4_default()),
43525
+ entityId: runtime.agentId,
43526
+ agentId: runtime.agentId,
43527
+ content: responseContent,
43528
+ roomId: message.roomId,
43529
+ createdAt: Date.now()
43530
+ }
43531
+ ];
43532
+ return {
43533
+ responseContent,
43534
+ responseMessages,
43535
+ state,
43536
+ mode: isSimple && responseContent.text ? "simple" : "actions"
43537
+ };
43538
+ }
43539
+ async runMultiStepCore(runtime, message, state, callback, opts) {
43540
+ const traceActionResult = [];
43541
+ let accumulatedState = state;
43542
+ let iterationCount = 0;
43543
+ while (iterationCount < opts.maxMultiStepIterations) {
43544
+ iterationCount++;
43545
+ runtime.logger.debug(`[MultiStep] Starting iteration ${iterationCount}/${opts.maxMultiStepIterations}`);
43546
+ accumulatedState = await runtime.composeState(message, [
43547
+ "RECENT_MESSAGES",
43548
+ "ACTION_STATE"
43549
+ ]);
43550
+ accumulatedState.data.actionResults = traceActionResult;
43551
+ const prompt = composePromptFromState({
43552
+ state: accumulatedState,
43553
+ template: runtime.character.templates?.multiStepDecisionTemplate || multiStepDecisionTemplate
43554
+ });
43555
+ const stepResultRaw = await runtime.useModel(ModelType.TEXT_LARGE, { prompt });
43556
+ const parsedStep = parseKeyValueXml(stepResultRaw);
43557
+ if (!parsedStep) {
43558
+ runtime.logger.warn(`[MultiStep] Failed to parse step result at iteration ${iterationCount}`);
43559
+ traceActionResult.push({
43560
+ data: { actionName: "parse_error" },
43561
+ success: false,
43562
+ error: "Failed to parse step result"
43563
+ });
43564
+ break;
43565
+ }
43566
+ const { thought, providers = [], action, isFinish } = parsedStep;
43567
+ if (isFinish === "true" || isFinish === true) {
43568
+ runtime.logger.info(`[MultiStep] Task marked as complete at iteration ${iterationCount}`);
43569
+ if (callback) {
43570
+ await callback({
43571
+ text: "",
43572
+ thought: thought ?? ""
43573
+ });
43574
+ }
43575
+ break;
43576
+ }
43577
+ if ((!providers || providers.length === 0) && !action) {
43578
+ runtime.logger.warn(`[MultiStep] No providers or action specified at iteration ${iterationCount}, forcing completion`);
43579
+ break;
43580
+ }
43581
+ try {
43582
+ for (const providerName of providers) {
43583
+ const provider = runtime.providers.find((p) => p.name === providerName);
43584
+ if (!provider) {
43585
+ runtime.logger.warn(`[MultiStep] Provider not found: ${providerName}`);
43586
+ traceActionResult.push({
43587
+ data: { actionName: providerName },
43588
+ success: false,
43589
+ error: `Provider not found: ${providerName}`
43590
+ });
43591
+ continue;
43592
+ }
43593
+ const providerResult = await provider.get(runtime, message, state);
43594
+ if (!providerResult) {
43595
+ runtime.logger.warn(`[MultiStep] Provider returned no result: ${providerName}`);
43596
+ traceActionResult.push({
43597
+ data: { actionName: providerName },
43598
+ success: false,
43599
+ error: `Provider returned no result`
43600
+ });
43601
+ continue;
43602
+ }
43603
+ const success = !!providerResult.text;
43604
+ traceActionResult.push({
43605
+ data: { actionName: providerName },
43606
+ success,
43607
+ text: success ? providerResult.text : undefined,
43608
+ error: success ? undefined : "Provider returned no result"
43609
+ });
43610
+ if (callback) {
43611
+ await callback({
43612
+ text: `\uD83D\uDD0E Provider executed: ${providerName}`,
43613
+ actions: [providerName],
43614
+ thought: thought ?? ""
43615
+ });
43616
+ }
43617
+ }
43618
+ if (action) {
43619
+ const actionContent = {
43620
+ text: `\uD83D\uDD0E Executing action: ${action}`,
43621
+ actions: [action],
43622
+ thought: thought ?? ""
43623
+ };
43624
+ await runtime.processActions(message, [
43625
+ {
43626
+ id: v4_default(),
43627
+ entityId: runtime.agentId,
43628
+ roomId: message.roomId,
43629
+ createdAt: Date.now(),
43630
+ content: actionContent
43631
+ }
43632
+ ], state, async () => {
43633
+ return [];
43634
+ });
43635
+ const cachedState = runtime.stateCache?.get(`${message.id}_action_results`);
43636
+ const actionResults = cachedState?.values?.actionResults || [];
43637
+ const result = actionResults.length > 0 ? actionResults[0] : null;
43638
+ const success = result?.success ?? false;
43639
+ traceActionResult.push({
43640
+ data: { actionName: action },
43641
+ success,
43642
+ text: result?.text,
43643
+ values: result?.values,
43644
+ error: success ? undefined : result?.text
43645
+ });
43646
+ }
43647
+ } catch (err) {
43648
+ runtime.logger.error({ err }, "[MultiStep] Error executing step");
43649
+ traceActionResult.push({
43650
+ data: { actionName: action || "unknown" },
43651
+ success: false,
43652
+ error: err instanceof Error ? err.message : String(err)
43653
+ });
43654
+ }
43655
+ }
43656
+ if (iterationCount >= opts.maxMultiStepIterations) {
43657
+ runtime.logger.warn(`[MultiStep] Reached maximum iterations (${opts.maxMultiStepIterations}), forcing completion`);
43658
+ }
43659
+ accumulatedState = await runtime.composeState(message, [
43660
+ "RECENT_MESSAGES",
43661
+ "ACTION_STATE"
43662
+ ]);
43663
+ const summaryPrompt = composePromptFromState({
43664
+ state: accumulatedState,
43665
+ template: runtime.character.templates?.multiStepSummaryTemplate || multiStepSummaryTemplate
43666
+ });
43667
+ const finalOutput = await runtime.useModel(ModelType.TEXT_LARGE, { prompt: summaryPrompt });
43668
+ const summary = parseKeyValueXml(finalOutput);
43669
+ let responseContent = null;
43670
+ if (summary?.text) {
43671
+ responseContent = {
43672
+ actions: ["MULTI_STEP_SUMMARY"],
43673
+ text: summary.text,
43674
+ thought: summary.thought || "Final user-facing message after task completion.",
43675
+ simple: true
43676
+ };
43677
+ }
43678
+ const responseMessages = responseContent ? [
43679
+ {
43680
+ id: asUUID(v4_default()),
43681
+ entityId: runtime.agentId,
43682
+ agentId: runtime.agentId,
43683
+ content: responseContent,
43684
+ roomId: message.roomId,
43685
+ createdAt: Date.now()
43686
+ }
43687
+ ] : [];
43688
+ return {
43689
+ responseContent,
43690
+ responseMessages,
43691
+ state: accumulatedState,
43692
+ mode: responseContent ? "simple" : "none"
43693
+ };
43694
+ }
43695
+ async emitRunEnded(runtime, runId, message, startTime, status) {
43696
+ await runtime.emitEvent("RUN_ENDED" /* RUN_ENDED */, {
43697
+ runtime,
43698
+ runId,
43699
+ messageId: message.id,
43700
+ roomId: message.roomId,
43701
+ entityId: message.entityId,
43702
+ startTime,
43703
+ status,
43704
+ endTime: Date.now(),
43705
+ duration: Date.now() - startTime,
43706
+ source: "messageHandler"
43707
+ });
43708
+ }
43709
+ async deleteMessage(runtime, message) {
43710
+ try {
43711
+ if (!message.id) {
43712
+ runtime.logger.error("[MessageService] Cannot delete memory: message ID is missing");
43713
+ return;
43714
+ }
43715
+ runtime.logger.info("[MessageService] Deleting memory for message", message.id, "from room", message.roomId);
43716
+ await runtime.deleteMemory(message.id);
43717
+ runtime.logger.debug({ messageId: message.id }, "[MessageService] Successfully deleted memory for message");
43718
+ } catch (error) {
43719
+ runtime.logger.error({ error }, "[MessageService] Error in deleteMessage:");
43720
+ throw error;
43721
+ }
43722
+ }
43723
+ async clearChannel(runtime, roomId, channelId) {
43724
+ try {
43725
+ runtime.logger.info(`[MessageService] Clearing message memories from channel ${channelId} -> room ${roomId}`);
43726
+ const memories = await runtime.getMemoriesByRoomIds({
43727
+ tableName: "messages",
43728
+ roomIds: [roomId]
43729
+ });
43730
+ runtime.logger.info(`[MessageService] Found ${memories.length} message memories to delete from channel ${channelId}`);
43731
+ let deletedCount = 0;
43732
+ for (const memory of memories) {
43733
+ if (memory.id) {
43734
+ try {
43735
+ await runtime.deleteMemory(memory.id);
43736
+ deletedCount++;
43737
+ } catch (error) {
43738
+ runtime.logger.warn({ error, memoryId: memory.id }, `[MessageService] Failed to delete message memory ${memory.id}:`);
43739
+ }
43740
+ }
43741
+ }
43742
+ runtime.logger.info(`[MessageService] Successfully cleared ${deletedCount}/${memories.length} message memories from channel ${channelId}`);
43743
+ } catch (error) {
43744
+ runtime.logger.error({ error }, "[MessageService] Error in clearChannel:");
43745
+ throw error;
43746
+ }
43747
+ }
43748
+ }
43749
+
43007
43750
  // src/search.ts
43008
43751
  var isV = (char) => {
43009
43752
  switch (char) {
@@ -43880,6 +44623,7 @@ class AgentRuntime {
43880
44623
  currentRunId;
43881
44624
  currentActionContext;
43882
44625
  maxWorkingMemoryEntries = 50;
44626
+ messageService = null;
43883
44627
  constructor(opts) {
43884
44628
  this.agentId = opts.character?.id ?? opts?.agentId ?? stringToUuid(opts.character?.name ?? v4_default());
43885
44629
  this.character = opts.character;
@@ -44044,6 +44788,7 @@ class AgentRuntime {
44044
44788
  if (!await this.adapter.isReady()) {
44045
44789
  await this.adapter.init();
44046
44790
  }
44791
+ this.messageService = new DefaultMessageService;
44047
44792
  this.logger.info("Running plugin migrations...");
44048
44793
  await this.runPluginMigrations();
44049
44794
  this.logger.info("Plugin migrations completed.");
@@ -46956,6 +47701,7 @@ export {
46956
47701
  EventType,
46957
47702
  Environment,
46958
47703
  ElizaOS,
47704
+ DefaultMessageService,
46959
47705
  DatabaseAdapter,
46960
47706
  ContentType,
46961
47707
  ChannelType,
@@ -46965,5 +47711,5 @@ export {
46965
47711
  AgentRuntime
46966
47712
  };
46967
47713
 
46968
- //# debugId=5DD1578DC5F08BED64756E2164756E21
47714
+ //# debugId=738C38AE1C103AEB64756E2164756E21
46969
47715
  //# sourceMappingURL=index.node.js.map