@elizaos/python 2.0.0-alpha.10 → 2.0.0-alpha.11
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/__init__.py +0 -1
- package/elizaos/advanced_capabilities/actions/schedule_follow_up.py +70 -15
- package/elizaos/advanced_capabilities/actions/send_message.py +9 -184
- package/elizaos/advanced_memory/memory_service.py +15 -17
- package/elizaos/advanced_planning/planning_service.py +26 -14
- package/elizaos/basic_capabilities/providers/actions.py +118 -29
- package/elizaos/basic_capabilities/providers/character.py +19 -21
- package/elizaos/basic_capabilities/providers/current_time.py +7 -4
- package/elizaos/basic_capabilities/providers/time.py +7 -4
- package/elizaos/bootstrap/__init__.py +21 -2
- package/elizaos/bootstrap/actions/schedule_follow_up.py +65 -7
- package/elizaos/bootstrap/actions/send_message.py +162 -15
- package/elizaos/bootstrap/autonomy/service.py +230 -28
- package/elizaos/bootstrap/providers/actions.py +118 -27
- package/elizaos/bootstrap/providers/agent_settings.py +1 -0
- package/elizaos/bootstrap/providers/attachments.py +1 -0
- package/elizaos/bootstrap/providers/capabilities.py +1 -0
- package/elizaos/bootstrap/providers/character.py +1 -0
- package/elizaos/bootstrap/providers/choice.py +1 -0
- package/elizaos/bootstrap/providers/contacts.py +1 -0
- package/elizaos/bootstrap/providers/current_time.py +8 -2
- package/elizaos/bootstrap/providers/entities.py +1 -0
- package/elizaos/bootstrap/providers/evaluators.py +1 -0
- package/elizaos/bootstrap/providers/facts.py +1 -0
- package/elizaos/bootstrap/providers/follow_ups.py +1 -0
- package/elizaos/bootstrap/providers/knowledge.py +1 -0
- package/elizaos/bootstrap/providers/providers_list.py +1 -0
- package/elizaos/bootstrap/providers/relationships.py +1 -0
- package/elizaos/bootstrap/providers/roles.py +1 -0
- package/elizaos/bootstrap/providers/settings.py +1 -0
- package/elizaos/bootstrap/providers/time.py +8 -4
- package/elizaos/bootstrap/providers/world.py +1 -0
- package/elizaos/deterministic.py +193 -0
- package/elizaos/generated/__init__.py +1 -0
- package/elizaos/generated/action_docs.py +3181 -0
- package/elizaos/generated/spec_helpers.py +175 -0
- package/elizaos/media/mime.py +2 -2
- package/elizaos/media/search.py +23 -23
- package/elizaos/runtime.py +152 -39
- package/elizaos/services/message_service.py +2 -6
- package/elizaos/types/components.py +2 -2
- package/elizaos/types/generated/__init__.py +12 -0
- package/elizaos/types/generated/eliza/v1/agent_pb2.py +63 -0
- package/elizaos/types/generated/eliza/v1/agent_pb2.pyi +161 -0
- package/elizaos/types/generated/eliza/v1/components_pb2.py +65 -0
- package/elizaos/types/generated/eliza/v1/components_pb2.pyi +160 -0
- package/elizaos/types/generated/eliza/v1/database_pb2.py +78 -0
- package/elizaos/types/generated/eliza/v1/database_pb2.pyi +305 -0
- package/elizaos/types/generated/eliza/v1/environment_pb2.py +58 -0
- package/elizaos/types/generated/eliza/v1/environment_pb2.pyi +135 -0
- package/elizaos/types/generated/eliza/v1/events_pb2.py +82 -0
- package/elizaos/types/generated/eliza/v1/events_pb2.pyi +322 -0
- package/elizaos/types/generated/eliza/v1/ipc_pb2.py +113 -0
- package/elizaos/types/generated/eliza/v1/ipc_pb2.pyi +367 -0
- package/elizaos/types/generated/eliza/v1/knowledge_pb2.py +41 -0
- package/elizaos/types/generated/eliza/v1/knowledge_pb2.pyi +26 -0
- package/elizaos/types/generated/eliza/v1/memory_pb2.py +55 -0
- package/elizaos/types/generated/eliza/v1/memory_pb2.pyi +111 -0
- package/elizaos/types/generated/eliza/v1/message_service_pb2.py +48 -0
- package/elizaos/types/generated/eliza/v1/message_service_pb2.pyi +69 -0
- package/elizaos/types/generated/eliza/v1/messaging_pb2.py +51 -0
- package/elizaos/types/generated/eliza/v1/messaging_pb2.pyi +97 -0
- package/elizaos/types/generated/eliza/v1/model_pb2.py +84 -0
- package/elizaos/types/generated/eliza/v1/model_pb2.pyi +280 -0
- package/elizaos/types/generated/eliza/v1/payment_pb2.py +44 -0
- package/elizaos/types/generated/eliza/v1/payment_pb2.pyi +70 -0
- package/elizaos/types/generated/eliza/v1/plugin_pb2.py +68 -0
- package/elizaos/types/generated/eliza/v1/plugin_pb2.pyi +145 -0
- package/elizaos/types/generated/eliza/v1/primitives_pb2.py +48 -0
- package/elizaos/types/generated/eliza/v1/primitives_pb2.pyi +92 -0
- package/elizaos/types/generated/eliza/v1/prompts_pb2.py +52 -0
- package/elizaos/types/generated/eliza/v1/prompts_pb2.pyi +74 -0
- package/elizaos/types/generated/eliza/v1/service_interfaces_pb2.py +211 -0
- package/elizaos/types/generated/eliza/v1/service_interfaces_pb2.pyi +1296 -0
- package/elizaos/types/generated/eliza/v1/service_pb2.py +42 -0
- package/elizaos/types/generated/eliza/v1/service_pb2.pyi +69 -0
- package/elizaos/types/generated/eliza/v1/settings_pb2.py +58 -0
- package/elizaos/types/generated/eliza/v1/settings_pb2.pyi +85 -0
- package/elizaos/types/generated/eliza/v1/state_pb2.py +60 -0
- package/elizaos/types/generated/eliza/v1/state_pb2.pyi +114 -0
- package/elizaos/types/generated/eliza/v1/task_pb2.py +42 -0
- package/elizaos/types/generated/eliza/v1/task_pb2.pyi +58 -0
- package/elizaos/types/generated/eliza/v1/tee_pb2.py +52 -0
- package/elizaos/types/generated/eliza/v1/tee_pb2.pyi +90 -0
- package/elizaos/types/generated/eliza/v1/testing_pb2.py +39 -0
- package/elizaos/types/generated/eliza/v1/testing_pb2.pyi +23 -0
- package/elizaos/types/model.py +3 -0
- package/elizaos/types/runtime.py +1 -1
- package/package.json +3 -2
- package/tests/test_action_parameters.py +2 -3
- package/tests/test_advanced_memory_behavior.py +0 -2
- package/tests/test_advanced_memory_flag.py +0 -2
- package/tests/test_advanced_planning_behavior.py +11 -5
- package/tests/test_autonomy.py +11 -1
- package/tests/test_runtime.py +8 -17
- package/tests/test_schedule_follow_up_action.py +260 -0
- package/tests/test_send_message_action_targets.py +114 -0
- package/tests/test_settings_crypto.py +0 -2
- package/uv.lock +1565 -0
package/elizaos/__init__.py
CHANGED
|
@@ -108,7 +108,6 @@ from elizaos.types import (
|
|
|
108
108
|
string_to_uuid,
|
|
109
109
|
)
|
|
110
110
|
from elizaos.types.database import IDatabaseAdapter # noqa: E402
|
|
111
|
-
from elizaos.types.environment import ChannelType # noqa: E402
|
|
112
111
|
from elizaos.types.primitives import ( # noqa: E402
|
|
113
112
|
ChannelType,
|
|
114
113
|
Content,
|
|
@@ -3,8 +3,10 @@ from __future__ import annotations
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
|
+
from uuid import UUID as StdUUID
|
|
6
7
|
|
|
7
8
|
from elizaos.bootstrap.utils.xml import parse_key_value_xml
|
|
9
|
+
from elizaos.deterministic import get_prompt_reference_datetime
|
|
8
10
|
from elizaos.generated.spec_helpers import require_action_spec
|
|
9
11
|
from elizaos.prompts import SCHEDULE_FOLLOW_UP_TEMPLATE
|
|
10
12
|
from elizaos.types import (
|
|
@@ -34,6 +36,25 @@ def _convert_spec_examples() -> list[list[ActionExample]]:
|
|
|
34
36
|
return convert_spec_examples(_spec)
|
|
35
37
|
|
|
36
38
|
|
|
39
|
+
def _normalize_priority(raw_priority: str) -> str:
|
|
40
|
+
normalized = raw_priority.strip().lower()
|
|
41
|
+
if normalized in {"high", "medium", "low"}:
|
|
42
|
+
return normalized
|
|
43
|
+
return "medium"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _coerce_uuid(value: object | None) -> StdUUID | None:
|
|
47
|
+
if value is None:
|
|
48
|
+
return None
|
|
49
|
+
text = str(value).strip()
|
|
50
|
+
if not text:
|
|
51
|
+
return None
|
|
52
|
+
try:
|
|
53
|
+
return StdUUID(text)
|
|
54
|
+
except ValueError:
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
|
|
37
58
|
@dataclass
|
|
38
59
|
class ScheduleFollowUpAction:
|
|
39
60
|
name: str = _spec["name"]
|
|
@@ -79,7 +100,12 @@ class ScheduleFollowUpAction:
|
|
|
79
100
|
)
|
|
80
101
|
|
|
81
102
|
state = await runtime.compose_state(message, ["RECENT_MESSAGES", "ENTITIES"])
|
|
82
|
-
state.values["currentDateTime"] =
|
|
103
|
+
state.values["currentDateTime"] = get_prompt_reference_datetime(
|
|
104
|
+
runtime,
|
|
105
|
+
message,
|
|
106
|
+
state,
|
|
107
|
+
"action:schedule_follow_up",
|
|
108
|
+
).isoformat()
|
|
83
109
|
|
|
84
110
|
prompt = runtime.compose_prompt_from_state(
|
|
85
111
|
state=state,
|
|
@@ -100,24 +126,53 @@ class ScheduleFollowUpAction:
|
|
|
100
126
|
contact_name = str(parsed.get("contactName", ""))
|
|
101
127
|
scheduled_at_str = str(parsed.get("scheduledAt", ""))
|
|
102
128
|
reason = str(parsed.get("reason", "Follow-up"))
|
|
103
|
-
priority = str(parsed.get("priority", "medium"))
|
|
129
|
+
priority = _normalize_priority(str(parsed.get("priority", "medium")))
|
|
104
130
|
follow_up_message = str(parsed.get("message", ""))
|
|
131
|
+
parsed_entity_id = _coerce_uuid(parsed.get("entityId"))
|
|
132
|
+
message_entity_id = _coerce_uuid(message.entity_id)
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
scheduled_at = datetime.fromisoformat(scheduled_at_str.replace("Z", "+00:00"))
|
|
136
|
+
except ValueError:
|
|
137
|
+
return ActionResult(
|
|
138
|
+
text="Could not parse the follow-up date/time",
|
|
139
|
+
success=False,
|
|
140
|
+
values={"error": True},
|
|
141
|
+
data={"error": "Invalid follow-up datetime"},
|
|
142
|
+
)
|
|
105
143
|
|
|
106
|
-
|
|
144
|
+
entity_id_uuid = parsed_entity_id or message_entity_id
|
|
107
145
|
|
|
108
|
-
|
|
146
|
+
if entity_id_uuid is None and contact_name:
|
|
147
|
+
contacts = await rolodex_service.search_contacts(search_term=contact_name)
|
|
148
|
+
if contacts:
|
|
149
|
+
entity_id_uuid = contacts[0].entity_id
|
|
109
150
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
reason=reason,
|
|
117
|
-
priority=priority,
|
|
118
|
-
message=follow_up_message,
|
|
151
|
+
if entity_id_uuid is None:
|
|
152
|
+
return ActionResult(
|
|
153
|
+
text=f"Could not determine which contact to schedule for ({contact_name}).",
|
|
154
|
+
success=False,
|
|
155
|
+
values={"error": True},
|
|
156
|
+
data={"error": "Missing contact entity id"},
|
|
119
157
|
)
|
|
120
158
|
|
|
159
|
+
contact = await rolodex_service.get_contact(entity_id_uuid)
|
|
160
|
+
if contact is None:
|
|
161
|
+
return ActionResult(
|
|
162
|
+
text=f"Contact '{contact_name}' was not found in the rolodex.",
|
|
163
|
+
success=False,
|
|
164
|
+
values={"error": True},
|
|
165
|
+
data={"error": "Contact not found"},
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
await follow_up_service.schedule_follow_up(
|
|
169
|
+
entity_id=entity_id_uuid,
|
|
170
|
+
scheduled_at=scheduled_at,
|
|
171
|
+
reason=reason,
|
|
172
|
+
priority=priority,
|
|
173
|
+
message=follow_up_message,
|
|
174
|
+
)
|
|
175
|
+
|
|
121
176
|
response_text = f"I've scheduled a follow-up with {contact_name} for {scheduled_at.strftime('%B %d, %Y')}. Reason: {reason}"
|
|
122
177
|
|
|
123
178
|
if callback:
|
|
@@ -127,11 +182,11 @@ class ScheduleFollowUpAction:
|
|
|
127
182
|
text=response_text,
|
|
128
183
|
success=True,
|
|
129
184
|
values={
|
|
130
|
-
"contactId": str(
|
|
185
|
+
"contactId": str(entity_id_uuid),
|
|
131
186
|
"scheduledAt": scheduled_at.isoformat(),
|
|
132
187
|
},
|
|
133
188
|
data={
|
|
134
|
-
"contactId": str(
|
|
189
|
+
"contactId": str(entity_id_uuid),
|
|
135
190
|
"contactName": contact_name,
|
|
136
191
|
"scheduledAt": scheduled_at.isoformat(),
|
|
137
192
|
"reason": reason,
|
|
@@ -1,187 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
"""Advanced capabilities SEND_MESSAGE action.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Keep this action implementation aligned with bootstrap to guarantee identical
|
|
4
|
+
target parsing and dispatch behavior across capability variants.
|
|
5
|
+
"""
|
|
6
6
|
|
|
7
|
-
from elizaos.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from elizaos.types import HandlerCallback, HandlerOptions, IAgentRuntime, Memory, State
|
|
13
|
-
|
|
14
|
-
# Get text content from centralized specs
|
|
15
|
-
_spec = require_action_spec("SEND_MESSAGE")
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def _convert_spec_examples() -> list[list[ActionExample]]:
|
|
19
|
-
"""Convert spec examples to ActionExample format."""
|
|
20
|
-
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(
|
|
41
|
-
ActionExample(
|
|
42
|
-
name=str(msg.get("name", "")),
|
|
43
|
-
content=Content(text=text, actions=actions),
|
|
44
|
-
)
|
|
45
|
-
)
|
|
46
|
-
if row:
|
|
47
|
-
result.append(row)
|
|
48
|
-
return result
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@dataclass
|
|
52
|
-
class SendMessageAction:
|
|
53
|
-
name: str = _spec["name"]
|
|
54
|
-
similes: list[str] = field(default_factory=lambda: list(_spec.get("similes", [])))
|
|
55
|
-
description: str = _spec["description"]
|
|
56
|
-
|
|
57
|
-
async def validate(
|
|
58
|
-
self, runtime: IAgentRuntime, message: Memory, _state: State | None = None
|
|
59
|
-
) -> bool:
|
|
60
|
-
if message.content and message.content.target:
|
|
61
|
-
return True
|
|
62
|
-
return True
|
|
63
|
-
|
|
64
|
-
async def handler(
|
|
65
|
-
self,
|
|
66
|
-
runtime: IAgentRuntime,
|
|
67
|
-
message: Memory,
|
|
68
|
-
state: State | None = None,
|
|
69
|
-
options: HandlerOptions | None = None,
|
|
70
|
-
callback: HandlerCallback | None = None,
|
|
71
|
-
responses: list[Memory] | None = None,
|
|
72
|
-
) -> ActionResult:
|
|
73
|
-
message_text = ""
|
|
74
|
-
if responses and responses[0].content:
|
|
75
|
-
message_text = str(responses[0].content.text or "")
|
|
76
|
-
|
|
77
|
-
if not message_text:
|
|
78
|
-
return ActionResult(
|
|
79
|
-
text="No message content to send",
|
|
80
|
-
values={"success": False, "error": "no_content"},
|
|
81
|
-
data={"actionName": "SEND_MESSAGE"},
|
|
82
|
-
success=False,
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
from uuid import UUID as StdUUID
|
|
86
|
-
|
|
87
|
-
target_room_id_val: str | None = str(message.room_id) if message.room_id else None
|
|
88
|
-
target_entity_id: str | None = None
|
|
89
|
-
|
|
90
|
-
if message.content and message.content.target:
|
|
91
|
-
target = message.content.target
|
|
92
|
-
if isinstance(target, dict):
|
|
93
|
-
room_str = target.get("roomId")
|
|
94
|
-
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:
|
|
103
|
-
return ActionResult(
|
|
104
|
-
text="No target room specified",
|
|
105
|
-
values={"success": False, "error": "no_target"},
|
|
106
|
-
data={"actionName": "SEND_MESSAGE"},
|
|
107
|
-
success=False,
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
message_content = Content(
|
|
111
|
-
text=message_text,
|
|
112
|
-
source="agent",
|
|
113
|
-
actions=["SEND_MESSAGE"],
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
# Create the message memory for event emission
|
|
117
|
-
import time
|
|
118
|
-
import uuid as uuid_module
|
|
119
|
-
|
|
120
|
-
from elizaos.types.primitives import as_uuid
|
|
121
|
-
|
|
122
|
-
message_memory = MemoryType(
|
|
123
|
-
id=as_uuid(str(uuid_module.uuid4())),
|
|
124
|
-
entity_id=runtime.agent_id,
|
|
125
|
-
room_id=as_uuid(target_room_id_val) if target_room_id_val else None,
|
|
126
|
-
content=message_content,
|
|
127
|
-
created_at=int(time.time() * 1000),
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
await runtime.create_memory(
|
|
131
|
-
content=message_content,
|
|
132
|
-
room_id=target_room_id_val,
|
|
133
|
-
entity_id=runtime.agent_id,
|
|
134
|
-
memory_type="message",
|
|
135
|
-
metadata={
|
|
136
|
-
"type": "SEND_MESSAGE",
|
|
137
|
-
"targetEntityId": str(target_entity_id) if target_entity_id else None,
|
|
138
|
-
},
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
# Emit MESSAGE_SENT event
|
|
142
|
-
await runtime.emit_event(
|
|
143
|
-
"MESSAGE_SENT",
|
|
144
|
-
{
|
|
145
|
-
"runtime": runtime,
|
|
146
|
-
"source": "send-message-action",
|
|
147
|
-
"message": message_memory,
|
|
148
|
-
},
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
response_content = Content(
|
|
152
|
-
text=f"Message sent: {message_text[:50]}...",
|
|
153
|
-
actions=["SEND_MESSAGE"],
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
if callback:
|
|
157
|
-
await callback(response_content)
|
|
158
|
-
|
|
159
|
-
return ActionResult(
|
|
160
|
-
text="Message sent to room",
|
|
161
|
-
values={
|
|
162
|
-
"success": True,
|
|
163
|
-
"messageSent": True,
|
|
164
|
-
"targetRoomId": str(target_room_id_val),
|
|
165
|
-
"targetEntityId": str(target_entity_id) if target_entity_id else None,
|
|
166
|
-
},
|
|
167
|
-
data={
|
|
168
|
-
"actionName": "SEND_MESSAGE",
|
|
169
|
-
"targetRoomId": str(target_room_id_val),
|
|
170
|
-
"messagePreview": message_text[:100],
|
|
171
|
-
},
|
|
172
|
-
success=True,
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
@property
|
|
176
|
-
def examples(self) -> list[list[ActionExample]]:
|
|
177
|
-
return _convert_spec_examples()
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
send_message_action = Action(
|
|
181
|
-
name=SendMessageAction.name,
|
|
182
|
-
similes=SendMessageAction().similes,
|
|
183
|
-
description=SendMessageAction.description,
|
|
184
|
-
validate=SendMessageAction().validate,
|
|
185
|
-
handler=SendMessageAction().handler,
|
|
186
|
-
examples=SendMessageAction().examples,
|
|
7
|
+
from elizaos.bootstrap.actions.send_message import ( # re-export for parity
|
|
8
|
+
SendMessageAction,
|
|
9
|
+
send_message_action,
|
|
187
10
|
)
|
|
11
|
+
|
|
12
|
+
__all__ = ["SendMessageAction", "send_message_action"]
|
|
@@ -95,38 +95,36 @@ class MemoryService(Service):
|
|
|
95
95
|
@classmethod
|
|
96
96
|
async def start(cls, runtime):
|
|
97
97
|
svc = cls(runtime=runtime)
|
|
98
|
-
|
|
99
|
-
settings = runtime.character.settings or {}
|
|
100
|
-
if (v := settings.get("MEMORY_SUMMARIZATION_THRESHOLD")) is not None and isinstance(
|
|
98
|
+
if (v := runtime.get_setting("MEMORY_SUMMARIZATION_THRESHOLD")) is not None and isinstance(
|
|
101
99
|
v, (int, float, str)
|
|
102
100
|
):
|
|
103
101
|
svc._config.short_term_summarization_threshold = int(v)
|
|
104
|
-
if (v :=
|
|
102
|
+
if (v := runtime.get_setting("MEMORY_RETAIN_RECENT")) is not None and isinstance(
|
|
105
103
|
v, (int, float, str)
|
|
106
104
|
):
|
|
107
105
|
svc._config.short_term_retain_recent = int(v)
|
|
108
|
-
if (v :=
|
|
106
|
+
if (v := runtime.get_setting("MEMORY_SUMMARIZATION_INTERVAL")) is not None and isinstance(
|
|
109
107
|
v, (int, float, str)
|
|
110
108
|
):
|
|
111
109
|
svc._config.short_term_summarization_interval = int(v)
|
|
112
|
-
if (v :=
|
|
110
|
+
if (v := runtime.get_setting("MEMORY_MAX_NEW_MESSAGES")) is not None and isinstance(
|
|
113
111
|
v, (int, float, str)
|
|
114
112
|
):
|
|
115
113
|
svc._config.summary_max_new_messages = int(v)
|
|
116
|
-
if (v :=
|
|
114
|
+
if (v := runtime.get_setting("MEMORY_LONG_TERM_ENABLED")) is not None:
|
|
117
115
|
if str(v).lower() == "false":
|
|
118
116
|
svc._config.long_term_extraction_enabled = False
|
|
119
117
|
elif str(v).lower() == "true":
|
|
120
118
|
svc._config.long_term_extraction_enabled = True
|
|
121
|
-
if (v :=
|
|
119
|
+
if (v := runtime.get_setting("MEMORY_CONFIDENCE_THRESHOLD")) is not None and isinstance(
|
|
122
120
|
v, (int, float, str)
|
|
123
121
|
):
|
|
124
122
|
svc._config.long_term_confidence_threshold = float(v)
|
|
125
|
-
if (v :=
|
|
123
|
+
if (v := runtime.get_setting("MEMORY_EXTRACTION_THRESHOLD")) is not None and isinstance(
|
|
126
124
|
v, (int, float, str)
|
|
127
125
|
):
|
|
128
126
|
svc._config.long_term_extraction_threshold = int(v)
|
|
129
|
-
if (v :=
|
|
127
|
+
if (v := runtime.get_setting("MEMORY_EXTRACTION_INTERVAL")) is not None and isinstance(
|
|
130
128
|
v, (int, float, str)
|
|
131
129
|
):
|
|
132
130
|
svc._config.long_term_extraction_interval = int(v)
|
|
@@ -146,7 +144,7 @@ class MemoryService(Service):
|
|
|
146
144
|
return f"memory:extraction:{entity_id}:{room_id}"
|
|
147
145
|
|
|
148
146
|
async def get_last_extraction_checkpoint(self, entity_id: UUID, room_id: UUID) -> int:
|
|
149
|
-
runtime = self.
|
|
147
|
+
runtime = self._runtime
|
|
150
148
|
key = self._checkpoint_key(entity_id, room_id)
|
|
151
149
|
if runtime is not None and getattr(runtime, "_adapter", None) is not None:
|
|
152
150
|
cached = await runtime.get_cache(key)
|
|
@@ -163,7 +161,7 @@ class MemoryService(Service):
|
|
|
163
161
|
async def set_last_extraction_checkpoint(
|
|
164
162
|
self, entity_id: UUID, room_id: UUID, message_count: int
|
|
165
163
|
) -> None:
|
|
166
|
-
runtime = self.
|
|
164
|
+
runtime = self._runtime
|
|
167
165
|
key = self._checkpoint_key(entity_id, room_id)
|
|
168
166
|
if runtime is not None and getattr(runtime, "_adapter", None) is not None:
|
|
169
167
|
_ = await runtime.set_cache(key, int(message_count))
|
|
@@ -182,7 +180,7 @@ class MemoryService(Service):
|
|
|
182
180
|
return current_cp > last_cp
|
|
183
181
|
|
|
184
182
|
async def get_current_session_summary(self, room_id: UUID) -> SessionSummary | None:
|
|
185
|
-
runtime = self.
|
|
183
|
+
runtime = self._runtime
|
|
186
184
|
if runtime is None:
|
|
187
185
|
return None
|
|
188
186
|
|
|
@@ -234,7 +232,7 @@ class MemoryService(Service):
|
|
|
234
232
|
topics: list[str] | None = None,
|
|
235
233
|
metadata: dict[str, object] | None = None,
|
|
236
234
|
) -> SessionSummary:
|
|
237
|
-
runtime = self.
|
|
235
|
+
runtime = self._runtime
|
|
238
236
|
s = SessionSummary(
|
|
239
237
|
id=uuid4(),
|
|
240
238
|
agent_id=agent_id,
|
|
@@ -279,7 +277,7 @@ class MemoryService(Service):
|
|
|
279
277
|
async def update_session_summary(
|
|
280
278
|
self, summary_id: UUID, room_id: UUID, **updates: object
|
|
281
279
|
) -> None:
|
|
282
|
-
runtime = self.
|
|
280
|
+
runtime = self._runtime
|
|
283
281
|
if runtime is not None and getattr(runtime, "_adapter", None) is not None:
|
|
284
282
|
existing = await self.get_current_session_summary(room_id)
|
|
285
283
|
if not existing or existing.id != summary_id:
|
|
@@ -350,7 +348,7 @@ class MemoryService(Service):
|
|
|
350
348
|
source: str | None = None,
|
|
351
349
|
metadata: dict[str, object] | None = None,
|
|
352
350
|
) -> LongTermMemory:
|
|
353
|
-
runtime = self.
|
|
351
|
+
runtime = self._runtime
|
|
354
352
|
m = LongTermMemory(
|
|
355
353
|
id=uuid4(),
|
|
356
354
|
agent_id=agent_id,
|
|
@@ -394,7 +392,7 @@ class MemoryService(Service):
|
|
|
394
392
|
) -> list[LongTermMemory]:
|
|
395
393
|
if limit <= 0:
|
|
396
394
|
return []
|
|
397
|
-
runtime = self.
|
|
395
|
+
runtime = self._runtime
|
|
398
396
|
if runtime is not None and getattr(runtime, "_adapter", None) is not None:
|
|
399
397
|
db_mems = await runtime.get_memories(
|
|
400
398
|
{
|
|
@@ -10,7 +10,7 @@ from uuid import UUID, uuid4
|
|
|
10
10
|
from google.protobuf.json_format import MessageToDict
|
|
11
11
|
|
|
12
12
|
from elizaos.logger import Logger
|
|
13
|
-
from elizaos.types.components import ActionContext, ActionResult, HandlerCallback
|
|
13
|
+
from elizaos.types.components import ActionContext, ActionResult, HandlerCallback
|
|
14
14
|
from elizaos.types.memory import Memory
|
|
15
15
|
from elizaos.types.primitives import Content
|
|
16
16
|
from elizaos.types.service import Service
|
|
@@ -538,6 +538,8 @@ Focus on:
|
|
|
538
538
|
]
|
|
539
539
|
results = await asyncio.gather(*tasks, return_exceptions=True)
|
|
540
540
|
for r in results:
|
|
541
|
+
if isinstance(r, Exception):
|
|
542
|
+
raise RuntimeError(f"Plan step failed during parallel execution: {r}") from r
|
|
541
543
|
if isinstance(r, ActionResult):
|
|
542
544
|
execution.results.append(r)
|
|
543
545
|
|
|
@@ -586,6 +588,10 @@ Focus on:
|
|
|
586
588
|
|
|
587
589
|
for step, r in zip(ready_batch, results, strict=False):
|
|
588
590
|
completed_count += 1
|
|
591
|
+
if isinstance(r, Exception):
|
|
592
|
+
raise RuntimeError(
|
|
593
|
+
f"Plan step '{step.action_name}' failed during DAG execution: {r}"
|
|
594
|
+
) from r
|
|
589
595
|
if isinstance(r, ActionResult):
|
|
590
596
|
execution.results.append(r)
|
|
591
597
|
|
|
@@ -622,13 +628,16 @@ Focus on:
|
|
|
622
628
|
if execution.abort_event.is_set():
|
|
623
629
|
raise RuntimeError("Plan execution aborted")
|
|
624
630
|
try:
|
|
625
|
-
options =
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
631
|
+
options = type(
|
|
632
|
+
"_PlanningHandlerOptions",
|
|
633
|
+
(),
|
|
634
|
+
{
|
|
635
|
+
"action_context": action_context,
|
|
636
|
+
"parameters": step.parameters,
|
|
637
|
+
"previous_results": previous_results,
|
|
638
|
+
"context": {"workingMemory": execution.working_memory},
|
|
639
|
+
},
|
|
640
|
+
)()
|
|
632
641
|
|
|
633
642
|
validate_fn = getattr(action, "validate", None) or getattr(
|
|
634
643
|
action, "validate_fn", None
|
|
@@ -641,12 +650,15 @@ Focus on:
|
|
|
641
650
|
if result is None:
|
|
642
651
|
return None
|
|
643
652
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
653
|
+
step_metadata = {
|
|
654
|
+
"stepId": str(step.id),
|
|
655
|
+
"actionName": step.action_name,
|
|
656
|
+
"executedAt": int(time.time() * 1000),
|
|
657
|
+
}
|
|
658
|
+
if isinstance(result.data, dict) or hasattr(result.data, "update"):
|
|
659
|
+
result.data.update(step_metadata)
|
|
660
|
+
else:
|
|
661
|
+
result.data = step_metadata
|
|
650
662
|
return result
|
|
651
663
|
except Exception as e:
|
|
652
664
|
retries += 1
|