@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.
- package/LICENSE +26 -0
- package/README.md +239 -0
- package/elizaos/__init__.py +280 -0
- package/elizaos/action_docs.py +149 -0
- package/elizaos/advanced_capabilities/__init__.py +85 -0
- package/elizaos/advanced_capabilities/actions/__init__.py +54 -0
- package/elizaos/advanced_capabilities/actions/add_contact.py +139 -0
- package/elizaos/advanced_capabilities/actions/follow_room.py +151 -0
- package/elizaos/advanced_capabilities/actions/image_generation.py +148 -0
- package/elizaos/advanced_capabilities/actions/mute_room.py +164 -0
- package/elizaos/advanced_capabilities/actions/remove_contact.py +145 -0
- package/elizaos/advanced_capabilities/actions/roles.py +207 -0
- package/elizaos/advanced_capabilities/actions/schedule_follow_up.py +154 -0
- package/elizaos/advanced_capabilities/actions/search_contacts.py +145 -0
- package/elizaos/advanced_capabilities/actions/send_message.py +187 -0
- package/elizaos/advanced_capabilities/actions/settings.py +151 -0
- package/elizaos/advanced_capabilities/actions/unfollow_room.py +164 -0
- package/elizaos/advanced_capabilities/actions/unmute_room.py +164 -0
- package/elizaos/advanced_capabilities/actions/update_contact.py +164 -0
- package/elizaos/advanced_capabilities/actions/update_entity.py +161 -0
- package/elizaos/advanced_capabilities/evaluators/__init__.py +18 -0
- package/elizaos/advanced_capabilities/evaluators/reflection.py +134 -0
- package/elizaos/advanced_capabilities/evaluators/relationship_extraction.py +203 -0
- package/elizaos/advanced_capabilities/providers/__init__.py +36 -0
- package/elizaos/advanced_capabilities/providers/agent_settings.py +60 -0
- package/elizaos/advanced_capabilities/providers/contacts.py +77 -0
- package/elizaos/advanced_capabilities/providers/facts.py +82 -0
- package/elizaos/advanced_capabilities/providers/follow_ups.py +113 -0
- package/elizaos/advanced_capabilities/providers/knowledge.py +83 -0
- package/elizaos/advanced_capabilities/providers/relationships.py +112 -0
- package/elizaos/advanced_capabilities/providers/roles.py +97 -0
- package/elizaos/advanced_capabilities/providers/settings.py +51 -0
- package/elizaos/advanced_capabilities/services/__init__.py +18 -0
- package/elizaos/advanced_capabilities/services/follow_up.py +138 -0
- package/elizaos/advanced_capabilities/services/rolodex.py +244 -0
- package/elizaos/advanced_memory/__init__.py +3 -0
- package/elizaos/advanced_memory/evaluators.py +97 -0
- package/elizaos/advanced_memory/memory_service.py +556 -0
- package/elizaos/advanced_memory/plugin.py +30 -0
- package/elizaos/advanced_memory/prompts.py +12 -0
- package/elizaos/advanced_memory/providers.py +90 -0
- package/elizaos/advanced_memory/types.py +65 -0
- package/elizaos/advanced_planning/__init__.py +10 -0
- package/elizaos/advanced_planning/actions.py +145 -0
- package/elizaos/advanced_planning/message_classifier.py +127 -0
- package/elizaos/advanced_planning/planning_service.py +712 -0
- package/elizaos/advanced_planning/plugin.py +40 -0
- package/elizaos/advanced_planning/prompts.py +4 -0
- package/elizaos/basic_capabilities/__init__.py +66 -0
- package/elizaos/basic_capabilities/actions/__init__.py +24 -0
- package/elizaos/basic_capabilities/actions/choice.py +140 -0
- package/elizaos/basic_capabilities/actions/ignore.py +66 -0
- package/elizaos/basic_capabilities/actions/none.py +56 -0
- package/elizaos/basic_capabilities/actions/reply.py +120 -0
- package/elizaos/basic_capabilities/providers/__init__.py +54 -0
- package/elizaos/basic_capabilities/providers/action_state.py +113 -0
- package/elizaos/basic_capabilities/providers/actions.py +263 -0
- package/elizaos/basic_capabilities/providers/attachments.py +76 -0
- package/elizaos/basic_capabilities/providers/capabilities.py +62 -0
- package/elizaos/basic_capabilities/providers/character.py +113 -0
- package/elizaos/basic_capabilities/providers/choice.py +73 -0
- package/elizaos/basic_capabilities/providers/context_bench.py +44 -0
- package/elizaos/basic_capabilities/providers/current_time.py +58 -0
- package/elizaos/basic_capabilities/providers/entities.py +99 -0
- package/elizaos/basic_capabilities/providers/evaluators.py +54 -0
- package/elizaos/basic_capabilities/providers/providers_list.py +55 -0
- package/elizaos/basic_capabilities/providers/recent_messages.py +85 -0
- package/elizaos/basic_capabilities/providers/time.py +45 -0
- package/elizaos/basic_capabilities/providers/world.py +93 -0
- package/elizaos/basic_capabilities/services/__init__.py +18 -0
- package/elizaos/basic_capabilities/services/embedding.py +122 -0
- package/elizaos/basic_capabilities/services/task.py +178 -0
- package/elizaos/bootstrap/__init__.py +12 -0
- package/elizaos/bootstrap/actions/__init__.py +68 -0
- package/elizaos/bootstrap/actions/add_contact.py +149 -0
- package/elizaos/bootstrap/actions/choice.py +147 -0
- package/elizaos/bootstrap/actions/follow_room.py +151 -0
- package/elizaos/bootstrap/actions/ignore.py +80 -0
- package/elizaos/bootstrap/actions/image_generation.py +135 -0
- package/elizaos/bootstrap/actions/mute_room.py +151 -0
- package/elizaos/bootstrap/actions/none.py +71 -0
- package/elizaos/bootstrap/actions/remove_contact.py +159 -0
- package/elizaos/bootstrap/actions/reply.py +140 -0
- package/elizaos/bootstrap/actions/roles.py +193 -0
- package/elizaos/bootstrap/actions/schedule_follow_up.py +164 -0
- package/elizaos/bootstrap/actions/search_contacts.py +159 -0
- package/elizaos/bootstrap/actions/send_message.py +173 -0
- package/elizaos/bootstrap/actions/settings.py +165 -0
- package/elizaos/bootstrap/actions/unfollow_room.py +151 -0
- package/elizaos/bootstrap/actions/unmute_room.py +151 -0
- package/elizaos/bootstrap/actions/update_contact.py +178 -0
- package/elizaos/bootstrap/actions/update_entity.py +175 -0
- package/elizaos/bootstrap/autonomy/__init__.py +18 -0
- package/elizaos/bootstrap/autonomy/action.py +197 -0
- package/elizaos/bootstrap/autonomy/providers.py +165 -0
- package/elizaos/bootstrap/autonomy/routes.py +171 -0
- package/elizaos/bootstrap/autonomy/service.py +562 -0
- package/elizaos/bootstrap/autonomy/types.py +18 -0
- package/elizaos/bootstrap/evaluators/__init__.py +19 -0
- package/elizaos/bootstrap/evaluators/reflection.py +118 -0
- package/elizaos/bootstrap/evaluators/relationship_extraction.py +192 -0
- package/elizaos/bootstrap/plugin.py +140 -0
- package/elizaos/bootstrap/providers/__init__.py +80 -0
- package/elizaos/bootstrap/providers/action_state.py +71 -0
- package/elizaos/bootstrap/providers/actions.py +256 -0
- package/elizaos/bootstrap/providers/agent_settings.py +63 -0
- package/elizaos/bootstrap/providers/attachments.py +76 -0
- package/elizaos/bootstrap/providers/capabilities.py +66 -0
- package/elizaos/bootstrap/providers/character.py +128 -0
- package/elizaos/bootstrap/providers/choice.py +77 -0
- package/elizaos/bootstrap/providers/contacts.py +78 -0
- package/elizaos/bootstrap/providers/context_bench.py +49 -0
- package/elizaos/bootstrap/providers/current_time.py +56 -0
- package/elizaos/bootstrap/providers/entities.py +99 -0
- package/elizaos/bootstrap/providers/evaluators.py +58 -0
- package/elizaos/bootstrap/providers/facts.py +86 -0
- package/elizaos/bootstrap/providers/follow_ups.py +116 -0
- package/elizaos/bootstrap/providers/knowledge.py +73 -0
- package/elizaos/bootstrap/providers/providers_list.py +59 -0
- package/elizaos/bootstrap/providers/recent_messages.py +85 -0
- package/elizaos/bootstrap/providers/relationships.py +106 -0
- package/elizaos/bootstrap/providers/roles.py +95 -0
- package/elizaos/bootstrap/providers/settings.py +55 -0
- package/elizaos/bootstrap/providers/time.py +45 -0
- package/elizaos/bootstrap/providers/world.py +97 -0
- package/elizaos/bootstrap/services/__init__.py +26 -0
- package/elizaos/bootstrap/services/embedding.py +122 -0
- package/elizaos/bootstrap/services/follow_up.py +138 -0
- package/elizaos/bootstrap/services/rolodex.py +244 -0
- package/elizaos/bootstrap/services/task.py +585 -0
- package/elizaos/bootstrap/types.py +54 -0
- package/elizaos/bootstrap/utils/__init__.py +7 -0
- package/elizaos/bootstrap/utils/xml.py +69 -0
- package/elizaos/character.py +149 -0
- package/elizaos/logger.py +179 -0
- package/elizaos/media/__init__.py +45 -0
- package/elizaos/media/mime.py +315 -0
- package/elizaos/media/search.py +161 -0
- package/elizaos/media/tests/__init__.py +1 -0
- package/elizaos/media/tests/test_mime.py +117 -0
- package/elizaos/media/tests/test_search.py +156 -0
- package/elizaos/plugin.py +191 -0
- package/elizaos/prompts.py +1071 -0
- package/elizaos/py.typed +0 -0
- package/elizaos/runtime.py +2572 -0
- package/elizaos/services/__init__.py +49 -0
- package/elizaos/services/hook_service.py +511 -0
- package/elizaos/services/message_service.py +1248 -0
- package/elizaos/settings.py +182 -0
- package/elizaos/streaming_context.py +159 -0
- package/elizaos/trajectory_context.py +18 -0
- package/elizaos/types/__init__.py +512 -0
- package/elizaos/types/agent.py +31 -0
- package/elizaos/types/components.py +208 -0
- package/elizaos/types/database.py +64 -0
- package/elizaos/types/environment.py +46 -0
- package/elizaos/types/events.py +47 -0
- package/elizaos/types/memory.py +45 -0
- package/elizaos/types/model.py +393 -0
- package/elizaos/types/plugin.py +188 -0
- package/elizaos/types/primitives.py +100 -0
- package/elizaos/types/runtime.py +460 -0
- package/elizaos/types/service.py +113 -0
- package/elizaos/types/service_interfaces.py +244 -0
- package/elizaos/types/state.py +188 -0
- package/elizaos/types/task.py +29 -0
- package/elizaos/utils/__init__.py +108 -0
- package/elizaos/utils/spec_examples.py +48 -0
- package/elizaos/utils/streaming.py +426 -0
- package/elizaos_atropos_shared/__init__.py +1 -0
- package/elizaos_atropos_shared/canonical_eliza.py +282 -0
- package/package.json +19 -0
- package/pyproject.toml +143 -0
- package/requirements-dev.in +11 -0
- package/requirements-dev.lock +134 -0
- package/requirements.in +9 -0
- package/requirements.lock +64 -0
- package/tests/__init__.py +0 -0
- package/tests/test_action_parameters.py +154 -0
- package/tests/test_actions_provider_examples.py +39 -0
- package/tests/test_advanced_memory_behavior.py +96 -0
- package/tests/test_advanced_memory_flag.py +30 -0
- package/tests/test_advanced_planning_behavior.py +225 -0
- package/tests/test_advanced_planning_flag.py +26 -0
- package/tests/test_autonomy.py +445 -0
- package/tests/test_bootstrap_initialize.py +37 -0
- package/tests/test_character.py +163 -0
- package/tests/test_character_provider.py +231 -0
- package/tests/test_dynamic_prompt_exec.py +561 -0
- package/tests/test_logger_redaction.py +43 -0
- package/tests/test_plugin.py +117 -0
- package/tests/test_runtime.py +422 -0
- package/tests/test_salt_production_enforcement.py +22 -0
- package/tests/test_settings_crypto.py +118 -0
- package/tests/test_streaming.py +295 -0
- package/tests/test_types.py +221 -0
- 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
|