@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,156 @@
|
|
|
1
|
+
"""Tests for hybrid search utilities."""
|
|
2
|
+
|
|
3
|
+
from elizaos.media.search import (
|
|
4
|
+
HybridKeywordResult,
|
|
5
|
+
HybridVectorResult,
|
|
6
|
+
bm25_rank_to_score,
|
|
7
|
+
build_fts_query,
|
|
8
|
+
merge_hybrid_results,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestBuildFtsQuery:
|
|
13
|
+
def test_simple_query(self):
|
|
14
|
+
result = build_fts_query("hello world")
|
|
15
|
+
assert result == '"hello" AND "world"'
|
|
16
|
+
|
|
17
|
+
def test_single_token(self):
|
|
18
|
+
result = build_fts_query("test_function")
|
|
19
|
+
assert result == '"test_function"'
|
|
20
|
+
|
|
21
|
+
def test_empty_string(self):
|
|
22
|
+
assert build_fts_query("") is None
|
|
23
|
+
|
|
24
|
+
def test_whitespace_only(self):
|
|
25
|
+
assert build_fts_query(" ") is None
|
|
26
|
+
|
|
27
|
+
def test_special_characters(self):
|
|
28
|
+
result = build_fts_query("hello! world?")
|
|
29
|
+
assert result == '"hello" AND "world"'
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TestBm25RankToScore:
|
|
33
|
+
def test_zero_rank(self):
|
|
34
|
+
score = bm25_rank_to_score(0.0)
|
|
35
|
+
assert abs(score - 1.0) < 0.001
|
|
36
|
+
|
|
37
|
+
def test_one_rank(self):
|
|
38
|
+
score = bm25_rank_to_score(1.0)
|
|
39
|
+
assert abs(score - 0.5) < 0.001
|
|
40
|
+
|
|
41
|
+
def test_infinite_rank(self):
|
|
42
|
+
score = bm25_rank_to_score(float("inf"))
|
|
43
|
+
assert score < 0.01
|
|
44
|
+
|
|
45
|
+
def test_negative_rank(self):
|
|
46
|
+
# Negative ranks should be clamped to 0
|
|
47
|
+
score = bm25_rank_to_score(-5.0)
|
|
48
|
+
assert abs(score - 1.0) < 0.001
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class TestMergeHybridResults:
|
|
52
|
+
def test_merge_single_result(self):
|
|
53
|
+
vector = [
|
|
54
|
+
HybridVectorResult(
|
|
55
|
+
id="a",
|
|
56
|
+
path="file.py",
|
|
57
|
+
start_line=1,
|
|
58
|
+
end_line=10,
|
|
59
|
+
source="test",
|
|
60
|
+
snippet="hello",
|
|
61
|
+
vector_score=0.8,
|
|
62
|
+
)
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
keyword = [
|
|
66
|
+
HybridKeywordResult(
|
|
67
|
+
id="a",
|
|
68
|
+
path="file.py",
|
|
69
|
+
start_line=1,
|
|
70
|
+
end_line=10,
|
|
71
|
+
source="test",
|
|
72
|
+
snippet="hello world",
|
|
73
|
+
text_score=0.6,
|
|
74
|
+
)
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
merged = merge_hybrid_results(vector, keyword, 0.7, 0.3)
|
|
78
|
+
|
|
79
|
+
assert len(merged) == 1
|
|
80
|
+
expected_score = 0.7 * 0.8 + 0.3 * 0.6
|
|
81
|
+
assert abs(merged[0].score - expected_score) < 0.001
|
|
82
|
+
# Keyword snippet should be preferred
|
|
83
|
+
assert merged[0].snippet == "hello world"
|
|
84
|
+
|
|
85
|
+
def test_merge_disjoint_results(self):
|
|
86
|
+
vector = [
|
|
87
|
+
HybridVectorResult(
|
|
88
|
+
id="a",
|
|
89
|
+
path="file1.py",
|
|
90
|
+
start_line=1,
|
|
91
|
+
end_line=10,
|
|
92
|
+
source="test",
|
|
93
|
+
snippet="first",
|
|
94
|
+
vector_score=0.9,
|
|
95
|
+
)
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
keyword = [
|
|
99
|
+
HybridKeywordResult(
|
|
100
|
+
id="b",
|
|
101
|
+
path="file2.py",
|
|
102
|
+
start_line=20,
|
|
103
|
+
end_line=30,
|
|
104
|
+
source="test",
|
|
105
|
+
snippet="second",
|
|
106
|
+
text_score=0.7,
|
|
107
|
+
)
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
merged = merge_hybrid_results(vector, keyword, 0.7, 0.3)
|
|
111
|
+
|
|
112
|
+
assert len(merged) == 2
|
|
113
|
+
# Results should be sorted by score descending
|
|
114
|
+
assert merged[0].score >= merged[1].score
|
|
115
|
+
|
|
116
|
+
def test_empty_inputs(self):
|
|
117
|
+
merged = merge_hybrid_results([], [], 0.7, 0.3)
|
|
118
|
+
assert len(merged) == 0
|
|
119
|
+
|
|
120
|
+
def test_vector_only(self):
|
|
121
|
+
vector = [
|
|
122
|
+
HybridVectorResult(
|
|
123
|
+
id="a",
|
|
124
|
+
path="file.py",
|
|
125
|
+
start_line=1,
|
|
126
|
+
end_line=10,
|
|
127
|
+
source="test",
|
|
128
|
+
snippet="hello",
|
|
129
|
+
vector_score=0.8,
|
|
130
|
+
)
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
merged = merge_hybrid_results(vector, [], 0.7, 0.3)
|
|
134
|
+
|
|
135
|
+
assert len(merged) == 1
|
|
136
|
+
expected_score = 0.7 * 0.8
|
|
137
|
+
assert abs(merged[0].score - expected_score) < 0.001
|
|
138
|
+
|
|
139
|
+
def test_keyword_only(self):
|
|
140
|
+
keyword = [
|
|
141
|
+
HybridKeywordResult(
|
|
142
|
+
id="a",
|
|
143
|
+
path="file.py",
|
|
144
|
+
start_line=1,
|
|
145
|
+
end_line=10,
|
|
146
|
+
source="test",
|
|
147
|
+
snippet="hello",
|
|
148
|
+
text_score=0.6,
|
|
149
|
+
)
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
merged = merge_hybrid_results([], keyword, 0.7, 0.3)
|
|
153
|
+
|
|
154
|
+
assert len(merged) == 1
|
|
155
|
+
expected_score = 0.3 * 0.6
|
|
156
|
+
assert abs(merged[0].score - expected_score) < 0.001
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from elizaos.logger import logger
|
|
7
|
+
from elizaos.types.plugin import Plugin
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from elizaos.types.runtime import IAgentRuntime
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PluginLoadError(Exception):
|
|
14
|
+
def __init__(self, message: str, plugin_name: str, cause: Exception | None = None) -> None:
|
|
15
|
+
super().__init__(message)
|
|
16
|
+
self.plugin_name = plugin_name
|
|
17
|
+
self.cause = cause
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class PluginRegistrationError(Exception):
|
|
21
|
+
def __init__(self, message: str, plugin_name: str, cause: Exception | None = None) -> None:
|
|
22
|
+
super().__init__(message)
|
|
23
|
+
self.plugin_name = plugin_name
|
|
24
|
+
self.cause = cause
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def load_plugin(name: str) -> Plugin:
|
|
28
|
+
try:
|
|
29
|
+
module = importlib.import_module(name)
|
|
30
|
+
if hasattr(module, "plugin"):
|
|
31
|
+
plugin = module.plugin
|
|
32
|
+
if isinstance(plugin, Plugin):
|
|
33
|
+
logger.debug(f"Loaded plugin: {plugin.name}")
|
|
34
|
+
return plugin
|
|
35
|
+
if isinstance(plugin, dict):
|
|
36
|
+
return Plugin(**plugin)
|
|
37
|
+
if hasattr(module, "default"):
|
|
38
|
+
default = module.default
|
|
39
|
+
if isinstance(default, Plugin):
|
|
40
|
+
logger.debug(f"Loaded plugin from default export: {default.name}")
|
|
41
|
+
return default
|
|
42
|
+
if isinstance(default, dict):
|
|
43
|
+
return Plugin(**default)
|
|
44
|
+
|
|
45
|
+
raise PluginLoadError(
|
|
46
|
+
f"Module {name} does not export a valid plugin",
|
|
47
|
+
plugin_name=name,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
except ImportError as e:
|
|
51
|
+
raise PluginLoadError(
|
|
52
|
+
f"Failed to import plugin module: {name}",
|
|
53
|
+
plugin_name=name,
|
|
54
|
+
cause=e,
|
|
55
|
+
) from e
|
|
56
|
+
except Exception as e:
|
|
57
|
+
raise PluginLoadError(
|
|
58
|
+
f"Failed to load plugin {name}: {e}",
|
|
59
|
+
plugin_name=name,
|
|
60
|
+
cause=e,
|
|
61
|
+
) from e
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
async def register_plugin(runtime: IAgentRuntime, plugin: Plugin) -> None:
|
|
65
|
+
try:
|
|
66
|
+
logger.info(f"Registering plugin: {plugin.name}")
|
|
67
|
+
# Use getattr for optional plugin attributes to handle non-standard plugins
|
|
68
|
+
dependencies = getattr(plugin, "dependencies", None)
|
|
69
|
+
if dependencies:
|
|
70
|
+
for dep in dependencies:
|
|
71
|
+
if dep not in [p.name for p in runtime.plugins]:
|
|
72
|
+
raise PluginRegistrationError(
|
|
73
|
+
f"Missing dependency: {dep}",
|
|
74
|
+
plugin_name=plugin.name,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
init_fn = getattr(plugin, "init", None)
|
|
78
|
+
if init_fn:
|
|
79
|
+
config = getattr(plugin, "config", None) or {}
|
|
80
|
+
# Handle different init signatures
|
|
81
|
+
import inspect
|
|
82
|
+
|
|
83
|
+
sig = inspect.signature(init_fn)
|
|
84
|
+
params = list(sig.parameters.values())
|
|
85
|
+
# Filter out 'self' parameter for bound methods
|
|
86
|
+
non_self_params = [p for p in params if p.name != "self"]
|
|
87
|
+
if len(non_self_params) >= 2:
|
|
88
|
+
await init_fn(config, runtime)
|
|
89
|
+
elif len(non_self_params) == 1:
|
|
90
|
+
await init_fn(config)
|
|
91
|
+
else:
|
|
92
|
+
await init_fn()
|
|
93
|
+
|
|
94
|
+
actions = getattr(plugin, "actions", None)
|
|
95
|
+
if actions:
|
|
96
|
+
for action in actions:
|
|
97
|
+
runtime.register_action(action)
|
|
98
|
+
logger.debug(f"Registered action: {action.name}")
|
|
99
|
+
|
|
100
|
+
providers = getattr(plugin, "providers", None)
|
|
101
|
+
if providers:
|
|
102
|
+
for provider in providers:
|
|
103
|
+
runtime.register_provider(provider)
|
|
104
|
+
logger.debug(f"Registered provider: {provider.name}")
|
|
105
|
+
|
|
106
|
+
evaluators = getattr(plugin, "evaluators", None)
|
|
107
|
+
if evaluators:
|
|
108
|
+
for evaluator in evaluators:
|
|
109
|
+
runtime.register_evaluator(evaluator)
|
|
110
|
+
logger.debug(f"Registered evaluator: {evaluator.name}")
|
|
111
|
+
|
|
112
|
+
services = getattr(plugin, "services", None)
|
|
113
|
+
if services:
|
|
114
|
+
for service_class in services:
|
|
115
|
+
await runtime.register_service(service_class)
|
|
116
|
+
logger.debug(
|
|
117
|
+
f"Registered service: {getattr(service_class, 'service_type', 'unknown')}"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
models = getattr(plugin, "models", None)
|
|
121
|
+
if models:
|
|
122
|
+
for model_type, handler in models.items():
|
|
123
|
+
runtime.register_model(
|
|
124
|
+
model_type,
|
|
125
|
+
handler,
|
|
126
|
+
provider=plugin.name,
|
|
127
|
+
)
|
|
128
|
+
logger.debug(f"Registered model: {model_type}")
|
|
129
|
+
|
|
130
|
+
streaming_models = getattr(plugin, "streaming_models", None)
|
|
131
|
+
if streaming_models:
|
|
132
|
+
for model_type, handler in streaming_models.items():
|
|
133
|
+
runtime.register_streaming_model(
|
|
134
|
+
model_type,
|
|
135
|
+
handler,
|
|
136
|
+
provider=plugin.name,
|
|
137
|
+
)
|
|
138
|
+
logger.debug(f"Registered streaming model: {model_type}")
|
|
139
|
+
|
|
140
|
+
events = getattr(plugin, "events", None)
|
|
141
|
+
if events:
|
|
142
|
+
for event_type, event_handlers in events.items():
|
|
143
|
+
for event_handler in event_handlers:
|
|
144
|
+
runtime.register_event(event_type, event_handler)
|
|
145
|
+
logger.debug(f"Registered event handlers for: {event_type}")
|
|
146
|
+
|
|
147
|
+
logger.info(f"Plugin registered successfully: {plugin.name}")
|
|
148
|
+
|
|
149
|
+
except PluginRegistrationError:
|
|
150
|
+
raise
|
|
151
|
+
except Exception as e:
|
|
152
|
+
raise PluginRegistrationError(
|
|
153
|
+
f"Failed to register plugin {plugin.name}: {e}",
|
|
154
|
+
plugin_name=plugin.name,
|
|
155
|
+
cause=e,
|
|
156
|
+
) from e
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def resolve_plugin_dependencies(plugins: list[Plugin]) -> list[Plugin]:
|
|
160
|
+
plugin_map = {p.name: p for p in plugins}
|
|
161
|
+
resolved: list[Plugin] = []
|
|
162
|
+
visiting: set[str] = set()
|
|
163
|
+
visited: set[str] = set()
|
|
164
|
+
|
|
165
|
+
def visit(name: str) -> None:
|
|
166
|
+
if name in visited:
|
|
167
|
+
return
|
|
168
|
+
if name in visiting:
|
|
169
|
+
raise PluginLoadError(
|
|
170
|
+
f"Circular dependency detected: {name}",
|
|
171
|
+
plugin_name=name,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
visiting.add(name)
|
|
175
|
+
plugin = plugin_map.get(name)
|
|
176
|
+
|
|
177
|
+
if plugin and plugin.dependencies:
|
|
178
|
+
for dep in plugin.dependencies:
|
|
179
|
+
if dep in plugin_map:
|
|
180
|
+
visit(dep)
|
|
181
|
+
|
|
182
|
+
visiting.remove(name)
|
|
183
|
+
visited.add(name)
|
|
184
|
+
|
|
185
|
+
if plugin:
|
|
186
|
+
resolved.append(plugin)
|
|
187
|
+
|
|
188
|
+
for plugin in plugins:
|
|
189
|
+
visit(plugin.name)
|
|
190
|
+
|
|
191
|
+
return resolved
|