@elizaos/core 1.6.2-alpha.23 → 1.6.2-alpha.25

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