@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,263 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from google.protobuf.json_format import MessageToDict
|
|
6
|
+
|
|
7
|
+
from elizaos.action_docs import get_canonical_action_example_calls
|
|
8
|
+
from elizaos.generated.spec_helpers import require_provider_spec
|
|
9
|
+
from elizaos.types import Provider, ProviderResult
|
|
10
|
+
from elizaos.types.components import ActionExample
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from elizaos.types import (
|
|
14
|
+
Action,
|
|
15
|
+
ActionParameter,
|
|
16
|
+
ActionParameterSchema,
|
|
17
|
+
IAgentRuntime,
|
|
18
|
+
Memory,
|
|
19
|
+
State,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# Get text content from centralized specs
|
|
23
|
+
_spec = require_provider_spec("ACTIONS")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def format_action_names(actions: list[Action]) -> str:
|
|
27
|
+
return ", ".join(action.name for action in actions)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _format_parameter_type(schema: ActionParameterSchema) -> str:
|
|
31
|
+
if schema.type == "number" and (schema.minimum is not None or schema.maximum is not None):
|
|
32
|
+
min_val = schema.minimum if schema.minimum is not None else "∞"
|
|
33
|
+
max_val = schema.maximum if schema.maximum is not None else "∞"
|
|
34
|
+
return f"number [{min_val}-{max_val}]"
|
|
35
|
+
return schema.type
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _get_param_schema(param: ActionParameter) -> object:
|
|
39
|
+
"""Get schema from ActionParameter, handling both Pydantic and protobuf variants."""
|
|
40
|
+
return getattr(param, "schema_def", None) or getattr(param, "schema", None)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _format_action_parameters(parameters: list[ActionParameter]) -> str:
|
|
44
|
+
lines: list[str] = []
|
|
45
|
+
for param in parameters:
|
|
46
|
+
schema = _get_param_schema(param)
|
|
47
|
+
if schema is None:
|
|
48
|
+
lines.append(f" - {param.name}: {param.description}")
|
|
49
|
+
continue
|
|
50
|
+
required_str = " (required)" if param.required else " (optional)"
|
|
51
|
+
type_str = _format_parameter_type(schema)
|
|
52
|
+
default_val = getattr(schema, "default", None) or getattr(schema, "default_value", None)
|
|
53
|
+
default_str = f" [default: {default_val}]" if default_val else ""
|
|
54
|
+
enum_vals = getattr(schema, "enum", None) or getattr(schema, "enum_values", None)
|
|
55
|
+
enum_str = f" [values: {', '.join(enum_vals)}]" if enum_vals else ""
|
|
56
|
+
examples_str = (
|
|
57
|
+
f" [examples: {', '.join(repr(v) for v in param.examples)}]"
|
|
58
|
+
if getattr(param, "examples", None)
|
|
59
|
+
else ""
|
|
60
|
+
)
|
|
61
|
+
lines.append(
|
|
62
|
+
f" - {param.name}{required_str}: {param.description} ({type_str}{enum_str}{default_str}{examples_str})"
|
|
63
|
+
)
|
|
64
|
+
return "\n".join(lines)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def format_actions(actions: list[Action]) -> str:
|
|
68
|
+
lines: list[str] = []
|
|
69
|
+
for action in actions:
|
|
70
|
+
line = f"- **{action.name}**: {action.description or 'No description'}"
|
|
71
|
+
if action.parameters:
|
|
72
|
+
params_text = _format_action_parameters(action.parameters)
|
|
73
|
+
if params_text:
|
|
74
|
+
line += f"\n Parameters:\n{params_text}"
|
|
75
|
+
lines.append(line)
|
|
76
|
+
return "\n".join(lines)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _replace_name_placeholders(text: str) -> str:
|
|
80
|
+
names = ["Alex", "Jordan", "Sam", "Taylor", "Riley"]
|
|
81
|
+
for i, name in enumerate(names, start=1):
|
|
82
|
+
text = text.replace(f"{{{{name{i}}}}}", name)
|
|
83
|
+
return text
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def format_action_examples(actions: list[Action], max_examples: int = 10) -> str:
|
|
87
|
+
"""
|
|
88
|
+
Format a deterministic subset of action examples for prompt context.
|
|
89
|
+
|
|
90
|
+
Deterministic ordering is important to keep tests stable and avoid prompt churn.
|
|
91
|
+
"""
|
|
92
|
+
if max_examples <= 0:
|
|
93
|
+
return ""
|
|
94
|
+
|
|
95
|
+
examples: list[list[ActionExample]] = []
|
|
96
|
+
for action in sorted(actions, key=lambda a: a.name):
|
|
97
|
+
if not action.examples:
|
|
98
|
+
continue
|
|
99
|
+
for ex in action.examples:
|
|
100
|
+
if isinstance(ex, list) and ex:
|
|
101
|
+
examples.append(ex)
|
|
102
|
+
if len(examples) >= max_examples:
|
|
103
|
+
break
|
|
104
|
+
if len(examples) >= max_examples:
|
|
105
|
+
break
|
|
106
|
+
|
|
107
|
+
if not examples:
|
|
108
|
+
return ""
|
|
109
|
+
|
|
110
|
+
blocks: list[str] = []
|
|
111
|
+
for ex in examples:
|
|
112
|
+
lines: list[str] = []
|
|
113
|
+
for msg in ex:
|
|
114
|
+
msg_text = msg.content.text if msg.content and msg.content.text else ""
|
|
115
|
+
lines.append(f"{msg.name}: {_replace_name_placeholders(msg_text)}")
|
|
116
|
+
blocks.append("\n".join(lines))
|
|
117
|
+
|
|
118
|
+
return "\n\n".join(blocks)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _escape_xml_text(text: str) -> str:
|
|
122
|
+
return text.replace("&", "&").replace("<", "<").replace(">", ">")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def format_action_call_examples(actions: list[Action], max_examples: int = 5) -> str:
|
|
126
|
+
"""
|
|
127
|
+
Format canonical action-call examples (including optional <params> blocks).
|
|
128
|
+
|
|
129
|
+
Deterministic ordering is important to keep tests stable and avoid prompt churn.
|
|
130
|
+
"""
|
|
131
|
+
if max_examples <= 0:
|
|
132
|
+
return ""
|
|
133
|
+
|
|
134
|
+
blocks: list[str] = []
|
|
135
|
+
for action in sorted(actions, key=lambda a: a.name):
|
|
136
|
+
calls = get_canonical_action_example_calls(action.name)
|
|
137
|
+
for call in calls:
|
|
138
|
+
user = call.get("user")
|
|
139
|
+
action_names = call.get("actions")
|
|
140
|
+
params = call.get("params")
|
|
141
|
+
|
|
142
|
+
if not isinstance(user, str) or not isinstance(action_names, list):
|
|
143
|
+
continue
|
|
144
|
+
if not all(isinstance(a, str) for a in action_names):
|
|
145
|
+
continue
|
|
146
|
+
|
|
147
|
+
actions_xml = "\n".join(
|
|
148
|
+
f" <action>{_escape_xml_text(a)}</action>" for a in action_names
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
params_xml = ""
|
|
152
|
+
if isinstance(params, dict):
|
|
153
|
+
blocks_xml: list[str] = []
|
|
154
|
+
for act_name, act_params in params.items():
|
|
155
|
+
if not isinstance(act_name, str) or not isinstance(act_params, dict):
|
|
156
|
+
continue
|
|
157
|
+
inner: list[str] = []
|
|
158
|
+
for k, v in act_params.items():
|
|
159
|
+
if not isinstance(k, str):
|
|
160
|
+
continue
|
|
161
|
+
if isinstance(v, str):
|
|
162
|
+
raw = v
|
|
163
|
+
elif v is None:
|
|
164
|
+
raw = "null"
|
|
165
|
+
elif isinstance(v, bool):
|
|
166
|
+
raw = "true" if v else "false"
|
|
167
|
+
elif isinstance(v, (int, float)):
|
|
168
|
+
raw = str(v)
|
|
169
|
+
else:
|
|
170
|
+
raw = repr(v)
|
|
171
|
+
inner.append(f" <{k}>{_escape_xml_text(raw)}</{k}>")
|
|
172
|
+
blocks_xml.append(f" <{act_name}>\n" + "\n".join(inner) + f"\n </{act_name}>")
|
|
173
|
+
if blocks_xml:
|
|
174
|
+
params_xml = "\n<params>\n" + "\n".join(blocks_xml) + "\n</params>"
|
|
175
|
+
|
|
176
|
+
blocks.append(
|
|
177
|
+
f"User: {user}\nAssistant:\n<actions>\n{actions_xml}\n</actions>{params_xml}"
|
|
178
|
+
)
|
|
179
|
+
if len(blocks) >= max_examples:
|
|
180
|
+
return "\n\n".join(blocks)
|
|
181
|
+
|
|
182
|
+
return "\n\n".join(blocks)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
async def get_actions(
|
|
186
|
+
runtime: IAgentRuntime,
|
|
187
|
+
message: Memory,
|
|
188
|
+
state: State | None = None,
|
|
189
|
+
) -> ProviderResult:
|
|
190
|
+
validated_actions: list[Action] = []
|
|
191
|
+
|
|
192
|
+
for action in runtime.actions:
|
|
193
|
+
# Support both validate and validate_fn for backwards compatibility
|
|
194
|
+
validate_fn = getattr(action, "validate", None) or getattr(action, "validate_fn", None)
|
|
195
|
+
if validate_fn:
|
|
196
|
+
is_valid = await validate_fn(runtime, message, state)
|
|
197
|
+
if is_valid:
|
|
198
|
+
validated_actions.append(action)
|
|
199
|
+
else:
|
|
200
|
+
# If no validation function, include the action
|
|
201
|
+
validated_actions.append(action)
|
|
202
|
+
|
|
203
|
+
action_names = format_action_names(validated_actions)
|
|
204
|
+
actions_text = format_actions(validated_actions)
|
|
205
|
+
examples_text = format_action_examples(validated_actions, max_examples=10)
|
|
206
|
+
call_examples_text = format_action_call_examples(validated_actions, max_examples=5)
|
|
207
|
+
|
|
208
|
+
text_parts: list[str] = [f"Possible response actions: {action_names}"]
|
|
209
|
+
if actions_text:
|
|
210
|
+
text_parts.append(f"# Available Actions\n{actions_text}")
|
|
211
|
+
if examples_text:
|
|
212
|
+
text_parts.append(f"# Action Examples\n{examples_text}")
|
|
213
|
+
if call_examples_text:
|
|
214
|
+
text_parts.append(f"# Action Call Examples (with <params>)\n{call_examples_text}")
|
|
215
|
+
|
|
216
|
+
return ProviderResult(
|
|
217
|
+
text="\n\n".join(text_parts),
|
|
218
|
+
values={
|
|
219
|
+
"actionNames": action_names,
|
|
220
|
+
"actionCount": len(validated_actions),
|
|
221
|
+
},
|
|
222
|
+
data={
|
|
223
|
+
"actions": [
|
|
224
|
+
{
|
|
225
|
+
"name": a.name,
|
|
226
|
+
"description": a.description,
|
|
227
|
+
"examples": [
|
|
228
|
+
[
|
|
229
|
+
{
|
|
230
|
+
"name": ex.name,
|
|
231
|
+
"content": MessageToDict(
|
|
232
|
+
ex.content, preserving_proto_field_name=False
|
|
233
|
+
),
|
|
234
|
+
}
|
|
235
|
+
for ex in example
|
|
236
|
+
]
|
|
237
|
+
for example in (a.examples or [])
|
|
238
|
+
],
|
|
239
|
+
"parameters": [
|
|
240
|
+
{
|
|
241
|
+
"name": p.name,
|
|
242
|
+
"description": p.description,
|
|
243
|
+
"required": bool(p.required),
|
|
244
|
+
"examples": getattr(p, "examples", None) or [],
|
|
245
|
+
"schema": MessageToDict(p.schema, preserving_proto_field_name=False)
|
|
246
|
+
if hasattr(p, "schema") and p.schema.ByteSize() > 0
|
|
247
|
+
else (getattr(p, "schema_def", None) or None),
|
|
248
|
+
}
|
|
249
|
+
for p in (a.parameters or [])
|
|
250
|
+
],
|
|
251
|
+
}
|
|
252
|
+
for a in validated_actions
|
|
253
|
+
],
|
|
254
|
+
},
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
actions_provider = Provider(
|
|
259
|
+
name=_spec["name"],
|
|
260
|
+
description=_spec["description"],
|
|
261
|
+
get=get_actions,
|
|
262
|
+
position=_spec.get("position", -1),
|
|
263
|
+
)
|
|
@@ -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,62 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.types import Provider, ProviderResult
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def get_capabilities(
|
|
12
|
+
runtime: IAgentRuntime,
|
|
13
|
+
message: Memory,
|
|
14
|
+
state: State | None = None,
|
|
15
|
+
) -> ProviderResult:
|
|
16
|
+
model_types = ["TEXT_LARGE", "TEXT_SMALL", "TEXT_EMBEDDING", "IMAGE", "AUDIO"]
|
|
17
|
+
available_models = [mt for mt in model_types if runtime.has_model(mt)]
|
|
18
|
+
service_names = [s.name for s in runtime.services if hasattr(s, "name")]
|
|
19
|
+
|
|
20
|
+
features: list[str] = []
|
|
21
|
+
if runtime.get_setting("ENABLE_VOICE"):
|
|
22
|
+
features.append("voice")
|
|
23
|
+
if runtime.get_setting("ENABLE_VISION"):
|
|
24
|
+
features.append("vision")
|
|
25
|
+
if runtime.get_setting("ENABLE_MEMORY"):
|
|
26
|
+
features.append("long_term_memory")
|
|
27
|
+
|
|
28
|
+
capabilities: dict[str, list[str] | bool] = {
|
|
29
|
+
"models": available_models,
|
|
30
|
+
"services": service_names,
|
|
31
|
+
"features": features,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
text_parts: list[str] = ["# Agent Capabilities"]
|
|
35
|
+
|
|
36
|
+
if available_models:
|
|
37
|
+
text_parts.append(f"Models: {', '.join(available_models)}")
|
|
38
|
+
|
|
39
|
+
if service_names:
|
|
40
|
+
text_parts.append(f"Services: {', '.join(service_names)}")
|
|
41
|
+
|
|
42
|
+
if features:
|
|
43
|
+
text_parts.append(f"Features: {', '.join(features)}")
|
|
44
|
+
|
|
45
|
+
return ProviderResult(
|
|
46
|
+
text="\n".join(text_parts),
|
|
47
|
+
values={
|
|
48
|
+
"modelCount": len(available_models),
|
|
49
|
+
"serviceCount": len(service_names),
|
|
50
|
+
"hasVoice": "voice" in features,
|
|
51
|
+
"hasVision": "vision" in features,
|
|
52
|
+
},
|
|
53
|
+
data=capabilities,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
capabilities_provider = Provider(
|
|
58
|
+
name="CAPABILITIES",
|
|
59
|
+
description="Agent capabilities including models, services, and features",
|
|
60
|
+
get=get_capabilities,
|
|
61
|
+
dynamic=False,
|
|
62
|
+
)
|
|
@@ -0,0 +1,113 @@
|
|
|
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("CHARACTER")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _resolve_name(text: str, name: str) -> str:
|
|
16
|
+
"""Replace ``{{name}}`` placeholders with the character's name.
|
|
17
|
+
|
|
18
|
+
Supports character template files where the name is injected at render
|
|
19
|
+
time so changing the character's name doesn't require rewriting every
|
|
20
|
+
field.
|
|
21
|
+
"""
|
|
22
|
+
return text.replace("{{name}}", name)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _resolve_name_list(items: list[str], name: str) -> list[str]:
|
|
26
|
+
"""Resolve ``{{name}}`` in every element of a string list."""
|
|
27
|
+
return [_resolve_name(s, name) for s in items]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
async def get_character_context(
|
|
31
|
+
runtime: IAgentRuntime,
|
|
32
|
+
message: Memory,
|
|
33
|
+
state: State | None = None,
|
|
34
|
+
) -> ProviderResult:
|
|
35
|
+
character = runtime.character
|
|
36
|
+
agent_name: str = character.name
|
|
37
|
+
|
|
38
|
+
sections: list[str] = []
|
|
39
|
+
|
|
40
|
+
sections.append(f"# Agent: {agent_name}")
|
|
41
|
+
|
|
42
|
+
if character.bio:
|
|
43
|
+
if isinstance(character.bio, str):
|
|
44
|
+
bio_text = _resolve_name(character.bio, agent_name)
|
|
45
|
+
else:
|
|
46
|
+
bio_text = "\n".join(_resolve_name_list(list(character.bio), agent_name))
|
|
47
|
+
sections.append(f"\n## Bio\n{bio_text}")
|
|
48
|
+
|
|
49
|
+
if character.adjectives:
|
|
50
|
+
adjectives = (
|
|
51
|
+
character.adjectives
|
|
52
|
+
if isinstance(character.adjectives, list)
|
|
53
|
+
else [character.adjectives]
|
|
54
|
+
)
|
|
55
|
+
resolved_adjectives = _resolve_name_list(adjectives, agent_name)
|
|
56
|
+
sections.append(f"\n## Personality Traits\n{', '.join(resolved_adjectives)}")
|
|
57
|
+
|
|
58
|
+
# lore is optional and may not exist on all Character instances
|
|
59
|
+
lore = getattr(character, "lore", None)
|
|
60
|
+
if lore:
|
|
61
|
+
if isinstance(lore, str):
|
|
62
|
+
lore_text = _resolve_name(lore, agent_name)
|
|
63
|
+
else:
|
|
64
|
+
lore_text = "\n".join(_resolve_name_list(list(lore), agent_name))
|
|
65
|
+
sections.append(f"\n## Background\n{lore_text}")
|
|
66
|
+
|
|
67
|
+
if character.topics:
|
|
68
|
+
topics = character.topics if isinstance(character.topics, list) else [character.topics]
|
|
69
|
+
resolved_topics = _resolve_name_list(topics, agent_name)
|
|
70
|
+
sections.append(f"\n## Knowledge Areas\n{', '.join(resolved_topics)}")
|
|
71
|
+
|
|
72
|
+
if character.style:
|
|
73
|
+
style_sections: list[str] = []
|
|
74
|
+
if character.style.all:
|
|
75
|
+
all_style = (
|
|
76
|
+
character.style.all
|
|
77
|
+
if isinstance(character.style.all, list)
|
|
78
|
+
else [character.style.all]
|
|
79
|
+
)
|
|
80
|
+
resolved_all = _resolve_name_list(all_style, agent_name)
|
|
81
|
+
style_sections.append(f"General: {', '.join(resolved_all)}")
|
|
82
|
+
if character.style.chat:
|
|
83
|
+
chat_style = (
|
|
84
|
+
character.style.chat
|
|
85
|
+
if isinstance(character.style.chat, list)
|
|
86
|
+
else [character.style.chat]
|
|
87
|
+
)
|
|
88
|
+
resolved_chat = _resolve_name_list(chat_style, agent_name)
|
|
89
|
+
style_sections.append(f"Chat: {', '.join(resolved_chat)}")
|
|
90
|
+
if character.style.post:
|
|
91
|
+
post_style = (
|
|
92
|
+
character.style.post
|
|
93
|
+
if isinstance(character.style.post, list)
|
|
94
|
+
else [character.style.post]
|
|
95
|
+
)
|
|
96
|
+
resolved_post = _resolve_name_list(post_style, agent_name)
|
|
97
|
+
style_sections.append(f"Posts: {', '.join(resolved_post)}")
|
|
98
|
+
if style_sections:
|
|
99
|
+
sections.append("\n## Communication Style\n" + "\n".join(style_sections))
|
|
100
|
+
|
|
101
|
+
context_text = "\n".join(sections)
|
|
102
|
+
|
|
103
|
+
# Note: Protobuf ProviderResult.data is a Struct which has limited type support.
|
|
104
|
+
# The text already contains all the information needed for the agent context.
|
|
105
|
+
return ProviderResult(text=context_text)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
character_provider = Provider(
|
|
109
|
+
name=_spec["name"],
|
|
110
|
+
description=_spec["description"],
|
|
111
|
+
get=get_character_context,
|
|
112
|
+
dynamic=_spec.get("dynamic", False),
|
|
113
|
+
)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.types import Provider, ProviderResult
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def format_choice(index: int, choice: dict[str, str]) -> str:
|
|
12
|
+
label = choice.get("label", f"Option {index + 1}")
|
|
13
|
+
description = choice.get("description", "")
|
|
14
|
+
value = choice.get("value", str(index))
|
|
15
|
+
|
|
16
|
+
if description:
|
|
17
|
+
return f"{index + 1}. [{value}] {label}: {description}"
|
|
18
|
+
return f"{index + 1}. [{value}] {label}"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def get_choice_options(
|
|
22
|
+
runtime: IAgentRuntime,
|
|
23
|
+
message: Memory,
|
|
24
|
+
state: State | None = None,
|
|
25
|
+
) -> ProviderResult:
|
|
26
|
+
choices: list[dict[str, str]] = []
|
|
27
|
+
|
|
28
|
+
if message.content and hasattr(message.content, "choices"):
|
|
29
|
+
raw_choices = message.content.choices or []
|
|
30
|
+
for choice in raw_choices:
|
|
31
|
+
if isinstance(choice, dict):
|
|
32
|
+
choices.append(choice)
|
|
33
|
+
elif isinstance(choice, str):
|
|
34
|
+
choices.append({"label": choice, "value": choice})
|
|
35
|
+
|
|
36
|
+
if state and hasattr(state, "choices"):
|
|
37
|
+
state_choices = state.choices or []
|
|
38
|
+
for choice in state_choices:
|
|
39
|
+
if isinstance(choice, dict):
|
|
40
|
+
choices.append(choice)
|
|
41
|
+
elif isinstance(choice, str):
|
|
42
|
+
choices.append({"label": choice, "value": choice})
|
|
43
|
+
|
|
44
|
+
if not choices:
|
|
45
|
+
return ProviderResult(
|
|
46
|
+
text="",
|
|
47
|
+
values={"hasChoices": False, "choiceCount": 0},
|
|
48
|
+
data={"choices": []},
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
formatted_choices = "\n".join(format_choice(i, choice) for i, choice in enumerate(choices))
|
|
52
|
+
|
|
53
|
+
text = f"# Available Choices\n{formatted_choices}"
|
|
54
|
+
|
|
55
|
+
return ProviderResult(
|
|
56
|
+
text=text,
|
|
57
|
+
values={
|
|
58
|
+
"hasChoices": True,
|
|
59
|
+
"choiceCount": len(choices),
|
|
60
|
+
"choiceLabels": [c.get("label", "") for c in choices],
|
|
61
|
+
},
|
|
62
|
+
data={
|
|
63
|
+
"choices": choices,
|
|
64
|
+
},
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
choice_provider = Provider(
|
|
69
|
+
name="CHOICE",
|
|
70
|
+
description="Available choice options for selection",
|
|
71
|
+
get=get_choice_options,
|
|
72
|
+
dynamic=True,
|
|
73
|
+
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from elizaos.types import Provider, ProviderResult
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def get_context_bench(
|
|
12
|
+
runtime: IAgentRuntime,
|
|
13
|
+
message: Memory,
|
|
14
|
+
state: State | None = None,
|
|
15
|
+
) -> ProviderResult:
|
|
16
|
+
_ = runtime
|
|
17
|
+
_ = state
|
|
18
|
+
meta = getattr(message, "metadata", None)
|
|
19
|
+
bench_ctx = None
|
|
20
|
+
if meta is not None:
|
|
21
|
+
maybe = getattr(meta, "benchmarkContext", None)
|
|
22
|
+
if isinstance(maybe, str) and maybe.strip():
|
|
23
|
+
bench_ctx = maybe.strip()
|
|
24
|
+
|
|
25
|
+
if not bench_ctx:
|
|
26
|
+
return ProviderResult(
|
|
27
|
+
text="",
|
|
28
|
+
values={"benchmark_has_context": False},
|
|
29
|
+
data={},
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
return ProviderResult(
|
|
33
|
+
text=f"# Benchmark Context\n{bench_ctx}",
|
|
34
|
+
values={"benchmark_has_context": True},
|
|
35
|
+
data={"benchmarkContext": bench_ctx},
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
context_bench_provider = Provider(
|
|
40
|
+
name="CONTEXT_BENCH",
|
|
41
|
+
description="Benchmark/task context injected by a benchmark harness",
|
|
42
|
+
get=get_context_bench,
|
|
43
|
+
dynamic=True,
|
|
44
|
+
)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import UTC, datetime
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from elizaos.generated.spec_helpers import require_provider_spec
|
|
7
|
+
from elizaos.types import Provider, ProviderResult
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from elizaos.types import IAgentRuntime, Memory, State
|
|
11
|
+
|
|
12
|
+
# Get text content from centralized specs
|
|
13
|
+
_spec = require_provider_spec("CURRENT_TIME")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def get_current_time_context(
|
|
17
|
+
runtime: IAgentRuntime,
|
|
18
|
+
message: Memory,
|
|
19
|
+
state: State | None = None,
|
|
20
|
+
) -> ProviderResult:
|
|
21
|
+
_ = runtime, message, state
|
|
22
|
+
|
|
23
|
+
now = datetime.now(UTC)
|
|
24
|
+
|
|
25
|
+
iso_timestamp = now.isoformat()
|
|
26
|
+
human_readable = now.strftime("%A, %B %d, %Y at %H:%M:%S UTC")
|
|
27
|
+
date_only = now.strftime("%Y-%m-%d")
|
|
28
|
+
time_only = now.strftime("%H:%M:%S")
|
|
29
|
+
day_of_week = now.strftime("%A")
|
|
30
|
+
unix_timestamp = int(now.timestamp())
|
|
31
|
+
|
|
32
|
+
context_text = f"# Current Time\n- Date: {date_only}\n- Time: {time_only} UTC\n- Day: {day_of_week}\n- Full: {human_readable}\n- ISO: {iso_timestamp}"
|
|
33
|
+
|
|
34
|
+
return ProviderResult(
|
|
35
|
+
text=context_text,
|
|
36
|
+
values={
|
|
37
|
+
"currentTime": iso_timestamp,
|
|
38
|
+
"currentDate": date_only,
|
|
39
|
+
"dayOfWeek": day_of_week,
|
|
40
|
+
"unixTimestamp": unix_timestamp,
|
|
41
|
+
},
|
|
42
|
+
data={
|
|
43
|
+
"iso": iso_timestamp,
|
|
44
|
+
"date": date_only,
|
|
45
|
+
"time": time_only,
|
|
46
|
+
"dayOfWeek": day_of_week,
|
|
47
|
+
"humanReadable": human_readable,
|
|
48
|
+
"unixTimestamp": unix_timestamp,
|
|
49
|
+
},
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
current_time_provider = Provider(
|
|
54
|
+
name=_spec["name"],
|
|
55
|
+
description=_spec["description"],
|
|
56
|
+
get=get_current_time_context,
|
|
57
|
+
dynamic=_spec.get("dynamic", True),
|
|
58
|
+
)
|