@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,231 @@
1
+ """Tests for the CHARACTER provider's ``{{name}}`` placeholder resolution.
2
+
3
+ The character provider replaces ``{{name}}`` in bio, system, topics,
4
+ adjectives, and style entries with the character's actual name so
5
+ character template files stay name-agnostic.
6
+
7
+ Note: We import the provider module carefully to avoid the circular import
8
+ between ``elizaos.basic_capabilities`` and ``elizaos.bootstrap``.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import importlib
14
+ import sys
15
+ from types import SimpleNamespace
16
+ from unittest.mock import AsyncMock, MagicMock
17
+
18
+ import pytest
19
+
20
+ # ---------------------------------------------------------------------------
21
+ # Import helpers — break the circular import chain by pre-populating
22
+ # the problematic module paths with stubs before importing the provider.
23
+ # ---------------------------------------------------------------------------
24
+
25
+
26
+ def _import_character_provider():
27
+ """Import the character provider module, bypassing circular import issues."""
28
+ # Stub the generated spec helper so the module-level call succeeds
29
+ _spec_mod = MagicMock()
30
+ _spec_mod.require_provider_spec.return_value = {
31
+ "name": "CHARACTER",
32
+ "description": "Character provider",
33
+ "dynamic": False,
34
+ }
35
+ saved = {}
36
+ stubs = {
37
+ "elizaos.generated.spec_helpers": _spec_mod,
38
+ }
39
+ for mod_name, stub in stubs.items():
40
+ saved[mod_name] = sys.modules.get(mod_name)
41
+ sys.modules[mod_name] = stub
42
+
43
+ try:
44
+ # Force a fresh import of just the character provider module
45
+ mod = importlib.import_module("elizaos.basic_capabilities.providers.character")
46
+ return mod
47
+ finally:
48
+ # Restore original module state
49
+ for mod_name, original in saved.items():
50
+ if original is None:
51
+ sys.modules.pop(mod_name, None)
52
+ else:
53
+ sys.modules[mod_name] = original
54
+
55
+
56
+ # Try direct import first; fall back to stub-based import
57
+ try:
58
+ from elizaos.basic_capabilities.providers.character import (
59
+ _resolve_name,
60
+ _resolve_name_list,
61
+ get_character_context,
62
+ )
63
+ except ImportError:
64
+ _mod = _import_character_provider()
65
+ _resolve_name = _mod._resolve_name
66
+ _resolve_name_list = _mod._resolve_name_list
67
+ get_character_context = _mod.get_character_context
68
+
69
+
70
+ # ---------------------------------------------------------------------------
71
+ # Unit tests for the helper functions
72
+ # ---------------------------------------------------------------------------
73
+
74
+
75
+ class TestResolveName:
76
+ def test_replaces_single_placeholder(self) -> None:
77
+ assert _resolve_name("Hello {{name}}!", "Sakuya") == "Hello Sakuya!"
78
+
79
+ def test_replaces_multiple_placeholders(self) -> None:
80
+ result = _resolve_name("{{name}} is {{name}}", "Reimu")
81
+ assert result == "Reimu is Reimu"
82
+
83
+ def test_no_placeholder_returns_unchanged(self) -> None:
84
+ assert _resolve_name("No placeholders here.", "Marisa") == "No placeholders here."
85
+
86
+ def test_empty_string(self) -> None:
87
+ assert _resolve_name("", "Sakuya") == ""
88
+
89
+ def test_placeholder_only(self) -> None:
90
+ assert _resolve_name("{{name}}", "Patchouli") == "Patchouli"
91
+
92
+
93
+ class TestResolveNameList:
94
+ def test_resolves_all_items(self) -> None:
95
+ items = ["{{name}} is great.", "I am {{name}}."]
96
+ result = _resolve_name_list(items, "Sakuya")
97
+ assert result == ["Sakuya is great.", "I am Sakuya."]
98
+
99
+ def test_empty_list(self) -> None:
100
+ assert _resolve_name_list([], "Sakuya") == []
101
+
102
+ def test_mixed_items(self) -> None:
103
+ items = ["{{name}} rocks", "no placeholder"]
104
+ result = _resolve_name_list(items, "Remilia")
105
+ assert result == ["Remilia rocks", "no placeholder"]
106
+
107
+
108
+ # ---------------------------------------------------------------------------
109
+ # Integration tests for the full provider
110
+ # ---------------------------------------------------------------------------
111
+
112
+
113
+ def _make_character(
114
+ name: str = "Sakuya",
115
+ bio: list[str] | str | None = None,
116
+ adjectives: list[str] | None = None,
117
+ topics: list[str] | None = None,
118
+ style: SimpleNamespace | None = None,
119
+ ) -> SimpleNamespace:
120
+ """Build a minimal character-like namespace for testing."""
121
+ return SimpleNamespace(
122
+ name=name,
123
+ bio=bio or [],
124
+ adjectives=adjectives or [],
125
+ topics=topics or [],
126
+ style=style,
127
+ )
128
+
129
+
130
+ def _make_runtime(character: SimpleNamespace) -> SimpleNamespace:
131
+ """Build a minimal runtime-like namespace for testing."""
132
+ return SimpleNamespace(character=character)
133
+
134
+
135
+ def _make_style(
136
+ all_: list[str] | None = None,
137
+ chat: list[str] | None = None,
138
+ post: list[str] | None = None,
139
+ ) -> SimpleNamespace:
140
+ return SimpleNamespace(
141
+ all=all_ or [],
142
+ chat=chat or [],
143
+ post=post or [],
144
+ )
145
+
146
+
147
+ @pytest.mark.asyncio
148
+ class TestCharacterProviderNameResolution:
149
+ async def test_resolves_name_in_bio_list(self) -> None:
150
+ character = _make_character(
151
+ bio=["{{name}} is a time-stopping maid.", "{{name}} works at the mansion."],
152
+ )
153
+ result = await get_character_context(_make_runtime(character), AsyncMock(), None)
154
+ assert "Sakuya is a time-stopping maid." in result.text
155
+ assert "Sakuya works at the mansion." in result.text
156
+ assert "{{name}}" not in result.text
157
+
158
+ async def test_resolves_name_in_bio_string(self) -> None:
159
+ character = _make_character(bio="{{name}} is an elegant maid.")
160
+ result = await get_character_context(_make_runtime(character), AsyncMock(), None)
161
+ assert "Sakuya is an elegant maid." in result.text
162
+ assert "{{name}}" not in result.text
163
+
164
+ async def test_resolves_name_in_adjectives(self) -> None:
165
+ character = _make_character(
166
+ adjectives=["{{name}}-like elegance", "precise"],
167
+ )
168
+ result = await get_character_context(_make_runtime(character), AsyncMock(), None)
169
+ assert "Sakuya-like elegance" in result.text
170
+ assert "{{name}}" not in result.text
171
+
172
+ async def test_resolves_name_in_topics(self) -> None:
173
+ character = _make_character(
174
+ topics=["{{name}}'s knives", "time manipulation"],
175
+ )
176
+ result = await get_character_context(_make_runtime(character), AsyncMock(), None)
177
+ assert "Sakuya's knives" in result.text
178
+ assert "{{name}}" not in result.text
179
+
180
+ async def test_resolves_name_in_style_all(self) -> None:
181
+ character = _make_character(
182
+ style=_make_style(all_=["Speak as {{name}} would."]),
183
+ )
184
+ result = await get_character_context(_make_runtime(character), AsyncMock(), None)
185
+ assert "Speak as Sakuya would." in result.text
186
+ assert "{{name}}" not in result.text
187
+
188
+ async def test_resolves_name_in_style_chat(self) -> None:
189
+ character = _make_character(
190
+ style=_make_style(chat=["In chat, {{name}} is direct."]),
191
+ )
192
+ result = await get_character_context(_make_runtime(character), AsyncMock(), None)
193
+ assert "In chat, Sakuya is direct." in result.text
194
+ assert "{{name}}" not in result.text
195
+
196
+ async def test_resolves_name_in_style_post(self) -> None:
197
+ character = _make_character(
198
+ style=_make_style(post=["When posting, {{name}} is brief."]),
199
+ )
200
+ result = await get_character_context(_make_runtime(character), AsyncMock(), None)
201
+ assert "When posting, Sakuya is brief." in result.text
202
+ assert "{{name}}" not in result.text
203
+
204
+ async def test_no_placeholder_passes_through(self) -> None:
205
+ character = _make_character(
206
+ bio=["A helpful assistant."],
207
+ adjectives=["calm"],
208
+ )
209
+ result = await get_character_context(_make_runtime(character), AsyncMock(), None)
210
+ assert "A helpful assistant." in result.text
211
+ assert "calm" in result.text
212
+
213
+ async def test_empty_fields_no_crash(self) -> None:
214
+ character = _make_character()
215
+ result = await get_character_context(_make_runtime(character), AsyncMock(), None)
216
+ assert "# Agent: Sakuya" in result.text
217
+
218
+ async def test_lore_resolves_name(self) -> None:
219
+ character = _make_character()
220
+ character.lore = "{{name}} has a mysterious past."
221
+ result = await get_character_context(_make_runtime(character), AsyncMock(), None)
222
+ assert "Sakuya has a mysterious past." in result.text
223
+ assert "{{name}}" not in result.text
224
+
225
+ async def test_lore_list_resolves_name(self) -> None:
226
+ character = _make_character()
227
+ character.lore = ["{{name}} arrived at the mansion.", "{{name}} never aged."]
228
+ result = await get_character_context(_make_runtime(character), AsyncMock(), None)
229
+ assert "Sakuya arrived at the mansion." in result.text
230
+ assert "Sakuya never aged." in result.text
231
+ assert "{{name}}" not in result.text