@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,178 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from datetime import UTC, datetime
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
from uuid import UUID, uuid4
|
|
8
|
+
|
|
9
|
+
from elizaos.types import Service, ServiceType
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from elizaos.types import IAgentRuntime
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TaskStatus(str, Enum):
|
|
16
|
+
PENDING = "PENDING"
|
|
17
|
+
IN_PROGRESS = "IN_PROGRESS"
|
|
18
|
+
COMPLETED = "COMPLETED"
|
|
19
|
+
FAILED = "FAILED"
|
|
20
|
+
CANCELLED = "CANCELLED"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TaskPriority(str, Enum):
|
|
24
|
+
LOW = "LOW"
|
|
25
|
+
MEDIUM = "MEDIUM"
|
|
26
|
+
HIGH = "HIGH"
|
|
27
|
+
URGENT = "URGENT"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class Task:
|
|
32
|
+
id: UUID
|
|
33
|
+
name: str
|
|
34
|
+
description: str
|
|
35
|
+
status: TaskStatus
|
|
36
|
+
priority: TaskPriority
|
|
37
|
+
created_at: datetime
|
|
38
|
+
updated_at: datetime
|
|
39
|
+
completed_at: datetime | None = None
|
|
40
|
+
metadata: dict[str, str | int | float | bool | None] = field(default_factory=dict)
|
|
41
|
+
assignee_id: UUID | None = None
|
|
42
|
+
parent_id: UUID | None = None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class TaskService(Service):
|
|
46
|
+
name = "task"
|
|
47
|
+
service_type = ServiceType.TASK
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def capability_description(self) -> str:
|
|
51
|
+
return "Task management service for creating, tracking, and completing tasks."
|
|
52
|
+
|
|
53
|
+
def __init__(self) -> None:
|
|
54
|
+
self._tasks: dict[UUID, Task] = {}
|
|
55
|
+
self._runtime: IAgentRuntime | None = None
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
async def start(cls, runtime: IAgentRuntime) -> TaskService:
|
|
59
|
+
service = cls()
|
|
60
|
+
service._runtime = runtime
|
|
61
|
+
runtime.logger.info(
|
|
62
|
+
"Task service started",
|
|
63
|
+
src="service:task",
|
|
64
|
+
agentId=str(runtime.agent_id),
|
|
65
|
+
)
|
|
66
|
+
return service
|
|
67
|
+
|
|
68
|
+
async def stop(self) -> None:
|
|
69
|
+
if self._runtime:
|
|
70
|
+
self._runtime.logger.info(
|
|
71
|
+
"Task service stopped",
|
|
72
|
+
src="service:task",
|
|
73
|
+
agentId=str(self._runtime.agent_id),
|
|
74
|
+
)
|
|
75
|
+
self._tasks.clear()
|
|
76
|
+
self._runtime = None
|
|
77
|
+
|
|
78
|
+
async def create_task(
|
|
79
|
+
self,
|
|
80
|
+
name: str,
|
|
81
|
+
description: str,
|
|
82
|
+
priority: TaskPriority = TaskPriority.MEDIUM,
|
|
83
|
+
assignee_id: UUID | None = None,
|
|
84
|
+
parent_id: UUID | None = None,
|
|
85
|
+
metadata: dict[str, str | int | float | bool | None] | None = None,
|
|
86
|
+
) -> Task:
|
|
87
|
+
now = datetime.now(UTC)
|
|
88
|
+
task = Task(
|
|
89
|
+
id=uuid4(),
|
|
90
|
+
name=name,
|
|
91
|
+
description=description,
|
|
92
|
+
status=TaskStatus.PENDING,
|
|
93
|
+
priority=priority,
|
|
94
|
+
created_at=now,
|
|
95
|
+
updated_at=now,
|
|
96
|
+
assignee_id=assignee_id,
|
|
97
|
+
parent_id=parent_id,
|
|
98
|
+
metadata=metadata or {},
|
|
99
|
+
)
|
|
100
|
+
self._tasks[task.id] = task
|
|
101
|
+
|
|
102
|
+
if self._runtime:
|
|
103
|
+
self._runtime.logger.debug(
|
|
104
|
+
"Task created",
|
|
105
|
+
src="service:task",
|
|
106
|
+
taskId=str(task.id),
|
|
107
|
+
taskName=name,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
return task
|
|
111
|
+
|
|
112
|
+
async def get_task(self, task_id: UUID) -> Task | None:
|
|
113
|
+
return self._tasks.get(task_id)
|
|
114
|
+
|
|
115
|
+
async def update_task_status(
|
|
116
|
+
self,
|
|
117
|
+
task_id: UUID,
|
|
118
|
+
status: TaskStatus,
|
|
119
|
+
) -> Task | None:
|
|
120
|
+
task = self._tasks.get(task_id)
|
|
121
|
+
if task is None:
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
task.status = status
|
|
125
|
+
task.updated_at = datetime.now(UTC)
|
|
126
|
+
|
|
127
|
+
if status == TaskStatus.COMPLETED:
|
|
128
|
+
task.completed_at = task.updated_at
|
|
129
|
+
|
|
130
|
+
if self._runtime:
|
|
131
|
+
self._runtime.logger.debug(
|
|
132
|
+
"Task status updated",
|
|
133
|
+
src="service:task",
|
|
134
|
+
taskId=str(task_id),
|
|
135
|
+
newStatus=status.value,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
return task
|
|
139
|
+
|
|
140
|
+
async def get_tasks_by_status(
|
|
141
|
+
self,
|
|
142
|
+
status: TaskStatus,
|
|
143
|
+
) -> list[Task]:
|
|
144
|
+
return [t for t in self._tasks.values() if t.status == status]
|
|
145
|
+
|
|
146
|
+
async def get_tasks_by_priority(
|
|
147
|
+
self,
|
|
148
|
+
priority: TaskPriority,
|
|
149
|
+
) -> list[Task]:
|
|
150
|
+
return [t for t in self._tasks.values() if t.priority == priority]
|
|
151
|
+
|
|
152
|
+
async def get_pending_tasks(self) -> list[Task]:
|
|
153
|
+
pending = [t for t in self._tasks.values() if t.status == TaskStatus.PENDING]
|
|
154
|
+
priority_order = {
|
|
155
|
+
TaskPriority.URGENT: 0,
|
|
156
|
+
TaskPriority.HIGH: 1,
|
|
157
|
+
TaskPriority.MEDIUM: 2,
|
|
158
|
+
TaskPriority.LOW: 3,
|
|
159
|
+
}
|
|
160
|
+
return sorted(pending, key=lambda t: priority_order[t.priority])
|
|
161
|
+
|
|
162
|
+
async def complete_task(self, task_id: UUID) -> Task | None:
|
|
163
|
+
return await self.update_task_status(task_id, TaskStatus.COMPLETED)
|
|
164
|
+
|
|
165
|
+
async def cancel_task(self, task_id: UUID) -> Task | None:
|
|
166
|
+
return await self.update_task_status(task_id, TaskStatus.CANCELLED)
|
|
167
|
+
|
|
168
|
+
async def delete_task(self, task_id: UUID) -> bool:
|
|
169
|
+
if task_id in self._tasks:
|
|
170
|
+
del self._tasks[task_id]
|
|
171
|
+
if self._runtime:
|
|
172
|
+
self._runtime.logger.debug(
|
|
173
|
+
"Task deleted",
|
|
174
|
+
src="service:task",
|
|
175
|
+
taskId=str(task_id),
|
|
176
|
+
)
|
|
177
|
+
return True
|
|
178
|
+
return False
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""elizaOS Bootstrap Plugin - Python implementation."""
|
|
2
|
+
|
|
3
|
+
from .plugin import bootstrap_plugin, create_bootstrap_plugin
|
|
4
|
+
from .types import CapabilityConfig
|
|
5
|
+
|
|
6
|
+
__version__ = "2.0.0-alpha.0"
|
|
7
|
+
__all__ = [
|
|
8
|
+
"bootstrap_plugin",
|
|
9
|
+
"create_bootstrap_plugin",
|
|
10
|
+
"CapabilityConfig",
|
|
11
|
+
"__version__",
|
|
12
|
+
]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from .add_contact import add_contact_action
|
|
2
|
+
from .choice import choose_option_action
|
|
3
|
+
from .follow_room import follow_room_action
|
|
4
|
+
from .ignore import ignore_action
|
|
5
|
+
from .image_generation import generate_image_action
|
|
6
|
+
from .mute_room import mute_room_action
|
|
7
|
+
from .none import none_action
|
|
8
|
+
from .remove_contact import remove_contact_action
|
|
9
|
+
from .reply import reply_action
|
|
10
|
+
from .roles import update_role_action
|
|
11
|
+
from .schedule_follow_up import schedule_follow_up_action
|
|
12
|
+
from .search_contacts import search_contacts_action
|
|
13
|
+
from .send_message import send_message_action
|
|
14
|
+
from .settings import update_settings_action
|
|
15
|
+
from .unfollow_room import unfollow_room_action
|
|
16
|
+
from .unmute_room import unmute_room_action
|
|
17
|
+
from .update_contact import update_contact_action
|
|
18
|
+
from .update_entity import update_entity_action
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"add_contact_action",
|
|
22
|
+
"choose_option_action",
|
|
23
|
+
"follow_room_action",
|
|
24
|
+
"generate_image_action",
|
|
25
|
+
"ignore_action",
|
|
26
|
+
"mute_room_action",
|
|
27
|
+
"none_action",
|
|
28
|
+
"remove_contact_action",
|
|
29
|
+
"reply_action",
|
|
30
|
+
"schedule_follow_up_action",
|
|
31
|
+
"search_contacts_action",
|
|
32
|
+
"send_message_action",
|
|
33
|
+
"unfollow_room_action",
|
|
34
|
+
"unmute_room_action",
|
|
35
|
+
"update_contact_action",
|
|
36
|
+
"update_entity_action",
|
|
37
|
+
"update_role_action",
|
|
38
|
+
"update_settings_action",
|
|
39
|
+
"BASIC_ACTIONS",
|
|
40
|
+
"EXTENDED_ACTIONS",
|
|
41
|
+
"ALL_ACTIONS",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
BASIC_ACTIONS = [
|
|
45
|
+
reply_action,
|
|
46
|
+
ignore_action,
|
|
47
|
+
none_action,
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
EXTENDED_ACTIONS = [
|
|
51
|
+
add_contact_action,
|
|
52
|
+
choose_option_action,
|
|
53
|
+
follow_room_action,
|
|
54
|
+
generate_image_action,
|
|
55
|
+
mute_room_action,
|
|
56
|
+
remove_contact_action,
|
|
57
|
+
schedule_follow_up_action,
|
|
58
|
+
search_contacts_action,
|
|
59
|
+
send_message_action,
|
|
60
|
+
unfollow_room_action,
|
|
61
|
+
unmute_room_action,
|
|
62
|
+
update_contact_action,
|
|
63
|
+
update_entity_action,
|
|
64
|
+
update_role_action,
|
|
65
|
+
update_settings_action,
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
ALL_ACTIONS = BASIC_ACTIONS + EXTENDED_ACTIONS
|
|
@@ -0,0 +1,149 @@
|
|
|
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
|
+
|
|
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("ADD_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 AddContactAction:
|
|
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 ContactPreferences, 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=ADD_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 extract contact information",
|
|
95
|
+
success=False,
|
|
96
|
+
values={"error": True},
|
|
97
|
+
data={"error": "Failed to parse contact info"},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
contact_name = str(parsed.get("contactName", ""))
|
|
101
|
+
categories_str = str(parsed.get("categories", "acquaintance"))
|
|
102
|
+
categories = [c.strip() for c in categories_str.split(",") if c.strip()]
|
|
103
|
+
notes = str(parsed.get("notes", ""))
|
|
104
|
+
reason = str(parsed.get("reason", ""))
|
|
105
|
+
|
|
106
|
+
entity_id = message.entity_id
|
|
107
|
+
preferences = ContactPreferences(notes=notes) if notes else None
|
|
108
|
+
|
|
109
|
+
await rolodex_service.add_contact(
|
|
110
|
+
entity_id=entity_id,
|
|
111
|
+
categories=categories,
|
|
112
|
+
preferences=preferences,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
response_text = (
|
|
116
|
+
f"I've added {contact_name} to your contacts as {', '.join(categories)}. {reason}"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
if callback:
|
|
120
|
+
await callback(Content(text=response_text, actions=["ADD_CONTACT"]))
|
|
121
|
+
|
|
122
|
+
return ActionResult(
|
|
123
|
+
text=response_text,
|
|
124
|
+
success=True,
|
|
125
|
+
values={
|
|
126
|
+
"contactId": str(entity_id),
|
|
127
|
+
"contactName": contact_name,
|
|
128
|
+
"categoriesStr": ",".join(categories),
|
|
129
|
+
},
|
|
130
|
+
data={
|
|
131
|
+
"contactId": str(entity_id),
|
|
132
|
+
"contactName": contact_name,
|
|
133
|
+
"categories": ",".join(categories),
|
|
134
|
+
},
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def examples(self) -> list[list[ActionExample]]:
|
|
139
|
+
return _convert_spec_examples()
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
add_contact_action = Action(
|
|
143
|
+
name=AddContactAction.name,
|
|
144
|
+
similes=AddContactAction().similes,
|
|
145
|
+
description=AddContactAction.description,
|
|
146
|
+
validate=AddContactAction().validate,
|
|
147
|
+
handler=AddContactAction().handler,
|
|
148
|
+
examples=AddContactAction().examples,
|
|
149
|
+
)
|
|
@@ -0,0 +1,147 @@
|
|
|
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 CHOOSE_OPTION_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("CHOOSE_OPTION")
|
|
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 ChooseOptionAction:
|
|
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
|
+
if message.content and message.content.options:
|
|
48
|
+
return len(message.content.options) > 0
|
|
49
|
+
return True
|
|
50
|
+
|
|
51
|
+
async def handler(
|
|
52
|
+
self,
|
|
53
|
+
runtime: IAgentRuntime,
|
|
54
|
+
message: Memory,
|
|
55
|
+
state: State | None = None,
|
|
56
|
+
options: HandlerOptions | None = None,
|
|
57
|
+
callback: HandlerCallback | None = None,
|
|
58
|
+
responses: list[Memory] | None = None,
|
|
59
|
+
) -> ActionResult:
|
|
60
|
+
if state is None:
|
|
61
|
+
raise ValueError("State is required for CHOOSE_OPTION action")
|
|
62
|
+
|
|
63
|
+
available_options: list[dict[str, str]] = []
|
|
64
|
+
if message.content and message.content.options:
|
|
65
|
+
available_options = message.content.options
|
|
66
|
+
|
|
67
|
+
if not available_options:
|
|
68
|
+
return ActionResult(
|
|
69
|
+
text="No options available to choose from",
|
|
70
|
+
values={"success": False, "error": "no_options"},
|
|
71
|
+
data={"actionName": "CHOOSE_OPTION"},
|
|
72
|
+
success=False,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
state = await runtime.compose_state(message, ["RECENT_MESSAGES", "ACTION_STATE"])
|
|
76
|
+
|
|
77
|
+
options_context = "\n".join(
|
|
78
|
+
f"- [{opt.get('id', idx)}] {opt.get('label', '')}: {opt.get('description', '')}"
|
|
79
|
+
for idx, opt in enumerate(available_options)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
template = (
|
|
83
|
+
runtime.character.templates.get("chooseOptionTemplate")
|
|
84
|
+
if runtime.character.templates and "chooseOptionTemplate" in runtime.character.templates
|
|
85
|
+
else CHOOSE_OPTION_TEMPLATE
|
|
86
|
+
)
|
|
87
|
+
prompt = runtime.compose_prompt(state=state, template=template)
|
|
88
|
+
prompt = prompt.replace("{{options}}", options_context)
|
|
89
|
+
|
|
90
|
+
response_text = await runtime.use_model(ModelType.TEXT_LARGE, prompt=prompt)
|
|
91
|
+
parsed_xml = parse_key_value_xml(response_text)
|
|
92
|
+
|
|
93
|
+
if parsed_xml is None:
|
|
94
|
+
raise ValueError("Failed to parse XML response")
|
|
95
|
+
|
|
96
|
+
thought = str(parsed_xml.get("thought", ""))
|
|
97
|
+
selected_id = str(parsed_xml.get("selected_id", ""))
|
|
98
|
+
|
|
99
|
+
if not selected_id:
|
|
100
|
+
raise ValueError("No option selected")
|
|
101
|
+
|
|
102
|
+
selected_option = next(
|
|
103
|
+
(opt for opt in available_options if str(opt.get("id", "")) == selected_id),
|
|
104
|
+
None,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
if selected_option is None:
|
|
108
|
+
raise ValueError(f"Selected option ID '{selected_id}' not found")
|
|
109
|
+
|
|
110
|
+
response_content = Content(
|
|
111
|
+
thought=thought,
|
|
112
|
+
text=f"Selected option: {selected_option.get('label', selected_id)}",
|
|
113
|
+
actions=["CHOOSE_OPTION"],
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if callback:
|
|
117
|
+
await callback(response_content)
|
|
118
|
+
|
|
119
|
+
return ActionResult(
|
|
120
|
+
text=f"Selected option: {selected_option.get('label', selected_id)}",
|
|
121
|
+
values={
|
|
122
|
+
"success": True,
|
|
123
|
+
"selectedId": selected_id,
|
|
124
|
+
"selectedLabel": selected_option.get("label", ""),
|
|
125
|
+
"thought": thought,
|
|
126
|
+
},
|
|
127
|
+
data={
|
|
128
|
+
"actionName": "CHOOSE_OPTION",
|
|
129
|
+
"selectedOption": selected_option,
|
|
130
|
+
"thought": thought,
|
|
131
|
+
},
|
|
132
|
+
success=True,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
@property
|
|
136
|
+
def examples(self) -> list[list[ActionExample]]:
|
|
137
|
+
return _convert_spec_examples()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
choose_option_action = Action(
|
|
141
|
+
name=ChooseOptionAction.name,
|
|
142
|
+
similes=ChooseOptionAction().similes,
|
|
143
|
+
description=ChooseOptionAction.description,
|
|
144
|
+
validate=ChooseOptionAction().validate,
|
|
145
|
+
handler=ChooseOptionAction().handler,
|
|
146
|
+
examples=ChooseOptionAction().examples,
|
|
147
|
+
)
|
|
@@ -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("FOLLOW_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 FollowRoomAction:
|
|
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
|
+
followed_rooms = world.metadata.get("followedRooms", [])
|
|
58
|
+
if str(room_id) in followed_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 follow",
|
|
76
|
+
values={"success": False, "error": "no_room_id"},
|
|
77
|
+
data={"actionName": "FOLLOW_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": "FOLLOW_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
|
+
followed_rooms = list(world.metadata.get("followedRooms", []))
|
|
97
|
+
room_id_str = str(room_id)
|
|
98
|
+
|
|
99
|
+
if room_id_str not in followed_rooms:
|
|
100
|
+
followed_rooms.append(room_id_str)
|
|
101
|
+
world.metadata["followedRooms"] = followed_rooms
|
|
102
|
+
await runtime.update_world(world)
|
|
103
|
+
|
|
104
|
+
await runtime.create_memory(
|
|
105
|
+
content=Content(
|
|
106
|
+
text=f"Now following room: {room_name}",
|
|
107
|
+
actions=["FOLLOW_ROOM"],
|
|
108
|
+
),
|
|
109
|
+
room_id=room_id,
|
|
110
|
+
entity_id=runtime.agent_id,
|
|
111
|
+
memory_type="action",
|
|
112
|
+
metadata={"type": "FOLLOW_ROOM", "roomName": room_name},
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
response_content = Content(
|
|
116
|
+
text=f"I am now following {room_name} and will monitor its messages.",
|
|
117
|
+
actions=["FOLLOW_ROOM"],
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if callback:
|
|
121
|
+
await callback(response_content)
|
|
122
|
+
|
|
123
|
+
return ActionResult(
|
|
124
|
+
text=f"Now following room: {room_name}",
|
|
125
|
+
values={
|
|
126
|
+
"success": True,
|
|
127
|
+
"following": True,
|
|
128
|
+
"roomId": str(room_id),
|
|
129
|
+
"roomName": room_name,
|
|
130
|
+
},
|
|
131
|
+
data={
|
|
132
|
+
"actionName": "FOLLOW_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
|
+
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
|
+
)
|