@elizaos/python 2.0.0-alpha.10 → 2.0.0-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.
Files changed (145) hide show
  1. package/elizaos/__init__.py +0 -1
  2. package/elizaos/advanced_capabilities/__init__.py +6 -41
  3. package/elizaos/advanced_capabilities/actions/__init__.py +1 -21
  4. package/elizaos/advanced_capabilities/actions/add_contact.py +21 -11
  5. package/elizaos/advanced_capabilities/actions/follow_room.py +28 -28
  6. package/elizaos/advanced_capabilities/actions/image_generation.py +13 -26
  7. package/elizaos/advanced_capabilities/actions/mute_room.py +13 -26
  8. package/elizaos/advanced_capabilities/actions/remove_contact.py +16 -2
  9. package/elizaos/advanced_capabilities/actions/roles.py +13 -27
  10. package/elizaos/advanced_capabilities/actions/schedule_follow_up.py +70 -15
  11. package/elizaos/advanced_capabilities/actions/search_contacts.py +17 -3
  12. package/elizaos/advanced_capabilities/actions/send_message.py +183 -50
  13. package/elizaos/advanced_capabilities/actions/settings.py +16 -2
  14. package/elizaos/advanced_capabilities/actions/unfollow_room.py +13 -26
  15. package/elizaos/advanced_capabilities/actions/unmute_room.py +13 -26
  16. package/elizaos/advanced_capabilities/actions/update_contact.py +16 -2
  17. package/elizaos/advanced_capabilities/actions/update_entity.py +16 -2
  18. package/elizaos/advanced_capabilities/evaluators/__init__.py +2 -9
  19. package/elizaos/advanced_capabilities/evaluators/reflection.py +3 -132
  20. package/elizaos/advanced_capabilities/evaluators/relationship_extraction.py +5 -201
  21. package/elizaos/advanced_capabilities/providers/__init__.py +1 -12
  22. package/elizaos/advanced_capabilities/providers/knowledge.py +24 -3
  23. package/elizaos/advanced_capabilities/services/__init__.py +2 -9
  24. package/elizaos/advanced_memory/actions/reset_session.py +11 -0
  25. package/elizaos/advanced_memory/evaluators/reflection.py +134 -0
  26. package/elizaos/advanced_memory/evaluators/relationship_extraction.py +203 -0
  27. package/elizaos/advanced_memory/memory_service.py +15 -17
  28. package/elizaos/advanced_memory/test_advanced_memory.py +357 -0
  29. package/elizaos/advanced_planning/actions/schedule_follow_up.py +222 -0
  30. package/elizaos/advanced_planning/planning_service.py +26 -14
  31. package/elizaos/basic_capabilities/__init__.py +0 -2
  32. package/elizaos/basic_capabilities/providers/__init__.py +0 -3
  33. package/elizaos/basic_capabilities/providers/actions.py +118 -29
  34. package/elizaos/basic_capabilities/providers/agent_settings.py +64 -0
  35. package/elizaos/basic_capabilities/providers/character.py +19 -21
  36. package/elizaos/basic_capabilities/providers/contacts.py +79 -0
  37. package/elizaos/basic_capabilities/providers/current_time.py +7 -4
  38. package/elizaos/basic_capabilities/providers/facts.py +87 -0
  39. package/elizaos/basic_capabilities/providers/follow_ups.py +117 -0
  40. package/elizaos/basic_capabilities/providers/knowledge.py +97 -0
  41. package/elizaos/basic_capabilities/providers/relationships.py +107 -0
  42. package/elizaos/basic_capabilities/providers/roles.py +96 -0
  43. package/elizaos/basic_capabilities/providers/settings.py +56 -0
  44. package/elizaos/basic_capabilities/providers/time.py +7 -4
  45. package/elizaos/bootstrap/__init__.py +21 -2
  46. package/elizaos/bootstrap/actions/schedule_follow_up.py +65 -7
  47. package/elizaos/bootstrap/actions/send_message.py +162 -15
  48. package/elizaos/bootstrap/autonomy/__init__.py +5 -1
  49. package/elizaos/bootstrap/autonomy/action.py +161 -0
  50. package/elizaos/bootstrap/autonomy/evaluators.py +217 -0
  51. package/elizaos/bootstrap/autonomy/service.py +238 -28
  52. package/elizaos/bootstrap/plugin.py +7 -0
  53. package/elizaos/bootstrap/providers/actions.py +118 -27
  54. package/elizaos/bootstrap/providers/agent_settings.py +1 -0
  55. package/elizaos/bootstrap/providers/attachments.py +1 -0
  56. package/elizaos/bootstrap/providers/capabilities.py +1 -0
  57. package/elizaos/bootstrap/providers/character.py +1 -0
  58. package/elizaos/bootstrap/providers/choice.py +1 -0
  59. package/elizaos/bootstrap/providers/contacts.py +1 -0
  60. package/elizaos/bootstrap/providers/current_time.py +8 -2
  61. package/elizaos/bootstrap/providers/entities.py +1 -0
  62. package/elizaos/bootstrap/providers/evaluators.py +1 -0
  63. package/elizaos/bootstrap/providers/facts.py +1 -0
  64. package/elizaos/bootstrap/providers/follow_ups.py +1 -0
  65. package/elizaos/bootstrap/providers/knowledge.py +27 -3
  66. package/elizaos/bootstrap/providers/providers_list.py +1 -0
  67. package/elizaos/bootstrap/providers/relationships.py +1 -0
  68. package/elizaos/bootstrap/providers/roles.py +1 -0
  69. package/elizaos/bootstrap/providers/settings.py +1 -0
  70. package/elizaos/bootstrap/providers/time.py +8 -4
  71. package/elizaos/bootstrap/providers/world.py +1 -0
  72. package/elizaos/bootstrap/services/embedding.py +156 -1
  73. package/elizaos/deterministic.py +193 -0
  74. package/elizaos/generated/__init__.py +1 -0
  75. package/elizaos/generated/action_docs.py +3181 -0
  76. package/elizaos/generated/spec_helpers.py +175 -0
  77. package/elizaos/media/mime.py +2 -2
  78. package/elizaos/media/search.py +23 -23
  79. package/elizaos/runtime.py +215 -57
  80. package/elizaos/services/message_service.py +175 -29
  81. package/elizaos/types/components.py +2 -2
  82. package/elizaos/types/generated/__init__.py +12 -0
  83. package/elizaos/types/generated/eliza/v1/agent_pb2.py +63 -0
  84. package/elizaos/types/generated/eliza/v1/agent_pb2.pyi +159 -0
  85. package/elizaos/types/generated/eliza/v1/components_pb2.py +65 -0
  86. package/elizaos/types/generated/eliza/v1/components_pb2.pyi +160 -0
  87. package/elizaos/types/generated/eliza/v1/database_pb2.py +78 -0
  88. package/elizaos/types/generated/eliza/v1/database_pb2.pyi +305 -0
  89. package/elizaos/types/generated/eliza/v1/environment_pb2.py +58 -0
  90. package/elizaos/types/generated/eliza/v1/environment_pb2.pyi +135 -0
  91. package/elizaos/types/generated/eliza/v1/events_pb2.py +82 -0
  92. package/elizaos/types/generated/eliza/v1/events_pb2.pyi +322 -0
  93. package/elizaos/types/generated/eliza/v1/ipc_pb2.py +113 -0
  94. package/elizaos/types/generated/eliza/v1/ipc_pb2.pyi +367 -0
  95. package/elizaos/types/generated/eliza/v1/knowledge_pb2.py +41 -0
  96. package/elizaos/types/generated/eliza/v1/knowledge_pb2.pyi +26 -0
  97. package/elizaos/types/generated/eliza/v1/memory_pb2.py +55 -0
  98. package/elizaos/types/generated/eliza/v1/memory_pb2.pyi +111 -0
  99. package/elizaos/types/generated/eliza/v1/message_service_pb2.py +48 -0
  100. package/elizaos/types/generated/eliza/v1/message_service_pb2.pyi +69 -0
  101. package/elizaos/types/generated/eliza/v1/messaging_pb2.py +51 -0
  102. package/elizaos/types/generated/eliza/v1/messaging_pb2.pyi +97 -0
  103. package/elizaos/types/generated/eliza/v1/model_pb2.py +84 -0
  104. package/elizaos/types/generated/eliza/v1/model_pb2.pyi +280 -0
  105. package/elizaos/types/generated/eliza/v1/payment_pb2.py +44 -0
  106. package/elizaos/types/generated/eliza/v1/payment_pb2.pyi +70 -0
  107. package/elizaos/types/generated/eliza/v1/plugin_pb2.py +68 -0
  108. package/elizaos/types/generated/eliza/v1/plugin_pb2.pyi +145 -0
  109. package/elizaos/types/generated/eliza/v1/primitives_pb2.py +48 -0
  110. package/elizaos/types/generated/eliza/v1/primitives_pb2.pyi +92 -0
  111. package/elizaos/types/generated/eliza/v1/prompts_pb2.py +52 -0
  112. package/elizaos/types/generated/eliza/v1/prompts_pb2.pyi +74 -0
  113. package/elizaos/types/generated/eliza/v1/service_interfaces_pb2.py +211 -0
  114. package/elizaos/types/generated/eliza/v1/service_interfaces_pb2.pyi +1296 -0
  115. package/elizaos/types/generated/eliza/v1/service_pb2.py +42 -0
  116. package/elizaos/types/generated/eliza/v1/service_pb2.pyi +69 -0
  117. package/elizaos/types/generated/eliza/v1/settings_pb2.py +58 -0
  118. package/elizaos/types/generated/eliza/v1/settings_pb2.pyi +85 -0
  119. package/elizaos/types/generated/eliza/v1/state_pb2.py +60 -0
  120. package/elizaos/types/generated/eliza/v1/state_pb2.pyi +114 -0
  121. package/elizaos/types/generated/eliza/v1/task_pb2.py +42 -0
  122. package/elizaos/types/generated/eliza/v1/task_pb2.pyi +58 -0
  123. package/elizaos/types/generated/eliza/v1/tee_pb2.py +52 -0
  124. package/elizaos/types/generated/eliza/v1/tee_pb2.pyi +90 -0
  125. package/elizaos/types/generated/eliza/v1/testing_pb2.py +39 -0
  126. package/elizaos/types/generated/eliza/v1/testing_pb2.pyi +23 -0
  127. package/elizaos/types/model.py +30 -0
  128. package/elizaos/types/runtime.py +6 -2
  129. package/elizaos/utils/validation.py +76 -0
  130. package/package.json +3 -2
  131. package/tests/test_action_parameters.py +2 -3
  132. package/tests/test_actions_provider_examples.py +58 -1
  133. package/tests/test_advanced_memory_behavior.py +0 -2
  134. package/tests/test_advanced_memory_flag.py +0 -2
  135. package/tests/test_advanced_planning_behavior.py +11 -5
  136. package/tests/test_async_embedding.py +124 -0
  137. package/tests/test_autonomy.py +24 -3
  138. package/tests/test_runtime.py +8 -17
  139. package/tests/test_schedule_follow_up_action.py +260 -0
  140. package/tests/test_send_message_action_targets.py +114 -0
  141. package/tests/test_settings_crypto.py +0 -2
  142. package/tests/test_validation.py +141 -0
  143. package/tests/verify_memory_architecture.py +192 -0
  144. package/uv.lock +1565 -0
  145. package/elizaos/basic_capabilities/providers/capabilities.py +0 -62
@@ -2,11 +2,12 @@ from __future__ import annotations
2
2
 
3
3
  import contextlib
4
4
  from dataclasses import dataclass, field
5
- from typing import TYPE_CHECKING
5
+ from typing import TYPE_CHECKING, Any
6
6
 
7
7
  from elizaos.generated.spec_helpers import require_action_spec
8
8
  from elizaos.types import Action, ActionExample, ActionResult, Content
9
9
  from elizaos.types.memory import Memory as MemoryType
10
+ from elizaos.types.primitives import UUID, as_uuid
10
11
 
11
12
  if TYPE_CHECKING:
12
13
  from elizaos.types import HandlerCallback, HandlerOptions, IAgentRuntime, Memory, State
@@ -18,34 +19,69 @@ _spec = require_action_spec("SEND_MESSAGE")
18
19
  def _convert_spec_examples() -> list[list[ActionExample]]:
19
20
  """Convert spec examples to ActionExample format."""
20
21
  spec_examples = _spec.get("examples", [])
21
- if not isinstance(spec_examples, list):
22
- return []
23
- result: list[list[ActionExample]] = []
24
- for example in spec_examples:
25
- if not isinstance(example, list):
26
- continue
27
- row: list[ActionExample] = []
28
- for msg in example:
29
- if not isinstance(msg, dict):
30
- continue
31
- content = msg.get("content", {})
32
- text = ""
33
- actions: list[str] | None = None
34
- if isinstance(content, dict):
35
- text_val = content.get("text", "")
36
- text = str(text_val) if text_val else ""
37
- actions_val = content.get("actions")
38
- if isinstance(actions_val, list) and all(isinstance(a, str) for a in actions_val):
39
- actions = list(actions_val)
40
- row.append(
22
+ if spec_examples:
23
+ return [
24
+ [
41
25
  ActionExample(
42
- name=str(msg.get("name", "")),
43
- content=Content(text=text, actions=actions),
26
+ name=msg.get("name", ""),
27
+ content=Content(
28
+ text=msg.get("content", {}).get("text", ""),
29
+ actions=msg.get("content", {}).get("actions"),
30
+ ),
44
31
  )
45
- )
46
- if row:
47
- result.append(row)
48
- return result
32
+ for msg in example
33
+ ]
34
+ for example in spec_examples
35
+ ]
36
+ return []
37
+
38
+
39
+ def _parse_uuid(value: object) -> UUID | None:
40
+ if not isinstance(value, str) or not value.strip():
41
+ return None
42
+ with contextlib.suppress(Exception):
43
+ return as_uuid(value.strip())
44
+ return None
45
+
46
+
47
+ def _normalize_parameters(options: HandlerOptions | None) -> dict[str, Any]:
48
+ raw = getattr(options, "parameters", None)
49
+ if isinstance(raw, dict):
50
+ return raw
51
+
52
+ if raw is None:
53
+ return {}
54
+
55
+ if hasattr(raw, "items"):
56
+ try:
57
+ return {str(k): v for k, v in raw.items()}
58
+ except Exception:
59
+ return {}
60
+
61
+ return {}
62
+
63
+
64
+ def _coerce_entity_name(entity: object) -> list[str]:
65
+ if isinstance(entity, dict):
66
+ names = entity.get("names")
67
+ if isinstance(names, list):
68
+ return [str(n).strip() for n in names if isinstance(n, str) and n.strip()]
69
+ name = entity.get("name")
70
+ if isinstance(name, str) and name.strip():
71
+ return [name.strip()]
72
+ return []
73
+
74
+ names = getattr(entity, "names", None)
75
+ if isinstance(names, list):
76
+ clean = [str(n).strip() for n in names if isinstance(n, str) and str(n).strip()]
77
+ if clean:
78
+ return clean
79
+
80
+ name = getattr(entity, "name", None)
81
+ if isinstance(name, str) and name.strip():
82
+ return [name.strip()]
83
+
84
+ return []
49
85
 
50
86
 
51
87
  @dataclass
@@ -70,9 +106,14 @@ class SendMessageAction:
70
106
  callback: HandlerCallback | None = None,
71
107
  responses: list[Memory] | None = None,
72
108
  ) -> ActionResult:
73
- message_text = ""
74
- if responses and responses[0].content:
75
- message_text = str(responses[0].content.text or "")
109
+ params = _normalize_parameters(options)
110
+
111
+ text_param = params.get("text")
112
+ message_text = str(text_param).strip() if isinstance(text_param, str) else ""
113
+ if not message_text and responses and responses[0].content:
114
+ message_text = str(responses[0].content.text or "").strip()
115
+ if not message_text and message.content and isinstance(message.content.text, str):
116
+ message_text = message.content.text.strip()
76
117
 
77
118
  if not message_text:
78
119
  return ActionResult(
@@ -82,24 +123,95 @@ class SendMessageAction:
82
123
  success=False,
83
124
  )
84
125
 
85
- from uuid import UUID as StdUUID
126
+ target_room_id = message.room_id
127
+ target_entity_id: UUID | None = None
128
+ target_type = "room"
129
+
130
+ target_type_param = params.get("targetType") or params.get("target_type")
131
+ target_param = params.get("target")
132
+ source_param = params.get("source")
133
+
134
+ source = (
135
+ source_param.strip()
136
+ if isinstance(source_param, str) and source_param.strip()
137
+ else (
138
+ message.content.source
139
+ if message.content and isinstance(message.content.source, str)
140
+ else "agent"
141
+ )
142
+ )
143
+
144
+ if isinstance(target_type_param, str):
145
+ normalized_target_type = target_type_param.strip().lower()
146
+ if normalized_target_type in {"user", "entity"}:
147
+ target_type = "user"
148
+ elif normalized_target_type == "room":
149
+ target_type = "room"
86
150
 
87
- target_room_id_val: str | None = str(message.room_id) if message.room_id else None
88
- target_entity_id: str | None = None
151
+ if isinstance(target_param, str) and target_param.strip():
152
+ target_value = target_param.strip()
153
+ if target_type == "room":
154
+ parsed_room = _parse_uuid(target_value)
155
+ if parsed_room:
156
+ target_room_id = parsed_room
157
+ else:
158
+ world_id = None
159
+ room_data = (
160
+ getattr(getattr(state, "data", None), "room", None) if state else None
161
+ )
162
+ if room_data is not None:
163
+ world_id = getattr(room_data, "world_id", None) or getattr(
164
+ room_data, "worldId", None
165
+ )
166
+ if world_id is None:
167
+ with contextlib.suppress(Exception):
168
+ current_room = await runtime.get_room(message.room_id)
169
+ if current_room:
170
+ world_id = getattr(current_room, "world_id", None) or getattr(
171
+ current_room, "worldId", None
172
+ )
173
+
174
+ if world_id is not None:
175
+ with contextlib.suppress(Exception):
176
+ rooms = await runtime.get_rooms(world_id)
177
+ for room in rooms:
178
+ room_name = getattr(room, "name", None)
179
+ if (
180
+ isinstance(room_name, str)
181
+ and room_name.strip().lower() == target_value.lower()
182
+ ):
183
+ room_id = getattr(room, "id", None)
184
+ if room_id is not None:
185
+ target_room_id = as_uuid(str(room_id))
186
+ break
187
+ else:
188
+ parsed_entity = _parse_uuid(target_value)
189
+ if parsed_entity:
190
+ target_entity_id = parsed_entity
191
+ else:
192
+ with contextlib.suppress(Exception):
193
+ entities = await runtime.get_entities_for_room(message.room_id)
194
+ for entity in entities:
195
+ names = _coerce_entity_name(entity)
196
+ if any(name.lower() == target_value.lower() for name in names):
197
+ entity_id = getattr(entity, "id", None)
198
+ if entity_id is not None:
199
+ target_entity_id = as_uuid(str(entity_id))
200
+ break
89
201
 
90
202
  if message.content and message.content.target:
91
203
  target = message.content.target
92
204
  if isinstance(target, dict):
93
205
  room_str = target.get("roomId")
94
206
  entity_str = target.get("entityId")
95
- if room_str:
96
- with contextlib.suppress(ValueError):
97
- target_room_id_val = str(StdUUID(str(room_str)))
98
- if entity_str:
99
- with contextlib.suppress(ValueError):
100
- target_entity_id = str(StdUUID(str(entity_str)))
101
-
102
- if not target_room_id_val:
207
+ if room_str and target_type == "room":
208
+ with contextlib.suppress(Exception):
209
+ target_room_id = as_uuid(room_str)
210
+ if entity_str and target_type == "user":
211
+ with contextlib.suppress(Exception):
212
+ target_entity_id = as_uuid(entity_str)
213
+
214
+ if not target_room_id:
103
215
  return ActionResult(
104
216
  text="No target room specified",
105
217
  values={"success": False, "error": "no_target"},
@@ -109,27 +221,39 @@ class SendMessageAction:
109
221
 
110
222
  message_content = Content(
111
223
  text=message_text,
112
- source="agent",
224
+ source=source,
113
225
  actions=["SEND_MESSAGE"],
114
226
  )
115
227
 
116
- # Create the message memory for event emission
228
+ send_message_to_target = getattr(runtime, "send_message_to_target", None)
229
+ if callable(send_message_to_target):
230
+ with contextlib.suppress(Exception):
231
+ from elizaos.types.runtime import TargetInfo
232
+
233
+ await send_message_to_target(
234
+ TargetInfo(
235
+ roomId=str(target_room_id),
236
+ entityId=str(target_entity_id) if target_entity_id else None,
237
+ source=source,
238
+ ),
239
+ message_content,
240
+ )
241
+
242
+ # Create the message memory
117
243
  import time
118
244
  import uuid as uuid_module
119
245
 
120
- from elizaos.types.primitives import as_uuid
121
-
122
246
  message_memory = MemoryType(
123
247
  id=as_uuid(str(uuid_module.uuid4())),
124
248
  entity_id=runtime.agent_id,
125
- room_id=as_uuid(target_room_id_val) if target_room_id_val else None,
249
+ room_id=target_room_id,
126
250
  content=message_content,
127
251
  created_at=int(time.time() * 1000),
128
252
  )
129
253
 
130
254
  await runtime.create_memory(
131
255
  content=message_content,
132
- room_id=target_room_id_val,
256
+ room_id=target_room_id,
133
257
  entity_id=runtime.agent_id,
134
258
  memory_type="message",
135
259
  metadata={
@@ -156,17 +280,26 @@ class SendMessageAction:
156
280
  if callback:
157
281
  await callback(response_content)
158
282
 
283
+ target_id = (
284
+ target_entity_id if target_type == "user" and target_entity_id else target_room_id
285
+ )
159
286
  return ActionResult(
160
- text="Message sent to room",
287
+ text="Message sent",
161
288
  values={
162
289
  "success": True,
163
290
  "messageSent": True,
164
- "targetRoomId": str(target_room_id_val),
291
+ "targetType": target_type,
292
+ "target": str(target_id),
293
+ "source": source,
294
+ "targetRoomId": str(target_room_id),
165
295
  "targetEntityId": str(target_entity_id) if target_entity_id else None,
166
296
  },
167
297
  data={
168
298
  "actionName": "SEND_MESSAGE",
169
- "targetRoomId": str(target_room_id_val),
299
+ "targetType": target_type,
300
+ "target": str(target_id),
301
+ "source": source,
302
+ "targetRoomId": str(target_room_id),
170
303
  "messagePreview": message_text[:100],
171
304
  },
172
305
  success=True,
@@ -7,7 +7,6 @@ from elizaos.bootstrap.utils.xml import parse_key_value_xml
7
7
  from elizaos.generated.spec_helpers import require_action_spec
8
8
  from elizaos.prompts import UPDATE_SETTINGS_TEMPLATE
9
9
  from elizaos.types import Action, ActionExample, ActionResult, Content, ModelType
10
- from elizaos.utils.spec_examples import convert_spec_examples
11
10
 
12
11
  if TYPE_CHECKING:
13
12
  from elizaos.types import HandlerCallback, HandlerOptions, IAgentRuntime, Memory, State
@@ -18,7 +17,22 @@ _spec = require_action_spec("UPDATE_SETTINGS")
18
17
 
19
18
  def _convert_spec_examples() -> list[list[ActionExample]]:
20
19
  """Convert spec examples to ActionExample format."""
21
- return convert_spec_examples(_spec)
20
+ spec_examples = _spec.get("examples", [])
21
+ if spec_examples:
22
+ return [
23
+ [
24
+ ActionExample(
25
+ name=msg.get("name", ""),
26
+ content=Content(
27
+ text=msg.get("content", {}).get("text", ""),
28
+ actions=msg.get("content", {}).get("actions"),
29
+ ),
30
+ )
31
+ for msg in example
32
+ ]
33
+ for example in spec_examples
34
+ ]
35
+ return []
22
36
 
23
37
 
24
38
  @dataclass
@@ -16,34 +16,21 @@ _spec = require_action_spec("UNFOLLOW_ROOM")
16
16
  def _convert_spec_examples() -> list[list[ActionExample]]:
17
17
  """Convert spec examples to ActionExample format."""
18
18
  spec_examples = _spec.get("examples", [])
19
- if not isinstance(spec_examples, list):
20
- return []
21
- result: list[list[ActionExample]] = []
22
- for example in spec_examples:
23
- if not isinstance(example, list):
24
- continue
25
- row: list[ActionExample] = []
26
- for msg in example:
27
- if not isinstance(msg, dict):
28
- continue
29
- content = msg.get("content", {})
30
- text = ""
31
- actions: list[str] | None = None
32
- if isinstance(content, dict):
33
- text_val = content.get("text", "")
34
- text = str(text_val) if text_val else ""
35
- actions_val = content.get("actions")
36
- if isinstance(actions_val, list) and all(isinstance(a, str) for a in actions_val):
37
- actions = list(actions_val)
38
- row.append(
19
+ if spec_examples:
20
+ return [
21
+ [
39
22
  ActionExample(
40
- name=str(msg.get("name", "")),
41
- content=Content(text=text, actions=actions),
23
+ name=msg.get("name", ""),
24
+ content=Content(
25
+ text=msg.get("content", {}).get("text", ""),
26
+ actions=msg.get("content", {}).get("actions"),
27
+ ),
42
28
  )
43
- )
44
- if row:
45
- result.append(row)
46
- return result
29
+ for msg in example
30
+ ]
31
+ for example in spec_examples
32
+ ]
33
+ return []
47
34
 
48
35
 
49
36
  @dataclass
@@ -16,34 +16,21 @@ _spec = require_action_spec("UNMUTE_ROOM")
16
16
  def _convert_spec_examples() -> list[list[ActionExample]]:
17
17
  """Convert spec examples to ActionExample format."""
18
18
  spec_examples = _spec.get("examples", [])
19
- if not isinstance(spec_examples, list):
20
- return []
21
- result: list[list[ActionExample]] = []
22
- for example in spec_examples:
23
- if not isinstance(example, list):
24
- continue
25
- row: list[ActionExample] = []
26
- for msg in example:
27
- if not isinstance(msg, dict):
28
- continue
29
- content = msg.get("content", {})
30
- text = ""
31
- actions: list[str] | None = None
32
- if isinstance(content, dict):
33
- text_val = content.get("text", "")
34
- text = str(text_val) if text_val else ""
35
- actions_val = content.get("actions")
36
- if isinstance(actions_val, list) and all(isinstance(a, str) for a in actions_val):
37
- actions = list(actions_val)
38
- row.append(
19
+ if spec_examples:
20
+ return [
21
+ [
39
22
  ActionExample(
40
- name=str(msg.get("name", "")),
41
- content=Content(text=text, actions=actions),
23
+ name=msg.get("name", ""),
24
+ content=Content(
25
+ text=msg.get("content", {}).get("text", ""),
26
+ actions=msg.get("content", {}).get("actions"),
27
+ ),
42
28
  )
43
- )
44
- if row:
45
- result.append(row)
46
- return result
29
+ for msg in example
30
+ ]
31
+ for example in spec_examples
32
+ ]
33
+ return []
47
34
 
48
35
 
49
36
  @dataclass
@@ -13,7 +13,6 @@ from elizaos.types import (
13
13
  Content,
14
14
  ModelType,
15
15
  )
16
- from elizaos.utils.spec_examples import convert_spec_examples
17
16
 
18
17
  if TYPE_CHECKING:
19
18
  from elizaos.types import (
@@ -30,7 +29,22 @@ _spec = require_action_spec("UPDATE_CONTACT")
30
29
 
31
30
  def _convert_spec_examples() -> list[list[ActionExample]]:
32
31
  """Convert spec examples to ActionExample format."""
33
- return convert_spec_examples(_spec)
32
+ spec_examples = _spec.get("examples", [])
33
+ if spec_examples:
34
+ return [
35
+ [
36
+ ActionExample(
37
+ name=msg.get("name", ""),
38
+ content=Content(
39
+ text=msg.get("content", {}).get("text", ""),
40
+ actions=msg.get("content", {}).get("actions"),
41
+ ),
42
+ )
43
+ for msg in example
44
+ ]
45
+ for example in spec_examples
46
+ ]
47
+ return []
34
48
 
35
49
 
36
50
  @dataclass
@@ -8,7 +8,6 @@ from elizaos.bootstrap.utils.xml import parse_key_value_xml
8
8
  from elizaos.generated.spec_helpers import require_action_spec
9
9
  from elizaos.prompts import UPDATE_ENTITY_TEMPLATE
10
10
  from elizaos.types import Action, ActionExample, ActionResult, Content, ModelType
11
- from elizaos.utils.spec_examples import convert_spec_examples
12
11
 
13
12
  if TYPE_CHECKING:
14
13
  from elizaos.types import HandlerCallback, HandlerOptions, IAgentRuntime, Memory, State
@@ -19,7 +18,22 @@ _spec = require_action_spec("UPDATE_ENTITY")
19
18
 
20
19
  def _convert_spec_examples() -> list[list[ActionExample]]:
21
20
  """Convert spec examples to ActionExample format."""
22
- return convert_spec_examples(_spec)
21
+ spec_examples = _spec.get("examples", [])
22
+ if spec_examples:
23
+ return [
24
+ [
25
+ ActionExample(
26
+ name=msg.get("name", ""),
27
+ content=Content(
28
+ text=msg.get("content", {}).get("text", ""),
29
+ actions=msg.get("content", {}).get("actions"),
30
+ ),
31
+ )
32
+ for msg in example
33
+ ]
34
+ for example in spec_examples
35
+ ]
36
+ return []
23
37
 
24
38
 
25
39
  @dataclass
@@ -3,16 +3,9 @@
3
3
  Evaluators that can be enabled with `advanced_capabilities=True`.
4
4
  """
5
5
 
6
- from .reflection import reflection_evaluator
7
- from .relationship_extraction import relationship_extraction_evaluator
8
-
9
6
  __all__ = [
10
- "reflection_evaluator",
11
- "relationship_extraction_evaluator",
12
7
  "advanced_evaluators",
13
8
  ]
14
9
 
15
- advanced_evaluators = [
16
- reflection_evaluator,
17
- relationship_extraction_evaluator,
18
- ]
10
+ # Relationship evaluators are owned by the plugin-rolodex package.
11
+ advanced_evaluators: list = []
@@ -1,134 +1,5 @@
1
- from __future__ import annotations
1
+ """Compatibility wrapper for reflection evaluator."""
2
2
 
3
- from collections.abc import Awaitable, Callable
4
- from typing import TYPE_CHECKING
3
+ from elizaos.bootstrap.evaluators.reflection import reflection_evaluator
5
4
 
6
- from elizaos.bootstrap.types import EvaluatorResult
7
- from elizaos.bootstrap.utils.xml import parse_key_value_xml
8
- from elizaos.generated.spec_helpers import require_evaluator_spec
9
- from elizaos.prompts import REFLECTION_TEMPLATE
10
- from elizaos.types import ActionResult, Evaluator, HandlerOptions, ModelType
11
-
12
- if TYPE_CHECKING:
13
- from elizaos.types import Content, IAgentRuntime, Memory, State
14
-
15
- # Get text content from centralized specs
16
- _spec = require_evaluator_spec("REFLECTION")
17
-
18
-
19
- async def evaluate_reflection(
20
- runtime: IAgentRuntime,
21
- message: Memory,
22
- state: State | None = None,
23
- ) -> EvaluatorResult:
24
- if state is None:
25
- return EvaluatorResult(
26
- score=50,
27
- passed=True,
28
- reason="No state for reflection",
29
- details={},
30
- )
31
-
32
- recent_interactions: list[str] = []
33
- room_id = message.room_id
34
-
35
- if room_id:
36
- recent_messages = await runtime.get_memories(
37
- room_id=room_id,
38
- limit=10,
39
- order_by="created_at",
40
- order_direction="desc",
41
- )
42
-
43
- for msg in recent_messages:
44
- if msg.content and msg.content.text:
45
- sender = "Unknown"
46
- if msg.entity_id:
47
- if str(msg.entity_id) == str(runtime.agent_id):
48
- sender = runtime.character.name
49
- else:
50
- entity = await runtime.get_entity(msg.entity_id)
51
- if entity and entity.name:
52
- sender = entity.name
53
- recent_interactions.append(f"{sender}: {msg.content.text}")
54
-
55
- if not recent_interactions:
56
- return EvaluatorResult(
57
- score=50,
58
- passed=True,
59
- reason="No recent interactions to reflect on",
60
- details={"noInteractions": True},
61
- )
62
-
63
- interactions_text = "\n".join(recent_interactions)
64
-
65
- template = (
66
- runtime.character.templates.get("reflectionTemplate")
67
- if runtime.character.templates and "reflectionTemplate" in runtime.character.templates
68
- else REFLECTION_TEMPLATE
69
- )
70
- prompt = runtime.compose_prompt(state=state, template=template)
71
- prompt = prompt.replace("{{recentInteractions}}", interactions_text)
72
-
73
- response_text = await runtime.use_model(ModelType.TEXT_LARGE, prompt=prompt)
74
- parsed_xml = parse_key_value_xml(response_text)
75
-
76
- if parsed_xml is None:
77
- raise ValueError("Failed to parse reflection response")
78
-
79
- quality_str = str(parsed_xml.get("quality_score", "50"))
80
- quality_score = max(0, min(100, int(quality_str)))
81
-
82
- thought = str(parsed_xml.get("thought", ""))
83
- strengths = str(parsed_xml.get("strengths", ""))
84
- improvements = str(parsed_xml.get("improvements", ""))
85
- learnings = str(parsed_xml.get("learnings", ""))
86
-
87
- passed = quality_score >= 50
88
-
89
- return EvaluatorResult(
90
- score=quality_score,
91
- passed=passed,
92
- reason=f"Strengths: {strengths}\nImprovements: {improvements}",
93
- details={
94
- "thought": thought,
95
- "strengths": strengths,
96
- "improvements": improvements,
97
- "learnings": learnings,
98
- "interactionCount": len(recent_interactions),
99
- },
100
- )
101
-
102
-
103
- async def validate_reflection(
104
- runtime: IAgentRuntime,
105
- message: Memory,
106
- _state: State | None = None,
107
- ) -> bool:
108
- return True
109
-
110
-
111
- async def _reflection_handler(
112
- runtime: IAgentRuntime,
113
- message: Memory,
114
- state: State | None = None,
115
- options: HandlerOptions | None = None,
116
- callback: Callable[[Content], Awaitable[list[Memory]]] | None = None,
117
- responses: list[Memory] | None = None,
118
- ) -> ActionResult | None:
119
- """Wrapper handler that matches the expected signature."""
120
- _ = options, callback, responses # Unused parameters
121
- result = await evaluate_reflection(runtime, message, state)
122
- # Return ActionResult - evaluators don't typically return action results
123
- return ActionResult(text=result.reason, success=result.passed, values={}, data={})
124
-
125
-
126
- reflection_evaluator = Evaluator(
127
- name=str(_spec["name"]),
128
- description=str(_spec["description"]),
129
- similes=list(_spec.get("similes", [])) if _spec.get("similes") else [],
130
- validate=validate_reflection,
131
- handler=_reflection_handler,
132
- always_run=bool(_spec.get("alwaysRun", False)),
133
- examples=[],
134
- )
5
+ __all__ = ["reflection_evaluator"]