@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,99 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.generated.spec_helpers import require_provider_spec
|
|
6
|
+
from elizaos.types import Provider, ProviderResult
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
10
|
+
|
|
11
|
+
# Get text content from centralized specs
|
|
12
|
+
_spec = require_provider_spec("ENTITIES")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def get_entities_context(
|
|
16
|
+
runtime: IAgentRuntime,
|
|
17
|
+
message: Memory,
|
|
18
|
+
state: State | None = None,
|
|
19
|
+
) -> ProviderResult:
|
|
20
|
+
room_id = message.room_id
|
|
21
|
+
sender_id = message.entity_id
|
|
22
|
+
|
|
23
|
+
sections: list[str] = []
|
|
24
|
+
entity_list: list[dict[str, str]] = []
|
|
25
|
+
|
|
26
|
+
if sender_id:
|
|
27
|
+
sender = await runtime.get_entity(sender_id)
|
|
28
|
+
if sender:
|
|
29
|
+
sender_info = {
|
|
30
|
+
"id": str(sender.id),
|
|
31
|
+
"name": sender.name or "Unknown",
|
|
32
|
+
"type": sender.entity_type or "user",
|
|
33
|
+
"role": "sender",
|
|
34
|
+
}
|
|
35
|
+
entity_list.append(sender_info)
|
|
36
|
+
sections.append(
|
|
37
|
+
f"- **{sender.name or 'Unknown'}** (sender): {sender.entity_type or 'user'}"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if room_id:
|
|
41
|
+
room = await runtime.get_room(room_id)
|
|
42
|
+
if room and room.world_id:
|
|
43
|
+
world = await runtime.get_world(room.world_id)
|
|
44
|
+
if world and world.metadata:
|
|
45
|
+
member_ids = world.metadata.get("members", [])
|
|
46
|
+
roles = world.metadata.get("roles", {})
|
|
47
|
+
|
|
48
|
+
for member_id in member_ids:
|
|
49
|
+
if str(member_id) == str(sender_id):
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
entity = await runtime.get_entity(member_id)
|
|
53
|
+
if entity:
|
|
54
|
+
role = roles.get(str(member_id), "member")
|
|
55
|
+
entity_info = {
|
|
56
|
+
"id": str(entity.id),
|
|
57
|
+
"name": entity.name or "Unknown",
|
|
58
|
+
"type": entity.entity_type or "user",
|
|
59
|
+
"role": role,
|
|
60
|
+
}
|
|
61
|
+
entity_list.append(entity_info)
|
|
62
|
+
sections.append(
|
|
63
|
+
f"- **{entity.name or 'Unknown'}** ({role}): {entity.entity_type or 'user'}"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
agent_entity = await runtime.get_entity(runtime.agent_id)
|
|
67
|
+
if agent_entity:
|
|
68
|
+
agent_info = {
|
|
69
|
+
"id": str(agent_entity.id),
|
|
70
|
+
"name": agent_entity.name or runtime.character.name,
|
|
71
|
+
"type": "agent",
|
|
72
|
+
"role": "self",
|
|
73
|
+
}
|
|
74
|
+
entity_list.append(agent_info)
|
|
75
|
+
sections.append(f"- **{agent_entity.name or runtime.character.name}** (self): agent")
|
|
76
|
+
|
|
77
|
+
context_text = "# Entities in Context\n" + "\n".join(sections) if sections else ""
|
|
78
|
+
|
|
79
|
+
return ProviderResult(
|
|
80
|
+
text=context_text,
|
|
81
|
+
values={
|
|
82
|
+
"entityCount": len(entity_list),
|
|
83
|
+
"hasSender": sender_id is not None,
|
|
84
|
+
"agentId": str(runtime.agent_id),
|
|
85
|
+
},
|
|
86
|
+
data={
|
|
87
|
+
"entities": entity_list,
|
|
88
|
+
"senderId": str(sender_id) if sender_id else None,
|
|
89
|
+
"agentId": str(runtime.agent_id),
|
|
90
|
+
},
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
entities_provider = Provider(
|
|
95
|
+
name=_spec["name"],
|
|
96
|
+
description=_spec["description"],
|
|
97
|
+
get=get_entities_context,
|
|
98
|
+
dynamic=_spec.get("dynamic", True),
|
|
99
|
+
)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.types import Provider, ProviderResult
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def get_evaluators(
|
|
12
|
+
runtime: IAgentRuntime,
|
|
13
|
+
message: Memory,
|
|
14
|
+
state: State | None = None,
|
|
15
|
+
) -> ProviderResult:
|
|
16
|
+
evaluator_info: list[dict[str, str]] = []
|
|
17
|
+
|
|
18
|
+
for evaluator in runtime.evaluators:
|
|
19
|
+
evaluator_info.append(
|
|
20
|
+
{
|
|
21
|
+
"name": evaluator.name,
|
|
22
|
+
"description": getattr(evaluator, "description", "No description"),
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
if not evaluator_info:
|
|
27
|
+
return ProviderResult(
|
|
28
|
+
text="No evaluators available.",
|
|
29
|
+
values={"evaluatorCount": 0},
|
|
30
|
+
data={"evaluators": []},
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
formatted_evaluators = "\n".join(f"- {e['name']}: {e['description']}" for e in evaluator_info)
|
|
34
|
+
|
|
35
|
+
text = f"# Available Evaluators\n{formatted_evaluators}"
|
|
36
|
+
|
|
37
|
+
return ProviderResult(
|
|
38
|
+
text=text,
|
|
39
|
+
values={
|
|
40
|
+
"evaluatorCount": len(evaluator_info),
|
|
41
|
+
"evaluatorNames": [e["name"] for e in evaluator_info],
|
|
42
|
+
},
|
|
43
|
+
data={
|
|
44
|
+
"evaluators": evaluator_info,
|
|
45
|
+
},
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
evaluators_provider = Provider(
|
|
50
|
+
name="EVALUATORS",
|
|
51
|
+
description="Available evaluators for assessing agent behavior",
|
|
52
|
+
get=get_evaluators,
|
|
53
|
+
dynamic=False,
|
|
54
|
+
)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.types import Provider, ProviderResult
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def get_providers_list(
|
|
12
|
+
runtime: IAgentRuntime,
|
|
13
|
+
message: Memory,
|
|
14
|
+
state: State | None = None,
|
|
15
|
+
) -> ProviderResult:
|
|
16
|
+
provider_info: list[dict[str, str | bool]] = []
|
|
17
|
+
|
|
18
|
+
for provider in runtime.providers:
|
|
19
|
+
provider_info.append(
|
|
20
|
+
{
|
|
21
|
+
"name": provider.name,
|
|
22
|
+
"description": getattr(provider, "description", "No description"),
|
|
23
|
+
"dynamic": getattr(provider, "dynamic", True),
|
|
24
|
+
}
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if not provider_info:
|
|
28
|
+
return ProviderResult(
|
|
29
|
+
text="No providers available.",
|
|
30
|
+
values={"providerCount": 0},
|
|
31
|
+
data={"providers": []},
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
formatted_providers = "\n".join(f"- {p['name']}: {p['description']}" for p in provider_info)
|
|
35
|
+
|
|
36
|
+
text = f"# Available Providers\n{formatted_providers}"
|
|
37
|
+
|
|
38
|
+
return ProviderResult(
|
|
39
|
+
text=text,
|
|
40
|
+
values={
|
|
41
|
+
"providerCount": len(provider_info),
|
|
42
|
+
"providerNames": [p["name"] for p in provider_info],
|
|
43
|
+
},
|
|
44
|
+
data={
|
|
45
|
+
"providers": provider_info,
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
providers_list_provider = Provider(
|
|
51
|
+
name="PROVIDERS",
|
|
52
|
+
description="Available context providers",
|
|
53
|
+
get=get_providers_list,
|
|
54
|
+
dynamic=False,
|
|
55
|
+
)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.generated.spec_helpers import require_provider_spec
|
|
6
|
+
from elizaos.types import Provider, ProviderResult
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
10
|
+
|
|
11
|
+
# Get text content from centralized specs
|
|
12
|
+
_spec = require_provider_spec("RECENT_MESSAGES")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def get_recent_messages_context(
|
|
16
|
+
runtime: IAgentRuntime,
|
|
17
|
+
message: Memory,
|
|
18
|
+
state: State | None = None,
|
|
19
|
+
) -> ProviderResult:
|
|
20
|
+
room_id = message.room_id
|
|
21
|
+
if not room_id:
|
|
22
|
+
return ProviderResult(
|
|
23
|
+
text="", values={"messageCount": 0, "hasHistory": False}, data={"messages": []}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
sections: list[str] = []
|
|
27
|
+
message_list: list[dict[str, str | int]] = []
|
|
28
|
+
|
|
29
|
+
recent_messages = await runtime.get_memories(
|
|
30
|
+
room_id=room_id,
|
|
31
|
+
limit=20,
|
|
32
|
+
order_by="created_at",
|
|
33
|
+
order_direction="desc",
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
recent_messages = list(reversed(recent_messages))
|
|
37
|
+
|
|
38
|
+
for msg in recent_messages:
|
|
39
|
+
if not msg.content or not msg.content.text:
|
|
40
|
+
continue
|
|
41
|
+
|
|
42
|
+
sender_name = "Unknown"
|
|
43
|
+
if msg.entity_id:
|
|
44
|
+
entity = await runtime.get_entity(msg.entity_id)
|
|
45
|
+
if entity and entity.name:
|
|
46
|
+
sender_name = entity.name
|
|
47
|
+
elif str(msg.entity_id) == str(runtime.agent_id):
|
|
48
|
+
sender_name = runtime.character.name
|
|
49
|
+
|
|
50
|
+
message_text = msg.content.text
|
|
51
|
+
if len(message_text) > 300:
|
|
52
|
+
message_text = message_text[:300] + "..."
|
|
53
|
+
|
|
54
|
+
msg_dict = {
|
|
55
|
+
"id": str(msg.id) if msg.id else "",
|
|
56
|
+
"sender": sender_name,
|
|
57
|
+
"text": message_text,
|
|
58
|
+
"timestamp": msg.created_at or 0,
|
|
59
|
+
}
|
|
60
|
+
message_list.append(msg_dict)
|
|
61
|
+
sections.append(f"**{sender_name}**: {message_text}")
|
|
62
|
+
|
|
63
|
+
context_text = "# Recent Messages\n" + "\n".join(sections) if sections else ""
|
|
64
|
+
|
|
65
|
+
return ProviderResult(
|
|
66
|
+
text=context_text,
|
|
67
|
+
values={
|
|
68
|
+
"messageCount": len(message_list),
|
|
69
|
+
"hasHistory": len(message_list) > 0,
|
|
70
|
+
"roomId": str(room_id),
|
|
71
|
+
},
|
|
72
|
+
data={
|
|
73
|
+
"messages": message_list,
|
|
74
|
+
"roomId": str(room_id),
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
recent_messages_provider = Provider(
|
|
80
|
+
name=_spec["name"],
|
|
81
|
+
description=_spec["description"],
|
|
82
|
+
get=get_recent_messages_context,
|
|
83
|
+
position=_spec.get("position"),
|
|
84
|
+
dynamic=_spec.get("dynamic", True),
|
|
85
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import UTC, datetime
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from elizaos.generated.spec_helpers import require_provider_spec
|
|
7
|
+
from elizaos.types import Provider, ProviderResult
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
11
|
+
|
|
12
|
+
# Get text content from centralized specs
|
|
13
|
+
_spec = require_provider_spec("TIME")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def get_time_context(
|
|
17
|
+
runtime: IAgentRuntime,
|
|
18
|
+
message: Memory,
|
|
19
|
+
state: State | None = None,
|
|
20
|
+
) -> ProviderResult:
|
|
21
|
+
_ = runtime, message, state
|
|
22
|
+
|
|
23
|
+
now = datetime.now(UTC)
|
|
24
|
+
iso_string = now.isoformat()
|
|
25
|
+
timestamp_ms = int(now.timestamp() * 1000)
|
|
26
|
+
human_readable = now.strftime("%A, %B %d, %Y at %H:%M:%S UTC")
|
|
27
|
+
|
|
28
|
+
text = (
|
|
29
|
+
f"The current date and time is {human_readable}. "
|
|
30
|
+
"Please use this as your reference for any time-based operations or responses."
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
return ProviderResult(
|
|
34
|
+
text=text,
|
|
35
|
+
values={"time": human_readable},
|
|
36
|
+
data={"timestamp": timestamp_ms, "isoString": iso_string},
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
time_provider = Provider(
|
|
41
|
+
name=_spec["name"],
|
|
42
|
+
description=_spec["description"],
|
|
43
|
+
get=get_time_context,
|
|
44
|
+
dynamic=_spec.get("dynamic", True),
|
|
45
|
+
)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.types import Provider, ProviderResult
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def get_world_context(
|
|
12
|
+
runtime: IAgentRuntime,
|
|
13
|
+
message: Memory,
|
|
14
|
+
state: State | None = None,
|
|
15
|
+
) -> ProviderResult:
|
|
16
|
+
room_id = message.room_id
|
|
17
|
+
if not room_id:
|
|
18
|
+
return ProviderResult(text="", values={"hasWorld": False}, data={})
|
|
19
|
+
|
|
20
|
+
room = await runtime.get_room(room_id)
|
|
21
|
+
if not room or not room.world_id:
|
|
22
|
+
return ProviderResult(
|
|
23
|
+
text="",
|
|
24
|
+
values={"hasWorld": False, "roomId": str(room_id)},
|
|
25
|
+
data={"roomId": str(room_id)},
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
world = await runtime.get_world(room.world_id)
|
|
29
|
+
if not world:
|
|
30
|
+
return ProviderResult(
|
|
31
|
+
text="",
|
|
32
|
+
values={"hasWorld": False, "roomId": str(room_id)},
|
|
33
|
+
data={"roomId": str(room_id)},
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
sections: list[str] = []
|
|
37
|
+
|
|
38
|
+
sections.append(f"# World: {world.name or 'Unknown'}")
|
|
39
|
+
if world.metadata and world.metadata.get("description"):
|
|
40
|
+
sections.append(f"\n{world.metadata['description']}")
|
|
41
|
+
|
|
42
|
+
sections.append(f"\n## Current Room: {room.name or 'Unknown'}")
|
|
43
|
+
if room.metadata and room.metadata.get("topic"):
|
|
44
|
+
sections.append(f"Topic: {room.metadata['topic']}")
|
|
45
|
+
|
|
46
|
+
member_count = 0
|
|
47
|
+
if world.metadata and world.metadata.get("members"):
|
|
48
|
+
member_count = len(world.metadata["members"])
|
|
49
|
+
sections.append(f"\n## Members: {member_count}")
|
|
50
|
+
|
|
51
|
+
if world.metadata and world.metadata.get("settings"):
|
|
52
|
+
safe_settings = {
|
|
53
|
+
k: v
|
|
54
|
+
for k, v in world.metadata["settings"].items()
|
|
55
|
+
if not k.lower().endswith(("key", "secret", "password", "token"))
|
|
56
|
+
}
|
|
57
|
+
if safe_settings:
|
|
58
|
+
settings_list = [f"- {k}: {v}" for k, v in safe_settings.items()]
|
|
59
|
+
sections.append("\n## Settings\n" + "\n".join(settings_list))
|
|
60
|
+
|
|
61
|
+
context_text = "\n".join(sections)
|
|
62
|
+
|
|
63
|
+
return ProviderResult(
|
|
64
|
+
text=context_text,
|
|
65
|
+
values={
|
|
66
|
+
"hasWorld": True,
|
|
67
|
+
"worldId": str(world.id),
|
|
68
|
+
"worldName": world.name or "Unknown",
|
|
69
|
+
"roomId": str(room_id),
|
|
70
|
+
"roomName": room.name or "Unknown",
|
|
71
|
+
"memberCount": member_count,
|
|
72
|
+
},
|
|
73
|
+
data={
|
|
74
|
+
"world": {
|
|
75
|
+
"id": str(world.id),
|
|
76
|
+
"name": world.name,
|
|
77
|
+
"metadata": world.metadata,
|
|
78
|
+
},
|
|
79
|
+
"room": {
|
|
80
|
+
"id": str(room_id),
|
|
81
|
+
"name": room.name,
|
|
82
|
+
"metadata": room.metadata,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
world_provider = Provider(
|
|
89
|
+
name="WORLD",
|
|
90
|
+
description="Provides information about the current world context including settings and members",
|
|
91
|
+
get=get_world_context,
|
|
92
|
+
dynamic=True,
|
|
93
|
+
)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Basic Services - Essential services for agent operation.
|
|
2
|
+
|
|
3
|
+
Core services included by default in the bootstrap plugin.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .embedding import EmbeddingService
|
|
7
|
+
from .task import TaskService
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"EmbeddingService",
|
|
11
|
+
"TaskService",
|
|
12
|
+
"basic_services",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
basic_services: list[type] = [
|
|
16
|
+
TaskService,
|
|
17
|
+
EmbeddingService,
|
|
18
|
+
]
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.types import ModelType, Service, ServiceType
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from elizaos.types import IAgentRuntime
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class EmbeddingService(Service):
|
|
12
|
+
name = "embedding"
|
|
13
|
+
service_type = ServiceType.UNKNOWN
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def capability_description(self) -> str:
|
|
17
|
+
return "Text embedding service for generating and caching text embeddings."
|
|
18
|
+
|
|
19
|
+
def __init__(self) -> None:
|
|
20
|
+
self._runtime: IAgentRuntime | None = None
|
|
21
|
+
self._cache: dict[str, list[float]] = {}
|
|
22
|
+
self._cache_enabled: bool = True
|
|
23
|
+
self._max_cache_size: int = 1000
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
async def start(cls, runtime: IAgentRuntime) -> EmbeddingService:
|
|
27
|
+
service = cls()
|
|
28
|
+
service._runtime = runtime
|
|
29
|
+
runtime.logger.info(
|
|
30
|
+
"Embedding service started",
|
|
31
|
+
src="service:embedding",
|
|
32
|
+
agentId=str(runtime.agent_id),
|
|
33
|
+
)
|
|
34
|
+
return service
|
|
35
|
+
|
|
36
|
+
async def stop(self) -> None:
|
|
37
|
+
if self._runtime:
|
|
38
|
+
self._runtime.logger.info(
|
|
39
|
+
"Embedding service stopped",
|
|
40
|
+
src="service:embedding",
|
|
41
|
+
agentId=str(self._runtime.agent_id),
|
|
42
|
+
)
|
|
43
|
+
self._cache.clear()
|
|
44
|
+
self._runtime = None
|
|
45
|
+
|
|
46
|
+
# Max characters for embedding input (~8K tokens at ~4 chars/token)
|
|
47
|
+
MAX_EMBEDDING_CHARS = 32_000
|
|
48
|
+
|
|
49
|
+
async def embed(self, text: str) -> list[float]:
|
|
50
|
+
if self._runtime is None:
|
|
51
|
+
raise ValueError("Embedding service not started - no runtime available")
|
|
52
|
+
|
|
53
|
+
if self._cache_enabled and text in self._cache:
|
|
54
|
+
return self._cache[text]
|
|
55
|
+
|
|
56
|
+
# Truncate to stay within embedding model token limits
|
|
57
|
+
embed_text = text
|
|
58
|
+
if len(embed_text) > self.MAX_EMBEDDING_CHARS:
|
|
59
|
+
self._runtime.logger.warning(
|
|
60
|
+
"Truncating embedding input from %d to %d chars",
|
|
61
|
+
len(embed_text),
|
|
62
|
+
self.MAX_EMBEDDING_CHARS,
|
|
63
|
+
src="service:embedding",
|
|
64
|
+
)
|
|
65
|
+
embed_text = embed_text[: self.MAX_EMBEDDING_CHARS]
|
|
66
|
+
|
|
67
|
+
embedding = await self._runtime.use_model(
|
|
68
|
+
ModelType.TEXT_EMBEDDING,
|
|
69
|
+
text=embed_text,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if not isinstance(embedding, list):
|
|
73
|
+
raise ValueError(f"Expected list for embedding, got {type(embedding)}")
|
|
74
|
+
|
|
75
|
+
embedding = [float(x) for x in embedding]
|
|
76
|
+
|
|
77
|
+
if self._cache_enabled:
|
|
78
|
+
self._add_to_cache(text, embedding)
|
|
79
|
+
|
|
80
|
+
return embedding
|
|
81
|
+
|
|
82
|
+
async def embed_batch(self, texts: list[str]) -> list[list[float]]:
|
|
83
|
+
embeddings: list[list[float]] = []
|
|
84
|
+
for text in texts:
|
|
85
|
+
embedding = await self.embed(text)
|
|
86
|
+
embeddings.append(embedding)
|
|
87
|
+
return embeddings
|
|
88
|
+
|
|
89
|
+
def _add_to_cache(self, text: str, embedding: list[float]) -> None:
|
|
90
|
+
if len(self._cache) >= self._max_cache_size:
|
|
91
|
+
oldest_key = next(iter(self._cache))
|
|
92
|
+
del self._cache[oldest_key]
|
|
93
|
+
self._cache[text] = embedding
|
|
94
|
+
|
|
95
|
+
def clear_cache(self) -> None:
|
|
96
|
+
self._cache.clear()
|
|
97
|
+
|
|
98
|
+
def set_cache_enabled(self, enabled: bool) -> None:
|
|
99
|
+
self._cache_enabled = enabled
|
|
100
|
+
if not enabled:
|
|
101
|
+
self._cache.clear()
|
|
102
|
+
|
|
103
|
+
def set_max_cache_size(self, size: int) -> None:
|
|
104
|
+
if size <= 0:
|
|
105
|
+
raise ValueError("Cache size must be positive")
|
|
106
|
+
self._max_cache_size = size
|
|
107
|
+
while len(self._cache) > self._max_cache_size:
|
|
108
|
+
oldest_key = next(iter(self._cache))
|
|
109
|
+
del self._cache[oldest_key]
|
|
110
|
+
|
|
111
|
+
async def similarity(self, text1: str, text2: str) -> float:
|
|
112
|
+
embedding1 = await self.embed(text1)
|
|
113
|
+
embedding2 = await self.embed(text2)
|
|
114
|
+
|
|
115
|
+
dot_product = sum(a * b for a, b in zip(embedding1, embedding2, strict=True))
|
|
116
|
+
magnitude1 = sum(a * a for a in embedding1) ** 0.5
|
|
117
|
+
magnitude2 = sum(b * b for b in embedding2) ** 0.5
|
|
118
|
+
|
|
119
|
+
if magnitude1 == 0 or magnitude2 == 0:
|
|
120
|
+
return 0.0
|
|
121
|
+
|
|
122
|
+
return dot_product / (magnitude1 * magnitude2)
|