@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,80 @@
|
|
|
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("IGNORE")
|
|
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 IgnoreAction:
|
|
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
|
+
return True
|
|
46
|
+
|
|
47
|
+
async def handler(
|
|
48
|
+
self,
|
|
49
|
+
runtime: IAgentRuntime,
|
|
50
|
+
message: Memory,
|
|
51
|
+
state: State | None = None,
|
|
52
|
+
options: HandlerOptions | None = None,
|
|
53
|
+
callback: HandlerCallback | None = None,
|
|
54
|
+
responses: list[Memory] | None = None,
|
|
55
|
+
) -> ActionResult:
|
|
56
|
+
if callback and responses and len(responses) > 0:
|
|
57
|
+
first_response = responses[0]
|
|
58
|
+
if first_response.content:
|
|
59
|
+
await callback(first_response.content)
|
|
60
|
+
|
|
61
|
+
return ActionResult(
|
|
62
|
+
text="Ignoring message",
|
|
63
|
+
values={"success": True, "ignored": True},
|
|
64
|
+
data={"actionName": "IGNORE"},
|
|
65
|
+
success=True,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def examples(self) -> list[list[ActionExample]]:
|
|
70
|
+
return _convert_spec_examples()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
ignore_action = Action(
|
|
74
|
+
name=IgnoreAction.name,
|
|
75
|
+
similes=IgnoreAction().similes,
|
|
76
|
+
description=IgnoreAction.description,
|
|
77
|
+
validate=IgnoreAction().validate,
|
|
78
|
+
handler=IgnoreAction().handler,
|
|
79
|
+
examples=IgnoreAction().examples,
|
|
80
|
+
)
|
|
@@ -0,0 +1,135 @@
|
|
|
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 IMAGE_GENERATION_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("GENERATE_IMAGE")
|
|
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 GenerateImageAction:
|
|
40
|
+
name: str = _spec["name"]
|
|
41
|
+
similes: list[str] = field(default_factory=lambda: list(_spec.get("similes", [])))
|
|
42
|
+
description: str = _spec["description"]
|
|
43
|
+
|
|
44
|
+
async def validate(
|
|
45
|
+
self, runtime: IAgentRuntime, message: Memory, _state: State | None = None
|
|
46
|
+
) -> bool:
|
|
47
|
+
return runtime.has_model(ModelType.IMAGE)
|
|
48
|
+
|
|
49
|
+
async def handler(
|
|
50
|
+
self,
|
|
51
|
+
runtime: IAgentRuntime,
|
|
52
|
+
message: Memory,
|
|
53
|
+
state: State | None = None,
|
|
54
|
+
options: HandlerOptions | None = None,
|
|
55
|
+
callback: HandlerCallback | None = None,
|
|
56
|
+
responses: list[Memory] | None = None,
|
|
57
|
+
) -> ActionResult:
|
|
58
|
+
if state is None:
|
|
59
|
+
raise ValueError("State is required for GENERATE_IMAGE action")
|
|
60
|
+
|
|
61
|
+
state = await runtime.compose_state(message, ["RECENT_MESSAGES", "ACTION_STATE"])
|
|
62
|
+
|
|
63
|
+
template = (
|
|
64
|
+
runtime.character.templates.get("imageGenerationTemplate")
|
|
65
|
+
if runtime.character.templates
|
|
66
|
+
and "imageGenerationTemplate" in runtime.character.templates
|
|
67
|
+
else IMAGE_GENERATION_TEMPLATE
|
|
68
|
+
)
|
|
69
|
+
prompt = runtime.compose_prompt(state=state, template=template)
|
|
70
|
+
|
|
71
|
+
prompt_response = await runtime.use_model(ModelType.TEXT_LARGE, prompt=prompt)
|
|
72
|
+
parsed_xml = parse_key_value_xml(prompt_response)
|
|
73
|
+
|
|
74
|
+
if parsed_xml is None:
|
|
75
|
+
raise ValueError("Failed to parse XML response for image prompt")
|
|
76
|
+
|
|
77
|
+
thought = str(parsed_xml.get("thought", ""))
|
|
78
|
+
image_prompt = str(parsed_xml.get("prompt", ""))
|
|
79
|
+
|
|
80
|
+
if not image_prompt:
|
|
81
|
+
raise ValueError("No image prompt generated")
|
|
82
|
+
|
|
83
|
+
image_result = await runtime.use_model(
|
|
84
|
+
ModelType.IMAGE,
|
|
85
|
+
prompt=image_prompt,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
image_url: str | None = None
|
|
89
|
+
if isinstance(image_result, str):
|
|
90
|
+
image_url = image_result
|
|
91
|
+
elif isinstance(image_result, dict):
|
|
92
|
+
image_url = image_result.get("url") or image_result.get("data")
|
|
93
|
+
|
|
94
|
+
if not image_url:
|
|
95
|
+
raise ValueError("No image URL returned from generation")
|
|
96
|
+
|
|
97
|
+
response_content = Content(
|
|
98
|
+
text=f"Generated image with prompt: {image_prompt}",
|
|
99
|
+
attachments=[{"type": "image", "url": image_url}],
|
|
100
|
+
actions=["GENERATE_IMAGE"],
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
if callback:
|
|
104
|
+
await callback(response_content)
|
|
105
|
+
|
|
106
|
+
return ActionResult(
|
|
107
|
+
text=f"Generated image: {image_prompt}",
|
|
108
|
+
values={
|
|
109
|
+
"success": True,
|
|
110
|
+
"imageGenerated": True,
|
|
111
|
+
"imageUrl": image_url,
|
|
112
|
+
"imagePrompt": image_prompt,
|
|
113
|
+
},
|
|
114
|
+
data={
|
|
115
|
+
"actionName": "GENERATE_IMAGE",
|
|
116
|
+
"prompt": image_prompt,
|
|
117
|
+
"thought": thought,
|
|
118
|
+
"imageUrl": image_url,
|
|
119
|
+
},
|
|
120
|
+
success=True,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def examples(self) -> list[list[ActionExample]]:
|
|
125
|
+
return _convert_spec_examples()
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
generate_image_action = Action(
|
|
129
|
+
name=GenerateImageAction.name,
|
|
130
|
+
similes=GenerateImageAction().similes,
|
|
131
|
+
description=GenerateImageAction.description,
|
|
132
|
+
validate=GenerateImageAction().validate,
|
|
133
|
+
handler=GenerateImageAction().handler,
|
|
134
|
+
examples=GenerateImageAction().examples,
|
|
135
|
+
)
|
|
@@ -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("MUTE_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 MuteRoomAction:
|
|
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 False
|
|
60
|
+
|
|
61
|
+
return True
|
|
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 mute",
|
|
76
|
+
values={"success": False, "error": "no_room_id"},
|
|
77
|
+
data={"actionName": "MUTE_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": "MUTE_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 not in muted_rooms:
|
|
100
|
+
muted_rooms.append(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"Muted room: {room_name}",
|
|
107
|
+
actions=["MUTE_ROOM"],
|
|
108
|
+
),
|
|
109
|
+
room_id=room_id,
|
|
110
|
+
entity_id=runtime.agent_id,
|
|
111
|
+
memory_type="action",
|
|
112
|
+
metadata={"type": "MUTE_ROOM", "roomName": room_name},
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
response_content = Content(
|
|
116
|
+
text=f"I have muted {room_name}. I won't respond to messages there.",
|
|
117
|
+
actions=["MUTE_ROOM"],
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if callback:
|
|
121
|
+
await callback(response_content)
|
|
122
|
+
|
|
123
|
+
return ActionResult(
|
|
124
|
+
text=f"Muted room: {room_name}",
|
|
125
|
+
values={
|
|
126
|
+
"success": True,
|
|
127
|
+
"muted": True,
|
|
128
|
+
"roomId": str(room_id),
|
|
129
|
+
"roomName": room_name,
|
|
130
|
+
},
|
|
131
|
+
data={
|
|
132
|
+
"actionName": "MUTE_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
|
+
mute_room_action = Action(
|
|
145
|
+
name=MuteRoomAction.name,
|
|
146
|
+
similes=MuteRoomAction().similes,
|
|
147
|
+
description=MuteRoomAction.description,
|
|
148
|
+
validate=MuteRoomAction().validate,
|
|
149
|
+
handler=MuteRoomAction().handler,
|
|
150
|
+
examples=MuteRoomAction().examples,
|
|
151
|
+
)
|
|
@@ -0,0 +1,71 @@
|
|
|
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("NONE")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class NoneAction:
|
|
18
|
+
name: str = _spec["name"]
|
|
19
|
+
similes: list[str] = field(default_factory=lambda: list(_spec.get("similes", [])))
|
|
20
|
+
description: str = _spec["description"]
|
|
21
|
+
|
|
22
|
+
async def validate(
|
|
23
|
+
self, runtime: IAgentRuntime, _message: Memory, _state: State | None = None
|
|
24
|
+
) -> bool:
|
|
25
|
+
return True
|
|
26
|
+
|
|
27
|
+
async def handler(
|
|
28
|
+
self,
|
|
29
|
+
runtime: IAgentRuntime,
|
|
30
|
+
message: Memory,
|
|
31
|
+
state: State | None = None,
|
|
32
|
+
options: HandlerOptions | None = None,
|
|
33
|
+
callback: HandlerCallback | None = None,
|
|
34
|
+
responses: list[Memory] | None = None,
|
|
35
|
+
) -> ActionResult:
|
|
36
|
+
return ActionResult(
|
|
37
|
+
text="No action taken",
|
|
38
|
+
values={"success": True, "noAction": True},
|
|
39
|
+
data={"actionName": "NONE"},
|
|
40
|
+
success=True,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def examples(self) -> list[list[ActionExample]]:
|
|
45
|
+
# Convert spec examples to ActionExample format
|
|
46
|
+
spec_examples = _spec.get("examples", [])
|
|
47
|
+
if spec_examples:
|
|
48
|
+
return [
|
|
49
|
+
[
|
|
50
|
+
ActionExample(
|
|
51
|
+
name=msg.get("name", ""),
|
|
52
|
+
content=Content(
|
|
53
|
+
text=msg.get("content", {}).get("text", ""),
|
|
54
|
+
actions=msg.get("content", {}).get("actions"),
|
|
55
|
+
),
|
|
56
|
+
)
|
|
57
|
+
for msg in example
|
|
58
|
+
]
|
|
59
|
+
for example in spec_examples
|
|
60
|
+
]
|
|
61
|
+
return []
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
none_action = Action(
|
|
65
|
+
name=NoneAction.name,
|
|
66
|
+
similes=NoneAction().similes,
|
|
67
|
+
description=NoneAction.description,
|
|
68
|
+
validate=NoneAction().validate,
|
|
69
|
+
handler=NoneAction().handler,
|
|
70
|
+
examples=NoneAction().examples,
|
|
71
|
+
)
|
|
@@ -0,0 +1,159 @@
|
|
|
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 REMOVE_CONTACT_TEMPLATE
|
|
9
|
+
from elizaos.types import (
|
|
10
|
+
Action,
|
|
11
|
+
ActionExample,
|
|
12
|
+
ActionResult,
|
|
13
|
+
Content,
|
|
14
|
+
ModelType,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from elizaos.types import (
|
|
19
|
+
HandlerCallback,
|
|
20
|
+
HandlerOptions,
|
|
21
|
+
IAgentRuntime,
|
|
22
|
+
Memory,
|
|
23
|
+
State,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Get text content from centralized specs
|
|
27
|
+
_spec = require_action_spec("REMOVE_CONTACT")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _convert_spec_examples() -> list[list[ActionExample]]:
|
|
31
|
+
"""Convert spec examples to ActionExample format."""
|
|
32
|
+
spec_examples = _spec.get("examples", [])
|
|
33
|
+
if spec_examples:
|
|
34
|
+
return [
|
|
35
|
+
[
|
|
36
|
+
ActionExample(
|
|
37
|
+
name=msg.get("name", ""),
|
|
38
|
+
content=Content(
|
|
39
|
+
text=msg.get("content", {}).get("text", ""),
|
|
40
|
+
actions=msg.get("content", {}).get("actions"),
|
|
41
|
+
),
|
|
42
|
+
)
|
|
43
|
+
for msg in example
|
|
44
|
+
]
|
|
45
|
+
for example in spec_examples
|
|
46
|
+
]
|
|
47
|
+
return []
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class RemoveContactAction:
|
|
52
|
+
name: str = _spec["name"]
|
|
53
|
+
similes: list[str] = field(default_factory=lambda: list(_spec.get("similes", [])))
|
|
54
|
+
description: str = _spec["description"]
|
|
55
|
+
|
|
56
|
+
async def validate(
|
|
57
|
+
self, runtime: IAgentRuntime, _message: Memory, _state: State | None = None
|
|
58
|
+
) -> bool:
|
|
59
|
+
rolodex_service = runtime.get_service("rolodex")
|
|
60
|
+
return rolodex_service is not None
|
|
61
|
+
|
|
62
|
+
async def handler(
|
|
63
|
+
self,
|
|
64
|
+
runtime: IAgentRuntime,
|
|
65
|
+
message: Memory,
|
|
66
|
+
state: State | None = None,
|
|
67
|
+
options: HandlerOptions | None = None,
|
|
68
|
+
callback: HandlerCallback | None = None,
|
|
69
|
+
responses: list[Memory] | None = None,
|
|
70
|
+
) -> ActionResult:
|
|
71
|
+
from elizaos.bootstrap.services.rolodex import RolodexService
|
|
72
|
+
|
|
73
|
+
rolodex_service = runtime.get_service("rolodex")
|
|
74
|
+
if not rolodex_service or not isinstance(rolodex_service, RolodexService):
|
|
75
|
+
return ActionResult(
|
|
76
|
+
text="Rolodex service not available",
|
|
77
|
+
success=False,
|
|
78
|
+
values={"error": True},
|
|
79
|
+
data={"error": "RolodexService not available"},
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
state = await runtime.compose_state(message, ["RECENT_MESSAGES", "ENTITIES"])
|
|
83
|
+
|
|
84
|
+
prompt = runtime.compose_prompt_from_state(
|
|
85
|
+
state=state,
|
|
86
|
+
template=REMOVE_CONTACT_TEMPLATE,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
response = await runtime.use_model(ModelType.TEXT_SMALL, {"prompt": prompt})
|
|
90
|
+
parsed = parse_key_value_xml(response)
|
|
91
|
+
|
|
92
|
+
if not parsed or not parsed.get("contactName"):
|
|
93
|
+
return ActionResult(
|
|
94
|
+
text="Could not determine which contact to remove",
|
|
95
|
+
success=False,
|
|
96
|
+
values={"error": True},
|
|
97
|
+
data={"error": "No contact name provided"},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
contact_name = str(parsed.get("contactName", ""))
|
|
101
|
+
confirmed = str(parsed.get("confirmed", "no")).lower() == "yes"
|
|
102
|
+
|
|
103
|
+
if not confirmed:
|
|
104
|
+
response_text = (
|
|
105
|
+
f'To remove {contact_name}, please confirm by saying "yes, remove {contact_name}".'
|
|
106
|
+
)
|
|
107
|
+
if callback:
|
|
108
|
+
await callback(Content(text=response_text, actions=["REMOVE_CONTACT"]))
|
|
109
|
+
return ActionResult(
|
|
110
|
+
text=response_text,
|
|
111
|
+
success=True,
|
|
112
|
+
values={"needsConfirmation": True},
|
|
113
|
+
data={"contactName": contact_name},
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
contacts = await rolodex_service.search_contacts(search_term=contact_name)
|
|
117
|
+
|
|
118
|
+
if not contacts:
|
|
119
|
+
return ActionResult(
|
|
120
|
+
text=f"Could not find a contact named '{contact_name}'",
|
|
121
|
+
success=False,
|
|
122
|
+
values={"error": True},
|
|
123
|
+
data={"error": "Contact not found"},
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
contact = contacts[0]
|
|
127
|
+
removed = await rolodex_service.remove_contact(contact.entity_id)
|
|
128
|
+
|
|
129
|
+
if removed:
|
|
130
|
+
response_text = f"I've removed {contact_name} from your contacts."
|
|
131
|
+
if callback:
|
|
132
|
+
await callback(Content(text=response_text, actions=["REMOVE_CONTACT"]))
|
|
133
|
+
return ActionResult(
|
|
134
|
+
text=response_text,
|
|
135
|
+
success=True,
|
|
136
|
+
values={"contactId": str(contact.entity_id)},
|
|
137
|
+
data={"success": True},
|
|
138
|
+
)
|
|
139
|
+
else:
|
|
140
|
+
return ActionResult(
|
|
141
|
+
text="Failed to remove contact",
|
|
142
|
+
success=False,
|
|
143
|
+
values={"error": True},
|
|
144
|
+
data={"error": "Remove operation failed"},
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def examples(self) -> list[list[ActionExample]]:
|
|
149
|
+
return _convert_spec_examples()
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
remove_contact_action = Action(
|
|
153
|
+
name=RemoveContactAction.name,
|
|
154
|
+
similes=RemoveContactAction().similes,
|
|
155
|
+
description=RemoveContactAction.description,
|
|
156
|
+
validate=RemoveContactAction().validate,
|
|
157
|
+
handler=RemoveContactAction().handler,
|
|
158
|
+
examples=RemoveContactAction().examples,
|
|
159
|
+
)
|