@elizaos/python 2.0.0-alpha.10

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 (197) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +239 -0
  3. package/elizaos/__init__.py +280 -0
  4. package/elizaos/action_docs.py +149 -0
  5. package/elizaos/advanced_capabilities/__init__.py +85 -0
  6. package/elizaos/advanced_capabilities/actions/__init__.py +54 -0
  7. package/elizaos/advanced_capabilities/actions/add_contact.py +139 -0
  8. package/elizaos/advanced_capabilities/actions/follow_room.py +151 -0
  9. package/elizaos/advanced_capabilities/actions/image_generation.py +148 -0
  10. package/elizaos/advanced_capabilities/actions/mute_room.py +164 -0
  11. package/elizaos/advanced_capabilities/actions/remove_contact.py +145 -0
  12. package/elizaos/advanced_capabilities/actions/roles.py +207 -0
  13. package/elizaos/advanced_capabilities/actions/schedule_follow_up.py +154 -0
  14. package/elizaos/advanced_capabilities/actions/search_contacts.py +145 -0
  15. package/elizaos/advanced_capabilities/actions/send_message.py +187 -0
  16. package/elizaos/advanced_capabilities/actions/settings.py +151 -0
  17. package/elizaos/advanced_capabilities/actions/unfollow_room.py +164 -0
  18. package/elizaos/advanced_capabilities/actions/unmute_room.py +164 -0
  19. package/elizaos/advanced_capabilities/actions/update_contact.py +164 -0
  20. package/elizaos/advanced_capabilities/actions/update_entity.py +161 -0
  21. package/elizaos/advanced_capabilities/evaluators/__init__.py +18 -0
  22. package/elizaos/advanced_capabilities/evaluators/reflection.py +134 -0
  23. package/elizaos/advanced_capabilities/evaluators/relationship_extraction.py +203 -0
  24. package/elizaos/advanced_capabilities/providers/__init__.py +36 -0
  25. package/elizaos/advanced_capabilities/providers/agent_settings.py +60 -0
  26. package/elizaos/advanced_capabilities/providers/contacts.py +77 -0
  27. package/elizaos/advanced_capabilities/providers/facts.py +82 -0
  28. package/elizaos/advanced_capabilities/providers/follow_ups.py +113 -0
  29. package/elizaos/advanced_capabilities/providers/knowledge.py +83 -0
  30. package/elizaos/advanced_capabilities/providers/relationships.py +112 -0
  31. package/elizaos/advanced_capabilities/providers/roles.py +97 -0
  32. package/elizaos/advanced_capabilities/providers/settings.py +51 -0
  33. package/elizaos/advanced_capabilities/services/__init__.py +18 -0
  34. package/elizaos/advanced_capabilities/services/follow_up.py +138 -0
  35. package/elizaos/advanced_capabilities/services/rolodex.py +244 -0
  36. package/elizaos/advanced_memory/__init__.py +3 -0
  37. package/elizaos/advanced_memory/evaluators.py +97 -0
  38. package/elizaos/advanced_memory/memory_service.py +556 -0
  39. package/elizaos/advanced_memory/plugin.py +30 -0
  40. package/elizaos/advanced_memory/prompts.py +12 -0
  41. package/elizaos/advanced_memory/providers.py +90 -0
  42. package/elizaos/advanced_memory/types.py +65 -0
  43. package/elizaos/advanced_planning/__init__.py +10 -0
  44. package/elizaos/advanced_planning/actions.py +145 -0
  45. package/elizaos/advanced_planning/message_classifier.py +127 -0
  46. package/elizaos/advanced_planning/planning_service.py +712 -0
  47. package/elizaos/advanced_planning/plugin.py +40 -0
  48. package/elizaos/advanced_planning/prompts.py +4 -0
  49. package/elizaos/basic_capabilities/__init__.py +66 -0
  50. package/elizaos/basic_capabilities/actions/__init__.py +24 -0
  51. package/elizaos/basic_capabilities/actions/choice.py +140 -0
  52. package/elizaos/basic_capabilities/actions/ignore.py +66 -0
  53. package/elizaos/basic_capabilities/actions/none.py +56 -0
  54. package/elizaos/basic_capabilities/actions/reply.py +120 -0
  55. package/elizaos/basic_capabilities/providers/__init__.py +54 -0
  56. package/elizaos/basic_capabilities/providers/action_state.py +113 -0
  57. package/elizaos/basic_capabilities/providers/actions.py +263 -0
  58. package/elizaos/basic_capabilities/providers/attachments.py +76 -0
  59. package/elizaos/basic_capabilities/providers/capabilities.py +62 -0
  60. package/elizaos/basic_capabilities/providers/character.py +113 -0
  61. package/elizaos/basic_capabilities/providers/choice.py +73 -0
  62. package/elizaos/basic_capabilities/providers/context_bench.py +44 -0
  63. package/elizaos/basic_capabilities/providers/current_time.py +58 -0
  64. package/elizaos/basic_capabilities/providers/entities.py +99 -0
  65. package/elizaos/basic_capabilities/providers/evaluators.py +54 -0
  66. package/elizaos/basic_capabilities/providers/providers_list.py +55 -0
  67. package/elizaos/basic_capabilities/providers/recent_messages.py +85 -0
  68. package/elizaos/basic_capabilities/providers/time.py +45 -0
  69. package/elizaos/basic_capabilities/providers/world.py +93 -0
  70. package/elizaos/basic_capabilities/services/__init__.py +18 -0
  71. package/elizaos/basic_capabilities/services/embedding.py +122 -0
  72. package/elizaos/basic_capabilities/services/task.py +178 -0
  73. package/elizaos/bootstrap/__init__.py +12 -0
  74. package/elizaos/bootstrap/actions/__init__.py +68 -0
  75. package/elizaos/bootstrap/actions/add_contact.py +149 -0
  76. package/elizaos/bootstrap/actions/choice.py +147 -0
  77. package/elizaos/bootstrap/actions/follow_room.py +151 -0
  78. package/elizaos/bootstrap/actions/ignore.py +80 -0
  79. package/elizaos/bootstrap/actions/image_generation.py +135 -0
  80. package/elizaos/bootstrap/actions/mute_room.py +151 -0
  81. package/elizaos/bootstrap/actions/none.py +71 -0
  82. package/elizaos/bootstrap/actions/remove_contact.py +159 -0
  83. package/elizaos/bootstrap/actions/reply.py +140 -0
  84. package/elizaos/bootstrap/actions/roles.py +193 -0
  85. package/elizaos/bootstrap/actions/schedule_follow_up.py +164 -0
  86. package/elizaos/bootstrap/actions/search_contacts.py +159 -0
  87. package/elizaos/bootstrap/actions/send_message.py +173 -0
  88. package/elizaos/bootstrap/actions/settings.py +165 -0
  89. package/elizaos/bootstrap/actions/unfollow_room.py +151 -0
  90. package/elizaos/bootstrap/actions/unmute_room.py +151 -0
  91. package/elizaos/bootstrap/actions/update_contact.py +178 -0
  92. package/elizaos/bootstrap/actions/update_entity.py +175 -0
  93. package/elizaos/bootstrap/autonomy/__init__.py +18 -0
  94. package/elizaos/bootstrap/autonomy/action.py +197 -0
  95. package/elizaos/bootstrap/autonomy/providers.py +165 -0
  96. package/elizaos/bootstrap/autonomy/routes.py +171 -0
  97. package/elizaos/bootstrap/autonomy/service.py +562 -0
  98. package/elizaos/bootstrap/autonomy/types.py +18 -0
  99. package/elizaos/bootstrap/evaluators/__init__.py +19 -0
  100. package/elizaos/bootstrap/evaluators/reflection.py +118 -0
  101. package/elizaos/bootstrap/evaluators/relationship_extraction.py +192 -0
  102. package/elizaos/bootstrap/plugin.py +140 -0
  103. package/elizaos/bootstrap/providers/__init__.py +80 -0
  104. package/elizaos/bootstrap/providers/action_state.py +71 -0
  105. package/elizaos/bootstrap/providers/actions.py +256 -0
  106. package/elizaos/bootstrap/providers/agent_settings.py +63 -0
  107. package/elizaos/bootstrap/providers/attachments.py +76 -0
  108. package/elizaos/bootstrap/providers/capabilities.py +66 -0
  109. package/elizaos/bootstrap/providers/character.py +128 -0
  110. package/elizaos/bootstrap/providers/choice.py +77 -0
  111. package/elizaos/bootstrap/providers/contacts.py +78 -0
  112. package/elizaos/bootstrap/providers/context_bench.py +49 -0
  113. package/elizaos/bootstrap/providers/current_time.py +56 -0
  114. package/elizaos/bootstrap/providers/entities.py +99 -0
  115. package/elizaos/bootstrap/providers/evaluators.py +58 -0
  116. package/elizaos/bootstrap/providers/facts.py +86 -0
  117. package/elizaos/bootstrap/providers/follow_ups.py +116 -0
  118. package/elizaos/bootstrap/providers/knowledge.py +73 -0
  119. package/elizaos/bootstrap/providers/providers_list.py +59 -0
  120. package/elizaos/bootstrap/providers/recent_messages.py +85 -0
  121. package/elizaos/bootstrap/providers/relationships.py +106 -0
  122. package/elizaos/bootstrap/providers/roles.py +95 -0
  123. package/elizaos/bootstrap/providers/settings.py +55 -0
  124. package/elizaos/bootstrap/providers/time.py +45 -0
  125. package/elizaos/bootstrap/providers/world.py +97 -0
  126. package/elizaos/bootstrap/services/__init__.py +26 -0
  127. package/elizaos/bootstrap/services/embedding.py +122 -0
  128. package/elizaos/bootstrap/services/follow_up.py +138 -0
  129. package/elizaos/bootstrap/services/rolodex.py +244 -0
  130. package/elizaos/bootstrap/services/task.py +585 -0
  131. package/elizaos/bootstrap/types.py +54 -0
  132. package/elizaos/bootstrap/utils/__init__.py +7 -0
  133. package/elizaos/bootstrap/utils/xml.py +69 -0
  134. package/elizaos/character.py +149 -0
  135. package/elizaos/logger.py +179 -0
  136. package/elizaos/media/__init__.py +45 -0
  137. package/elizaos/media/mime.py +315 -0
  138. package/elizaos/media/search.py +161 -0
  139. package/elizaos/media/tests/__init__.py +1 -0
  140. package/elizaos/media/tests/test_mime.py +117 -0
  141. package/elizaos/media/tests/test_search.py +156 -0
  142. package/elizaos/plugin.py +191 -0
  143. package/elizaos/prompts.py +1071 -0
  144. package/elizaos/py.typed +0 -0
  145. package/elizaos/runtime.py +2572 -0
  146. package/elizaos/services/__init__.py +49 -0
  147. package/elizaos/services/hook_service.py +511 -0
  148. package/elizaos/services/message_service.py +1248 -0
  149. package/elizaos/settings.py +182 -0
  150. package/elizaos/streaming_context.py +159 -0
  151. package/elizaos/trajectory_context.py +18 -0
  152. package/elizaos/types/__init__.py +512 -0
  153. package/elizaos/types/agent.py +31 -0
  154. package/elizaos/types/components.py +208 -0
  155. package/elizaos/types/database.py +64 -0
  156. package/elizaos/types/environment.py +46 -0
  157. package/elizaos/types/events.py +47 -0
  158. package/elizaos/types/memory.py +45 -0
  159. package/elizaos/types/model.py +393 -0
  160. package/elizaos/types/plugin.py +188 -0
  161. package/elizaos/types/primitives.py +100 -0
  162. package/elizaos/types/runtime.py +460 -0
  163. package/elizaos/types/service.py +113 -0
  164. package/elizaos/types/service_interfaces.py +244 -0
  165. package/elizaos/types/state.py +188 -0
  166. package/elizaos/types/task.py +29 -0
  167. package/elizaos/utils/__init__.py +108 -0
  168. package/elizaos/utils/spec_examples.py +48 -0
  169. package/elizaos/utils/streaming.py +426 -0
  170. package/elizaos_atropos_shared/__init__.py +1 -0
  171. package/elizaos_atropos_shared/canonical_eliza.py +282 -0
  172. package/package.json +19 -0
  173. package/pyproject.toml +143 -0
  174. package/requirements-dev.in +11 -0
  175. package/requirements-dev.lock +134 -0
  176. package/requirements.in +9 -0
  177. package/requirements.lock +64 -0
  178. package/tests/__init__.py +0 -0
  179. package/tests/test_action_parameters.py +154 -0
  180. package/tests/test_actions_provider_examples.py +39 -0
  181. package/tests/test_advanced_memory_behavior.py +96 -0
  182. package/tests/test_advanced_memory_flag.py +30 -0
  183. package/tests/test_advanced_planning_behavior.py +225 -0
  184. package/tests/test_advanced_planning_flag.py +26 -0
  185. package/tests/test_autonomy.py +445 -0
  186. package/tests/test_bootstrap_initialize.py +37 -0
  187. package/tests/test_character.py +163 -0
  188. package/tests/test_character_provider.py +231 -0
  189. package/tests/test_dynamic_prompt_exec.py +561 -0
  190. package/tests/test_logger_redaction.py +43 -0
  191. package/tests/test_plugin.py +117 -0
  192. package/tests/test_runtime.py +422 -0
  193. package/tests/test_salt_production_enforcement.py +22 -0
  194. package/tests/test_settings_crypto.py +118 -0
  195. package/tests/test_streaming.py +295 -0
  196. package/tests/test_types.py +221 -0
  197. package/tests/test_uuid_parity.py +46 -0
@@ -0,0 +1,173 @@
1
+ from __future__ import annotations
2
+
3
+ import contextlib
4
+ from dataclasses import dataclass, field
5
+ from typing import TYPE_CHECKING
6
+ from uuid import UUID
7
+
8
+ from elizaos.generated.spec_helpers import require_action_spec
9
+ from elizaos.types import Action, ActionExample, ActionResult, Content
10
+ from elizaos.types.memory import Memory as MemoryType
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
+ @dataclass
40
+ class SendMessageAction:
41
+ name: str = _spec["name"]
42
+ similes: list[str] = field(default_factory=lambda: list(_spec.get("similes", [])))
43
+ description: str = _spec["description"]
44
+
45
+ async def validate(
46
+ self, runtime: IAgentRuntime, message: Memory, _state: State | None = None
47
+ ) -> bool:
48
+ if message.content and message.content.target:
49
+ return True
50
+ return True
51
+
52
+ async def handler(
53
+ self,
54
+ runtime: IAgentRuntime,
55
+ message: Memory,
56
+ state: State | None = None,
57
+ options: HandlerOptions | None = None,
58
+ callback: HandlerCallback | None = None,
59
+ responses: list[Memory] | None = None,
60
+ ) -> ActionResult:
61
+ message_text = ""
62
+ if responses and responses[0].content:
63
+ message_text = str(responses[0].content.text or "")
64
+
65
+ if not message_text:
66
+ return ActionResult(
67
+ text="No message content to send",
68
+ values={"success": False, "error": "no_content"},
69
+ data={"actionName": "SEND_MESSAGE"},
70
+ success=False,
71
+ )
72
+
73
+ target_room_id = message.room_id
74
+ target_entity_id: UUID | None = None
75
+
76
+ if message.content and message.content.target:
77
+ target = message.content.target
78
+ if isinstance(target, dict):
79
+ room_str = target.get("roomId")
80
+ entity_str = target.get("entityId")
81
+ if room_str:
82
+ with contextlib.suppress(ValueError):
83
+ target_room_id = UUID(room_str)
84
+ if entity_str:
85
+ with contextlib.suppress(ValueError):
86
+ target_entity_id = UUID(entity_str)
87
+
88
+ if not target_room_id:
89
+ return ActionResult(
90
+ text="No target room specified",
91
+ values={"success": False, "error": "no_target"},
92
+ data={"actionName": "SEND_MESSAGE"},
93
+ success=False,
94
+ )
95
+
96
+ message_content = Content(
97
+ text=message_text,
98
+ source="agent",
99
+ actions=["SEND_MESSAGE"],
100
+ )
101
+
102
+ # Create the message memory
103
+ import time
104
+ import uuid as uuid_module
105
+
106
+ from elizaos.types.primitives import as_uuid
107
+
108
+ message_memory = MemoryType(
109
+ id=as_uuid(str(uuid_module.uuid4())),
110
+ entity_id=runtime.agent_id,
111
+ room_id=target_room_id,
112
+ content=message_content,
113
+ created_at=int(time.time() * 1000),
114
+ )
115
+
116
+ await runtime.create_memory(
117
+ content=message_content,
118
+ room_id=target_room_id,
119
+ entity_id=runtime.agent_id,
120
+ memory_type="message",
121
+ metadata={
122
+ "type": "SEND_MESSAGE",
123
+ "targetEntityId": str(target_entity_id) if target_entity_id else None,
124
+ },
125
+ )
126
+
127
+ # Emit MESSAGE_SENT event
128
+ await runtime.emit_event(
129
+ "MESSAGE_SENT",
130
+ {
131
+ "runtime": runtime,
132
+ "source": "send-message-action",
133
+ "message": message_memory,
134
+ },
135
+ )
136
+
137
+ response_content = Content(
138
+ text=f"Message sent: {message_text[:50]}...",
139
+ actions=["SEND_MESSAGE"],
140
+ )
141
+
142
+ if callback:
143
+ await callback(response_content)
144
+
145
+ return ActionResult(
146
+ text="Message sent to room",
147
+ values={
148
+ "success": True,
149
+ "messageSent": True,
150
+ "targetRoomId": str(target_room_id),
151
+ "targetEntityId": str(target_entity_id) if target_entity_id else None,
152
+ },
153
+ data={
154
+ "actionName": "SEND_MESSAGE",
155
+ "targetRoomId": str(target_room_id),
156
+ "messagePreview": message_text[:100],
157
+ },
158
+ success=True,
159
+ )
160
+
161
+ @property
162
+ def examples(self) -> list[list[ActionExample]]:
163
+ return _convert_spec_examples()
164
+
165
+
166
+ send_message_action = Action(
167
+ name=SendMessageAction.name,
168
+ similes=SendMessageAction().similes,
169
+ description=SendMessageAction.description,
170
+ validate=SendMessageAction().validate,
171
+ handler=SendMessageAction().handler,
172
+ examples=SendMessageAction().examples,
173
+ )
@@ -0,0 +1,165 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import TYPE_CHECKING
5
+
6
+ from elizaos.bootstrap.utils.xml import parse_key_value_xml
7
+ from elizaos.generated.spec_helpers import require_action_spec
8
+ from elizaos.prompts import UPDATE_SETTINGS_TEMPLATE
9
+ from elizaos.types import Action, ActionExample, ActionResult, Content, ModelType
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("UPDATE_SETTINGS")
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 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 []
36
+
37
+
38
+ @dataclass
39
+ class SettingUpdate:
40
+ key: str
41
+ value: str
42
+
43
+
44
+ @dataclass
45
+ class UpdateSettingsAction:
46
+ name: str = _spec["name"]
47
+ similes: list[str] = field(default_factory=lambda: list(_spec.get("similes", [])))
48
+ description: str = _spec["description"]
49
+
50
+ async def validate(
51
+ self, runtime: IAgentRuntime, _message: Memory, _state: State | None = None
52
+ ) -> bool:
53
+ return True
54
+
55
+ async def handler(
56
+ self,
57
+ runtime: IAgentRuntime,
58
+ message: Memory,
59
+ state: State | None = None,
60
+ options: HandlerOptions | None = None,
61
+ callback: HandlerCallback | None = None,
62
+ responses: list[Memory] | None = None,
63
+ ) -> ActionResult:
64
+ if state is None:
65
+ raise ValueError("State is required for UPDATE_SETTINGS action")
66
+
67
+ state = await runtime.compose_state(
68
+ message, ["RECENT_MESSAGES", "ACTION_STATE", "AGENT_SETTINGS"]
69
+ )
70
+
71
+ current_settings = runtime.get_all_settings()
72
+ settings_context = "\n".join(
73
+ f"- {key}: {value}"
74
+ for key, value in current_settings.items()
75
+ if not key.lower().endswith(("key", "secret", "password", "token"))
76
+ )
77
+
78
+ template = (
79
+ runtime.character.templates.get("updateSettingsTemplate")
80
+ if runtime.character.templates
81
+ and "updateSettingsTemplate" in runtime.character.templates
82
+ else UPDATE_SETTINGS_TEMPLATE
83
+ )
84
+ prompt = runtime.compose_prompt(state=state, template=template)
85
+ prompt = prompt.replace("{{settings}}", settings_context)
86
+
87
+ response_text = await runtime.use_model(ModelType.TEXT_LARGE, prompt=prompt)
88
+ parsed_xml = parse_key_value_xml(response_text)
89
+
90
+ if parsed_xml is None:
91
+ raise ValueError("Failed to parse XML response")
92
+
93
+ thought = str(parsed_xml.get("thought", ""))
94
+ updates_raw = parsed_xml.get("updates", [])
95
+
96
+ updated_settings: list[SettingUpdate] = []
97
+
98
+ if isinstance(updates_raw, list):
99
+ for update in updates_raw:
100
+ if isinstance(update, dict):
101
+ key = str(update.get("key", ""))
102
+ value = str(update.get("value", ""))
103
+ if key and value:
104
+ updated_settings.append(SettingUpdate(key=key, value=value))
105
+ elif isinstance(updates_raw, dict):
106
+ update_list = updates_raw.get("update", [])
107
+ if isinstance(update_list, dict):
108
+ update_list = [update_list]
109
+ for update in update_list:
110
+ if isinstance(update, dict):
111
+ key = str(update.get("key", ""))
112
+ value = str(update.get("value", ""))
113
+ if key and value:
114
+ updated_settings.append(SettingUpdate(key=key, value=value))
115
+
116
+ if not updated_settings:
117
+ return ActionResult(
118
+ text="No settings to update",
119
+ values={"success": True, "noChanges": True},
120
+ data={"actionName": "UPDATE_SETTINGS", "thought": thought},
121
+ success=True,
122
+ )
123
+
124
+ for setting in updated_settings:
125
+ runtime.set_setting(setting.key, setting.value)
126
+
127
+ updated_keys = [s.key for s in updated_settings]
128
+
129
+ response_content = Content(
130
+ text=f"Updated {len(updated_settings)} setting(s): {', '.join(updated_keys)}",
131
+ actions=["UPDATE_SETTINGS"],
132
+ )
133
+
134
+ if callback:
135
+ await callback(response_content)
136
+
137
+ return ActionResult(
138
+ text=f"Updated settings: {', '.join(updated_keys)}",
139
+ values={
140
+ "success": True,
141
+ "settingsUpdated": True,
142
+ "updatedCount": len(updated_settings),
143
+ "updatedKeys": ", ".join(updated_keys),
144
+ },
145
+ data={
146
+ "actionName": "UPDATE_SETTINGS",
147
+ "updatedSettings": updated_keys,
148
+ "thought": thought,
149
+ },
150
+ success=True,
151
+ )
152
+
153
+ @property
154
+ def examples(self) -> list[list[ActionExample]]:
155
+ return _convert_spec_examples()
156
+
157
+
158
+ update_settings_action = Action(
159
+ name=UpdateSettingsAction.name,
160
+ similes=UpdateSettingsAction().similes,
161
+ description=UpdateSettingsAction.description,
162
+ validate=UpdateSettingsAction().validate,
163
+ handler=UpdateSettingsAction().handler,
164
+ examples=UpdateSettingsAction().examples,
165
+ )
@@ -0,0 +1,151 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import TYPE_CHECKING
5
+
6
+ from elizaos.generated.spec_helpers import require_action_spec
7
+ from elizaos.types import Action, ActionExample, ActionResult, Content
8
+
9
+ if TYPE_CHECKING:
10
+ from elizaos.types import HandlerCallback, HandlerOptions, IAgentRuntime, Memory, State
11
+
12
+ # Get text content from centralized specs
13
+ _spec = require_action_spec("UNFOLLOW_ROOM")
14
+
15
+
16
+ def _convert_spec_examples() -> list[list[ActionExample]]:
17
+ """Convert spec examples to ActionExample format."""
18
+ spec_examples = _spec.get("examples", [])
19
+ if spec_examples:
20
+ return [
21
+ [
22
+ ActionExample(
23
+ name=msg.get("name", ""),
24
+ content=Content(
25
+ text=msg.get("content", {}).get("text", ""),
26
+ actions=msg.get("content", {}).get("actions"),
27
+ ),
28
+ )
29
+ for msg in example
30
+ ]
31
+ for example in spec_examples
32
+ ]
33
+ return []
34
+
35
+
36
+ @dataclass
37
+ class UnfollowRoomAction:
38
+ name: str = _spec["name"]
39
+ similes: list[str] = field(default_factory=lambda: list(_spec.get("similes", [])))
40
+ description: str = _spec["description"]
41
+
42
+ async def validate(
43
+ self, runtime: IAgentRuntime, message: Memory, _state: State | None = None
44
+ ) -> bool:
45
+ room_id = message.room_id
46
+ if not room_id:
47
+ return False
48
+
49
+ room = await runtime.get_room(room_id)
50
+ if room is None:
51
+ return False
52
+
53
+ world_id = room.world_id
54
+ if world_id:
55
+ world = await runtime.get_world(world_id)
56
+ if world and world.metadata:
57
+ followed_rooms = world.metadata.get("followedRooms", [])
58
+ if str(room_id) in followed_rooms:
59
+ return True
60
+
61
+ return False
62
+
63
+ async def handler(
64
+ self,
65
+ runtime: IAgentRuntime,
66
+ message: Memory,
67
+ state: State | None = None,
68
+ options: HandlerOptions | None = None,
69
+ callback: HandlerCallback | None = None,
70
+ responses: list[Memory] | None = None,
71
+ ) -> ActionResult:
72
+ room_id = message.room_id
73
+ if not room_id:
74
+ return ActionResult(
75
+ text="No room specified to unfollow",
76
+ values={"success": False, "error": "no_room_id"},
77
+ data={"actionName": "UNFOLLOW_ROOM"},
78
+ success=False,
79
+ )
80
+
81
+ room = await runtime.get_room(room_id)
82
+ if room is None:
83
+ return ActionResult(
84
+ text="Room not found",
85
+ values={"success": False, "error": "room_not_found"},
86
+ data={"actionName": "UNFOLLOW_ROOM"},
87
+ success=False,
88
+ )
89
+
90
+ room_name = str(room.name) if room.name else "Unknown Room"
91
+
92
+ world_id = room.world_id
93
+ if world_id:
94
+ world = await runtime.get_world(world_id)
95
+ if world and world.metadata:
96
+ followed_rooms = list(world.metadata.get("followedRooms", []))
97
+ room_id_str = str(room_id)
98
+
99
+ if room_id_str in followed_rooms:
100
+ followed_rooms.remove(room_id_str)
101
+ world.metadata["followedRooms"] = followed_rooms
102
+ await runtime.update_world(world)
103
+
104
+ await runtime.create_memory(
105
+ content=Content(
106
+ text=f"Stopped following room: {room_name}",
107
+ actions=["UNFOLLOW_ROOM"],
108
+ ),
109
+ room_id=room_id,
110
+ entity_id=runtime.agent_id,
111
+ memory_type="action",
112
+ metadata={"type": "UNFOLLOW_ROOM", "roomName": room_name},
113
+ )
114
+
115
+ response_content = Content(
116
+ text=f"I am no longer following {room_name}.",
117
+ actions=["UNFOLLOW_ROOM"],
118
+ )
119
+
120
+ if callback:
121
+ await callback(response_content)
122
+
123
+ return ActionResult(
124
+ text=f"Stopped following room: {room_name}",
125
+ values={
126
+ "success": True,
127
+ "unfollowed": True,
128
+ "roomId": str(room_id),
129
+ "roomName": room_name,
130
+ },
131
+ data={
132
+ "actionName": "UNFOLLOW_ROOM",
133
+ "roomId": str(room_id),
134
+ "roomName": room_name,
135
+ },
136
+ success=True,
137
+ )
138
+
139
+ @property
140
+ def examples(self) -> list[list[ActionExample]]:
141
+ return _convert_spec_examples()
142
+
143
+
144
+ unfollow_room_action = Action(
145
+ name=UnfollowRoomAction.name,
146
+ similes=UnfollowRoomAction().similes,
147
+ description=UnfollowRoomAction.description,
148
+ validate=UnfollowRoomAction().validate,
149
+ handler=UnfollowRoomAction().handler,
150
+ examples=UnfollowRoomAction().examples,
151
+ )
@@ -0,0 +1,151 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import TYPE_CHECKING
5
+
6
+ from elizaos.generated.spec_helpers import require_action_spec
7
+ from elizaos.types import Action, ActionExample, ActionResult, Content
8
+
9
+ if TYPE_CHECKING:
10
+ from elizaos.types import HandlerCallback, HandlerOptions, IAgentRuntime, Memory, State
11
+
12
+ # Get text content from centralized specs
13
+ _spec = require_action_spec("UNMUTE_ROOM")
14
+
15
+
16
+ def _convert_spec_examples() -> list[list[ActionExample]]:
17
+ """Convert spec examples to ActionExample format."""
18
+ spec_examples = _spec.get("examples", [])
19
+ if spec_examples:
20
+ return [
21
+ [
22
+ ActionExample(
23
+ name=msg.get("name", ""),
24
+ content=Content(
25
+ text=msg.get("content", {}).get("text", ""),
26
+ actions=msg.get("content", {}).get("actions"),
27
+ ),
28
+ )
29
+ for msg in example
30
+ ]
31
+ for example in spec_examples
32
+ ]
33
+ return []
34
+
35
+
36
+ @dataclass
37
+ class UnmuteRoomAction:
38
+ name: str = _spec["name"]
39
+ similes: list[str] = field(default_factory=lambda: list(_spec.get("similes", [])))
40
+ description: str = _spec["description"]
41
+
42
+ async def validate(
43
+ self, runtime: IAgentRuntime, message: Memory, _state: State | None = None
44
+ ) -> bool:
45
+ room_id = message.room_id
46
+ if not room_id:
47
+ return False
48
+
49
+ room = await runtime.get_room(room_id)
50
+ if room is None:
51
+ return False
52
+
53
+ world_id = room.world_id
54
+ if world_id:
55
+ world = await runtime.get_world(world_id)
56
+ if world and world.metadata:
57
+ muted_rooms = world.metadata.get("mutedRooms", [])
58
+ if str(room_id) in muted_rooms:
59
+ return True
60
+
61
+ return False
62
+
63
+ async def handler(
64
+ self,
65
+ runtime: IAgentRuntime,
66
+ message: Memory,
67
+ state: State | None = None,
68
+ options: HandlerOptions | None = None,
69
+ callback: HandlerCallback | None = None,
70
+ responses: list[Memory] | None = None,
71
+ ) -> ActionResult:
72
+ room_id = message.room_id
73
+ if not room_id:
74
+ return ActionResult(
75
+ text="No room specified to unmute",
76
+ values={"success": False, "error": "no_room_id"},
77
+ data={"actionName": "UNMUTE_ROOM"},
78
+ success=False,
79
+ )
80
+
81
+ room = await runtime.get_room(room_id)
82
+ if room is None:
83
+ return ActionResult(
84
+ text="Room not found",
85
+ values={"success": False, "error": "room_not_found"},
86
+ data={"actionName": "UNMUTE_ROOM"},
87
+ success=False,
88
+ )
89
+
90
+ room_name = str(room.name) if room.name else "Unknown Room"
91
+
92
+ world_id = room.world_id
93
+ if world_id:
94
+ world = await runtime.get_world(world_id)
95
+ if world and world.metadata:
96
+ muted_rooms = list(world.metadata.get("mutedRooms", []))
97
+ room_id_str = str(room_id)
98
+
99
+ if room_id_str in muted_rooms:
100
+ muted_rooms.remove(room_id_str)
101
+ world.metadata["mutedRooms"] = muted_rooms
102
+ await runtime.update_world(world)
103
+
104
+ await runtime.create_memory(
105
+ content=Content(
106
+ text=f"Unmuted room: {room_name}",
107
+ actions=["UNMUTE_ROOM"],
108
+ ),
109
+ room_id=room_id,
110
+ entity_id=runtime.agent_id,
111
+ memory_type="action",
112
+ metadata={"type": "UNMUTE_ROOM", "roomName": room_name},
113
+ )
114
+
115
+ response_content = Content(
116
+ text=f"I have unmuted {room_name}. I will now respond to messages there.",
117
+ actions=["UNMUTE_ROOM"],
118
+ )
119
+
120
+ if callback:
121
+ await callback(response_content)
122
+
123
+ return ActionResult(
124
+ text=f"Unmuted room: {room_name}",
125
+ values={
126
+ "success": True,
127
+ "unmuted": True,
128
+ "roomId": str(room_id),
129
+ "roomName": room_name,
130
+ },
131
+ data={
132
+ "actionName": "UNMUTE_ROOM",
133
+ "roomId": str(room_id),
134
+ "roomName": room_name,
135
+ },
136
+ success=True,
137
+ )
138
+
139
+ @property
140
+ def examples(self) -> list[list[ActionExample]]:
141
+ return _convert_spec_examples()
142
+
143
+
144
+ unmute_room_action = Action(
145
+ name=UnmuteRoomAction.name,
146
+ similes=UnmuteRoomAction().similes,
147
+ description=UnmuteRoomAction.description,
148
+ validate=UnmuteRoomAction().validate,
149
+ handler=UnmuteRoomAction().handler,
150
+ examples=UnmuteRoomAction().examples,
151
+ )