@elizaos/python 2.0.0-alpha.11 → 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.
- package/elizaos/advanced_capabilities/__init__.py +6 -41
- package/elizaos/advanced_capabilities/actions/__init__.py +1 -21
- package/elizaos/advanced_capabilities/actions/add_contact.py +21 -11
- package/elizaos/advanced_capabilities/actions/follow_room.py +28 -28
- package/elizaos/advanced_capabilities/actions/image_generation.py +13 -26
- package/elizaos/advanced_capabilities/actions/mute_room.py +13 -26
- package/elizaos/advanced_capabilities/actions/remove_contact.py +16 -2
- package/elizaos/advanced_capabilities/actions/roles.py +13 -27
- package/elizaos/advanced_capabilities/actions/search_contacts.py +17 -3
- package/elizaos/advanced_capabilities/actions/send_message.py +317 -9
- package/elizaos/advanced_capabilities/actions/settings.py +16 -2
- package/elizaos/advanced_capabilities/actions/unfollow_room.py +13 -26
- package/elizaos/advanced_capabilities/actions/unmute_room.py +13 -26
- package/elizaos/advanced_capabilities/actions/update_contact.py +16 -2
- package/elizaos/advanced_capabilities/actions/update_entity.py +16 -2
- package/elizaos/advanced_capabilities/evaluators/__init__.py +2 -9
- package/elizaos/advanced_capabilities/evaluators/reflection.py +3 -132
- package/elizaos/advanced_capabilities/evaluators/relationship_extraction.py +5 -201
- package/elizaos/advanced_capabilities/providers/__init__.py +1 -12
- package/elizaos/advanced_capabilities/providers/knowledge.py +24 -3
- package/elizaos/advanced_capabilities/services/__init__.py +2 -9
- package/elizaos/advanced_memory/actions/reset_session.py +11 -0
- package/elizaos/advanced_memory/evaluators/reflection.py +134 -0
- package/elizaos/advanced_memory/evaluators/relationship_extraction.py +203 -0
- package/elizaos/advanced_memory/test_advanced_memory.py +357 -0
- package/elizaos/advanced_planning/actions/schedule_follow_up.py +222 -0
- package/elizaos/basic_capabilities/__init__.py +0 -2
- package/elizaos/basic_capabilities/providers/__init__.py +0 -3
- package/elizaos/basic_capabilities/providers/agent_settings.py +64 -0
- package/elizaos/basic_capabilities/providers/contacts.py +79 -0
- package/elizaos/basic_capabilities/providers/facts.py +87 -0
- package/elizaos/basic_capabilities/providers/follow_ups.py +117 -0
- package/elizaos/basic_capabilities/providers/knowledge.py +97 -0
- package/elizaos/basic_capabilities/providers/relationships.py +107 -0
- package/elizaos/basic_capabilities/providers/roles.py +96 -0
- package/elizaos/basic_capabilities/providers/settings.py +56 -0
- package/elizaos/bootstrap/autonomy/__init__.py +5 -1
- package/elizaos/bootstrap/autonomy/action.py +161 -0
- package/elizaos/bootstrap/autonomy/evaluators.py +217 -0
- package/elizaos/bootstrap/autonomy/service.py +8 -0
- package/elizaos/bootstrap/plugin.py +7 -0
- package/elizaos/bootstrap/providers/knowledge.py +26 -3
- package/elizaos/bootstrap/services/embedding.py +156 -1
- package/elizaos/runtime.py +63 -18
- package/elizaos/services/message_service.py +173 -23
- package/elizaos/types/generated/eliza/v1/agent_pb2.py +16 -16
- package/elizaos/types/generated/eliza/v1/agent_pb2.pyi +2 -4
- package/elizaos/types/model.py +27 -0
- package/elizaos/types/runtime.py +5 -1
- package/elizaos/utils/validation.py +76 -0
- package/package.json +2 -2
- package/tests/test_actions_provider_examples.py +58 -1
- package/tests/test_async_embedding.py +124 -0
- package/tests/test_autonomy.py +13 -2
- package/tests/test_validation.py +141 -0
- package/tests/verify_memory_architecture.py +192 -0
- package/elizaos/basic_capabilities/providers/capabilities.py +0 -62
|
@@ -1,12 +1,320 @@
|
|
|
1
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import contextlib
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
6
|
|
|
7
|
-
from elizaos.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
from elizaos.generated.spec_helpers import require_action_spec
|
|
8
|
+
from elizaos.types import Action, ActionExample, ActionResult, Content
|
|
9
|
+
from elizaos.types.memory import Memory as MemoryType
|
|
10
|
+
from elizaos.types.primitives import UUID, as_uuid
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from elizaos.types import HandlerCallback, HandlerOptions, IAgentRuntime, Memory, State
|
|
14
|
+
|
|
15
|
+
# Get text content from centralized specs
|
|
16
|
+
_spec = require_action_spec("SEND_MESSAGE")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _convert_spec_examples() -> list[list[ActionExample]]:
|
|
20
|
+
"""Convert spec examples to ActionExample format."""
|
|
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 []
|
|
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 []
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class SendMessageAction:
|
|
89
|
+
name: str = _spec["name"]
|
|
90
|
+
similes: list[str] = field(default_factory=lambda: list(_spec.get("similes", [])))
|
|
91
|
+
description: str = _spec["description"]
|
|
92
|
+
|
|
93
|
+
async def validate(
|
|
94
|
+
self, runtime: IAgentRuntime, message: Memory, _state: State | None = None
|
|
95
|
+
) -> bool:
|
|
96
|
+
if message.content and message.content.target:
|
|
97
|
+
return True
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
async def handler(
|
|
101
|
+
self,
|
|
102
|
+
runtime: IAgentRuntime,
|
|
103
|
+
message: Memory,
|
|
104
|
+
state: State | None = None,
|
|
105
|
+
options: HandlerOptions | None = None,
|
|
106
|
+
callback: HandlerCallback | None = None,
|
|
107
|
+
responses: list[Memory] | None = None,
|
|
108
|
+
) -> ActionResult:
|
|
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()
|
|
11
117
|
|
|
12
|
-
|
|
118
|
+
if not message_text:
|
|
119
|
+
return ActionResult(
|
|
120
|
+
text="No message content to send",
|
|
121
|
+
values={"success": False, "error": "no_content"},
|
|
122
|
+
data={"actionName": "SEND_MESSAGE"},
|
|
123
|
+
success=False,
|
|
124
|
+
)
|
|
125
|
+
|
|
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"
|
|
150
|
+
|
|
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
|
|
201
|
+
|
|
202
|
+
if message.content and message.content.target:
|
|
203
|
+
target = message.content.target
|
|
204
|
+
if isinstance(target, dict):
|
|
205
|
+
room_str = target.get("roomId")
|
|
206
|
+
entity_str = target.get("entityId")
|
|
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:
|
|
215
|
+
return ActionResult(
|
|
216
|
+
text="No target room specified",
|
|
217
|
+
values={"success": False, "error": "no_target"},
|
|
218
|
+
data={"actionName": "SEND_MESSAGE"},
|
|
219
|
+
success=False,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
message_content = Content(
|
|
223
|
+
text=message_text,
|
|
224
|
+
source=source,
|
|
225
|
+
actions=["SEND_MESSAGE"],
|
|
226
|
+
)
|
|
227
|
+
|
|
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
|
|
243
|
+
import time
|
|
244
|
+
import uuid as uuid_module
|
|
245
|
+
|
|
246
|
+
message_memory = MemoryType(
|
|
247
|
+
id=as_uuid(str(uuid_module.uuid4())),
|
|
248
|
+
entity_id=runtime.agent_id,
|
|
249
|
+
room_id=target_room_id,
|
|
250
|
+
content=message_content,
|
|
251
|
+
created_at=int(time.time() * 1000),
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
await runtime.create_memory(
|
|
255
|
+
content=message_content,
|
|
256
|
+
room_id=target_room_id,
|
|
257
|
+
entity_id=runtime.agent_id,
|
|
258
|
+
memory_type="message",
|
|
259
|
+
metadata={
|
|
260
|
+
"type": "SEND_MESSAGE",
|
|
261
|
+
"targetEntityId": str(target_entity_id) if target_entity_id else None,
|
|
262
|
+
},
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
# Emit MESSAGE_SENT event
|
|
266
|
+
await runtime.emit_event(
|
|
267
|
+
"MESSAGE_SENT",
|
|
268
|
+
{
|
|
269
|
+
"runtime": runtime,
|
|
270
|
+
"source": "send-message-action",
|
|
271
|
+
"message": message_memory,
|
|
272
|
+
},
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
response_content = Content(
|
|
276
|
+
text=f"Message sent: {message_text[:50]}...",
|
|
277
|
+
actions=["SEND_MESSAGE"],
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
if callback:
|
|
281
|
+
await callback(response_content)
|
|
282
|
+
|
|
283
|
+
target_id = (
|
|
284
|
+
target_entity_id if target_type == "user" and target_entity_id else target_room_id
|
|
285
|
+
)
|
|
286
|
+
return ActionResult(
|
|
287
|
+
text="Message sent",
|
|
288
|
+
values={
|
|
289
|
+
"success": True,
|
|
290
|
+
"messageSent": True,
|
|
291
|
+
"targetType": target_type,
|
|
292
|
+
"target": str(target_id),
|
|
293
|
+
"source": source,
|
|
294
|
+
"targetRoomId": str(target_room_id),
|
|
295
|
+
"targetEntityId": str(target_entity_id) if target_entity_id else None,
|
|
296
|
+
},
|
|
297
|
+
data={
|
|
298
|
+
"actionName": "SEND_MESSAGE",
|
|
299
|
+
"targetType": target_type,
|
|
300
|
+
"target": str(target_id),
|
|
301
|
+
"source": source,
|
|
302
|
+
"targetRoomId": str(target_room_id),
|
|
303
|
+
"messagePreview": message_text[:100],
|
|
304
|
+
},
|
|
305
|
+
success=True,
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
@property
|
|
309
|
+
def examples(self) -> list[list[ActionExample]]:
|
|
310
|
+
return _convert_spec_examples()
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
send_message_action = Action(
|
|
314
|
+
name=SendMessageAction.name,
|
|
315
|
+
similes=SendMessageAction().similes,
|
|
316
|
+
description=SendMessageAction.description,
|
|
317
|
+
validate=SendMessageAction().validate,
|
|
318
|
+
handler=SendMessageAction().handler,
|
|
319
|
+
examples=SendMessageAction().examples,
|
|
320
|
+
)
|
|
@@ -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
|
-
|
|
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
|
|
20
|
-
return [
|
|
21
|
-
|
|
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=
|
|
41
|
-
content=Content(
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
20
|
-
return [
|
|
21
|
-
|
|
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=
|
|
41
|
-
content=Content(
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
relationship_extraction_evaluator,
|
|
18
|
-
]
|
|
10
|
+
# Relationship evaluators are owned by the plugin-rolodex package.
|
|
11
|
+
advanced_evaluators: list = []
|
|
@@ -1,134 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
"""Compatibility wrapper for reflection evaluator."""
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from elizaos.bootstrap.evaluators.reflection import reflection_evaluator
|
|
5
4
|
|
|
6
|
-
|
|
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"]
|