@elizaos/python 2.0.0-alpha.10 → 2.0.0-alpha.11
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/elizaos/__init__.py +0 -1
- package/elizaos/advanced_capabilities/actions/schedule_follow_up.py +70 -15
- package/elizaos/advanced_capabilities/actions/send_message.py +9 -184
- package/elizaos/advanced_memory/memory_service.py +15 -17
- package/elizaos/advanced_planning/planning_service.py +26 -14
- package/elizaos/basic_capabilities/providers/actions.py +118 -29
- package/elizaos/basic_capabilities/providers/character.py +19 -21
- package/elizaos/basic_capabilities/providers/current_time.py +7 -4
- package/elizaos/basic_capabilities/providers/time.py +7 -4
- package/elizaos/bootstrap/__init__.py +21 -2
- package/elizaos/bootstrap/actions/schedule_follow_up.py +65 -7
- package/elizaos/bootstrap/actions/send_message.py +162 -15
- package/elizaos/bootstrap/autonomy/service.py +230 -28
- package/elizaos/bootstrap/providers/actions.py +118 -27
- package/elizaos/bootstrap/providers/agent_settings.py +1 -0
- package/elizaos/bootstrap/providers/attachments.py +1 -0
- package/elizaos/bootstrap/providers/capabilities.py +1 -0
- package/elizaos/bootstrap/providers/character.py +1 -0
- package/elizaos/bootstrap/providers/choice.py +1 -0
- package/elizaos/bootstrap/providers/contacts.py +1 -0
- package/elizaos/bootstrap/providers/current_time.py +8 -2
- package/elizaos/bootstrap/providers/entities.py +1 -0
- package/elizaos/bootstrap/providers/evaluators.py +1 -0
- package/elizaos/bootstrap/providers/facts.py +1 -0
- package/elizaos/bootstrap/providers/follow_ups.py +1 -0
- package/elizaos/bootstrap/providers/knowledge.py +1 -0
- package/elizaos/bootstrap/providers/providers_list.py +1 -0
- package/elizaos/bootstrap/providers/relationships.py +1 -0
- package/elizaos/bootstrap/providers/roles.py +1 -0
- package/elizaos/bootstrap/providers/settings.py +1 -0
- package/elizaos/bootstrap/providers/time.py +8 -4
- package/elizaos/bootstrap/providers/world.py +1 -0
- package/elizaos/deterministic.py +193 -0
- package/elizaos/generated/__init__.py +1 -0
- package/elizaos/generated/action_docs.py +3181 -0
- package/elizaos/generated/spec_helpers.py +175 -0
- package/elizaos/media/mime.py +2 -2
- package/elizaos/media/search.py +23 -23
- package/elizaos/runtime.py +152 -39
- package/elizaos/services/message_service.py +2 -6
- package/elizaos/types/components.py +2 -2
- package/elizaos/types/generated/__init__.py +12 -0
- package/elizaos/types/generated/eliza/v1/agent_pb2.py +63 -0
- package/elizaos/types/generated/eliza/v1/agent_pb2.pyi +161 -0
- package/elizaos/types/generated/eliza/v1/components_pb2.py +65 -0
- package/elizaos/types/generated/eliza/v1/components_pb2.pyi +160 -0
- package/elizaos/types/generated/eliza/v1/database_pb2.py +78 -0
- package/elizaos/types/generated/eliza/v1/database_pb2.pyi +305 -0
- package/elizaos/types/generated/eliza/v1/environment_pb2.py +58 -0
- package/elizaos/types/generated/eliza/v1/environment_pb2.pyi +135 -0
- package/elizaos/types/generated/eliza/v1/events_pb2.py +82 -0
- package/elizaos/types/generated/eliza/v1/events_pb2.pyi +322 -0
- package/elizaos/types/generated/eliza/v1/ipc_pb2.py +113 -0
- package/elizaos/types/generated/eliza/v1/ipc_pb2.pyi +367 -0
- package/elizaos/types/generated/eliza/v1/knowledge_pb2.py +41 -0
- package/elizaos/types/generated/eliza/v1/knowledge_pb2.pyi +26 -0
- package/elizaos/types/generated/eliza/v1/memory_pb2.py +55 -0
- package/elizaos/types/generated/eliza/v1/memory_pb2.pyi +111 -0
- package/elizaos/types/generated/eliza/v1/message_service_pb2.py +48 -0
- package/elizaos/types/generated/eliza/v1/message_service_pb2.pyi +69 -0
- package/elizaos/types/generated/eliza/v1/messaging_pb2.py +51 -0
- package/elizaos/types/generated/eliza/v1/messaging_pb2.pyi +97 -0
- package/elizaos/types/generated/eliza/v1/model_pb2.py +84 -0
- package/elizaos/types/generated/eliza/v1/model_pb2.pyi +280 -0
- package/elizaos/types/generated/eliza/v1/payment_pb2.py +44 -0
- package/elizaos/types/generated/eliza/v1/payment_pb2.pyi +70 -0
- package/elizaos/types/generated/eliza/v1/plugin_pb2.py +68 -0
- package/elizaos/types/generated/eliza/v1/plugin_pb2.pyi +145 -0
- package/elizaos/types/generated/eliza/v1/primitives_pb2.py +48 -0
- package/elizaos/types/generated/eliza/v1/primitives_pb2.pyi +92 -0
- package/elizaos/types/generated/eliza/v1/prompts_pb2.py +52 -0
- package/elizaos/types/generated/eliza/v1/prompts_pb2.pyi +74 -0
- package/elizaos/types/generated/eliza/v1/service_interfaces_pb2.py +211 -0
- package/elizaos/types/generated/eliza/v1/service_interfaces_pb2.pyi +1296 -0
- package/elizaos/types/generated/eliza/v1/service_pb2.py +42 -0
- package/elizaos/types/generated/eliza/v1/service_pb2.pyi +69 -0
- package/elizaos/types/generated/eliza/v1/settings_pb2.py +58 -0
- package/elizaos/types/generated/eliza/v1/settings_pb2.pyi +85 -0
- package/elizaos/types/generated/eliza/v1/state_pb2.py +60 -0
- package/elizaos/types/generated/eliza/v1/state_pb2.pyi +114 -0
- package/elizaos/types/generated/eliza/v1/task_pb2.py +42 -0
- package/elizaos/types/generated/eliza/v1/task_pb2.pyi +58 -0
- package/elizaos/types/generated/eliza/v1/tee_pb2.py +52 -0
- package/elizaos/types/generated/eliza/v1/tee_pb2.pyi +90 -0
- package/elizaos/types/generated/eliza/v1/testing_pb2.py +39 -0
- package/elizaos/types/generated/eliza/v1/testing_pb2.pyi +23 -0
- package/elizaos/types/model.py +3 -0
- package/elizaos/types/runtime.py +1 -1
- package/package.json +3 -2
- package/tests/test_action_parameters.py +2 -3
- package/tests/test_advanced_memory_behavior.py +0 -2
- package/tests/test_advanced_memory_flag.py +0 -2
- package/tests/test_advanced_planning_behavior.py +11 -5
- package/tests/test_autonomy.py +11 -1
- package/tests/test_runtime.py +8 -17
- package/tests/test_schedule_follow_up_action.py +260 -0
- package/tests/test_send_message_action_targets.py +114 -0
- package/tests/test_settings_crypto.py +0 -2
- package/uv.lock +1565 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Helper functions to lookup action/provider/evaluator specs by name.
|
|
3
|
+
These allow language-specific implementations to import their text content
|
|
4
|
+
(description, similes, examples) from the centralized specs.
|
|
5
|
+
|
|
6
|
+
DO NOT EDIT the spec data - update packages/prompts/specs/** and regenerate.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .action_docs import (
|
|
10
|
+
ActionDoc,
|
|
11
|
+
EvaluatorDoc,
|
|
12
|
+
ProviderDoc,
|
|
13
|
+
all_action_docs,
|
|
14
|
+
all_evaluator_docs,
|
|
15
|
+
all_provider_docs,
|
|
16
|
+
core_action_docs,
|
|
17
|
+
core_evaluator_docs,
|
|
18
|
+
core_provider_docs,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _get_items(doc: object, key: str) -> list[dict[str, object]]:
|
|
23
|
+
if not isinstance(doc, dict):
|
|
24
|
+
return []
|
|
25
|
+
raw = doc.get(key)
|
|
26
|
+
if not isinstance(raw, list):
|
|
27
|
+
return []
|
|
28
|
+
return [item for item in raw if isinstance(item, dict)]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Build lookup dicts for O(1) access
|
|
32
|
+
_core_action_map: dict[str, ActionDoc] = {}
|
|
33
|
+
for action in _get_items(core_action_docs, "actions"):
|
|
34
|
+
name = action.get("name")
|
|
35
|
+
if isinstance(name, str):
|
|
36
|
+
_core_action_map[name] = action # type: ignore[assignment]
|
|
37
|
+
|
|
38
|
+
_all_action_map: dict[str, ActionDoc] = {}
|
|
39
|
+
for action in _get_items(all_action_docs, "actions"):
|
|
40
|
+
name = action.get("name")
|
|
41
|
+
if isinstance(name, str):
|
|
42
|
+
_all_action_map[name] = action # type: ignore[assignment]
|
|
43
|
+
|
|
44
|
+
_core_provider_map: dict[str, ProviderDoc] = {}
|
|
45
|
+
for provider in _get_items(core_provider_docs, "providers"):
|
|
46
|
+
name = provider.get("name")
|
|
47
|
+
if isinstance(name, str):
|
|
48
|
+
_core_provider_map[name] = provider # type: ignore[assignment]
|
|
49
|
+
|
|
50
|
+
_all_provider_map: dict[str, ProviderDoc] = {}
|
|
51
|
+
for provider in _get_items(all_provider_docs, "providers"):
|
|
52
|
+
name = provider.get("name")
|
|
53
|
+
if isinstance(name, str):
|
|
54
|
+
_all_provider_map[name] = provider # type: ignore[assignment]
|
|
55
|
+
|
|
56
|
+
_core_evaluator_map: dict[str, EvaluatorDoc] = {}
|
|
57
|
+
for evaluator in _get_items(core_evaluator_docs, "evaluators"):
|
|
58
|
+
name = evaluator.get("name")
|
|
59
|
+
if isinstance(name, str):
|
|
60
|
+
_core_evaluator_map[name] = evaluator # type: ignore[assignment]
|
|
61
|
+
|
|
62
|
+
_all_evaluator_map: dict[str, EvaluatorDoc] = {}
|
|
63
|
+
for evaluator in _get_items(all_evaluator_docs, "evaluators"):
|
|
64
|
+
name = evaluator.get("name")
|
|
65
|
+
if isinstance(name, str):
|
|
66
|
+
_all_evaluator_map[name] = evaluator # type: ignore[assignment]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def get_action_spec(name: str) -> ActionDoc | None:
|
|
70
|
+
"""
|
|
71
|
+
Get an action spec by name from the core specs.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
name: The action name (e.g., "REPLY", "IGNORE")
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
The action spec or None if not found
|
|
78
|
+
"""
|
|
79
|
+
return _core_action_map.get(name) or _all_action_map.get(name)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def require_action_spec(name: str) -> ActionDoc:
|
|
83
|
+
"""
|
|
84
|
+
Get an action spec by name, raising if not found.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
name: The action name
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
The action spec
|
|
91
|
+
|
|
92
|
+
Raises:
|
|
93
|
+
ValueError: If the action is not found
|
|
94
|
+
"""
|
|
95
|
+
spec = get_action_spec(name)
|
|
96
|
+
if spec is None:
|
|
97
|
+
raise ValueError(f"Action spec not found: {name}")
|
|
98
|
+
return spec
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def get_provider_spec(name: str) -> ProviderDoc | None:
|
|
102
|
+
"""
|
|
103
|
+
Get a provider spec by name from the core specs.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
name: The provider name (e.g., "CHARACTER", "TIME")
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
The provider spec or None if not found
|
|
110
|
+
"""
|
|
111
|
+
return _core_provider_map.get(name) or _all_provider_map.get(name)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def require_provider_spec(name: str) -> ProviderDoc:
|
|
115
|
+
"""
|
|
116
|
+
Get a provider spec by name, raising if not found.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
name: The provider name
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
The provider spec
|
|
123
|
+
|
|
124
|
+
Raises:
|
|
125
|
+
ValueError: If the provider is not found
|
|
126
|
+
"""
|
|
127
|
+
spec = get_provider_spec(name)
|
|
128
|
+
if spec is None:
|
|
129
|
+
raise ValueError(f"Provider spec not found: {name}")
|
|
130
|
+
return spec
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def get_evaluator_spec(name: str) -> EvaluatorDoc | None:
|
|
134
|
+
"""
|
|
135
|
+
Get an evaluator spec by name from the core specs.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
name: The evaluator name (e.g., "REFLECTION")
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
The evaluator spec or None if not found
|
|
142
|
+
"""
|
|
143
|
+
return _core_evaluator_map.get(name) or _all_evaluator_map.get(name)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def require_evaluator_spec(name: str) -> EvaluatorDoc:
|
|
147
|
+
"""
|
|
148
|
+
Get an evaluator spec by name, raising if not found.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
name: The evaluator name
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
The evaluator spec
|
|
155
|
+
|
|
156
|
+
Raises:
|
|
157
|
+
ValueError: If the evaluator is not found
|
|
158
|
+
"""
|
|
159
|
+
spec = get_evaluator_spec(name)
|
|
160
|
+
if spec is None:
|
|
161
|
+
raise ValueError(f"Evaluator spec not found: {name}")
|
|
162
|
+
return spec
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
__all__ = [
|
|
166
|
+
"ActionDoc",
|
|
167
|
+
"ProviderDoc",
|
|
168
|
+
"EvaluatorDoc",
|
|
169
|
+
"get_action_spec",
|
|
170
|
+
"require_action_spec",
|
|
171
|
+
"get_provider_spec",
|
|
172
|
+
"require_provider_spec",
|
|
173
|
+
"get_evaluator_spec",
|
|
174
|
+
"require_evaluator_spec",
|
|
175
|
+
]
|
package/elizaos/media/mime.py
CHANGED
|
@@ -12,14 +12,14 @@ from urllib.parse import urlparse
|
|
|
12
12
|
|
|
13
13
|
# Try to import python-magic for MIME sniffing, fallback to filetype
|
|
14
14
|
try:
|
|
15
|
-
import magic
|
|
15
|
+
import magic # type: ignore[import-not-found]
|
|
16
16
|
|
|
17
17
|
HAS_MAGIC = True
|
|
18
18
|
except ImportError:
|
|
19
19
|
HAS_MAGIC = False
|
|
20
20
|
|
|
21
21
|
try:
|
|
22
|
-
import filetype
|
|
22
|
+
import filetype # type: ignore[import-not-found]
|
|
23
23
|
|
|
24
24
|
HAS_FILETYPE = True
|
|
25
25
|
except ImportError:
|
package/elizaos/media/search.py
CHANGED
|
@@ -109,36 +109,36 @@ def merge_hybrid_results(
|
|
|
109
109
|
by_id: dict[str, dict] = {}
|
|
110
110
|
|
|
111
111
|
# Add vector search results
|
|
112
|
-
for
|
|
113
|
-
by_id[
|
|
114
|
-
"id":
|
|
115
|
-
"path":
|
|
116
|
-
"start_line":
|
|
117
|
-
"end_line":
|
|
118
|
-
"source":
|
|
119
|
-
"snippet":
|
|
120
|
-
"vector_score":
|
|
112
|
+
for vector_result in vector:
|
|
113
|
+
by_id[vector_result.id] = {
|
|
114
|
+
"id": vector_result.id,
|
|
115
|
+
"path": vector_result.path,
|
|
116
|
+
"start_line": vector_result.start_line,
|
|
117
|
+
"end_line": vector_result.end_line,
|
|
118
|
+
"source": vector_result.source,
|
|
119
|
+
"snippet": vector_result.snippet,
|
|
120
|
+
"vector_score": vector_result.vector_score,
|
|
121
121
|
"text_score": 0.0,
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
# Merge keyword search results
|
|
125
|
-
for
|
|
126
|
-
if
|
|
127
|
-
existing = by_id[
|
|
128
|
-
existing["text_score"] =
|
|
125
|
+
for keyword_result in keyword:
|
|
126
|
+
if keyword_result.id in by_id:
|
|
127
|
+
existing = by_id[keyword_result.id]
|
|
128
|
+
existing["text_score"] = keyword_result.text_score
|
|
129
129
|
# Prefer keyword snippet if available (may have highlights)
|
|
130
|
-
if
|
|
131
|
-
existing["snippet"] =
|
|
130
|
+
if keyword_result.snippet:
|
|
131
|
+
existing["snippet"] = keyword_result.snippet
|
|
132
132
|
else:
|
|
133
|
-
by_id[
|
|
134
|
-
"id":
|
|
135
|
-
"path":
|
|
136
|
-
"start_line":
|
|
137
|
-
"end_line":
|
|
138
|
-
"source":
|
|
139
|
-
"snippet":
|
|
133
|
+
by_id[keyword_result.id] = {
|
|
134
|
+
"id": keyword_result.id,
|
|
135
|
+
"path": keyword_result.path,
|
|
136
|
+
"start_line": keyword_result.start_line,
|
|
137
|
+
"end_line": keyword_result.end_line,
|
|
138
|
+
"source": keyword_result.source,
|
|
139
|
+
"snippet": keyword_result.snippet,
|
|
140
140
|
"vector_score": 0.0,
|
|
141
|
-
"text_score":
|
|
141
|
+
"text_score": keyword_result.text_score,
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
# Calculate weighted scores and create results
|
package/elizaos/runtime.py
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import contextlib
|
|
4
5
|
import re
|
|
5
6
|
import uuid
|
|
6
7
|
import xml.etree.ElementTree as ET
|
|
7
|
-
from collections.abc import AsyncIterator, Awaitable, Callable
|
|
8
|
+
from collections.abc import AsyncIterator, Awaitable, Callable, Mapping, MutableMapping
|
|
8
9
|
from dataclasses import dataclass
|
|
9
10
|
from typing import Any
|
|
10
11
|
|
|
12
|
+
from google.protobuf.struct_pb2 import Value as StructValue
|
|
13
|
+
|
|
11
14
|
from elizaos.action_docs import with_canonical_action_docs, with_canonical_evaluator_docs
|
|
15
|
+
from elizaos.deterministic import (
|
|
16
|
+
build_conversation_seed,
|
|
17
|
+
deterministic_hex,
|
|
18
|
+
deterministic_uuid,
|
|
19
|
+
)
|
|
12
20
|
from elizaos.logger import Logger, create_logger
|
|
13
21
|
from elizaos.settings import decrypt_secret, get_salt
|
|
14
22
|
from elizaos.types.agent import Character, TemplateType
|
|
@@ -18,6 +26,7 @@ from elizaos.types.components import (
|
|
|
18
26
|
Evaluator,
|
|
19
27
|
HandlerCallback,
|
|
20
28
|
HandlerOptions,
|
|
29
|
+
PreEvaluatorResult,
|
|
21
30
|
Provider,
|
|
22
31
|
)
|
|
23
32
|
from elizaos.types.database import AgentRunSummaryResult, IDatabaseAdapter, Log
|
|
@@ -81,6 +90,48 @@ class StreamingModelHandlerWrapper:
|
|
|
81
90
|
|
|
82
91
|
_anonymous_agent_counter = 0
|
|
83
92
|
|
|
93
|
+
_MISSING = object()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _struct_value_to_python(value: StructValue) -> object | None:
|
|
97
|
+
kind = value.WhichOneof("kind")
|
|
98
|
+
if kind == "null_value":
|
|
99
|
+
return None
|
|
100
|
+
if kind == "number_value":
|
|
101
|
+
return value.number_value
|
|
102
|
+
if kind == "string_value":
|
|
103
|
+
return value.string_value
|
|
104
|
+
if kind == "bool_value":
|
|
105
|
+
return value.bool_value
|
|
106
|
+
if kind == "struct_value":
|
|
107
|
+
return {
|
|
108
|
+
key: _struct_value_to_python(item) for key, item in value.struct_value.fields.items()
|
|
109
|
+
}
|
|
110
|
+
if kind == "list_value":
|
|
111
|
+
return [_struct_value_to_python(item) for item in value.list_value.values]
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _is_struct_compatible(value: object) -> bool:
|
|
116
|
+
if value is None:
|
|
117
|
+
return True
|
|
118
|
+
if isinstance(value, (str, int, float, bool)):
|
|
119
|
+
return True
|
|
120
|
+
if isinstance(value, list):
|
|
121
|
+
return all(_is_struct_compatible(item) for item in value)
|
|
122
|
+
if isinstance(value, Mapping):
|
|
123
|
+
return all(
|
|
124
|
+
isinstance(map_key, str) and _is_struct_compatible(map_value)
|
|
125
|
+
for map_key, map_value in value.items()
|
|
126
|
+
)
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _to_runtime_setting_value(value: object | None) -> str | bool | int | float | None:
|
|
131
|
+
if value is None or isinstance(value, (str, bool, int, float)):
|
|
132
|
+
return value
|
|
133
|
+
return str(value)
|
|
134
|
+
|
|
84
135
|
|
|
85
136
|
class AgentRuntime(IAgentRuntime):
|
|
86
137
|
def __init__(
|
|
@@ -354,37 +405,58 @@ class AgentRuntime(IAgentRuntime):
|
|
|
354
405
|
if secret:
|
|
355
406
|
if self._character.secrets is None:
|
|
356
407
|
self._character.secrets = {}
|
|
357
|
-
if isinstance(self._character.secrets,
|
|
408
|
+
if isinstance(self._character.secrets, MutableMapping):
|
|
358
409
|
self._character.secrets[key] = value # type: ignore[assignment]
|
|
359
410
|
else:
|
|
360
411
|
# Fall back to internal settings dict for protobuf objects
|
|
361
|
-
self._settings[key] = value
|
|
412
|
+
self._settings[key] = _to_runtime_setting_value(value)
|
|
362
413
|
return
|
|
363
414
|
|
|
364
415
|
# Try to set on character.settings if it's a dict
|
|
365
|
-
if isinstance(self._character.settings,
|
|
416
|
+
if isinstance(self._character.settings, MutableMapping):
|
|
366
417
|
self._character.settings[key] = value # type: ignore[assignment]
|
|
418
|
+
return
|
|
419
|
+
|
|
420
|
+
settings_extra = getattr(self._character.settings, "extra", None)
|
|
421
|
+
if (
|
|
422
|
+
settings_extra is not None
|
|
423
|
+
and hasattr(settings_extra, "update")
|
|
424
|
+
and _is_struct_compatible(value)
|
|
425
|
+
):
|
|
426
|
+
settings_extra.update({key: value})
|
|
367
427
|
else:
|
|
368
428
|
# Fall back to internal settings dict for protobuf objects
|
|
369
|
-
self._settings[key] = value
|
|
429
|
+
self._settings[key] = _to_runtime_setting_value(value)
|
|
370
430
|
|
|
371
431
|
def get_setting(self, key: str) -> object | None:
|
|
372
432
|
settings = self._character.settings
|
|
373
433
|
secrets = self._character.secrets
|
|
374
434
|
|
|
375
|
-
nested_secrets:
|
|
376
|
-
|
|
435
|
+
nested_secrets: Mapping[str, object] | None = None
|
|
436
|
+
extra_value: object = _MISSING
|
|
437
|
+
if isinstance(settings, Mapping):
|
|
377
438
|
nested = settings.get("secrets")
|
|
378
|
-
if isinstance(nested,
|
|
439
|
+
if isinstance(nested, Mapping):
|
|
379
440
|
nested_secrets = nested
|
|
441
|
+
else:
|
|
442
|
+
settings_extra = getattr(settings, "extra", None)
|
|
443
|
+
settings_fields = getattr(settings_extra, "fields", None)
|
|
444
|
+
if isinstance(settings_fields, Mapping) and key in settings_fields:
|
|
445
|
+
struct_candidate = settings_fields[key]
|
|
446
|
+
if isinstance(struct_candidate, StructValue):
|
|
447
|
+
extra_value = _struct_value_to_python(struct_candidate)
|
|
448
|
+
else:
|
|
449
|
+
extra_value = struct_candidate
|
|
380
450
|
|
|
381
451
|
value: object | None
|
|
382
|
-
if isinstance(secrets,
|
|
452
|
+
if isinstance(secrets, Mapping) and key in secrets:
|
|
383
453
|
value = secrets.get(key)
|
|
384
|
-
elif isinstance(settings,
|
|
454
|
+
elif isinstance(settings, Mapping) and key in settings:
|
|
385
455
|
value = settings.get(key)
|
|
386
|
-
elif isinstance(nested_secrets,
|
|
456
|
+
elif isinstance(nested_secrets, Mapping) and key in nested_secrets:
|
|
387
457
|
value = nested_secrets.get(key)
|
|
458
|
+
elif extra_value is not _MISSING:
|
|
459
|
+
value = extra_value
|
|
388
460
|
else:
|
|
389
461
|
value = self._settings.get(key)
|
|
390
462
|
|
|
@@ -409,12 +481,17 @@ class AgentRuntime(IAgentRuntime):
|
|
|
409
481
|
|
|
410
482
|
def get_all_settings(self) -> dict[str, object | None]:
|
|
411
483
|
keys: set[str] = set(self._settings.keys())
|
|
412
|
-
if isinstance(self._character.settings,
|
|
484
|
+
if isinstance(self._character.settings, Mapping):
|
|
413
485
|
keys.update(self._character.settings.keys())
|
|
414
486
|
nested = self._character.settings.get("secrets")
|
|
415
|
-
if isinstance(nested,
|
|
487
|
+
if isinstance(nested, Mapping):
|
|
416
488
|
keys.update(nested.keys())
|
|
417
|
-
|
|
489
|
+
else:
|
|
490
|
+
settings_extra = getattr(self._character.settings, "extra", None)
|
|
491
|
+
settings_fields = getattr(settings_extra, "fields", None)
|
|
492
|
+
if isinstance(settings_fields, Mapping):
|
|
493
|
+
keys.update(settings_fields.keys())
|
|
494
|
+
if isinstance(self._character.secrets, Mapping):
|
|
418
495
|
keys.update(self._character.secrets.keys())
|
|
419
496
|
|
|
420
497
|
return {k: self.get_setting(k) for k in keys}
|
|
@@ -608,8 +685,14 @@ class AgentRuntime(IAgentRuntime):
|
|
|
608
685
|
errors.append(
|
|
609
686
|
f"Required parameter '{param_def.name}' was not provided for action {action.name}"
|
|
610
687
|
)
|
|
611
|
-
|
|
612
|
-
|
|
688
|
+
else:
|
|
689
|
+
default_value = getattr(param_def.schema, "default_value", None)
|
|
690
|
+
if isinstance(default_value, StructValue):
|
|
691
|
+
parsed_default = _struct_value_to_python(default_value)
|
|
692
|
+
if parsed_default is not None:
|
|
693
|
+
validated[param_def.name] = parsed_default
|
|
694
|
+
elif default_value is not None:
|
|
695
|
+
validated[param_def.name] = default_value
|
|
613
696
|
continue
|
|
614
697
|
|
|
615
698
|
schema_type = param_def.schema.type
|
|
@@ -770,6 +853,7 @@ class AgentRuntime(IAgentRuntime):
|
|
|
770
853
|
if data_params is not None:
|
|
771
854
|
# Convert protobuf Struct to dict for _parse_action_params
|
|
772
855
|
from google.protobuf.json_format import MessageToDict
|
|
856
|
+
|
|
773
857
|
if hasattr(data_params, "DESCRIPTOR"):
|
|
774
858
|
params_raw = MessageToDict(data_params)
|
|
775
859
|
else:
|
|
@@ -802,11 +886,8 @@ class AgentRuntime(IAgentRuntime):
|
|
|
802
886
|
actionName=action.name,
|
|
803
887
|
errors=errors,
|
|
804
888
|
)
|
|
805
|
-
|
|
889
|
+
with contextlib.suppress(AttributeError, ValueError):
|
|
806
890
|
options_obj.parameter_errors = errors
|
|
807
|
-
except (AttributeError, ValueError):
|
|
808
|
-
# Protobuf HandlerOptions may not have parameter_errors field
|
|
809
|
-
pass
|
|
810
891
|
|
|
811
892
|
if validated_params:
|
|
812
893
|
from google.protobuf import struct_pb2
|
|
@@ -891,7 +972,7 @@ class AgentRuntime(IAgentRuntime):
|
|
|
891
972
|
self,
|
|
892
973
|
message: Memory,
|
|
893
974
|
state: State | None = None,
|
|
894
|
-
) ->
|
|
975
|
+
) -> PreEvaluatorResult:
|
|
895
976
|
"""Run phase='pre' evaluators as middleware before memory storage.
|
|
896
977
|
|
|
897
978
|
Pre-evaluators can inspect, rewrite, or block a message before it
|
|
@@ -902,8 +983,6 @@ class AgentRuntime(IAgentRuntime):
|
|
|
902
983
|
Returns:
|
|
903
984
|
A merged PreEvaluatorResult.
|
|
904
985
|
"""
|
|
905
|
-
from elizaos.types.components import PreEvaluatorResult
|
|
906
|
-
|
|
907
986
|
pre_evaluators = [e for e in self._evaluators if getattr(e, "phase", "post") == "pre"]
|
|
908
987
|
if not pre_evaluators:
|
|
909
988
|
return PreEvaluatorResult(blocked=False)
|
|
@@ -1982,6 +2061,12 @@ class AgentRuntime(IAgentRuntime):
|
|
|
1982
2061
|
|
|
1983
2062
|
schema_key = ",".join(s.field for s in schema)
|
|
1984
2063
|
model_schema_key = f"{model_type_str}:{schema_key}"
|
|
2064
|
+
deterministic_seed = build_conversation_seed(
|
|
2065
|
+
self,
|
|
2066
|
+
None,
|
|
2067
|
+
state,
|
|
2068
|
+
f"dynamic-prompt:{model_schema_key}",
|
|
2069
|
+
)
|
|
1985
2070
|
|
|
1986
2071
|
# Get validation level from settings or options (mirrors TypeScript behavior)
|
|
1987
2072
|
default_context_level = 2
|
|
@@ -2023,7 +2108,11 @@ class AgentRuntime(IAgentRuntime):
|
|
|
2023
2108
|
row.validate_field if row.validate_field is not None else default_validate
|
|
2024
2109
|
)
|
|
2025
2110
|
if needs_validation:
|
|
2026
|
-
per_field_codes[row.field] =
|
|
2111
|
+
per_field_codes[row.field] = deterministic_hex(
|
|
2112
|
+
deterministic_seed,
|
|
2113
|
+
f"field-code:{row.field}",
|
|
2114
|
+
8,
|
|
2115
|
+
)
|
|
2027
2116
|
|
|
2028
2117
|
# Streaming extractor (created on first iteration if streaming enabled)
|
|
2029
2118
|
extractor: ValidationStreamExtractor | None = None
|
|
@@ -2147,9 +2236,18 @@ class AgentRuntime(IAgentRuntime):
|
|
|
2147
2236
|
example_lines.append(container_end)
|
|
2148
2237
|
example = "\n".join(example_lines)
|
|
2149
2238
|
|
|
2150
|
-
init_code =
|
|
2151
|
-
|
|
2152
|
-
|
|
2239
|
+
init_code = deterministic_uuid(
|
|
2240
|
+
deterministic_seed,
|
|
2241
|
+
f"init-code:{current_retry}",
|
|
2242
|
+
)
|
|
2243
|
+
mid_code = deterministic_uuid(
|
|
2244
|
+
deterministic_seed,
|
|
2245
|
+
f"mid-code:{current_retry}",
|
|
2246
|
+
)
|
|
2247
|
+
final_code = deterministic_uuid(
|
|
2248
|
+
deterministic_seed,
|
|
2249
|
+
f"final-code:{current_retry}",
|
|
2250
|
+
)
|
|
2153
2251
|
|
|
2154
2252
|
section_start = "<output>" if is_xml else "# Strict Output instructions"
|
|
2155
2253
|
section_end = "</output>" if is_xml else ""
|
|
@@ -2223,25 +2321,40 @@ end code: {final_code}
|
|
|
2223
2321
|
if not stream_fields and any(row.field == "text" for row in schema):
|
|
2224
2322
|
stream_fields = ["text"]
|
|
2225
2323
|
|
|
2226
|
-
stream_message_id =
|
|
2324
|
+
stream_message_id = "stream-" + deterministic_hex(
|
|
2325
|
+
deterministic_seed,
|
|
2326
|
+
f"stream-message-id:{current_retry}",
|
|
2327
|
+
20,
|
|
2328
|
+
)
|
|
2329
|
+
|
|
2330
|
+
on_stream_chunk = options.on_stream_chunk
|
|
2331
|
+
on_stream_event = options.on_stream_event
|
|
2332
|
+
|
|
2333
|
+
def _emit_chunk(
|
|
2334
|
+
chunk: str,
|
|
2335
|
+
_field: str | None,
|
|
2336
|
+
cb=on_stream_chunk,
|
|
2337
|
+
msg_id=stream_message_id,
|
|
2338
|
+
) -> None:
|
|
2339
|
+
if cb is not None:
|
|
2340
|
+
cb(chunk, msg_id)
|
|
2341
|
+
|
|
2342
|
+
def _emit_event(
|
|
2343
|
+
event: StreamEvent,
|
|
2344
|
+
cb=on_stream_event,
|
|
2345
|
+
msg_id=stream_message_id,
|
|
2346
|
+
) -> None:
|
|
2347
|
+
if cb is not None:
|
|
2348
|
+
cb(event, msg_id)
|
|
2227
2349
|
|
|
2228
|
-
# Capture stream_message_id in default parameter to avoid late binding
|
|
2229
2350
|
extractor = ValidationStreamExtractor(
|
|
2230
2351
|
ValidationStreamExtractorConfig(
|
|
2231
2352
|
level=validation_level,
|
|
2232
2353
|
schema=schema,
|
|
2233
2354
|
stream_fields=stream_fields,
|
|
2234
2355
|
expected_codes=per_field_codes,
|
|
2235
|
-
on_chunk=
|
|
2236
|
-
|
|
2237
|
-
msg_id=stream_message_id: options.on_stream_chunk(chunk, msg_id)
|
|
2238
|
-
if options.on_stream_chunk
|
|
2239
|
-
else None,
|
|
2240
|
-
on_event=lambda event, msg_id=stream_message_id: options.on_stream_event(
|
|
2241
|
-
event, msg_id
|
|
2242
|
-
)
|
|
2243
|
-
if options.on_stream_event
|
|
2244
|
-
else None,
|
|
2356
|
+
on_chunk=_emit_chunk,
|
|
2357
|
+
on_event=_emit_event if on_stream_event is not None else None,
|
|
2245
2358
|
abort_signal=options.abort_signal,
|
|
2246
2359
|
has_rich_consumer=has_rich_consumer,
|
|
2247
2360
|
)
|
|
@@ -430,9 +430,7 @@ class DefaultMessageService(IMessageService):
|
|
|
430
430
|
# or rewrite it (e.g. redact credentials).
|
|
431
431
|
pre_result = await runtime.evaluate_pre(message)
|
|
432
432
|
if pre_result.blocked:
|
|
433
|
-
runtime.logger.warning(
|
|
434
|
-
f"Message blocked by pre-evaluator: {pre_result.reason}"
|
|
435
|
-
)
|
|
433
|
+
runtime.logger.warning(f"Message blocked by pre-evaluator: {pre_result.reason}")
|
|
436
434
|
return MessageProcessingResult(
|
|
437
435
|
did_respond=False,
|
|
438
436
|
response_content=None,
|
|
@@ -440,9 +438,7 @@ class DefaultMessageService(IMessageService):
|
|
|
440
438
|
state=None,
|
|
441
439
|
)
|
|
442
440
|
if pre_result.rewritten_text is not None:
|
|
443
|
-
runtime.logger.info(
|
|
444
|
-
f"Pre-evaluator rewrote message text: {pre_result.reason}"
|
|
445
|
-
)
|
|
441
|
+
runtime.logger.info(f"Pre-evaluator rewrote message text: {pre_result.reason}")
|
|
446
442
|
message.content.text = pre_result.rewritten_text
|
|
447
443
|
|
|
448
444
|
# Step 1: Save incoming message to memory (if adapter available)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections.abc import Awaitable, Callable
|
|
4
|
-
from dataclasses import dataclass
|
|
5
|
-
from enum import Enum
|
|
4
|
+
from dataclasses import dataclass
|
|
6
5
|
from typing import TYPE_CHECKING, Literal, TypeAlias
|
|
7
6
|
|
|
8
7
|
from elizaos.types.generated.eliza.v1 import components_pb2
|
|
@@ -47,6 +46,7 @@ class PreEvaluatorResult:
|
|
|
47
46
|
rewritten_text: str | None = None
|
|
48
47
|
reason: str | None = None
|
|
49
48
|
|
|
49
|
+
|
|
50
50
|
# Proto-backed data types
|
|
51
51
|
ActionExample = components_pb2.ActionExample
|
|
52
52
|
ActionParameterSchema = components_pb2.ActionParameterSchema
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Generated protobuf modules for elizaOS types.
|
|
2
|
+
|
|
3
|
+
This __init__.py adds the 'generated' directory to sys.path so that
|
|
4
|
+
protobuf-generated files can resolve ``from eliza.v1 import …`` imports.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
_generated_dir = os.path.dirname(os.path.abspath(__file__))
|
|
11
|
+
if _generated_dir not in sys.path:
|
|
12
|
+
sys.path.insert(0, _generated_dir)
|