@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,85 @@
|
|
|
1
|
+
"""Advanced Capabilities - Extended features for agent operation.
|
|
2
|
+
|
|
3
|
+
This module provides advanced capabilities that can be enabled with
|
|
4
|
+
`advanced_capabilities=True` or `enable_extended=True`:
|
|
5
|
+
- Extended actions (contacts, room management, image generation, etc.)
|
|
6
|
+
- Extended providers (facts, knowledge, relationships, etc.)
|
|
7
|
+
- Evaluators (reflection, relationship extraction)
|
|
8
|
+
- Extended services (rolodex, follow-up scheduling)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .actions import (
|
|
12
|
+
add_contact_action,
|
|
13
|
+
advanced_actions,
|
|
14
|
+
follow_room_action,
|
|
15
|
+
generate_image_action,
|
|
16
|
+
mute_room_action,
|
|
17
|
+
remove_contact_action,
|
|
18
|
+
schedule_follow_up_action,
|
|
19
|
+
search_contacts_action,
|
|
20
|
+
send_message_action,
|
|
21
|
+
unfollow_room_action,
|
|
22
|
+
unmute_room_action,
|
|
23
|
+
update_contact_action,
|
|
24
|
+
update_entity_action,
|
|
25
|
+
update_role_action,
|
|
26
|
+
update_settings_action,
|
|
27
|
+
)
|
|
28
|
+
from .evaluators import (
|
|
29
|
+
advanced_evaluators,
|
|
30
|
+
reflection_evaluator,
|
|
31
|
+
relationship_extraction_evaluator,
|
|
32
|
+
)
|
|
33
|
+
from .providers import (
|
|
34
|
+
advanced_providers,
|
|
35
|
+
agent_settings_provider,
|
|
36
|
+
contacts_provider,
|
|
37
|
+
facts_provider,
|
|
38
|
+
follow_ups_provider,
|
|
39
|
+
knowledge_provider,
|
|
40
|
+
relationships_provider,
|
|
41
|
+
roles_provider,
|
|
42
|
+
settings_provider,
|
|
43
|
+
)
|
|
44
|
+
from .services import (
|
|
45
|
+
FollowUpService,
|
|
46
|
+
RolodexService,
|
|
47
|
+
advanced_services,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
__all__ = [
|
|
51
|
+
# Actions
|
|
52
|
+
"advanced_actions",
|
|
53
|
+
"add_contact_action",
|
|
54
|
+
"follow_room_action",
|
|
55
|
+
"generate_image_action",
|
|
56
|
+
"mute_room_action",
|
|
57
|
+
"remove_contact_action",
|
|
58
|
+
"schedule_follow_up_action",
|
|
59
|
+
"search_contacts_action",
|
|
60
|
+
"send_message_action",
|
|
61
|
+
"unfollow_room_action",
|
|
62
|
+
"unmute_room_action",
|
|
63
|
+
"update_contact_action",
|
|
64
|
+
"update_entity_action",
|
|
65
|
+
"update_role_action",
|
|
66
|
+
"update_settings_action",
|
|
67
|
+
# Providers
|
|
68
|
+
"advanced_providers",
|
|
69
|
+
"agent_settings_provider",
|
|
70
|
+
"contacts_provider",
|
|
71
|
+
"facts_provider",
|
|
72
|
+
"follow_ups_provider",
|
|
73
|
+
"knowledge_provider",
|
|
74
|
+
"relationships_provider",
|
|
75
|
+
"roles_provider",
|
|
76
|
+
"settings_provider",
|
|
77
|
+
# Evaluators
|
|
78
|
+
"advanced_evaluators",
|
|
79
|
+
"reflection_evaluator",
|
|
80
|
+
"relationship_extraction_evaluator",
|
|
81
|
+
# Services
|
|
82
|
+
"advanced_services",
|
|
83
|
+
"FollowUpService",
|
|
84
|
+
"RolodexService",
|
|
85
|
+
]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Advanced Actions - Extended actions for agent operation.
|
|
2
|
+
|
|
3
|
+
Extended actions that can be enabled with `advanced_capabilities=True`.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .add_contact import add_contact_action
|
|
7
|
+
from .follow_room import follow_room_action
|
|
8
|
+
from .image_generation import generate_image_action
|
|
9
|
+
from .mute_room import mute_room_action
|
|
10
|
+
from .remove_contact import remove_contact_action
|
|
11
|
+
from .roles import update_role_action
|
|
12
|
+
from .schedule_follow_up import schedule_follow_up_action
|
|
13
|
+
from .search_contacts import search_contacts_action
|
|
14
|
+
from .send_message import send_message_action
|
|
15
|
+
from .settings import update_settings_action
|
|
16
|
+
from .unfollow_room import unfollow_room_action
|
|
17
|
+
from .unmute_room import unmute_room_action
|
|
18
|
+
from .update_contact import update_contact_action
|
|
19
|
+
from .update_entity import update_entity_action
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"add_contact_action",
|
|
23
|
+
"follow_room_action",
|
|
24
|
+
"generate_image_action",
|
|
25
|
+
"mute_room_action",
|
|
26
|
+
"remove_contact_action",
|
|
27
|
+
"schedule_follow_up_action",
|
|
28
|
+
"search_contacts_action",
|
|
29
|
+
"send_message_action",
|
|
30
|
+
"unfollow_room_action",
|
|
31
|
+
"unmute_room_action",
|
|
32
|
+
"update_contact_action",
|
|
33
|
+
"update_entity_action",
|
|
34
|
+
"update_role_action",
|
|
35
|
+
"update_settings_action",
|
|
36
|
+
"advanced_actions",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
advanced_actions = [
|
|
40
|
+
add_contact_action,
|
|
41
|
+
follow_room_action,
|
|
42
|
+
generate_image_action,
|
|
43
|
+
mute_room_action,
|
|
44
|
+
remove_contact_action,
|
|
45
|
+
schedule_follow_up_action,
|
|
46
|
+
search_contacts_action,
|
|
47
|
+
send_message_action,
|
|
48
|
+
unfollow_room_action,
|
|
49
|
+
unmute_room_action,
|
|
50
|
+
update_contact_action,
|
|
51
|
+
update_entity_action,
|
|
52
|
+
update_role_action,
|
|
53
|
+
update_settings_action,
|
|
54
|
+
]
|
|
@@ -0,0 +1,139 @@
|
|
|
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 ADD_CONTACT_TEMPLATE
|
|
9
|
+
from elizaos.types import (
|
|
10
|
+
Action,
|
|
11
|
+
ActionExample,
|
|
12
|
+
ActionResult,
|
|
13
|
+
Content,
|
|
14
|
+
ModelType,
|
|
15
|
+
)
|
|
16
|
+
from elizaos.utils.spec_examples import convert_spec_examples
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from elizaos.types import (
|
|
20
|
+
HandlerCallback,
|
|
21
|
+
HandlerOptions,
|
|
22
|
+
IAgentRuntime,
|
|
23
|
+
Memory,
|
|
24
|
+
State,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Get text content from centralized specs
|
|
28
|
+
_spec = require_action_spec("ADD_CONTACT")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _convert_spec_examples() -> list[list[ActionExample]]:
|
|
32
|
+
"""Convert spec examples to ActionExample format."""
|
|
33
|
+
return convert_spec_examples(_spec)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class AddContactAction:
|
|
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
|
+
rolodex_service = runtime.get_service("rolodex")
|
|
46
|
+
return rolodex_service is not None
|
|
47
|
+
|
|
48
|
+
async def handler(
|
|
49
|
+
self,
|
|
50
|
+
runtime: IAgentRuntime,
|
|
51
|
+
message: Memory,
|
|
52
|
+
state: State | None = None,
|
|
53
|
+
options: HandlerOptions | None = None,
|
|
54
|
+
callback: HandlerCallback | None = None,
|
|
55
|
+
responses: list[Memory] | None = None,
|
|
56
|
+
) -> ActionResult:
|
|
57
|
+
from elizaos.bootstrap.services.rolodex import ContactPreferences, RolodexService
|
|
58
|
+
|
|
59
|
+
rolodex_service = runtime.get_service("rolodex")
|
|
60
|
+
if not rolodex_service or not isinstance(rolodex_service, RolodexService):
|
|
61
|
+
return ActionResult(
|
|
62
|
+
text="Rolodex service not available",
|
|
63
|
+
success=False,
|
|
64
|
+
values={"error": True},
|
|
65
|
+
data={"error": "RolodexService not available"},
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
state = await runtime.compose_state(message, ["RECENT_MESSAGES", "ENTITIES"])
|
|
69
|
+
|
|
70
|
+
prompt = runtime.compose_prompt_from_state(
|
|
71
|
+
state=state,
|
|
72
|
+
template=ADD_CONTACT_TEMPLATE,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
response = await runtime.use_model(ModelType.TEXT_SMALL, {"prompt": prompt})
|
|
76
|
+
parsed = parse_key_value_xml(response)
|
|
77
|
+
|
|
78
|
+
if not parsed or not parsed.get("contactName"):
|
|
79
|
+
return ActionResult(
|
|
80
|
+
text="Could not extract contact information",
|
|
81
|
+
success=False,
|
|
82
|
+
values={"error": True},
|
|
83
|
+
data={"error": "Failed to parse contact info"},
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
contact_name = str(parsed.get("contactName", ""))
|
|
87
|
+
categories_str = str(parsed.get("categories", "acquaintance"))
|
|
88
|
+
categories = [c.strip() for c in categories_str.split(",") if c.strip()]
|
|
89
|
+
notes = str(parsed.get("notes", ""))
|
|
90
|
+
reason = str(parsed.get("reason", ""))
|
|
91
|
+
|
|
92
|
+
from uuid import UUID as StdUUID
|
|
93
|
+
|
|
94
|
+
entity_id = message.entity_id
|
|
95
|
+
entity_id_uuid = StdUUID(str(entity_id)) if entity_id else None
|
|
96
|
+
preferences = ContactPreferences(notes=notes) if notes else None
|
|
97
|
+
|
|
98
|
+
if entity_id_uuid:
|
|
99
|
+
await rolodex_service.add_contact(
|
|
100
|
+
entity_id=entity_id_uuid,
|
|
101
|
+
categories=categories,
|
|
102
|
+
preferences=preferences,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
response_text = (
|
|
106
|
+
f"I've added {contact_name} to your contacts as {', '.join(categories)}. {reason}"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
if callback:
|
|
110
|
+
await callback(Content(text=response_text, actions=["ADD_CONTACT"]))
|
|
111
|
+
|
|
112
|
+
return ActionResult(
|
|
113
|
+
text=response_text,
|
|
114
|
+
success=True,
|
|
115
|
+
values={
|
|
116
|
+
"contactId": str(entity_id),
|
|
117
|
+
"contactName": contact_name,
|
|
118
|
+
"categoriesStr": ",".join(categories),
|
|
119
|
+
},
|
|
120
|
+
data={
|
|
121
|
+
"contactId": str(entity_id),
|
|
122
|
+
"contactName": contact_name,
|
|
123
|
+
"categories": ",".join(categories),
|
|
124
|
+
},
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def examples(self) -> list[list[ActionExample]]:
|
|
129
|
+
return _convert_spec_examples()
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
add_contact_action = Action(
|
|
133
|
+
name=AddContactAction.name,
|
|
134
|
+
similes=AddContactAction().similes,
|
|
135
|
+
description=AddContactAction.description,
|
|
136
|
+
validate=AddContactAction().validate,
|
|
137
|
+
handler=AddContactAction().handler,
|
|
138
|
+
examples=AddContactAction().examples,
|
|
139
|
+
)
|
|
@@ -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.types import Action, ActionExample, ActionResult, Content
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from elizaos.types import HandlerCallback, HandlerOptions, IAgentRuntime, Memory, State
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class FollowRoomAction:
|
|
14
|
+
name: str = "FOLLOW_ROOM"
|
|
15
|
+
similes: list[str] = field(
|
|
16
|
+
default_factory=lambda: [
|
|
17
|
+
"JOIN_ROOM",
|
|
18
|
+
"SUBSCRIBE_ROOM",
|
|
19
|
+
"WATCH_ROOM",
|
|
20
|
+
"ENTER_ROOM",
|
|
21
|
+
]
|
|
22
|
+
)
|
|
23
|
+
description: str = (
|
|
24
|
+
"Follow a room to receive updates and monitor messages. "
|
|
25
|
+
"Use this when you want to actively engage with a room's content."
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
async def validate(
|
|
29
|
+
self, runtime: IAgentRuntime, message: Memory, _state: State | None = None
|
|
30
|
+
) -> bool:
|
|
31
|
+
room_id = message.room_id
|
|
32
|
+
if not room_id:
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
room = await runtime.get_room(room_id)
|
|
36
|
+
if room is None:
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
world_id = room.world_id
|
|
40
|
+
if world_id:
|
|
41
|
+
world = await runtime.get_world(world_id)
|
|
42
|
+
if world and world.metadata:
|
|
43
|
+
followed_rooms = world.metadata.get("followedRooms", [])
|
|
44
|
+
if str(room_id) in followed_rooms:
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
return True
|
|
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
|
+
room_id = message.room_id
|
|
59
|
+
if not room_id:
|
|
60
|
+
return ActionResult(
|
|
61
|
+
text="No room specified to follow",
|
|
62
|
+
values={"success": False, "error": "no_room_id"},
|
|
63
|
+
data={"actionName": "FOLLOW_ROOM"},
|
|
64
|
+
success=False,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
room = await runtime.get_room(room_id)
|
|
68
|
+
if room is None:
|
|
69
|
+
return ActionResult(
|
|
70
|
+
text="Room not found",
|
|
71
|
+
values={"success": False, "error": "room_not_found"},
|
|
72
|
+
data={"actionName": "FOLLOW_ROOM"},
|
|
73
|
+
success=False,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
room_name = str(room.name) if room.name else "Unknown Room"
|
|
77
|
+
|
|
78
|
+
world_id = room.world_id
|
|
79
|
+
if world_id:
|
|
80
|
+
world = await runtime.get_world(world_id)
|
|
81
|
+
if world and world.metadata:
|
|
82
|
+
followed_rooms = list(world.metadata.get("followedRooms", []))
|
|
83
|
+
room_id_str = str(room_id)
|
|
84
|
+
|
|
85
|
+
if room_id_str not in followed_rooms:
|
|
86
|
+
followed_rooms.append(room_id_str)
|
|
87
|
+
world.metadata["followedRooms"] = followed_rooms
|
|
88
|
+
await runtime.update_world(world)
|
|
89
|
+
|
|
90
|
+
await runtime.create_memory(
|
|
91
|
+
content=Content(
|
|
92
|
+
text=f"Now following room: {room_name}",
|
|
93
|
+
actions=["FOLLOW_ROOM"],
|
|
94
|
+
),
|
|
95
|
+
room_id=room_id,
|
|
96
|
+
entity_id=runtime.agent_id,
|
|
97
|
+
memory_type="action",
|
|
98
|
+
metadata={"type": "FOLLOW_ROOM", "roomName": room_name},
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
response_content = Content(
|
|
102
|
+
text=f"I am now following {room_name} and will monitor its messages.",
|
|
103
|
+
actions=["FOLLOW_ROOM"],
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if callback:
|
|
107
|
+
await callback(response_content)
|
|
108
|
+
|
|
109
|
+
return ActionResult(
|
|
110
|
+
text=f"Now following room: {room_name}",
|
|
111
|
+
values={
|
|
112
|
+
"success": True,
|
|
113
|
+
"following": True,
|
|
114
|
+
"roomId": str(room_id),
|
|
115
|
+
"roomName": room_name,
|
|
116
|
+
},
|
|
117
|
+
data={
|
|
118
|
+
"actionName": "FOLLOW_ROOM",
|
|
119
|
+
"roomId": str(room_id),
|
|
120
|
+
"roomName": room_name,
|
|
121
|
+
},
|
|
122
|
+
success=True,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def examples(self) -> list[list[ActionExample]]:
|
|
127
|
+
return [
|
|
128
|
+
[
|
|
129
|
+
ActionExample(
|
|
130
|
+
name="{{name1}}",
|
|
131
|
+
content=Content(text="Can you keep an eye on this channel?"),
|
|
132
|
+
),
|
|
133
|
+
ActionExample(
|
|
134
|
+
name="{{name2}}",
|
|
135
|
+
content=Content(
|
|
136
|
+
text="I'll follow this room and monitor its activity.",
|
|
137
|
+
actions=["FOLLOW_ROOM"],
|
|
138
|
+
),
|
|
139
|
+
),
|
|
140
|
+
],
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
follow_room_action = Action(
|
|
145
|
+
name=FollowRoomAction.name,
|
|
146
|
+
similes=FollowRoomAction().similes,
|
|
147
|
+
description=FollowRoomAction.description,
|
|
148
|
+
validate=FollowRoomAction().validate,
|
|
149
|
+
handler=FollowRoomAction().handler,
|
|
150
|
+
examples=FollowRoomAction().examples,
|
|
151
|
+
)
|
|
@@ -0,0 +1,148 @@
|
|
|
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 not isinstance(spec_examples, list):
|
|
22
|
+
return []
|
|
23
|
+
result: list[list[ActionExample]] = []
|
|
24
|
+
for example in spec_examples:
|
|
25
|
+
if not isinstance(example, list):
|
|
26
|
+
continue
|
|
27
|
+
row: list[ActionExample] = []
|
|
28
|
+
for msg in example:
|
|
29
|
+
if not isinstance(msg, dict):
|
|
30
|
+
continue
|
|
31
|
+
content = msg.get("content", {})
|
|
32
|
+
text = ""
|
|
33
|
+
actions: list[str] | None = None
|
|
34
|
+
if isinstance(content, dict):
|
|
35
|
+
text_val = content.get("text", "")
|
|
36
|
+
text = str(text_val) if text_val else ""
|
|
37
|
+
actions_val = content.get("actions")
|
|
38
|
+
if isinstance(actions_val, list) and all(isinstance(a, str) for a in actions_val):
|
|
39
|
+
actions = list(actions_val)
|
|
40
|
+
row.append(
|
|
41
|
+
ActionExample(
|
|
42
|
+
name=str(msg.get("name", "")),
|
|
43
|
+
content=Content(text=text, actions=actions),
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
if row:
|
|
47
|
+
result.append(row)
|
|
48
|
+
return result
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class GenerateImageAction:
|
|
53
|
+
name: str = _spec["name"]
|
|
54
|
+
similes: list[str] = field(default_factory=lambda: list(_spec.get("similes", [])))
|
|
55
|
+
description: str = _spec["description"]
|
|
56
|
+
|
|
57
|
+
async def validate(
|
|
58
|
+
self, runtime: IAgentRuntime, message: Memory, _state: State | None = None
|
|
59
|
+
) -> bool:
|
|
60
|
+
return runtime.has_model(ModelType.IMAGE)
|
|
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
|
+
if state is None:
|
|
72
|
+
raise ValueError("State is required for GENERATE_IMAGE action")
|
|
73
|
+
|
|
74
|
+
state = await runtime.compose_state(message, ["RECENT_MESSAGES", "ACTION_STATE"])
|
|
75
|
+
|
|
76
|
+
template = (
|
|
77
|
+
runtime.character.templates.get("imageGenerationTemplate")
|
|
78
|
+
if runtime.character.templates
|
|
79
|
+
and "imageGenerationTemplate" in runtime.character.templates
|
|
80
|
+
else IMAGE_GENERATION_TEMPLATE
|
|
81
|
+
)
|
|
82
|
+
prompt = runtime.compose_prompt(state=state, template=template)
|
|
83
|
+
|
|
84
|
+
prompt_response = await runtime.use_model(ModelType.TEXT_LARGE, prompt=prompt)
|
|
85
|
+
parsed_xml = parse_key_value_xml(prompt_response)
|
|
86
|
+
|
|
87
|
+
if parsed_xml is None:
|
|
88
|
+
raise ValueError("Failed to parse XML response for image prompt")
|
|
89
|
+
|
|
90
|
+
thought = str(parsed_xml.get("thought", ""))
|
|
91
|
+
image_prompt = str(parsed_xml.get("prompt", ""))
|
|
92
|
+
|
|
93
|
+
if not image_prompt:
|
|
94
|
+
raise ValueError("No image prompt generated")
|
|
95
|
+
|
|
96
|
+
image_result = await runtime.use_model(
|
|
97
|
+
ModelType.IMAGE,
|
|
98
|
+
prompt=image_prompt,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
image_url: str | None = None
|
|
102
|
+
if isinstance(image_result, str):
|
|
103
|
+
image_url = image_result
|
|
104
|
+
elif isinstance(image_result, dict):
|
|
105
|
+
image_url = image_result.get("url") or image_result.get("data")
|
|
106
|
+
|
|
107
|
+
if not image_url:
|
|
108
|
+
raise ValueError("No image URL returned from generation")
|
|
109
|
+
|
|
110
|
+
response_content = Content(
|
|
111
|
+
text=f"Generated image with prompt: {image_prompt}",
|
|
112
|
+
attachments=[{"type": "image", "url": image_url}],
|
|
113
|
+
actions=["GENERATE_IMAGE"],
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if callback:
|
|
117
|
+
await callback(response_content)
|
|
118
|
+
|
|
119
|
+
return ActionResult(
|
|
120
|
+
text=f"Generated image: {image_prompt}",
|
|
121
|
+
values={
|
|
122
|
+
"success": True,
|
|
123
|
+
"imageGenerated": True,
|
|
124
|
+
"imageUrl": image_url,
|
|
125
|
+
"imagePrompt": image_prompt,
|
|
126
|
+
},
|
|
127
|
+
data={
|
|
128
|
+
"actionName": "GENERATE_IMAGE",
|
|
129
|
+
"prompt": image_prompt,
|
|
130
|
+
"thought": thought,
|
|
131
|
+
"imageUrl": image_url,
|
|
132
|
+
},
|
|
133
|
+
success=True,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def examples(self) -> list[list[ActionExample]]:
|
|
138
|
+
return _convert_spec_examples()
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
generate_image_action = Action(
|
|
142
|
+
name=GenerateImageAction.name,
|
|
143
|
+
similes=GenerateImageAction().similes,
|
|
144
|
+
description=GenerateImageAction.description,
|
|
145
|
+
validate=GenerateImageAction().validate,
|
|
146
|
+
handler=GenerateImageAction().handler,
|
|
147
|
+
examples=GenerateImageAction().examples,
|
|
148
|
+
)
|