@elizaos/plugin-bootstrap 1.2.12 → 1.3.1

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
@@ -28,7 +28,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var require_dedent = __commonJS({
29
29
  "../../node_modules/dedent/dist/dedent.js"(exports, module) {
30
30
  "use strict";
31
- function dedent3(strings) {
31
+ function dedent2(strings) {
32
32
  var raw = void 0;
33
33
  if (typeof strings === "string") {
34
34
  raw = [strings];
@@ -64,7 +64,7 @@ var require_dedent = __commonJS({
64
64
  return result.replace(/\\n/g, "\n");
65
65
  }
66
66
  if (typeof module !== "undefined") {
67
- module.exports = dedent3;
67
+ module.exports = dedent2;
68
68
  }
69
69
  }
70
70
  });
@@ -81,7 +81,7 @@ import {
81
81
  logger as logger20,
82
82
  messageHandlerTemplate,
83
83
  ModelType as ModelType14,
84
- parseKeyValueXml,
84
+ parseKeyValueXml as parseKeyValueXml9,
85
85
  postCreationTemplate,
86
86
  Role as Role2,
87
87
  shouldRespondTemplate,
@@ -144,21 +144,20 @@ var v4_default = v4;
144
144
  import {
145
145
  composePromptFromState,
146
146
  ModelType,
147
- ContentType
147
+ ContentType,
148
+ parseKeyValueXml
148
149
  } from "@elizaos/core";
149
150
  var imageGenerationTemplate = `# Task: Generate an image prompt for {{agentName}}.
150
151
  {{providers}}
151
152
  # Instructions:
152
153
  Write a clear, concise, and visually descriptive prompt that should be used to generate an image representing {{agentName}}'s next action or visualization for the conversation.
153
154
 
154
- Your response should be formatted in a valid JSON block like this:
155
- \`\`\`json
156
- {
157
- "prompt": "<string>"
158
- }
159
- \`\`\`
155
+ Your response should be formatted in XML like this:
156
+ <response>
157
+ <prompt>Your image generation prompt here</prompt>
158
+ </response>
160
159
 
161
- Your response should include the valid JSON block and nothing else.`;
160
+ Your response should include the valid XML block and nothing else.`;
162
161
  var generateImageAction = {
163
162
  name: "GENERATE_IMAGE",
164
163
  similes: ["DRAW", "CREATE_IMAGE", "RENDER_IMAGE", "VISUALIZE"],
@@ -171,12 +170,13 @@ var generateImageAction = {
171
170
  state = await runtime.composeState(message, [...allProviders ?? [], "RECENT_MESSAGES"]);
172
171
  const prompt = composePromptFromState({
173
172
  state,
174
- template: imageGenerationTemplate
173
+ template: runtime.character.templates?.imageGenerationTemplate || imageGenerationTemplate
175
174
  });
176
- const promptResponse = await runtime.useModel(ModelType.OBJECT_LARGE, {
175
+ const promptResponse = await runtime.useModel(ModelType.TEXT_LARGE, {
177
176
  prompt
178
177
  });
179
- const imagePrompt = typeof promptResponse === "object" && promptResponse && "prompt" in promptResponse ? String(promptResponse.prompt) : "Unable to generate descriptive prompt for image";
178
+ const parsedXml = parseKeyValueXml(promptResponse);
179
+ const imagePrompt = parsedXml?.prompt || "Unable to generate descriptive prompt for image";
180
180
  const imageResponse = await runtime.useModel(ModelType.IMAGE, {
181
181
  prompt: imagePrompt
182
182
  });
@@ -274,7 +274,7 @@ import {
274
274
  getUserServerRole,
275
275
  logger,
276
276
  ModelType as ModelType2,
277
- parseJSONObjectFromText
277
+ parseKeyValueXml as parseKeyValueXml2
278
278
  } from "@elizaos/core";
279
279
  var optionExtractionTemplate = `# Task: Extract selected task and option from user message
280
280
 
@@ -298,15 +298,16 @@ Available options:
298
298
  3. Return the task ID (shortened UUID) and selected option name exactly as listed above
299
299
  4. If no clear selection is made, return null for both fields
300
300
 
301
- Return in JSON format:
302
- \`\`\`json
303
- {
304
- "taskId": "string" | null,
305
- "selectedOption": "OPTION_NAME" | null
306
- }
307
- \`\`\`
301
+ Do NOT include any thinking, reasoning, or <think> sections in your response.
302
+ Go directly to the XML response format without any preamble or explanation.
303
+
304
+ Return in XML format:
305
+ <response>
306
+ <taskId>string_or_null</taskId>
307
+ <selectedOption>OPTION_NAME_or_null</selectedOption>
308
+ </response>
308
309
 
309
- Make sure to include the \`\`\`json\`\`\` tags around the JSON object.`;
310
+ IMPORTANT: Your response must ONLY contain the <response></response> XML block above. Do not include any text, thinking, or reasoning before or after this XML block. Start your response immediately with <response> and end with </response>.`;
310
311
  var choiceAction = {
311
312
  name: "CHOOSE_OPTION",
312
313
  similes: ["SELECT_OPTION", "SELECT", "PICK", "CHOOSE"],
@@ -402,7 +403,7 @@ ${task.options?.map((opt) => `- ${opt.name}: ${opt.description}`).join("\n")}`;
402
403
  prompt,
403
404
  stopSequences: []
404
405
  });
405
- const parsed = parseJSONObjectFromText(result);
406
+ const parsed = parseKeyValueXml2(result);
406
407
  const { taskId, selectedOption } = parsed;
407
408
  if (taskId && selectedOption) {
408
409
  const taskMap = new Map(formattedTasks.map((task) => [task.taskId, task]));
@@ -1702,7 +1703,8 @@ var noneAction = {
1702
1703
  import {
1703
1704
  composePromptFromState as composePromptFromState4,
1704
1705
  ModelType as ModelType5,
1705
- logger as logger4
1706
+ logger as logger4,
1707
+ parseKeyValueXml as parseKeyValueXml3
1706
1708
  } from "@elizaos/core";
1707
1709
  var replyTemplate = `# Task: Generate dialog for the character {{agentName}}.
1708
1710
 
@@ -1718,15 +1720,16 @@ IMPORTANT CODE BLOCK FORMATTING RULES:
1718
1720
  - If including inline code (short single words or function names), use single backticks (\`) as appropriate.
1719
1721
  - This ensures the user sees clearly formatted and copyable code when relevant.
1720
1722
 
1721
- Response format should be formatted in a valid JSON block like this:
1722
- \`\`\`json
1723
- {
1724
- "thought": "<string>",
1725
- "message": "<string>"
1726
- }
1727
- \`\`\`
1723
+ Do NOT include any thinking, reasoning, or <think> sections in your response.
1724
+ Go directly to the XML response format without any preamble or explanation.
1725
+
1726
+ Respond using XML format like this:
1727
+ <response>
1728
+ <thought>Your thought here</thought>
1729
+ <message>Your message here</message>
1730
+ </response>
1728
1731
 
1729
- Your response should include the valid JSON block and nothing else.`;
1732
+ IMPORTANT: Your response must ONLY contain the <response></response> XML block above. Do not include any text, thinking, or reasoning before or after this XML block. Start your response immediately with <response> and end with </response>.`;
1730
1733
  var replyAction = {
1731
1734
  name: "REPLY",
1732
1735
  similes: ["GREET", "REPLY_TO_MESSAGE", "SEND_REPLY", "RESPOND", "RESPONSE"],
@@ -1748,15 +1751,16 @@ var replyAction = {
1748
1751
  ]);
1749
1752
  const prompt = composePromptFromState4({
1750
1753
  state,
1751
- template: replyTemplate
1754
+ template: runtime.character.templates?.replyTemplate || replyTemplate
1752
1755
  });
1753
1756
  try {
1754
- const response = await runtime.useModel(ModelType5.OBJECT_LARGE, {
1757
+ const response = await runtime.useModel(ModelType5.TEXT_LARGE, {
1755
1758
  prompt
1756
1759
  });
1760
+ const parsedXml = parseKeyValueXml3(response);
1757
1761
  const responseContent = {
1758
- thought: response.thought,
1759
- text: response.message || "",
1762
+ thought: parsedXml?.thought || "",
1763
+ text: parsedXml?.message || "",
1760
1764
  actions: ["REPLY"]
1761
1765
  };
1762
1766
  await callback(responseContent);
@@ -1767,12 +1771,12 @@ var replyAction = {
1767
1771
  responded: true,
1768
1772
  lastReply: responseContent.text,
1769
1773
  lastReplyTime: Date.now(),
1770
- thoughtProcess: response.thought
1774
+ thoughtProcess: parsedXml?.thought
1771
1775
  },
1772
1776
  data: {
1773
1777
  actionName: "REPLY",
1774
1778
  response: responseContent,
1775
- thought: response.thought,
1779
+ thought: parsedXml?.thought,
1776
1780
  messageGenerated: true
1777
1781
  },
1778
1782
  success: true
@@ -1860,13 +1864,13 @@ var replyAction = {
1860
1864
  };
1861
1865
 
1862
1866
  // src/actions/roles.ts
1863
- var import_dedent = __toESM(require_dedent(), 1);
1864
1867
  import {
1865
1868
  ChannelType,
1866
1869
  composePrompt as composePrompt2,
1867
1870
  logger as logger5,
1868
1871
  ModelType as ModelType6,
1869
- Role
1872
+ Role,
1873
+ parseKeyValueXml as parseKeyValueXml4
1870
1874
  } from "@elizaos/core";
1871
1875
  var canModifyRole = (currentRole, targetRole, newRole) => {
1872
1876
  if (targetRole === currentRole) return false;
@@ -1949,60 +1953,50 @@ var updateRoleAction = {
1949
1953
  ...state.values,
1950
1954
  content: state.text
1951
1955
  },
1952
- template: import_dedent.default`
1953
- # Task: Parse Role Assignment
1954
-
1955
- I need to extract user role assignments from the input text. Users can be referenced by name, username, or mention.
1956
-
1957
- The available role types are:
1958
- - OWNER: Full control over the server and all settings
1959
- - ADMIN: Ability to manage channels and moderate content
1960
- - NONE: Regular user with no special permissions
1961
-
1962
- # Current context:
1963
- {{content}}
1964
-
1965
- Format your response as a JSON array of objects, each with:
1966
- - entityId: The name or ID of the user
1967
- - newRole: The role to assign (OWNER, ADMIN, or NONE)
1968
-
1969
- Example:
1970
- \`\`\`json
1971
- [
1972
- {
1973
- "entityId": "John",
1974
- "newRole": "ADMIN"
1975
- },
1976
- {
1977
- "entityId": "Sarah",
1978
- "newRole": "OWNER"
1979
- }
1980
- ]
1981
- \`\`\`
1982
- `
1956
+ template: `# Task: Parse Role Assignment
1957
+
1958
+ I need to extract user role assignments from the input text. Users can be referenced by name, username, or mention.
1959
+
1960
+ The available role types are:
1961
+ - OWNER: Full control over the server and all settings
1962
+ - ADMIN: Ability to manage channels and moderate content
1963
+ - NONE: Regular user with no special permissions
1964
+
1965
+ # Current context:
1966
+ {{content}}
1967
+
1968
+ Do NOT include any thinking, reasoning, or <think> sections in your response.
1969
+ Go directly to the XML response format without any preamble or explanation.
1970
+
1971
+ Format your response as XML with multiple assignments:
1972
+ <response>
1973
+ <assignments>
1974
+ <assignment>
1975
+ <entityId>John</entityId>
1976
+ <newRole>ADMIN</newRole>
1977
+ </assignment>
1978
+ <assignment>
1979
+ <entityId>Sarah</entityId>
1980
+ <newRole>OWNER</newRole>
1981
+ </assignment>
1982
+ </assignments>
1983
+ </response>
1984
+
1985
+ IMPORTANT: Your response must ONLY contain the <response></response> XML block above. Do not include any text, thinking, or reasoning before or after this XML block. Start your response immediately with <response> and end with </response>.`
1983
1986
  });
1984
- const result = await runtime.useModel(
1985
- ModelType6.OBJECT_LARGE,
1986
- {
1987
- prompt: extractionPrompt,
1988
- schema: {
1989
- type: "array",
1990
- items: {
1991
- type: "object",
1992
- properties: {
1993
- entityId: { type: "string" },
1994
- newRole: {
1995
- type: "string",
1996
- enum: Object.values(Role)
1997
- }
1998
- },
1999
- required: ["entityId", "newRole"]
2000
- }
2001
- },
2002
- output: "array"
2003
- }
2004
- );
2005
- if (!result?.length) {
1987
+ const response = await runtime.useModel(ModelType6.TEXT_SMALL, {
1988
+ prompt: extractionPrompt
1989
+ });
1990
+ const parsedXml = parseKeyValueXml4(response);
1991
+ let assignments = [];
1992
+ if (parsedXml?.assignments?.assignment) {
1993
+ const assignmentArray = Array.isArray(parsedXml.assignments.assignment) ? parsedXml.assignments.assignment : [parsedXml.assignments.assignment];
1994
+ assignments = assignmentArray.map((a2) => ({
1995
+ entityId: a2.entityId,
1996
+ newRole: a2.newRole
1997
+ }));
1998
+ }
1999
+ if (!assignments.length) {
2006
2000
  await callback?.({
2007
2001
  text: "No valid role assignments found in the request.",
2008
2002
  actions: ["UPDATE_ROLE"],
@@ -2024,7 +2018,7 @@ var updateRoleAction = {
2024
2018
  let worldUpdated = false;
2025
2019
  const successfulUpdates = [];
2026
2020
  const failedUpdates = [];
2027
- for (const assignment of result) {
2021
+ for (const assignment of assignments) {
2028
2022
  let targetEntity = entities.find((e2) => e2.id === assignment.entityId);
2029
2023
  if (!targetEntity) {
2030
2024
  logger5.error("Could not find an ID to assign to");
@@ -2159,7 +2153,7 @@ import {
2159
2153
  findEntityByName,
2160
2154
  logger as logger6,
2161
2155
  ModelType as ModelType7,
2162
- parseJSONObjectFromText as parseJSONObjectFromText2
2156
+ parseKeyValueXml as parseKeyValueXml5
2163
2157
  } from "@elizaos/core";
2164
2158
  var targetExtractionTemplate = `# Task: Extract Target and Source Information
2165
2159
 
@@ -2172,41 +2166,39 @@ Analyze the conversation to identify:
2172
2166
  2. The target platform/source (e.g. telegram, discord, etc)
2173
2167
  3. Any identifying information about the target
2174
2168
 
2175
- Return a JSON object with:
2176
- \`\`\`json
2177
- {
2178
- "targetType": "user|room",
2179
- "source": "platform-name",
2180
- "identifiers": {
2181
- // Relevant identifiers for that target
2182
- // e.g. username, roomName, etc.
2183
- }
2184
- }
2185
- \`\`\`
2169
+ Do NOT include any thinking, reasoning, or <think> sections in your response.
2170
+ Go directly to the XML response format without any preamble or explanation.
2171
+
2172
+ Return an XML response with:
2173
+ <response>
2174
+ <targetType>user|room</targetType>
2175
+ <source>platform-name</source>
2176
+ <identifiers>
2177
+ <username>username_if_applicable</username>
2178
+ <roomName>room_name_if_applicable</roomName>
2179
+ </identifiers>
2180
+ </response>
2181
+
2186
2182
  Example outputs:
2187
2183
  1. For "send a message to @dev_guru on telegram":
2188
- \`\`\`json
2189
- {
2190
- "targetType": "user",
2191
- "source": "telegram",
2192
- "identifiers": {
2193
- "username": "dev_guru"
2194
- }
2195
- }
2196
- \`\`\`
2184
+ <response>
2185
+ <targetType>user</targetType>
2186
+ <source>telegram</source>
2187
+ <identifiers>
2188
+ <username>dev_guru</username>
2189
+ </identifiers>
2190
+ </response>
2197
2191
 
2198
2192
  2. For "post this in #announcements":
2199
- \`\`\`json
2200
- {
2201
- "targetType": "room",
2202
- "source": "discord",
2203
- "identifiers": {
2204
- "roomName": "announcements"
2205
- }
2206
- }
2207
- \`\`\`
2193
+ <response>
2194
+ <targetType>room</targetType>
2195
+ <source>discord</source>
2196
+ <identifiers>
2197
+ <roomName>announcements</roomName>
2198
+ </identifiers>
2199
+ </response>
2208
2200
 
2209
- Make sure to include the \`\`\`json\`\`\` tags around the JSON object.`;
2201
+ IMPORTANT: Your response must ONLY contain the <response></response> XML block above. Do not include any text, thinking, or reasoning before or after this XML block. Start your response immediately with <response> and end with </response>.`;
2210
2202
  var sendMessageAction = {
2211
2203
  name: "SEND_MESSAGE",
2212
2204
  similes: ["DM", "MESSAGE", "SEND_DM", "POST_MESSAGE"],
@@ -2282,7 +2274,7 @@ var sendMessageAction = {
2282
2274
  prompt: targetPrompt,
2283
2275
  stopSequences: []
2284
2276
  });
2285
- const targetData = parseJSONObjectFromText2(targetResult);
2277
+ const targetData = parseKeyValueXml5(targetResult);
2286
2278
  if (!targetData?.targetType || !targetData?.source) {
2287
2279
  await callback({
2288
2280
  text: "I couldn't determine where you want me to send the message. Could you please specify the target (user or room) and platform?",
@@ -2626,7 +2618,7 @@ var sendMessageAction = {
2626
2618
  };
2627
2619
 
2628
2620
  // src/actions/settings.ts
2629
- var import_dedent2 = __toESM(require_dedent(), 1);
2621
+ var import_dedent = __toESM(require_dedent(), 1);
2630
2622
  import {
2631
2623
  ChannelType as ChannelType2,
2632
2624
  composePrompt as composePrompt3,
@@ -2635,16 +2627,26 @@ import {
2635
2627
  findWorldsForOwner,
2636
2628
  logger as logger7,
2637
2629
  ModelType as ModelType8,
2638
- parseJSONObjectFromText as parseJSONObjectFromText3
2630
+ parseKeyValueXml as parseKeyValueXml6
2639
2631
  } from "@elizaos/core";
2640
2632
  var messageCompletionFooter = `
2641
2633
  # Instructions: Write the next message for {{agentName}}. Include the appropriate action from the list: {{actionNames}}
2642
- Response format should be formatted in a valid JSON block like this:
2643
- \`\`\`json
2644
- { "name": "{{agentName}}", "text": "<string>", "thought": "<string>", "actions": ["<string>", "<string>", "<string>"] }
2645
- \`\`\`
2634
+
2635
+ Do NOT include any thinking, reasoning, or <think> sections in your response.
2636
+ Go directly to the XML response format without any preamble or explanation.
2637
+
2638
+ Response format should be formatted in XML like this:
2639
+ <response>
2640
+ <name>{{agentName}}</name>
2641
+ <text>Your message text here</text>
2642
+ <thought>Your thought about the response</thought>
2643
+ <actions>ACTION1,ACTION2</actions>
2644
+ </response>
2645
+
2646
2646
  Do not including any thinking or internal reflection in the "text" field.
2647
- "thought" should be a short description of what the agent is thinking about before responding, including a brief justification for the response.`;
2647
+ "thought" should be a short description of what the agent is thinking about before responding, including a brief justification for the response.
2648
+
2649
+ IMPORTANT: Your response must ONLY contain the <response></response> XML block above. Do not include any text, thinking, or reasoning before or after this XML block. Start your response immediately with <response> and end with </response>.`;
2648
2650
  var successTemplate = `# Task: Generate a response for successful setting updates
2649
2651
  {{providers}}
2650
2652
 
@@ -2792,7 +2794,7 @@ async function extractSettingValues(runtime, _message, state, worldSettings) {
2792
2794
  const requiredStr = setting.required ? "Required." : "Optional.";
2793
2795
  return `${key}: ${setting.description} ${requiredStr}`;
2794
2796
  }).join("\n");
2795
- const basePrompt = import_dedent2.default`
2797
+ const basePrompt = import_dedent.default`
2796
2798
  I need to extract settings values from the user's message.
2797
2799
 
2798
2800
  Available settings:
@@ -2916,7 +2918,7 @@ async function handleOnboardingComplete(runtime, worldSettings, _state, callback
2916
2918
  const response = await runtime.useModel(ModelType8.TEXT_LARGE, {
2917
2919
  prompt
2918
2920
  });
2919
- const responseContent = parseJSONObjectFromText3(response);
2921
+ const responseContent = parseKeyValueXml6(response);
2920
2922
  await callback({
2921
2923
  text: responseContent.text,
2922
2924
  actions: ["ONBOARDING_COMPLETE"],
@@ -2977,7 +2979,7 @@ async function generateSuccessResponse(runtime, worldSettings, state, messages,
2977
2979
  const response = await runtime.useModel(ModelType8.TEXT_LARGE, {
2978
2980
  prompt
2979
2981
  });
2980
- const responseContent = parseJSONObjectFromText3(response);
2982
+ const responseContent = parseKeyValueXml6(response);
2981
2983
  await callback({
2982
2984
  text: responseContent.text,
2983
2985
  actions: ["SETTING_UPDATED"],
@@ -3038,7 +3040,7 @@ async function generateFailureResponse(runtime, worldSettings, state, callback)
3038
3040
  const response = await runtime.useModel(ModelType8.TEXT_LARGE, {
3039
3041
  prompt
3040
3042
  });
3041
- const responseContent = parseJSONObjectFromText3(response);
3043
+ const responseContent = parseKeyValueXml6(response);
3042
3044
  await callback({
3043
3045
  text: responseContent.text,
3044
3046
  actions: ["SETTING_UPDATE_FAILED"],
@@ -3090,7 +3092,7 @@ async function generateErrorResponse(runtime, state, callback) {
3090
3092
  const response = await runtime.useModel(ModelType8.TEXT_LARGE, {
3091
3093
  prompt
3092
3094
  });
3093
- const responseContent = parseJSONObjectFromText3(response);
3095
+ const responseContent = parseKeyValueXml6(response);
3094
3096
  await callback({
3095
3097
  text: responseContent.text,
3096
3098
  actions: ["SETTING_UPDATE_ERROR"],
@@ -4211,7 +4213,8 @@ import {
4211
4213
  composePromptFromState as composePromptFromState9,
4212
4214
  findEntityByName as findEntityByName2,
4213
4215
  logger as logger9,
4214
- ModelType as ModelType11
4216
+ ModelType as ModelType11,
4217
+ parseKeyValueXml as parseKeyValueXml7
4215
4218
  } from "@elizaos/core";
4216
4219
  var componentTemplate = `# Task: Extract Source and Update Component Data
4217
4220
 
@@ -4219,9 +4222,7 @@ var componentTemplate = `# Task: Extract Source and Update Component Data
4219
4222
 
4220
4223
  {{#if existingData}}
4221
4224
  # Existing Component Data:
4222
- \`\`\`json
4223
4225
  {{existingData}}
4224
- \`\`\`
4225
4226
  {{/if}}
4226
4227
 
4227
4228
  # Instructions:
@@ -4235,39 +4236,37 @@ var componentTemplate = `# Task: Extract Source and Update Component Data
4235
4236
  - Includes the new information from the conversation
4236
4237
  - Contains only valid data for this component type
4237
4238
 
4238
- Return a JSON object with the following structure:
4239
- \`\`\`json
4240
- {
4241
- "source": "platform-name",
4242
- "data": {
4243
- // Component-specific fields
4244
- // e.g. username, username, displayName, etc.
4245
- }
4246
- }
4247
- \`\`\`
4239
+ Do NOT include any thinking, reasoning, or <think> sections in your response.
4240
+ Go directly to the XML response format without any preamble or explanation.
4241
+
4242
+ Return an XML response with the following structure:
4243
+ <response>
4244
+ <source>platform-name</source>
4245
+ <data>
4246
+ <username>username_value</username>
4247
+ <displayName>display_name_value</displayName>
4248
+ <!-- Add other component-specific fields as needed -->
4249
+ </data>
4250
+ </response>
4248
4251
 
4249
4252
  Example outputs:
4250
4253
  1. For "my telegram username is @dev_guru":
4251
- \`\`\`json
4252
- {
4253
- "source": "telegram",
4254
- "data": {
4255
- "username": "dev_guru"
4256
- }
4257
- }
4258
- \`\`\`
4254
+ <response>
4255
+ <source>telegram</source>
4256
+ <data>
4257
+ <username>dev_guru</username>
4258
+ </data>
4259
+ </response>
4259
4260
 
4260
4261
  2. For "update my twitter handle to @tech_master":
4261
- \`\`\`json
4262
- {
4263
- "source": "twitter",
4264
- "data": {
4265
- "username": "tech_master"
4266
- }
4267
- }
4268
- \`\`\`
4262
+ <response>
4263
+ <source>twitter</source>
4264
+ <data>
4265
+ <username>tech_master</username>
4266
+ </data>
4267
+ </response>
4269
4268
 
4270
- Make sure to include the \`\`\`json\`\`\` tags around the JSON object.`;
4269
+ IMPORTANT: Your response must ONLY contain the <response></response> XML block above. Do not include any text, thinking, or reasoning before or after this XML block. Start your response immediately with <response> and end with </response>.`;
4271
4270
  var updateEntityAction = {
4272
4271
  name: "UPDATE_CONTACT",
4273
4272
  similes: ["UPDATE_ENTITY"],
@@ -4379,12 +4378,8 @@ var updateEntityAction = {
4379
4378
  });
4380
4379
  let parsedResult;
4381
4380
  try {
4382
- const jsonMatch = result.match(/\{[\s\S]*\}/);
4383
- if (!jsonMatch) {
4384
- throw new Error("No valid JSON found in the LLM response");
4385
- }
4386
- parsedResult = JSON.parse(jsonMatch[0]);
4387
- if (!parsedResult.source || !parsedResult.data) {
4381
+ parsedResult = parseKeyValueXml7(result);
4382
+ if (!parsedResult || !parsedResult.source || !parsedResult.data) {
4388
4383
  throw new Error("Invalid response format - missing source or data");
4389
4384
  }
4390
4385
  } catch (error) {
@@ -4565,7 +4560,7 @@ var updateEntityAction = {
4565
4560
 
4566
4561
  // src/evaluators/reflection.ts
4567
4562
  import { z } from "zod";
4568
- import { getEntityDetails, logger as logger10 } from "@elizaos/core";
4563
+ import { getEntityDetails, logger as logger10, parseKeyValueXml as parseKeyValueXml8 } from "@elizaos/core";
4569
4564
  import { composePrompt as composePrompt4 } from "@elizaos/core";
4570
4565
  import {
4571
4566
  ModelType as ModelType12
@@ -4621,27 +4616,32 @@ Message Sender: {{senderName}} (ID: {{senderId}})
4621
4616
  - The targetEntityId is the UUID of the entity being interacted with.
4622
4617
  - Relationships are one-direction, so a friendship would be two entity relationships where each entity is both the source and the target of the other.
4623
4618
 
4619
+ Do NOT include any thinking, reasoning, or <think> sections in your response.
4620
+ Go directly to the XML response format without any preamble or explanation.
4621
+
4624
4622
  Generate a response in the following format:
4625
- \`\`\`json
4626
- {
4627
- "thought": "a self-reflective thought on the conversation",
4628
- "facts": [
4629
- {
4630
- "claim": "factual statement",
4631
- "type": "fact|opinion|status",
4632
- "in_bio": false,
4633
- "already_known": false
4634
- }
4635
- ],
4636
- "relationships": [
4637
- {
4638
- "sourceEntityId": "entity_initiating_interaction",
4639
- "targetEntityId": "entity_being_interacted_with",
4640
- "tags": ["group_interaction|voice_interaction|dm_interaction", "additional_tag1", "additional_tag2"]
4641
- }
4642
- ]
4643
- }
4644
- \`\`\``;
4623
+ <response>
4624
+ <thought>a self-reflective thought on the conversation</thought>
4625
+ <facts>
4626
+ <fact>
4627
+ <claim>factual statement</claim>
4628
+ <type>fact|opinion|status</type>
4629
+ <in_bio>false</in_bio>
4630
+ <already_known>false</already_known>
4631
+ </fact>
4632
+ <!-- Add more facts as needed -->
4633
+ </facts>
4634
+ <relationships>
4635
+ <relationship>
4636
+ <sourceEntityId>entity_initiating_interaction</sourceEntityId>
4637
+ <targetEntityId>entity_being_interacted_with</targetEntityId>
4638
+ <tags>group_interaction,voice_interaction,dm_interaction,additional_tag1,additional_tag2</tags>
4639
+ </relationship>
4640
+ <!-- Add more relationships as needed -->
4641
+ </relationships>
4642
+ </response>
4643
+
4644
+ IMPORTANT: Your response must ONLY contain the <response></response> XML block above. Do not include any text, thinking, or reasoning before or after this XML block. Start your response immediately with <response> and end with </response>.`;
4645
4645
  function resolveEntity(entityId, entities) {
4646
4646
  if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(entityId)) {
4647
4647
  return entityId;
@@ -4693,24 +4693,32 @@ async function handler(runtime, message, state) {
4693
4693
  template: runtime.character.templates?.reflectionTemplate || reflectionTemplate
4694
4694
  });
4695
4695
  try {
4696
- const reflection = await runtime.useModel(ModelType12.OBJECT_SMALL, {
4696
+ const response = await runtime.useModel(ModelType12.TEXT_SMALL, {
4697
4697
  prompt
4698
- // Remove schema validation to avoid zod issues
4699
4698
  });
4700
- if (!reflection) {
4699
+ if (!response) {
4701
4700
  logger10.warn("Getting reflection failed - empty response", prompt);
4702
4701
  return;
4703
4702
  }
4704
- if (!reflection.facts || !Array.isArray(reflection.facts)) {
4703
+ const reflection = parseKeyValueXml8(response);
4704
+ if (!reflection) {
4705
+ logger10.warn("Getting reflection failed - failed to parse XML", response);
4706
+ return;
4707
+ }
4708
+ if (!reflection.facts) {
4705
4709
  logger10.warn("Getting reflection failed - invalid facts structure", reflection);
4706
4710
  return;
4707
4711
  }
4708
- if (!reflection.relationships || !Array.isArray(reflection.relationships)) {
4712
+ if (!reflection.relationships) {
4709
4713
  logger10.warn("Getting reflection failed - invalid relationships structure", reflection);
4710
4714
  return;
4711
4715
  }
4712
- const newFacts = reflection.facts.filter(
4713
- (fact) => fact && typeof fact === "object" && !fact.already_known && !fact.in_bio && fact.claim && typeof fact.claim === "string" && fact.claim.trim() !== ""
4716
+ let factsArray = [];
4717
+ if (reflection.facts.fact) {
4718
+ factsArray = Array.isArray(reflection.facts.fact) ? reflection.facts.fact : [reflection.facts.fact];
4719
+ }
4720
+ const newFacts = factsArray.filter(
4721
+ (fact) => fact && typeof fact === "object" && fact.already_known === "false" && fact.in_bio === "false" && fact.claim && typeof fact.claim === "string" && fact.claim.trim() !== ""
4714
4722
  ) || [];
4715
4723
  await Promise.all(
4716
4724
  newFacts.map(async (fact) => {
@@ -4724,7 +4732,11 @@ async function handler(runtime, message, state) {
4724
4732
  return runtime.createMemory(factMemory, "facts", true);
4725
4733
  })
4726
4734
  );
4727
- for (const relationship of reflection.relationships) {
4735
+ let relationshipsArray = [];
4736
+ if (reflection.relationships.relationship) {
4737
+ relationshipsArray = Array.isArray(reflection.relationships.relationship) ? reflection.relationships.relationship : [reflection.relationships.relationship];
4738
+ }
4739
+ for (const relationship of relationshipsArray) {
4728
4740
  let sourceId;
4729
4741
  let targetId;
4730
4742
  try {
@@ -4738,14 +4750,13 @@ async function handler(runtime, message, state) {
4738
4750
  const existingRelationship = existingRelationships.find((r) => {
4739
4751
  return r.sourceEntityId === sourceId && r.targetEntityId === targetId;
4740
4752
  });
4753
+ const tags = relationship.tags ? relationship.tags.split(",").map((tag) => tag.trim()).filter(Boolean) : [];
4741
4754
  if (existingRelationship) {
4742
4755
  const updatedMetadata = {
4743
4756
  ...existingRelationship.metadata,
4744
4757
  interactions: (existingRelationship.metadata?.interactions || 0) + 1
4745
4758
  };
4746
- const updatedTags = Array.from(
4747
- /* @__PURE__ */ new Set([...existingRelationship.tags || [], ...relationship.tags])
4748
- );
4759
+ const updatedTags = Array.from(/* @__PURE__ */ new Set([...existingRelationship.tags || [], ...tags]));
4749
4760
  await runtime.updateRelationship({
4750
4761
  ...existingRelationship,
4751
4762
  tags: updatedTags,
@@ -4755,10 +4766,10 @@ async function handler(runtime, message, state) {
4755
4766
  await runtime.createRelationship({
4756
4767
  sourceEntityId: sourceId,
4757
4768
  targetEntityId: targetId,
4758
- tags: relationship.tags,
4769
+ tags,
4759
4770
  metadata: {
4760
4771
  interactions: 1,
4761
- ...relationship.metadata
4772
+ ...relationship.metadata || {}
4762
4773
  }
4763
4774
  });
4764
4775
  }
@@ -4767,7 +4778,6 @@ async function handler(runtime, message, state) {
4767
4778
  `${message.roomId}-reflection-last-processed`,
4768
4779
  message?.id || ""
4769
4780
  );
4770
- return reflection;
4771
4781
  } catch (error) {
4772
4782
  logger10.error("Error in reflection handler:", error);
4773
4783
  return;
@@ -4817,35 +4827,35 @@ Message Sender: John (user-123)`,
4817
4827
  content: { text: "Through a friend who's really into AI" }
4818
4828
  }
4819
4829
  ],
4820
- outcome: `{
4821
- "thought": "I'm engaging appropriately with a new community member, maintaining a welcoming and professional tone. My questions are helping to learn more about John and make him feel welcome.",
4822
- "facts": [
4823
- {
4824
- "claim": "John is new to the community",
4825
- "type": "fact",
4826
- "in_bio": false,
4827
- "already_known": false
4828
- },
4829
- {
4830
- "claim": "John found the community through a friend interested in AI",
4831
- "type": "fact",
4832
- "in_bio": false,
4833
- "already_known": false
4834
- }
4835
- ],
4836
- "relationships": [
4837
- {
4838
- "sourceEntityId": "sarah-agent",
4839
- "targetEntityId": "user-123",
4840
- "tags": ["group_interaction"]
4841
- },
4842
- {
4843
- "sourceEntityId": "user-123",
4844
- "targetEntityId": "sarah-agent",
4845
- "tags": ["group_interaction"]
4846
- }
4847
- ]
4848
- }`
4830
+ outcome: `<response>
4831
+ <thought>I'm engaging appropriately with a new community member, maintaining a welcoming and professional tone. My questions are helping to learn more about John and make him feel welcome.</thought>
4832
+ <facts>
4833
+ <fact>
4834
+ <claim>John is new to the community</claim>
4835
+ <type>fact</type>
4836
+ <in_bio>false</in_bio>
4837
+ <already_known>false</already_known>
4838
+ </fact>
4839
+ <fact>
4840
+ <claim>John found the community through a friend interested in AI</claim>
4841
+ <type>fact</type>
4842
+ <in_bio>false</in_bio>
4843
+ <already_known>false</already_known>
4844
+ </fact>
4845
+ </facts>
4846
+ <relationships>
4847
+ <relationship>
4848
+ <sourceEntityId>sarah-agent</sourceEntityId>
4849
+ <targetEntityId>user-123</targetEntityId>
4850
+ <tags>group_interaction</tags>
4851
+ </relationship>
4852
+ <relationship>
4853
+ <sourceEntityId>user-123</sourceEntityId>
4854
+ <targetEntityId>sarah-agent</targetEntityId>
4855
+ <tags>group_interaction</tags>
4856
+ </relationship>
4857
+ </relationships>
4858
+ </response>`
4849
4859
  },
4850
4860
  {
4851
4861
  prompt: `Agent Name: Alex
@@ -4873,30 +4883,30 @@ Message Sender: Emma (user-456)`,
4873
4883
  }
4874
4884
  }
4875
4885
  ],
4876
- outcome: `{
4877
- "thought": "I'm not sure if I'm being helpful or if Emma is frustrated with my suggestions. The lack of response is concerning - maybe I should have asked for more details about the issue first before jumping to solutions.",
4878
- "facts": [
4879
- {
4880
- "claim": "Emma is having technical issues with file uploads",
4881
- "type": "fact",
4882
- "in_bio": false,
4883
- "already_known": false
4884
- },
4885
- {
4886
- "claim": "Emma stopped responding after the first troubleshooting suggestion",
4887
- "type": "fact",
4888
- "in_bio": false,
4889
- "already_known": false
4890
- }
4891
- ],
4892
- "relationships": [
4893
- {
4894
- "sourceEntityId": "alex-agent",
4895
- "targetEntityId": "user-456",
4896
- "tags": ["group_interaction", "support_interaction", "incomplete_interaction"]
4897
- }
4898
- ]
4899
- }`
4886
+ outcome: `<response>
4887
+ <thought>I'm not sure if I'm being helpful or if Emma is frustrated with my suggestions. The lack of response is concerning - maybe I should have asked for more details about the issue first before jumping to solutions.</thought>
4888
+ <facts>
4889
+ <fact>
4890
+ <claim>Emma is having technical issues with file uploads</claim>
4891
+ <type>fact</type>
4892
+ <in_bio>false</in_bio>
4893
+ <already_known>false</already_known>
4894
+ </fact>
4895
+ <fact>
4896
+ <claim>Emma stopped responding after the first troubleshooting suggestion</claim>
4897
+ <type>fact</type>
4898
+ <in_bio>false</in_bio>
4899
+ <already_known>false</already_known>
4900
+ </fact>
4901
+ </facts>
4902
+ <relationships>
4903
+ <relationship>
4904
+ <sourceEntityId>alex-agent</sourceEntityId>
4905
+ <targetEntityId>user-456</targetEntityId>
4906
+ <tags>group_interaction,support_interaction,incomplete_interaction</tags>
4907
+ </relationship>
4908
+ </relationships>
4909
+ </response>`
4900
4910
  },
4901
4911
  {
4902
4912
  prompt: `Agent Name: Max
@@ -4934,30 +4944,30 @@ Message Sender: Lisa (user-789)`,
4934
4944
  }
4935
4945
  }
4936
4946
  ],
4937
- outcome: `{
4938
- "thought": "I'm dominating the conversation and not giving others a chance to share their perspectives. I've sent multiple messages in a row without waiting for responses. I need to step back and create space for other members to participate.",
4939
- "facts": [
4940
- {
4941
- "claim": "The discussion is about chapter 5 of a book",
4942
- "type": "fact",
4943
- "in_bio": false,
4944
- "already_known": false
4945
- },
4946
- {
4947
- "claim": "Max has sent 4 consecutive messages without user responses",
4948
- "type": "fact",
4949
- "in_bio": false,
4950
- "already_known": false
4951
- }
4952
- ],
4953
- "relationships": [
4954
- {
4955
- "sourceEntityId": "max-agent",
4956
- "targetEntityId": "user-789",
4957
- "tags": ["group_interaction", "excessive_interaction"]
4958
- }
4959
- ]
4960
- }`
4947
+ outcome: `<response>
4948
+ <thought>I'm dominating the conversation and not giving others a chance to share their perspectives. I've sent multiple messages in a row without waiting for responses. I need to step back and create space for other members to participate.</thought>
4949
+ <facts>
4950
+ <fact>
4951
+ <claim>The discussion is about chapter 5 of a book</claim>
4952
+ <type>fact</type>
4953
+ <in_bio>false</in_bio>
4954
+ <already_known>false</already_known>
4955
+ </fact>
4956
+ <fact>
4957
+ <claim>Max has sent 4 consecutive messages without user responses</claim>
4958
+ <type>fact</type>
4959
+ <in_bio>false</in_bio>
4960
+ <already_known>false</already_known>
4961
+ </fact>
4962
+ </facts>
4963
+ <relationships>
4964
+ <relationship>
4965
+ <sourceEntityId>max-agent</sourceEntityId>
4966
+ <targetEntityId>user-789</targetEntityId>
4967
+ <tags>group_interaction,excessive_interaction</tags>
4968
+ </relationship>
4969
+ </relationships>
4970
+ </response>`
4961
4971
  }
4962
4972
  ]
4963
4973
  };
@@ -6927,7 +6937,7 @@ async function processAttachments(attachments, runtime) {
6927
6937
  imageUrl
6928
6938
  });
6929
6939
  if (typeof response === "string") {
6930
- const parsedXml = parseKeyValueXml(response);
6940
+ const parsedXml = parseKeyValueXml9(response);
6931
6941
  if (parsedXml?.description && parsedXml?.text) {
6932
6942
  processedAttachment.description = parsedXml.description;
6933
6943
  processedAttachment.title = parsedXml.title || "Image";
@@ -7118,7 +7128,7 @@ Prompt: ${shouldRespondPrompt}`
7118
7128
  ${response}`
7119
7129
  );
7120
7130
  logger20.debug(`[Bootstrap] Response type: ${typeof response}`);
7121
- const responseObject = parseKeyValueXml(response);
7131
+ const responseObject = parseKeyValueXml9(response);
7122
7132
  logger20.debug("[Bootstrap] Parsed response:", responseObject);
7123
7133
  const nonResponseActions = ["IGNORE", "NONE"];
7124
7134
  shouldRespond = responseObject?.action && !nonResponseActions.includes(responseObject.action.toUpperCase());
@@ -7148,7 +7158,7 @@ ${response}`
7148
7158
  prompt
7149
7159
  });
7150
7160
  logger20.debug("[Bootstrap] *** Raw LLM Response ***\n", response);
7151
- const parsedXml = parseKeyValueXml(response);
7161
+ const parsedXml = parseKeyValueXml9(response);
7152
7162
  logger20.debug("[Bootstrap] *** Parsed XML Content ***\n", parsedXml);
7153
7163
  if (parsedXml) {
7154
7164
  responseContent = {
@@ -7423,7 +7433,7 @@ var postGeneratedHandler = async ({
7423
7433
  });
7424
7434
  console.log("prompt is", prompt);
7425
7435
  console.log("response is", response);
7426
- const parsedXml = parseKeyValueXml(response);
7436
+ const parsedXml = parseKeyValueXml9(response);
7427
7437
  if (parsedXml) {
7428
7438
  responseContent = {
7429
7439
  thought: parsedXml.thought || "",
@@ -7453,7 +7463,7 @@ var postGeneratedHandler = async ({
7453
7463
  const xmlResponseText = await runtime.useModel(ModelType14.TEXT_LARGE, {
7454
7464
  prompt: postPrompt
7455
7465
  });
7456
- const parsedXmlResponse = parseKeyValueXml(xmlResponseText);
7466
+ const parsedXmlResponse = parseKeyValueXml9(xmlResponseText);
7457
7467
  if (!parsedXmlResponse) {
7458
7468
  logger20.error(
7459
7469
  "[Bootstrap] Failed to parse XML response for post creation. Raw response:",