@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,256 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.action_docs import get_canonical_action_example_calls
|
|
6
|
+
from elizaos.generated.spec_helpers import require_provider_spec
|
|
7
|
+
from elizaos.types import Provider, ProviderResult
|
|
8
|
+
from elizaos.types.components import ActionExample
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from elizaos.types import (
|
|
12
|
+
Action,
|
|
13
|
+
ActionParameter,
|
|
14
|
+
ActionParameterSchema,
|
|
15
|
+
IAgentRuntime,
|
|
16
|
+
Memory,
|
|
17
|
+
State,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# Get text content from centralized specs
|
|
21
|
+
_spec = require_provider_spec("ACTIONS")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def format_action_names(actions: list[Action]) -> str:
|
|
25
|
+
return ", ".join(action.name for action in actions)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _format_parameter_type(schema: ActionParameterSchema) -> str:
|
|
29
|
+
if schema.type == "number" and (schema.minimum is not None or schema.maximum is not None):
|
|
30
|
+
min_val = schema.minimum if schema.minimum is not None else "∞"
|
|
31
|
+
max_val = schema.maximum if schema.maximum is not None else "∞"
|
|
32
|
+
return f"number [{min_val}-{max_val}]"
|
|
33
|
+
return schema.type
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _get_param_schema(param: ActionParameter) -> object:
|
|
37
|
+
"""Get schema from ActionParameter, handling both Pydantic and protobuf variants."""
|
|
38
|
+
return getattr(param, "schema_def", None) or getattr(param, "schema", None)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _format_action_parameters(parameters: list[ActionParameter]) -> str:
|
|
42
|
+
lines: list[str] = []
|
|
43
|
+
for param in parameters:
|
|
44
|
+
schema = _get_param_schema(param)
|
|
45
|
+
if schema is None:
|
|
46
|
+
lines.append(f" - {param.name}: {param.description}")
|
|
47
|
+
continue
|
|
48
|
+
required_str = " (required)" if param.required else " (optional)"
|
|
49
|
+
type_str = _format_parameter_type(schema)
|
|
50
|
+
default_val = getattr(schema, "default", None) or getattr(schema, "default_value", None)
|
|
51
|
+
default_str = f" [default: {default_val}]" if default_val else ""
|
|
52
|
+
enum_vals = getattr(schema, "enum", None) or getattr(schema, "enum_values", None)
|
|
53
|
+
enum_str = f" [values: {', '.join(enum_vals)}]" if enum_vals else ""
|
|
54
|
+
examples_str = (
|
|
55
|
+
f" [examples: {', '.join(repr(v) for v in param.examples)}]"
|
|
56
|
+
if getattr(param, "examples", None)
|
|
57
|
+
else ""
|
|
58
|
+
)
|
|
59
|
+
lines.append(
|
|
60
|
+
f" - {param.name}{required_str}: {param.description} ({type_str}{enum_str}{default_str}{examples_str})"
|
|
61
|
+
)
|
|
62
|
+
return "\n".join(lines)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def format_actions(actions: list[Action]) -> str:
|
|
66
|
+
lines: list[str] = []
|
|
67
|
+
for action in actions:
|
|
68
|
+
line = f"- **{action.name}**: {action.description or 'No description'}"
|
|
69
|
+
if action.parameters:
|
|
70
|
+
params_text = _format_action_parameters(action.parameters)
|
|
71
|
+
if params_text:
|
|
72
|
+
line += f"\n Parameters:\n{params_text}"
|
|
73
|
+
lines.append(line)
|
|
74
|
+
return "\n".join(lines)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _replace_name_placeholders(text: str) -> str:
|
|
78
|
+
names = ["Alex", "Jordan", "Sam", "Taylor", "Riley"]
|
|
79
|
+
for i, name in enumerate(names, start=1):
|
|
80
|
+
text = text.replace(f"{{{{name{i}}}}}", name)
|
|
81
|
+
return text
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def format_action_examples(actions: list[Action], max_examples: int = 10) -> str:
|
|
85
|
+
"""
|
|
86
|
+
Format a deterministic subset of action examples for prompt context.
|
|
87
|
+
|
|
88
|
+
Deterministic ordering is important to keep tests stable and avoid prompt churn.
|
|
89
|
+
"""
|
|
90
|
+
if max_examples <= 0:
|
|
91
|
+
return ""
|
|
92
|
+
|
|
93
|
+
examples: list[list[ActionExample]] = []
|
|
94
|
+
for action in sorted(actions, key=lambda a: a.name):
|
|
95
|
+
if not action.examples:
|
|
96
|
+
continue
|
|
97
|
+
for ex in action.examples:
|
|
98
|
+
if isinstance(ex, list) and ex:
|
|
99
|
+
examples.append(ex)
|
|
100
|
+
if len(examples) >= max_examples:
|
|
101
|
+
break
|
|
102
|
+
if len(examples) >= max_examples:
|
|
103
|
+
break
|
|
104
|
+
|
|
105
|
+
if not examples:
|
|
106
|
+
return ""
|
|
107
|
+
|
|
108
|
+
blocks: list[str] = []
|
|
109
|
+
for ex in examples:
|
|
110
|
+
lines: list[str] = []
|
|
111
|
+
for msg in ex:
|
|
112
|
+
msg_text = msg.content.text if msg.content and msg.content.text else ""
|
|
113
|
+
lines.append(f"{msg.name}: {_replace_name_placeholders(msg_text)}")
|
|
114
|
+
blocks.append("\n".join(lines))
|
|
115
|
+
|
|
116
|
+
return "\n\n".join(blocks)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _escape_xml_text(text: str) -> str:
|
|
120
|
+
return text.replace("&", "&").replace("<", "<").replace(">", ">")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def format_action_call_examples(actions: list[Action], max_examples: int = 5) -> str:
|
|
124
|
+
"""
|
|
125
|
+
Format canonical action-call examples (including optional <params> blocks).
|
|
126
|
+
|
|
127
|
+
Deterministic ordering is important to keep tests stable and avoid prompt churn.
|
|
128
|
+
"""
|
|
129
|
+
if max_examples <= 0:
|
|
130
|
+
return ""
|
|
131
|
+
|
|
132
|
+
blocks: list[str] = []
|
|
133
|
+
for action in sorted(actions, key=lambda a: a.name):
|
|
134
|
+
calls = get_canonical_action_example_calls(action.name)
|
|
135
|
+
for call in calls:
|
|
136
|
+
user = call.get("user")
|
|
137
|
+
action_names = call.get("actions")
|
|
138
|
+
params = call.get("params")
|
|
139
|
+
|
|
140
|
+
if not isinstance(user, str) or not isinstance(action_names, list):
|
|
141
|
+
continue
|
|
142
|
+
if not all(isinstance(a, str) for a in action_names):
|
|
143
|
+
continue
|
|
144
|
+
|
|
145
|
+
actions_xml = "\n".join(
|
|
146
|
+
f" <action>{_escape_xml_text(a)}</action>" for a in action_names
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
params_xml = ""
|
|
150
|
+
if isinstance(params, dict):
|
|
151
|
+
blocks_xml: list[str] = []
|
|
152
|
+
for act_name, act_params in params.items():
|
|
153
|
+
if not isinstance(act_name, str) or not isinstance(act_params, dict):
|
|
154
|
+
continue
|
|
155
|
+
inner: list[str] = []
|
|
156
|
+
for k, v in act_params.items():
|
|
157
|
+
if not isinstance(k, str):
|
|
158
|
+
continue
|
|
159
|
+
if isinstance(v, str):
|
|
160
|
+
raw = v
|
|
161
|
+
elif v is None:
|
|
162
|
+
raw = "null"
|
|
163
|
+
elif isinstance(v, bool):
|
|
164
|
+
raw = "true" if v else "false"
|
|
165
|
+
elif isinstance(v, (int, float)):
|
|
166
|
+
raw = str(v)
|
|
167
|
+
else:
|
|
168
|
+
raw = repr(v)
|
|
169
|
+
inner.append(f" <{k}>{_escape_xml_text(raw)}</{k}>")
|
|
170
|
+
blocks_xml.append(f" <{act_name}>\n" + "\n".join(inner) + f"\n </{act_name}>")
|
|
171
|
+
if blocks_xml:
|
|
172
|
+
params_xml = "\n<params>\n" + "\n".join(blocks_xml) + "\n</params>"
|
|
173
|
+
|
|
174
|
+
blocks.append(
|
|
175
|
+
f"User: {user}\nAssistant:\n<actions>\n{actions_xml}\n</actions>{params_xml}"
|
|
176
|
+
)
|
|
177
|
+
if len(blocks) >= max_examples:
|
|
178
|
+
return "\n\n".join(blocks)
|
|
179
|
+
|
|
180
|
+
return "\n\n".join(blocks)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
async def get_actions(
|
|
184
|
+
runtime: IAgentRuntime,
|
|
185
|
+
message: Memory,
|
|
186
|
+
state: State | None = None,
|
|
187
|
+
) -> ProviderResult:
|
|
188
|
+
validated_actions: list[Action] = []
|
|
189
|
+
|
|
190
|
+
for action in runtime.actions:
|
|
191
|
+
validate_fn = getattr(action, "validate", None) or getattr(action, "validate_fn", None)
|
|
192
|
+
is_valid = await validate_fn(runtime, message, state) if validate_fn else True
|
|
193
|
+
if is_valid:
|
|
194
|
+
validated_actions.append(action)
|
|
195
|
+
|
|
196
|
+
action_names = format_action_names(validated_actions)
|
|
197
|
+
actions_text = format_actions(validated_actions)
|
|
198
|
+
examples_text = format_action_examples(validated_actions, max_examples=10)
|
|
199
|
+
call_examples_text = format_action_call_examples(validated_actions, max_examples=5)
|
|
200
|
+
|
|
201
|
+
text_parts: list[str] = [f"Possible response actions: {action_names}"]
|
|
202
|
+
if actions_text:
|
|
203
|
+
text_parts.append(f"# Available Actions\n{actions_text}")
|
|
204
|
+
if examples_text:
|
|
205
|
+
text_parts.append(f"# Action Examples\n{examples_text}")
|
|
206
|
+
if call_examples_text:
|
|
207
|
+
text_parts.append(f"# Action Call Examples (with <params>)\n{call_examples_text}")
|
|
208
|
+
|
|
209
|
+
return ProviderResult(
|
|
210
|
+
text="\n\n".join(text_parts),
|
|
211
|
+
values={
|
|
212
|
+
"actionNames": action_names,
|
|
213
|
+
"actionCount": len(validated_actions),
|
|
214
|
+
},
|
|
215
|
+
data={
|
|
216
|
+
"actions": [
|
|
217
|
+
{
|
|
218
|
+
"name": a.name,
|
|
219
|
+
"description": a.description,
|
|
220
|
+
"examples": [
|
|
221
|
+
[
|
|
222
|
+
{
|
|
223
|
+
"name": ex.name,
|
|
224
|
+
"content": ex.content.model_dump(),
|
|
225
|
+
}
|
|
226
|
+
for ex in example
|
|
227
|
+
]
|
|
228
|
+
for example in (a.examples or [])
|
|
229
|
+
],
|
|
230
|
+
"parameters": [
|
|
231
|
+
{
|
|
232
|
+
"name": p.name,
|
|
233
|
+
"description": p.description,
|
|
234
|
+
"required": bool(p.required),
|
|
235
|
+
"examples": getattr(p, "examples", None) or [],
|
|
236
|
+
"schema": (
|
|
237
|
+
p.schema_def.model_dump()
|
|
238
|
+
if hasattr(p, "schema_def") and hasattr(p.schema_def, "model_dump")
|
|
239
|
+
else getattr(p, "schema", None)
|
|
240
|
+
),
|
|
241
|
+
}
|
|
242
|
+
for p in (a.parameters or [])
|
|
243
|
+
],
|
|
244
|
+
}
|
|
245
|
+
for a in validated_actions
|
|
246
|
+
],
|
|
247
|
+
},
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
actions_provider = Provider(
|
|
252
|
+
name=_spec["name"],
|
|
253
|
+
description=_spec["description"],
|
|
254
|
+
get=get_actions,
|
|
255
|
+
position=_spec.get("position", -1),
|
|
256
|
+
)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.generated.spec_helpers import require_provider_spec
|
|
6
|
+
from elizaos.types import Provider, ProviderResult
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
10
|
+
|
|
11
|
+
# Get text content from centralized specs
|
|
12
|
+
_spec = require_provider_spec("AGENT_SETTINGS")
|
|
13
|
+
|
|
14
|
+
SENSITIVE_KEY_PATTERNS = (
|
|
15
|
+
"key",
|
|
16
|
+
"secret",
|
|
17
|
+
"password",
|
|
18
|
+
"token",
|
|
19
|
+
"credential",
|
|
20
|
+
"auth",
|
|
21
|
+
"private",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
async def get_agent_settings_context(
|
|
26
|
+
runtime: IAgentRuntime,
|
|
27
|
+
message: Memory,
|
|
28
|
+
state: State | None = None,
|
|
29
|
+
) -> ProviderResult:
|
|
30
|
+
all_settings = runtime.get_all_settings()
|
|
31
|
+
|
|
32
|
+
safe_settings: dict[str, str] = {}
|
|
33
|
+
for key, value in all_settings.items():
|
|
34
|
+
if not any(pattern in key.lower() for pattern in SENSITIVE_KEY_PATTERNS):
|
|
35
|
+
safe_settings[key] = str(value)
|
|
36
|
+
|
|
37
|
+
sections: list[str] = []
|
|
38
|
+
if safe_settings:
|
|
39
|
+
sections.append("# Agent Settings")
|
|
40
|
+
for key, value in safe_settings.items():
|
|
41
|
+
display_value = value if len(value) <= 50 else value[:50] + "..."
|
|
42
|
+
sections.append(f"- {key}: {display_value}")
|
|
43
|
+
|
|
44
|
+
context_text = "\n".join(sections) if sections else ""
|
|
45
|
+
|
|
46
|
+
return ProviderResult(
|
|
47
|
+
text=context_text,
|
|
48
|
+
values={
|
|
49
|
+
"settingsCount": len(safe_settings),
|
|
50
|
+
"hasSettings": len(safe_settings) > 0,
|
|
51
|
+
},
|
|
52
|
+
data={
|
|
53
|
+
"settings": safe_settings,
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
agent_settings_provider = Provider(
|
|
59
|
+
name=_spec["name"],
|
|
60
|
+
description=_spec["description"],
|
|
61
|
+
get=get_agent_settings_context,
|
|
62
|
+
dynamic=_spec.get("dynamic", True),
|
|
63
|
+
)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.generated.spec_helpers import require_provider_spec
|
|
6
|
+
from elizaos.types import Provider, ProviderResult
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
10
|
+
|
|
11
|
+
# Get text content from centralized specs
|
|
12
|
+
_spec = require_provider_spec("ATTACHMENTS")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def format_attachment(attachment: dict[str, str]) -> str:
|
|
16
|
+
att_type = attachment.get("type", "unknown")
|
|
17
|
+
url = attachment.get("url", "")
|
|
18
|
+
title = attachment.get("title", "")
|
|
19
|
+
description = attachment.get("description", "")
|
|
20
|
+
|
|
21
|
+
parts = [f"- Type: {att_type}"]
|
|
22
|
+
if title:
|
|
23
|
+
parts.append(f" Title: {title}")
|
|
24
|
+
if description:
|
|
25
|
+
parts.append(f" Description: {description}")
|
|
26
|
+
if url:
|
|
27
|
+
parts.append(f" URL: {url}")
|
|
28
|
+
|
|
29
|
+
return "\n".join(parts)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
async def get_attachments(
|
|
33
|
+
runtime: IAgentRuntime,
|
|
34
|
+
message: Memory,
|
|
35
|
+
state: State | None = None,
|
|
36
|
+
) -> ProviderResult:
|
|
37
|
+
attachments: list[dict[str, str]] = []
|
|
38
|
+
|
|
39
|
+
if message.content and hasattr(message.content, "attachments"):
|
|
40
|
+
raw_attachments = message.content.attachments or []
|
|
41
|
+
for att in raw_attachments:
|
|
42
|
+
if isinstance(att, dict):
|
|
43
|
+
attachments.append(att)
|
|
44
|
+
elif hasattr(att, "__dict__"):
|
|
45
|
+
attachments.append(att.__dict__)
|
|
46
|
+
|
|
47
|
+
if not attachments:
|
|
48
|
+
return ProviderResult(
|
|
49
|
+
text="",
|
|
50
|
+
values={"hasAttachments": False, "attachmentCount": 0},
|
|
51
|
+
data={"attachments": []},
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
formatted_attachments = "\n".join(format_attachment(att) for att in attachments)
|
|
55
|
+
|
|
56
|
+
text = f"# Attachments ({len(attachments)})\n{formatted_attachments}"
|
|
57
|
+
|
|
58
|
+
return ProviderResult(
|
|
59
|
+
text=text,
|
|
60
|
+
values={
|
|
61
|
+
"hasAttachments": True,
|
|
62
|
+
"attachmentCount": len(attachments),
|
|
63
|
+
"attachmentTypes": list({att.get("type", "unknown") for att in attachments}),
|
|
64
|
+
},
|
|
65
|
+
data={
|
|
66
|
+
"attachments": attachments,
|
|
67
|
+
},
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
attachments_provider = Provider(
|
|
72
|
+
name=_spec["name"],
|
|
73
|
+
description=_spec["description"],
|
|
74
|
+
get=get_attachments,
|
|
75
|
+
dynamic=_spec.get("dynamic", True),
|
|
76
|
+
)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.generated.spec_helpers import require_provider_spec
|
|
6
|
+
from elizaos.types import Provider, ProviderResult
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
10
|
+
|
|
11
|
+
# Get text content from centralized specs
|
|
12
|
+
_spec = require_provider_spec("CAPABILITIES")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def get_capabilities(
|
|
16
|
+
runtime: IAgentRuntime,
|
|
17
|
+
message: Memory,
|
|
18
|
+
state: State | None = None,
|
|
19
|
+
) -> ProviderResult:
|
|
20
|
+
model_types = ["TEXT_LARGE", "TEXT_SMALL", "TEXT_EMBEDDING", "IMAGE", "AUDIO"]
|
|
21
|
+
available_models = [mt for mt in model_types if runtime.has_model(mt)]
|
|
22
|
+
service_names = [s.name for s in runtime.services if hasattr(s, "name")]
|
|
23
|
+
|
|
24
|
+
features: list[str] = []
|
|
25
|
+
if runtime.get_setting("ENABLE_VOICE"):
|
|
26
|
+
features.append("voice")
|
|
27
|
+
if runtime.get_setting("ENABLE_VISION"):
|
|
28
|
+
features.append("vision")
|
|
29
|
+
if runtime.get_setting("ENABLE_MEMORY"):
|
|
30
|
+
features.append("long_term_memory")
|
|
31
|
+
|
|
32
|
+
capabilities: dict[str, list[str] | bool] = {
|
|
33
|
+
"models": available_models,
|
|
34
|
+
"services": service_names,
|
|
35
|
+
"features": features,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
text_parts: list[str] = ["# Agent Capabilities"]
|
|
39
|
+
|
|
40
|
+
if available_models:
|
|
41
|
+
text_parts.append(f"Models: {', '.join(available_models)}")
|
|
42
|
+
|
|
43
|
+
if service_names:
|
|
44
|
+
text_parts.append(f"Services: {', '.join(service_names)}")
|
|
45
|
+
|
|
46
|
+
if features:
|
|
47
|
+
text_parts.append(f"Features: {', '.join(features)}")
|
|
48
|
+
|
|
49
|
+
return ProviderResult(
|
|
50
|
+
text="\n".join(text_parts),
|
|
51
|
+
values={
|
|
52
|
+
"modelCount": len(available_models),
|
|
53
|
+
"serviceCount": len(service_names),
|
|
54
|
+
"hasVoice": "voice" in features,
|
|
55
|
+
"hasVision": "vision" in features,
|
|
56
|
+
},
|
|
57
|
+
data=capabilities,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
capabilities_provider = Provider(
|
|
62
|
+
name=_spec["name"],
|
|
63
|
+
description=_spec["description"],
|
|
64
|
+
get=get_capabilities,
|
|
65
|
+
dynamic=_spec.get("dynamic", False),
|
|
66
|
+
)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterable
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from elizaos.generated.spec_helpers import require_provider_spec
|
|
7
|
+
from elizaos.types import Provider, ProviderResult
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
11
|
+
|
|
12
|
+
# Get text content from centralized specs
|
|
13
|
+
_spec = require_provider_spec("CHARACTER")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _to_str_list(value: str | Iterable[str] | None) -> list[str]:
|
|
17
|
+
"""
|
|
18
|
+
Normalize a value to list[str].
|
|
19
|
+
|
|
20
|
+
Handles str, list, tuple, set, or any Iterable[str].
|
|
21
|
+
Returns empty list for None.
|
|
22
|
+
|
|
23
|
+
WHY: Character fields can be str | list[str] | tuple[str] depending on
|
|
24
|
+
how they're defined. This helper ensures consistent handling regardless
|
|
25
|
+
of the input type, avoiding issues like tuples being treated as scalars.
|
|
26
|
+
"""
|
|
27
|
+
if value is None:
|
|
28
|
+
return []
|
|
29
|
+
if isinstance(value, str):
|
|
30
|
+
return [value]
|
|
31
|
+
# Any other iterable (list, tuple, set, etc.) - convert to list
|
|
32
|
+
return list(value)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _to_str_list(value: str | Iterable[str] | None) -> list[str]:
|
|
36
|
+
"""
|
|
37
|
+
Normalize a value to list[str].
|
|
38
|
+
|
|
39
|
+
Handles str, list, tuple, set, or any Iterable[str].
|
|
40
|
+
Returns empty list for None.
|
|
41
|
+
|
|
42
|
+
WHY: Character fields can be str | list[str] | tuple[str] depending on
|
|
43
|
+
how they're defined. This helper ensures consistent handling regardless
|
|
44
|
+
of the input type, avoiding issues like tuples being treated as scalars.
|
|
45
|
+
"""
|
|
46
|
+
if value is None:
|
|
47
|
+
return []
|
|
48
|
+
if isinstance(value, str):
|
|
49
|
+
return [value]
|
|
50
|
+
# Any other iterable (list, tuple, set, etc.) - convert to list
|
|
51
|
+
return list(value)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
async def get_character_context(
|
|
55
|
+
runtime: IAgentRuntime,
|
|
56
|
+
message: Memory,
|
|
57
|
+
state: State | None = None,
|
|
58
|
+
) -> ProviderResult:
|
|
59
|
+
character = runtime.character
|
|
60
|
+
|
|
61
|
+
sections: list[str] = []
|
|
62
|
+
|
|
63
|
+
sections.append(f"# Agent: {character.name}")
|
|
64
|
+
|
|
65
|
+
bio = getattr(character, "bio", None)
|
|
66
|
+
if bio:
|
|
67
|
+
bio_list = _to_str_list(bio)
|
|
68
|
+
sections.append(f"\n## Bio\n{chr(10).join(bio_list)}")
|
|
69
|
+
|
|
70
|
+
adjectives = getattr(character, "adjectives", None)
|
|
71
|
+
if adjectives:
|
|
72
|
+
adjectives_list = _to_str_list(adjectives)
|
|
73
|
+
sections.append(f"\n## Personality Traits\n{', '.join(adjectives_list)}")
|
|
74
|
+
|
|
75
|
+
# lore is optional and may not exist on all Character instances
|
|
76
|
+
lore = getattr(character, "lore", None)
|
|
77
|
+
if lore:
|
|
78
|
+
lore_list = _to_str_list(lore)
|
|
79
|
+
sections.append(f"\n## Background\n{chr(10).join(lore_list)}")
|
|
80
|
+
|
|
81
|
+
topics = getattr(character, "topics", None)
|
|
82
|
+
if topics:
|
|
83
|
+
topics_list = _to_str_list(topics)
|
|
84
|
+
sections.append(f"\n## Knowledge Areas\n{', '.join(topics_list)}")
|
|
85
|
+
|
|
86
|
+
style = getattr(character, "style", None)
|
|
87
|
+
if style:
|
|
88
|
+
style_sections: list[str] = []
|
|
89
|
+
style_all = getattr(style, "all", None)
|
|
90
|
+
if style_all:
|
|
91
|
+
all_style = _to_str_list(style_all)
|
|
92
|
+
style_sections.append(f"General: {', '.join(all_style)}")
|
|
93
|
+
style_chat = getattr(style, "chat", None)
|
|
94
|
+
if style_chat:
|
|
95
|
+
chat_style = _to_str_list(style_chat)
|
|
96
|
+
style_sections.append(f"Chat: {', '.join(chat_style)}")
|
|
97
|
+
style_post = getattr(style, "post", None)
|
|
98
|
+
if style_post:
|
|
99
|
+
post_style = _to_str_list(style_post)
|
|
100
|
+
style_sections.append(f"Posts: {', '.join(post_style)}")
|
|
101
|
+
if style_sections:
|
|
102
|
+
sections.append("\n## Communication Style\n" + "\n".join(style_sections))
|
|
103
|
+
|
|
104
|
+
context_text = "\n".join(sections)
|
|
105
|
+
|
|
106
|
+
# Use variables retrieved via getattr above to avoid AttributeError
|
|
107
|
+
# if these optional attributes are missing from the character object
|
|
108
|
+
return ProviderResult(
|
|
109
|
+
text=context_text,
|
|
110
|
+
values={
|
|
111
|
+
"agentName": character.name,
|
|
112
|
+
"hasCharacter": True,
|
|
113
|
+
},
|
|
114
|
+
data={
|
|
115
|
+
"name": character.name,
|
|
116
|
+
"bio": bio,
|
|
117
|
+
"adjectives": adjectives,
|
|
118
|
+
"topics": topics,
|
|
119
|
+
},
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
character_provider = Provider(
|
|
124
|
+
name=_spec["name"],
|
|
125
|
+
description=_spec["description"],
|
|
126
|
+
get=get_character_context,
|
|
127
|
+
dynamic=_spec.get("dynamic", False),
|
|
128
|
+
)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.generated.spec_helpers import require_provider_spec
|
|
6
|
+
from elizaos.types import Provider, ProviderResult
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
10
|
+
|
|
11
|
+
# Get text content from centralized specs
|
|
12
|
+
_spec = require_provider_spec("CHOICE")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def format_choice(index: int, choice: dict[str, str]) -> str:
|
|
16
|
+
label = choice.get("label", f"Option {index + 1}")
|
|
17
|
+
description = choice.get("description", "")
|
|
18
|
+
value = choice.get("value", str(index))
|
|
19
|
+
|
|
20
|
+
if description:
|
|
21
|
+
return f"{index + 1}. [{value}] {label}: {description}"
|
|
22
|
+
return f"{index + 1}. [{value}] {label}"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
async def get_choice_options(
|
|
26
|
+
runtime: IAgentRuntime,
|
|
27
|
+
message: Memory,
|
|
28
|
+
state: State | None = None,
|
|
29
|
+
) -> ProviderResult:
|
|
30
|
+
choices: list[dict[str, str]] = []
|
|
31
|
+
|
|
32
|
+
if message.content and hasattr(message.content, "choices"):
|
|
33
|
+
raw_choices = message.content.choices or []
|
|
34
|
+
for choice in raw_choices:
|
|
35
|
+
if isinstance(choice, dict):
|
|
36
|
+
choices.append(choice)
|
|
37
|
+
elif isinstance(choice, str):
|
|
38
|
+
choices.append({"label": choice, "value": choice})
|
|
39
|
+
|
|
40
|
+
if state and hasattr(state, "choices"):
|
|
41
|
+
state_choices = state.choices or []
|
|
42
|
+
for choice in state_choices:
|
|
43
|
+
if isinstance(choice, dict):
|
|
44
|
+
choices.append(choice)
|
|
45
|
+
elif isinstance(choice, str):
|
|
46
|
+
choices.append({"label": choice, "value": choice})
|
|
47
|
+
|
|
48
|
+
if not choices:
|
|
49
|
+
return ProviderResult(
|
|
50
|
+
text="",
|
|
51
|
+
values={"hasChoices": False, "choiceCount": 0},
|
|
52
|
+
data={"choices": []},
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
formatted_choices = "\n".join(format_choice(i, choice) for i, choice in enumerate(choices))
|
|
56
|
+
|
|
57
|
+
text = f"# Available Choices\n{formatted_choices}"
|
|
58
|
+
|
|
59
|
+
return ProviderResult(
|
|
60
|
+
text=text,
|
|
61
|
+
values={
|
|
62
|
+
"hasChoices": True,
|
|
63
|
+
"choiceCount": len(choices),
|
|
64
|
+
"choiceLabels": [c.get("label", "") for c in choices],
|
|
65
|
+
},
|
|
66
|
+
data={
|
|
67
|
+
"choices": choices,
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
choice_provider = Provider(
|
|
73
|
+
name=_spec["name"],
|
|
74
|
+
description=_spec["description"],
|
|
75
|
+
get=get_choice_options,
|
|
76
|
+
dynamic=_spec.get("dynamic", True),
|
|
77
|
+
)
|