agent_os_kernel 3.1.0__py3-none-any.whl
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.
- agent_control_plane/__init__.py +662 -0
- agent_control_plane/a2a_adapter.py +543 -0
- agent_control_plane/adapter.py +417 -0
- agent_control_plane/agent_hibernation.py +394 -0
- agent_control_plane/agent_kernel.py +470 -0
- agent_control_plane/compliance.py +720 -0
- agent_control_plane/constraint_graphs.py +478 -0
- agent_control_plane/control_plane.py +854 -0
- agent_control_plane/example_executors.py +195 -0
- agent_control_plane/execution_engine.py +231 -0
- agent_control_plane/flight_recorder.py +846 -0
- agent_control_plane/governance_layer.py +435 -0
- agent_control_plane/hf_utils.py +563 -0
- agent_control_plane/interfaces/__init__.py +55 -0
- agent_control_plane/interfaces/kernel_interface.py +361 -0
- agent_control_plane/interfaces/plugin_interface.py +497 -0
- agent_control_plane/interfaces/protocol_interfaces.py +387 -0
- agent_control_plane/kernel_space.py +1009 -0
- agent_control_plane/langchain_adapter.py +424 -0
- agent_control_plane/lifecycle.py +3113 -0
- agent_control_plane/mcp_adapter.py +653 -0
- agent_control_plane/ml_safety.py +563 -0
- agent_control_plane/multimodal.py +727 -0
- agent_control_plane/mute_agent.py +422 -0
- agent_control_plane/observability.py +787 -0
- agent_control_plane/orchestrator.py +482 -0
- agent_control_plane/plugin_registry.py +750 -0
- agent_control_plane/policy_engine.py +954 -0
- agent_control_plane/process_isolation.py +777 -0
- agent_control_plane/shadow_mode.py +310 -0
- agent_control_plane/signals.py +493 -0
- agent_control_plane/supervisor_agents.py +430 -0
- agent_control_plane/time_travel_debugger.py +557 -0
- agent_control_plane/tool_registry.py +452 -0
- agent_control_plane/vfs.py +697 -0
- agent_kernel/__init__.py +69 -0
- agent_kernel/analyzer.py +435 -0
- agent_kernel/auditor.py +36 -0
- agent_kernel/completeness_auditor.py +237 -0
- agent_kernel/detector.py +203 -0
- agent_kernel/kernel.py +744 -0
- agent_kernel/memory_manager.py +85 -0
- agent_kernel/models.py +374 -0
- agent_kernel/nudge_mechanism.py +263 -0
- agent_kernel/outcome_analyzer.py +338 -0
- agent_kernel/patcher.py +582 -0
- agent_kernel/semantic_analyzer.py +316 -0
- agent_kernel/semantic_purge.py +349 -0
- agent_kernel/simulator.py +449 -0
- agent_kernel/teacher.py +85 -0
- agent_kernel/triage.py +152 -0
- agent_os/__init__.py +409 -0
- agent_os/_adversarial_impl.py +200 -0
- agent_os/_circuit_breaker_impl.py +232 -0
- agent_os/_mcp_metrics.py +193 -0
- agent_os/adversarial.py +20 -0
- agent_os/agents_compat.py +490 -0
- agent_os/audit_logger.py +135 -0
- agent_os/base_agent.py +651 -0
- agent_os/circuit_breaker.py +34 -0
- agent_os/cli/__init__.py +659 -0
- agent_os/cli/cmd_audit.py +128 -0
- agent_os/cli/cmd_init.py +152 -0
- agent_os/cli/cmd_policy.py +41 -0
- agent_os/cli/cmd_policy_gen.py +180 -0
- agent_os/cli/cmd_validate.py +258 -0
- agent_os/cli/mcp_scan.py +265 -0
- agent_os/cli/output.py +192 -0
- agent_os/cli/policy_checker.py +330 -0
- agent_os/compat.py +74 -0
- agent_os/constraint_graph.py +234 -0
- agent_os/content_governance.py +140 -0
- agent_os/context_budget.py +305 -0
- agent_os/credential_redactor.py +224 -0
- agent_os/diff_policy.py +89 -0
- agent_os/egress_policy.py +159 -0
- agent_os/escalation.py +276 -0
- agent_os/event_bus.py +124 -0
- agent_os/exceptions.py +180 -0
- agent_os/execution_context_policy.py +141 -0
- agent_os/github_enterprise.py +96 -0
- agent_os/health.py +20 -0
- agent_os/integrations/__init__.py +279 -0
- agent_os/integrations/a2a_adapter.py +279 -0
- agent_os/integrations/agent_lightning/__init__.py +30 -0
- agent_os/integrations/anthropic_adapter.py +420 -0
- agent_os/integrations/autogen_adapter.py +620 -0
- agent_os/integrations/base.py +1137 -0
- agent_os/integrations/compat.py +229 -0
- agent_os/integrations/config.py +98 -0
- agent_os/integrations/conversation_guardian.py +957 -0
- agent_os/integrations/crewai_adapter.py +467 -0
- agent_os/integrations/drift_detector.py +425 -0
- agent_os/integrations/dry_run.py +124 -0
- agent_os/integrations/escalation.py +582 -0
- agent_os/integrations/gemini_adapter.py +364 -0
- agent_os/integrations/google_adk_adapter.py +633 -0
- agent_os/integrations/guardrails_adapter.py +394 -0
- agent_os/integrations/health.py +197 -0
- agent_os/integrations/langchain_adapter.py +654 -0
- agent_os/integrations/llamafirewall.py +343 -0
- agent_os/integrations/llamaindex_adapter.py +188 -0
- agent_os/integrations/logging.py +191 -0
- agent_os/integrations/maf_adapter.py +631 -0
- agent_os/integrations/mistral_adapter.py +365 -0
- agent_os/integrations/openai_adapter.py +816 -0
- agent_os/integrations/openai_agents_sdk.py +406 -0
- agent_os/integrations/policy_compose.py +171 -0
- agent_os/integrations/profiling.py +144 -0
- agent_os/integrations/pydantic_ai_adapter.py +420 -0
- agent_os/integrations/rate_limiter.py +130 -0
- agent_os/integrations/rbac.py +143 -0
- agent_os/integrations/registry.py +113 -0
- agent_os/integrations/scope_guard.py +303 -0
- agent_os/integrations/semantic_kernel_adapter.py +769 -0
- agent_os/integrations/smolagents_adapter.py +629 -0
- agent_os/integrations/templates.py +178 -0
- agent_os/integrations/token_budget.py +134 -0
- agent_os/integrations/tool_aliases.py +190 -0
- agent_os/integrations/webhooks.py +177 -0
- agent_os/lite.py +208 -0
- agent_os/mcp_gateway.py +385 -0
- agent_os/mcp_message_signer.py +273 -0
- agent_os/mcp_protocols.py +161 -0
- agent_os/mcp_response_scanner.py +232 -0
- agent_os/mcp_security.py +924 -0
- agent_os/mcp_session_auth.py +231 -0
- agent_os/mcp_sliding_rate_limiter.py +184 -0
- agent_os/memory_guard.py +409 -0
- agent_os/metrics.py +134 -0
- agent_os/mute.py +428 -0
- agent_os/mute_agent.py +209 -0
- agent_os/policies/__init__.py +77 -0
- agent_os/policies/async_evaluator.py +275 -0
- agent_os/policies/backends.py +670 -0
- agent_os/policies/bridge.py +169 -0
- agent_os/policies/budget.py +85 -0
- agent_os/policies/cli.py +294 -0
- agent_os/policies/conflict_resolution.py +270 -0
- agent_os/policies/data_classification.py +252 -0
- agent_os/policies/evaluator.py +239 -0
- agent_os/policies/policy_schema.json +228 -0
- agent_os/policies/rate_limiting.py +145 -0
- agent_os/policies/schema.py +115 -0
- agent_os/policies/shared.py +331 -0
- agent_os/prompt_injection.py +694 -0
- agent_os/providers.py +182 -0
- agent_os/py.typed +0 -0
- agent_os/retry.py +81 -0
- agent_os/reversibility.py +251 -0
- agent_os/sandbox.py +432 -0
- agent_os/sandbox_provider.py +140 -0
- agent_os/secure_codegen.py +525 -0
- agent_os/security_skills.py +538 -0
- agent_os/semantic_policy.py +422 -0
- agent_os/server/__init__.py +15 -0
- agent_os/server/__main__.py +25 -0
- agent_os/server/app.py +277 -0
- agent_os/server/models.py +104 -0
- agent_os/shift_left_metrics.py +130 -0
- agent_os/stateless.py +742 -0
- agent_os/supervisor.py +148 -0
- agent_os/task_outcome.py +148 -0
- agent_os/transparency.py +181 -0
- agent_os/trust_root.py +128 -0
- agent_os_kernel-3.1.0.dist-info/METADATA +1269 -0
- agent_os_kernel-3.1.0.dist-info/RECORD +337 -0
- agent_os_kernel-3.1.0.dist-info/WHEEL +4 -0
- agent_os_kernel-3.1.0.dist-info/entry_points.txt +2 -0
- agent_os_kernel-3.1.0.dist-info/licenses/LICENSE +21 -0
- agent_os_observability/__init__.py +27 -0
- agent_os_observability/dashboards.py +898 -0
- agent_os_observability/metrics.py +398 -0
- agent_os_observability/server.py +223 -0
- agent_os_observability/tracer.py +232 -0
- agent_primitives/__init__.py +24 -0
- agent_primitives/failures.py +84 -0
- agent_primitives/py.typed +0 -0
- amb_core/__init__.py +177 -0
- amb_core/adapters/__init__.py +57 -0
- amb_core/adapters/aws_sqs_broker.py +376 -0
- amb_core/adapters/azure_servicebus_broker.py +340 -0
- amb_core/adapters/kafka_broker.py +260 -0
- amb_core/adapters/nats_broker.py +285 -0
- amb_core/adapters/rabbitmq_broker.py +235 -0
- amb_core/adapters/redis_broker.py +262 -0
- amb_core/broker.py +145 -0
- amb_core/bus.py +481 -0
- amb_core/cloudevents.py +509 -0
- amb_core/dlq.py +345 -0
- amb_core/hf_utils.py +536 -0
- amb_core/memory_broker.py +410 -0
- amb_core/models.py +141 -0
- amb_core/persistence.py +529 -0
- amb_core/schema.py +294 -0
- amb_core/tracing.py +358 -0
- atr/__init__.py +640 -0
- atr/access.py +348 -0
- atr/composition.py +645 -0
- atr/decorator.py +357 -0
- atr/executor.py +384 -0
- atr/health.py +557 -0
- atr/hf_utils.py +449 -0
- atr/injection.py +422 -0
- atr/metrics.py +440 -0
- atr/policies.py +403 -0
- atr/py.typed +2 -0
- atr/registry.py +452 -0
- atr/schema.py +480 -0
- atr/tools/safe/__init__.py +75 -0
- atr/tools/safe/calculator.py +467 -0
- atr/tools/safe/datetime_tool.py +443 -0
- atr/tools/safe/file_reader.py +402 -0
- atr/tools/safe/http_client.py +316 -0
- atr/tools/safe/json_parser.py +374 -0
- atr/tools/safe/text_tool.py +537 -0
- atr/tools/safe/toolkit.py +175 -0
- caas/__init__.py +162 -0
- caas/api/__init__.py +7 -0
- caas/api/server.py +1328 -0
- caas/caching.py +834 -0
- caas/cli.py +210 -0
- caas/conversation.py +223 -0
- caas/decay.py +72 -0
- caas/detection/__init__.py +9 -0
- caas/detection/detector.py +238 -0
- caas/enrichment.py +130 -0
- caas/gateway/__init__.py +27 -0
- caas/gateway/trust_gateway.py +474 -0
- caas/hf_utils.py +479 -0
- caas/ingestion/__init__.py +23 -0
- caas/ingestion/processors.py +253 -0
- caas/ingestion/structure_parser.py +188 -0
- caas/models.py +356 -0
- caas/pragmatic_truth.py +444 -0
- caas/routing/__init__.py +10 -0
- caas/routing/heuristic_router.py +58 -0
- caas/storage/__init__.py +9 -0
- caas/storage/store.py +389 -0
- caas/triad.py +213 -0
- caas/tuning/__init__.py +9 -0
- caas/tuning/tuner.py +329 -0
- caas/vfs/__init__.py +14 -0
- caas/vfs/filesystem.py +452 -0
- cmvk/__init__.py +218 -0
- cmvk/audit.py +402 -0
- cmvk/benchmarks.py +478 -0
- cmvk/constitutional.py +904 -0
- cmvk/hf_utils.py +301 -0
- cmvk/metrics.py +473 -0
- cmvk/profiles.py +300 -0
- cmvk/py.typed +0 -0
- cmvk/types.py +12 -0
- cmvk/verification.py +956 -0
- emk/__init__.py +89 -0
- emk/causal.py +352 -0
- emk/hf_utils.py +421 -0
- emk/indexer.py +83 -0
- emk/py.typed +0 -0
- emk/schema.py +204 -0
- emk/sleep_cycle.py +347 -0
- emk/store.py +281 -0
- iatp/__init__.py +166 -0
- iatp/attestation.py +461 -0
- iatp/cli.py +317 -0
- iatp/hf_utils.py +472 -0
- iatp/ipc_pipes.py +580 -0
- iatp/main.py +412 -0
- iatp/models/__init__.py +447 -0
- iatp/policy_engine.py +337 -0
- iatp/py.typed +2 -0
- iatp/recovery.py +321 -0
- iatp/security/__init__.py +270 -0
- iatp/sidecar/__init__.py +519 -0
- iatp/telemetry/__init__.py +164 -0
- iatp/tests/__init__.py +1 -0
- iatp/tests/test_attestation.py +370 -0
- iatp/tests/test_cli.py +131 -0
- iatp/tests/test_ed25519_attestation.py +211 -0
- iatp/tests/test_models.py +130 -0
- iatp/tests/test_policy_engine.py +347 -0
- iatp/tests/test_recovery.py +281 -0
- iatp/tests/test_security.py +222 -0
- iatp/tests/test_sidecar.py +167 -0
- iatp/tests/test_telemetry.py +175 -0
- mcp_kernel_server/__init__.py +28 -0
- mcp_kernel_server/cli.py +274 -0
- mcp_kernel_server/resources.py +217 -0
- mcp_kernel_server/server.py +564 -0
- mcp_kernel_server/tools.py +1174 -0
- mute_agent/__init__.py +68 -0
- mute_agent/core/__init__.py +1 -0
- mute_agent/core/execution_agent.py +166 -0
- mute_agent/core/handshake_protocol.py +201 -0
- mute_agent/core/reasoning_agent.py +238 -0
- mute_agent/knowledge_graph/__init__.py +1 -0
- mute_agent/knowledge_graph/graph_elements.py +65 -0
- mute_agent/knowledge_graph/multidimensional_graph.py +170 -0
- mute_agent/knowledge_graph/subgraph.py +224 -0
- mute_agent/listener/__init__.py +43 -0
- mute_agent/listener/adapters/__init__.py +31 -0
- mute_agent/listener/adapters/base_adapter.py +189 -0
- mute_agent/listener/adapters/caas_adapter.py +344 -0
- mute_agent/listener/adapters/control_plane_adapter.py +436 -0
- mute_agent/listener/adapters/iatp_adapter.py +332 -0
- mute_agent/listener/adapters/scak_adapter.py +251 -0
- mute_agent/listener/listener.py +610 -0
- mute_agent/listener/state_observer.py +436 -0
- mute_agent/listener/threshold_config.py +313 -0
- mute_agent/super_system/__init__.py +1 -0
- mute_agent/super_system/router.py +204 -0
- mute_agent/visualization/__init__.py +10 -0
- mute_agent/visualization/graph_debugger.py +502 -0
- nexus/README.md +60 -0
- nexus/__init__.py +51 -0
- nexus/arbiter.py +359 -0
- nexus/client.py +466 -0
- nexus/dmz.py +444 -0
- nexus/escrow.py +430 -0
- nexus/exceptions.py +286 -0
- nexus/pyproject.toml +36 -0
- nexus/registry.py +393 -0
- nexus/reputation.py +425 -0
- nexus/schemas/__init__.py +51 -0
- nexus/schemas/compliance.py +276 -0
- nexus/schemas/escrow.py +251 -0
- nexus/schemas/manifest.py +225 -0
- nexus/schemas/receipt.py +208 -0
- nexus/tests/__init__.py +0 -0
- nexus/tests/conftest.py +146 -0
- nexus/tests/test_arbiter.py +192 -0
- nexus/tests/test_dmz.py +194 -0
- nexus/tests/test_escrow.py +276 -0
- nexus/tests/test_exceptions.py +225 -0
- nexus/tests/test_registry.py +232 -0
- nexus/tests/test_reputation.py +328 -0
- nexus/tests/test_schemas.py +295 -0
|
@@ -0,0 +1,750 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Plugin Registry - Runtime Registration and Dependency Injection
|
|
5
|
+
|
|
6
|
+
This module provides a central registry for managing pluggable components:
|
|
7
|
+
- Kernels (e.g., SCAK, default kernel)
|
|
8
|
+
- Validators (e.g., capability validators, risk validators)
|
|
9
|
+
- Executors (e.g., sandboxed, remote, distributed)
|
|
10
|
+
- Context routers (e.g., CAAS integration)
|
|
11
|
+
- Policy providers (e.g., file-based, database, remote)
|
|
12
|
+
- Protocol integrations (iatp, cmvk, caas)
|
|
13
|
+
|
|
14
|
+
Layer 3: The Framework
|
|
15
|
+
- Components are registered at runtime via config or dependency injection
|
|
16
|
+
- No hard imports of specific implementations (scak, mute-agent are forbidden)
|
|
17
|
+
- Allowed dependencies: iatp, cmvk, caas (optional)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from typing import Any, Dict, List, Optional, Type, TypeVar, Callable, Union
|
|
21
|
+
from dataclasses import dataclass, field
|
|
22
|
+
from datetime import datetime
|
|
23
|
+
from enum import Enum
|
|
24
|
+
import logging
|
|
25
|
+
import importlib
|
|
26
|
+
|
|
27
|
+
from .interfaces.kernel_interface import KernelInterface, KernelMetadata, KernelCapability
|
|
28
|
+
from .interfaces.plugin_interface import (
|
|
29
|
+
PluginInterface,
|
|
30
|
+
PluginMetadata,
|
|
31
|
+
ValidatorInterface,
|
|
32
|
+
ExecutorInterface,
|
|
33
|
+
ContextRouterInterface,
|
|
34
|
+
PolicyProviderInterface,
|
|
35
|
+
SupervisorInterface,
|
|
36
|
+
CapabilityValidatorInterface,
|
|
37
|
+
)
|
|
38
|
+
from .interfaces.protocol_interfaces import (
|
|
39
|
+
MessageSecurityInterface,
|
|
40
|
+
VerificationInterface,
|
|
41
|
+
ContextRoutingInterface,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
logger = logging.getLogger("PluginRegistry")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PluginType(Enum):
|
|
49
|
+
"""Types of plugins that can be registered"""
|
|
50
|
+
KERNEL = "kernel"
|
|
51
|
+
VALIDATOR = "validator"
|
|
52
|
+
EXECUTOR = "executor"
|
|
53
|
+
CONTEXT_ROUTER = "context_router"
|
|
54
|
+
POLICY_PROVIDER = "policy_provider"
|
|
55
|
+
SUPERVISOR = "supervisor"
|
|
56
|
+
MESSAGE_SECURITY = "message_security"
|
|
57
|
+
VERIFIER = "verifier"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class PluginRegistration:
|
|
62
|
+
"""Registration record for a plugin"""
|
|
63
|
+
plugin_id: str
|
|
64
|
+
plugin_type: PluginType
|
|
65
|
+
instance: Any
|
|
66
|
+
metadata: Union[PluginMetadata, KernelMetadata]
|
|
67
|
+
registered_at: datetime = field(default_factory=datetime.now)
|
|
68
|
+
is_active: bool = True
|
|
69
|
+
config: Dict[str, Any] = field(default_factory=dict)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass
|
|
73
|
+
class RegistryConfiguration:
|
|
74
|
+
"""Configuration for the plugin registry"""
|
|
75
|
+
# Allow lazy loading of plugins
|
|
76
|
+
lazy_loading: bool = True
|
|
77
|
+
|
|
78
|
+
# Plugin discovery paths
|
|
79
|
+
plugin_paths: List[str] = field(default_factory=list)
|
|
80
|
+
|
|
81
|
+
# Auto-register built-in plugins
|
|
82
|
+
auto_register_builtins: bool = True
|
|
83
|
+
|
|
84
|
+
# Forbidden dependencies (will raise error if detected)
|
|
85
|
+
forbidden_dependencies: List[str] = field(default_factory=lambda: ["scak", "mute_agent"])
|
|
86
|
+
|
|
87
|
+
# Allowed protocol dependencies
|
|
88
|
+
allowed_protocols: List[str] = field(default_factory=lambda: ["iatp", "cmvk", "caas"])
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class PluginRegistry:
|
|
92
|
+
"""
|
|
93
|
+
Central registry for pluggable components.
|
|
94
|
+
|
|
95
|
+
The registry manages:
|
|
96
|
+
- Registration and lookup of plugins
|
|
97
|
+
- Dependency injection configuration
|
|
98
|
+
- Plugin lifecycle (initialize, configure, shutdown)
|
|
99
|
+
- Plugin discovery from paths
|
|
100
|
+
|
|
101
|
+
Example Usage:
|
|
102
|
+
```python
|
|
103
|
+
registry = PluginRegistry()
|
|
104
|
+
|
|
105
|
+
# Register a custom kernel
|
|
106
|
+
registry.register_kernel(my_kernel, config={"timeout": 30})
|
|
107
|
+
|
|
108
|
+
# Register a validator
|
|
109
|
+
registry.register_validator(my_validator, action_types=["code_execution"])
|
|
110
|
+
|
|
111
|
+
# Get the active kernel
|
|
112
|
+
kernel = registry.get_kernel()
|
|
113
|
+
|
|
114
|
+
# Get validators for an action type
|
|
115
|
+
validators = registry.get_validators_for_action("code_execution")
|
|
116
|
+
```
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
_instance: Optional["PluginRegistry"] = None
|
|
120
|
+
|
|
121
|
+
def __new__(cls, *args, **kwargs):
|
|
122
|
+
"""Singleton pattern - ensure single registry instance"""
|
|
123
|
+
if cls._instance is None:
|
|
124
|
+
cls._instance = super().__new__(cls)
|
|
125
|
+
cls._instance._initialized = False
|
|
126
|
+
return cls._instance
|
|
127
|
+
|
|
128
|
+
def __init__(self, config: Optional[RegistryConfiguration] = None):
|
|
129
|
+
if self._initialized:
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
self.config = config or RegistryConfiguration()
|
|
133
|
+
self._plugins: Dict[str, PluginRegistration] = {}
|
|
134
|
+
self._active_kernel: Optional[str] = None
|
|
135
|
+
self._validator_mappings: Dict[str, List[str]] = {} # action_type -> plugin_ids
|
|
136
|
+
self._executor_mappings: Dict[str, str] = {} # action_type -> plugin_id
|
|
137
|
+
self._initialized = True
|
|
138
|
+
|
|
139
|
+
logger.info("Plugin registry initialized")
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
def reset(cls):
|
|
143
|
+
"""Reset the singleton instance (mainly for testing)"""
|
|
144
|
+
cls._instance = None
|
|
145
|
+
|
|
146
|
+
# =========================================================================
|
|
147
|
+
# Kernel Registration
|
|
148
|
+
# =========================================================================
|
|
149
|
+
|
|
150
|
+
def register_kernel(
|
|
151
|
+
self,
|
|
152
|
+
kernel: KernelInterface,
|
|
153
|
+
plugin_id: Optional[str] = None,
|
|
154
|
+
config: Optional[Dict[str, Any]] = None,
|
|
155
|
+
set_active: bool = True
|
|
156
|
+
) -> str:
|
|
157
|
+
"""
|
|
158
|
+
Register a kernel implementation.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
kernel: The kernel instance to register
|
|
162
|
+
plugin_id: Optional ID (defaults to kernel name)
|
|
163
|
+
config: Optional configuration for the kernel
|
|
164
|
+
set_active: Whether to set this as the active kernel
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
The plugin ID
|
|
168
|
+
"""
|
|
169
|
+
self._check_forbidden_dependencies(kernel)
|
|
170
|
+
|
|
171
|
+
plugin_id = plugin_id or kernel.metadata.name
|
|
172
|
+
|
|
173
|
+
if config:
|
|
174
|
+
kernel.configure(config)
|
|
175
|
+
|
|
176
|
+
registration = PluginRegistration(
|
|
177
|
+
plugin_id=plugin_id,
|
|
178
|
+
plugin_type=PluginType.KERNEL,
|
|
179
|
+
instance=kernel,
|
|
180
|
+
metadata=kernel.metadata,
|
|
181
|
+
config=config or {}
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
self._plugins[plugin_id] = registration
|
|
185
|
+
|
|
186
|
+
if set_active:
|
|
187
|
+
self._active_kernel = plugin_id
|
|
188
|
+
|
|
189
|
+
kernel.metadata.is_loaded = True
|
|
190
|
+
kernel.metadata.load_timestamp = datetime.now()
|
|
191
|
+
|
|
192
|
+
logger.info(f"Registered kernel: {plugin_id} (version {kernel.metadata.version})")
|
|
193
|
+
return plugin_id
|
|
194
|
+
|
|
195
|
+
def get_kernel(self, plugin_id: Optional[str] = None) -> Optional[KernelInterface]:
|
|
196
|
+
"""
|
|
197
|
+
Get a kernel by ID or the active kernel.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
plugin_id: Optional specific kernel ID
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
The kernel instance or None
|
|
204
|
+
"""
|
|
205
|
+
target_id = plugin_id or self._active_kernel
|
|
206
|
+
if not target_id or target_id not in self._plugins:
|
|
207
|
+
return None
|
|
208
|
+
|
|
209
|
+
registration = self._plugins[target_id]
|
|
210
|
+
if registration.plugin_type != PluginType.KERNEL:
|
|
211
|
+
return None
|
|
212
|
+
|
|
213
|
+
return registration.instance
|
|
214
|
+
|
|
215
|
+
def set_active_kernel(self, plugin_id: str) -> bool:
|
|
216
|
+
"""Set the active kernel by ID"""
|
|
217
|
+
if plugin_id not in self._plugins:
|
|
218
|
+
return False
|
|
219
|
+
if self._plugins[plugin_id].plugin_type != PluginType.KERNEL:
|
|
220
|
+
return False
|
|
221
|
+
|
|
222
|
+
self._active_kernel = plugin_id
|
|
223
|
+
return True
|
|
224
|
+
|
|
225
|
+
# =========================================================================
|
|
226
|
+
# Validator Registration
|
|
227
|
+
# =========================================================================
|
|
228
|
+
|
|
229
|
+
def register_validator(
|
|
230
|
+
self,
|
|
231
|
+
validator: ValidatorInterface,
|
|
232
|
+
plugin_id: Optional[str] = None,
|
|
233
|
+
action_types: Optional[List[str]] = None,
|
|
234
|
+
config: Optional[Dict[str, Any]] = None
|
|
235
|
+
) -> str:
|
|
236
|
+
"""
|
|
237
|
+
Register a validator.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
validator: The validator instance
|
|
241
|
+
plugin_id: Optional ID (defaults to validator name)
|
|
242
|
+
action_types: List of action types this validator handles
|
|
243
|
+
config: Optional configuration
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
The plugin ID
|
|
247
|
+
"""
|
|
248
|
+
self._check_forbidden_dependencies(validator)
|
|
249
|
+
|
|
250
|
+
plugin_id = plugin_id or validator.metadata.name
|
|
251
|
+
|
|
252
|
+
if config:
|
|
253
|
+
validator.configure(config)
|
|
254
|
+
|
|
255
|
+
registration = PluginRegistration(
|
|
256
|
+
plugin_id=plugin_id,
|
|
257
|
+
plugin_type=PluginType.VALIDATOR,
|
|
258
|
+
instance=validator,
|
|
259
|
+
metadata=validator.metadata,
|
|
260
|
+
config=config or {}
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
self._plugins[plugin_id] = registration
|
|
264
|
+
|
|
265
|
+
# Map to action types
|
|
266
|
+
if action_types:
|
|
267
|
+
for action_type in action_types:
|
|
268
|
+
if action_type not in self._validator_mappings:
|
|
269
|
+
self._validator_mappings[action_type] = []
|
|
270
|
+
self._validator_mappings[action_type].append(plugin_id)
|
|
271
|
+
|
|
272
|
+
validator.metadata.is_loaded = True
|
|
273
|
+
validator.metadata.load_timestamp = datetime.now()
|
|
274
|
+
|
|
275
|
+
logger.info(f"Registered validator: {plugin_id}")
|
|
276
|
+
return plugin_id
|
|
277
|
+
|
|
278
|
+
def get_validators_for_action(self, action_type: str) -> List[ValidatorInterface]:
|
|
279
|
+
"""Get all validators for an action type"""
|
|
280
|
+
plugin_ids = self._validator_mappings.get(action_type, [])
|
|
281
|
+
return [
|
|
282
|
+
self._plugins[pid].instance
|
|
283
|
+
for pid in plugin_ids
|
|
284
|
+
if pid in self._plugins
|
|
285
|
+
]
|
|
286
|
+
|
|
287
|
+
def get_all_validators(self) -> List[ValidatorInterface]:
|
|
288
|
+
"""Get all registered validators"""
|
|
289
|
+
return [
|
|
290
|
+
reg.instance for reg in self._plugins.values()
|
|
291
|
+
if reg.plugin_type == PluginType.VALIDATOR
|
|
292
|
+
]
|
|
293
|
+
|
|
294
|
+
# =========================================================================
|
|
295
|
+
# Executor Registration
|
|
296
|
+
# =========================================================================
|
|
297
|
+
|
|
298
|
+
def register_executor(
|
|
299
|
+
self,
|
|
300
|
+
executor: ExecutorInterface,
|
|
301
|
+
plugin_id: Optional[str] = None,
|
|
302
|
+
action_types: Optional[List[str]] = None,
|
|
303
|
+
config: Optional[Dict[str, Any]] = None
|
|
304
|
+
) -> str:
|
|
305
|
+
"""
|
|
306
|
+
Register an executor.
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
executor: The executor instance
|
|
310
|
+
plugin_id: Optional ID
|
|
311
|
+
action_types: List of action types this executor handles
|
|
312
|
+
config: Optional configuration
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
The plugin ID
|
|
316
|
+
"""
|
|
317
|
+
self._check_forbidden_dependencies(executor)
|
|
318
|
+
|
|
319
|
+
plugin_id = plugin_id or executor.metadata.name
|
|
320
|
+
|
|
321
|
+
if config:
|
|
322
|
+
executor.configure(config)
|
|
323
|
+
|
|
324
|
+
registration = PluginRegistration(
|
|
325
|
+
plugin_id=plugin_id,
|
|
326
|
+
plugin_type=PluginType.EXECUTOR,
|
|
327
|
+
instance=executor,
|
|
328
|
+
metadata=executor.metadata,
|
|
329
|
+
config=config or {}
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
self._plugins[plugin_id] = registration
|
|
333
|
+
|
|
334
|
+
# Map to action types
|
|
335
|
+
if action_types:
|
|
336
|
+
for action_type in action_types:
|
|
337
|
+
self._executor_mappings[action_type] = plugin_id
|
|
338
|
+
|
|
339
|
+
executor.metadata.is_loaded = True
|
|
340
|
+
executor.metadata.load_timestamp = datetime.now()
|
|
341
|
+
|
|
342
|
+
logger.info(f"Registered executor: {plugin_id}")
|
|
343
|
+
return plugin_id
|
|
344
|
+
|
|
345
|
+
def get_executor_for_action(self, action_type: str) -> Optional[ExecutorInterface]:
|
|
346
|
+
"""Get the executor for an action type"""
|
|
347
|
+
plugin_id = self._executor_mappings.get(action_type)
|
|
348
|
+
if not plugin_id or plugin_id not in self._plugins:
|
|
349
|
+
return None
|
|
350
|
+
return self._plugins[plugin_id].instance
|
|
351
|
+
|
|
352
|
+
# =========================================================================
|
|
353
|
+
# Context Router Registration
|
|
354
|
+
# =========================================================================
|
|
355
|
+
|
|
356
|
+
def register_context_router(
|
|
357
|
+
self,
|
|
358
|
+
router: Union[ContextRouterInterface, ContextRoutingInterface],
|
|
359
|
+
plugin_id: Optional[str] = None,
|
|
360
|
+
config: Optional[Dict[str, Any]] = None
|
|
361
|
+
) -> str:
|
|
362
|
+
"""Register a context router (for caas integration)"""
|
|
363
|
+
self._check_forbidden_dependencies(router)
|
|
364
|
+
|
|
365
|
+
# Get plugin ID - prefer metadata if available
|
|
366
|
+
if plugin_id:
|
|
367
|
+
pass # Use provided plugin_id
|
|
368
|
+
elif hasattr(router, 'metadata') and hasattr(router.metadata, 'name'): # type: ignore
|
|
369
|
+
plugin_id = router.metadata.name # type: ignore
|
|
370
|
+
else:
|
|
371
|
+
plugin_id = f"router_{id(router)}"
|
|
372
|
+
|
|
373
|
+
if config and hasattr(router, 'configure'):
|
|
374
|
+
router.configure(config) # type: ignore
|
|
375
|
+
|
|
376
|
+
# Get metadata if available
|
|
377
|
+
if hasattr(router, 'metadata'):
|
|
378
|
+
metadata = router.metadata # type: ignore
|
|
379
|
+
else:
|
|
380
|
+
metadata = PluginMetadata(
|
|
381
|
+
name=plugin_id,
|
|
382
|
+
version="1.0.0",
|
|
383
|
+
description="Context router",
|
|
384
|
+
plugin_type="context_router"
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
registration = PluginRegistration(
|
|
388
|
+
plugin_id=plugin_id,
|
|
389
|
+
plugin_type=PluginType.CONTEXT_ROUTER,
|
|
390
|
+
instance=router,
|
|
391
|
+
metadata=metadata,
|
|
392
|
+
config=config or {}
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
self._plugins[plugin_id] = registration
|
|
396
|
+
logger.info(f"Registered context router: {plugin_id}")
|
|
397
|
+
return plugin_id
|
|
398
|
+
|
|
399
|
+
def get_context_router(self, plugin_id: Optional[str] = None) -> Optional[Union[ContextRouterInterface, ContextRoutingInterface]]:
|
|
400
|
+
"""Get a context router by ID or the first available"""
|
|
401
|
+
if plugin_id:
|
|
402
|
+
if plugin_id in self._plugins and self._plugins[plugin_id].plugin_type == PluginType.CONTEXT_ROUTER:
|
|
403
|
+
return self._plugins[plugin_id].instance
|
|
404
|
+
return None
|
|
405
|
+
|
|
406
|
+
# Return first available router
|
|
407
|
+
for reg in self._plugins.values():
|
|
408
|
+
if reg.plugin_type == PluginType.CONTEXT_ROUTER:
|
|
409
|
+
return reg.instance
|
|
410
|
+
return None
|
|
411
|
+
|
|
412
|
+
# =========================================================================
|
|
413
|
+
# Policy Provider Registration
|
|
414
|
+
# =========================================================================
|
|
415
|
+
|
|
416
|
+
def register_policy_provider(
|
|
417
|
+
self,
|
|
418
|
+
provider: PolicyProviderInterface,
|
|
419
|
+
plugin_id: Optional[str] = None,
|
|
420
|
+
config: Optional[Dict[str, Any]] = None
|
|
421
|
+
) -> str:
|
|
422
|
+
"""Register a policy provider"""
|
|
423
|
+
self._check_forbidden_dependencies(provider)
|
|
424
|
+
|
|
425
|
+
plugin_id = plugin_id or provider.metadata.name
|
|
426
|
+
|
|
427
|
+
if config:
|
|
428
|
+
provider.configure(config)
|
|
429
|
+
|
|
430
|
+
registration = PluginRegistration(
|
|
431
|
+
plugin_id=plugin_id,
|
|
432
|
+
plugin_type=PluginType.POLICY_PROVIDER,
|
|
433
|
+
instance=provider,
|
|
434
|
+
metadata=provider.metadata,
|
|
435
|
+
config=config or {}
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
self._plugins[plugin_id] = registration
|
|
439
|
+
logger.info(f"Registered policy provider: {plugin_id}")
|
|
440
|
+
return plugin_id
|
|
441
|
+
|
|
442
|
+
def get_policy_providers(self) -> List[PolicyProviderInterface]:
|
|
443
|
+
"""Get all registered policy providers"""
|
|
444
|
+
return [
|
|
445
|
+
reg.instance for reg in self._plugins.values()
|
|
446
|
+
if reg.plugin_type == PluginType.POLICY_PROVIDER
|
|
447
|
+
]
|
|
448
|
+
|
|
449
|
+
# =========================================================================
|
|
450
|
+
# Supervisor Registration
|
|
451
|
+
# =========================================================================
|
|
452
|
+
|
|
453
|
+
def register_supervisor(
|
|
454
|
+
self,
|
|
455
|
+
supervisor: SupervisorInterface,
|
|
456
|
+
plugin_id: Optional[str] = None,
|
|
457
|
+
config: Optional[Dict[str, Any]] = None
|
|
458
|
+
) -> str:
|
|
459
|
+
"""Register a supervisor agent"""
|
|
460
|
+
self._check_forbidden_dependencies(supervisor)
|
|
461
|
+
|
|
462
|
+
plugin_id = plugin_id or supervisor.metadata.name
|
|
463
|
+
|
|
464
|
+
if config:
|
|
465
|
+
supervisor.configure(config)
|
|
466
|
+
|
|
467
|
+
registration = PluginRegistration(
|
|
468
|
+
plugin_id=plugin_id,
|
|
469
|
+
plugin_type=PluginType.SUPERVISOR,
|
|
470
|
+
instance=supervisor,
|
|
471
|
+
metadata=supervisor.metadata,
|
|
472
|
+
config=config or {}
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
self._plugins[plugin_id] = registration
|
|
476
|
+
logger.info(f"Registered supervisor: {plugin_id}")
|
|
477
|
+
return plugin_id
|
|
478
|
+
|
|
479
|
+
def get_supervisors(self) -> List[SupervisorInterface]:
|
|
480
|
+
"""Get all registered supervisors"""
|
|
481
|
+
return [
|
|
482
|
+
reg.instance for reg in self._plugins.values()
|
|
483
|
+
if reg.plugin_type == PluginType.SUPERVISOR
|
|
484
|
+
]
|
|
485
|
+
|
|
486
|
+
# =========================================================================
|
|
487
|
+
# Protocol Integration (iatp, cmvk, caas)
|
|
488
|
+
# =========================================================================
|
|
489
|
+
|
|
490
|
+
def register_message_security(
|
|
491
|
+
self,
|
|
492
|
+
security: MessageSecurityInterface,
|
|
493
|
+
plugin_id: Optional[str] = None,
|
|
494
|
+
config: Optional[Dict[str, Any]] = None
|
|
495
|
+
) -> str:
|
|
496
|
+
"""Register a message security provider (for iatp integration)"""
|
|
497
|
+
plugin_id = plugin_id or f"message_security_{id(security)}"
|
|
498
|
+
|
|
499
|
+
registration = PluginRegistration(
|
|
500
|
+
plugin_id=plugin_id,
|
|
501
|
+
plugin_type=PluginType.MESSAGE_SECURITY,
|
|
502
|
+
instance=security,
|
|
503
|
+
metadata=PluginMetadata(
|
|
504
|
+
name=plugin_id,
|
|
505
|
+
version="1.0.0",
|
|
506
|
+
description="Message security provider",
|
|
507
|
+
plugin_type="message_security"
|
|
508
|
+
),
|
|
509
|
+
config=config or {}
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
self._plugins[plugin_id] = registration
|
|
513
|
+
logger.info(f"Registered message security: {plugin_id}")
|
|
514
|
+
return plugin_id
|
|
515
|
+
|
|
516
|
+
def get_message_security(self) -> Optional[MessageSecurityInterface]:
|
|
517
|
+
"""Get the message security provider"""
|
|
518
|
+
for reg in self._plugins.values():
|
|
519
|
+
if reg.plugin_type == PluginType.MESSAGE_SECURITY:
|
|
520
|
+
return reg.instance
|
|
521
|
+
return None
|
|
522
|
+
|
|
523
|
+
def register_verifier(
|
|
524
|
+
self,
|
|
525
|
+
verifier: VerificationInterface,
|
|
526
|
+
plugin_id: Optional[str] = None,
|
|
527
|
+
config: Optional[Dict[str, Any]] = None
|
|
528
|
+
) -> str:
|
|
529
|
+
"""Register a verifier (for cmvk integration)"""
|
|
530
|
+
plugin_id = plugin_id or f"verifier_{id(verifier)}"
|
|
531
|
+
|
|
532
|
+
registration = PluginRegistration(
|
|
533
|
+
plugin_id=plugin_id,
|
|
534
|
+
plugin_type=PluginType.VERIFIER,
|
|
535
|
+
instance=verifier,
|
|
536
|
+
metadata=PluginMetadata(
|
|
537
|
+
name=plugin_id,
|
|
538
|
+
version="1.0.0",
|
|
539
|
+
description="Verification provider",
|
|
540
|
+
plugin_type="verifier"
|
|
541
|
+
),
|
|
542
|
+
config=config or {}
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
self._plugins[plugin_id] = registration
|
|
546
|
+
logger.info(f"Registered verifier: {plugin_id}")
|
|
547
|
+
return plugin_id
|
|
548
|
+
|
|
549
|
+
def get_verifier(self) -> Optional[VerificationInterface]:
|
|
550
|
+
"""Get the verification provider"""
|
|
551
|
+
for reg in self._plugins.values():
|
|
552
|
+
if reg.plugin_type == PluginType.VERIFIER:
|
|
553
|
+
return reg.instance
|
|
554
|
+
return None
|
|
555
|
+
|
|
556
|
+
# =========================================================================
|
|
557
|
+
# Plugin Discovery and Loading
|
|
558
|
+
# =========================================================================
|
|
559
|
+
|
|
560
|
+
def discover_plugins(self, path: Optional[str] = None) -> List[str]:
|
|
561
|
+
"""
|
|
562
|
+
Discover plugins from a path.
|
|
563
|
+
|
|
564
|
+
Args:
|
|
565
|
+
path: Path to search for plugins (or use config paths)
|
|
566
|
+
|
|
567
|
+
Returns:
|
|
568
|
+
List of discovered plugin IDs
|
|
569
|
+
"""
|
|
570
|
+
paths = [path] if path else self.config.plugin_paths
|
|
571
|
+
discovered = []
|
|
572
|
+
|
|
573
|
+
for plugin_path in paths:
|
|
574
|
+
try:
|
|
575
|
+
# Import module and look for plugin classes
|
|
576
|
+
module = importlib.import_module(plugin_path)
|
|
577
|
+
|
|
578
|
+
# Look for classes implementing our interfaces
|
|
579
|
+
for attr_name in dir(module):
|
|
580
|
+
attr = getattr(module, attr_name)
|
|
581
|
+
if isinstance(attr, type):
|
|
582
|
+
if issubclass(attr, KernelInterface) and attr != KernelInterface:
|
|
583
|
+
discovered.append(f"{plugin_path}.{attr_name}")
|
|
584
|
+
elif issubclass(attr, ValidatorInterface) and attr != ValidatorInterface:
|
|
585
|
+
discovered.append(f"{plugin_path}.{attr_name}")
|
|
586
|
+
|
|
587
|
+
except ImportError as e:
|
|
588
|
+
logger.warning(f"Failed to import plugin path {plugin_path}: {e}")
|
|
589
|
+
|
|
590
|
+
return discovered
|
|
591
|
+
|
|
592
|
+
def load_plugin_from_path(
|
|
593
|
+
self,
|
|
594
|
+
module_path: str,
|
|
595
|
+
class_name: str,
|
|
596
|
+
config: Optional[Dict[str, Any]] = None
|
|
597
|
+
) -> str:
|
|
598
|
+
"""
|
|
599
|
+
Load and register a plugin from a module path.
|
|
600
|
+
|
|
601
|
+
Args:
|
|
602
|
+
module_path: Python module path
|
|
603
|
+
class_name: Name of the plugin class
|
|
604
|
+
config: Optional configuration
|
|
605
|
+
|
|
606
|
+
Returns:
|
|
607
|
+
The plugin ID
|
|
608
|
+
"""
|
|
609
|
+
# Check for forbidden dependencies
|
|
610
|
+
for forbidden in self.config.forbidden_dependencies:
|
|
611
|
+
if forbidden in module_path:
|
|
612
|
+
raise ValueError(
|
|
613
|
+
f"Cannot load plugin from forbidden dependency: {forbidden}. "
|
|
614
|
+
f"Forbidden dependencies: {self.config.forbidden_dependencies}"
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
module = importlib.import_module(module_path)
|
|
618
|
+
plugin_class = getattr(module, class_name)
|
|
619
|
+
instance = plugin_class()
|
|
620
|
+
|
|
621
|
+
if isinstance(instance, KernelInterface):
|
|
622
|
+
return self.register_kernel(instance, config=config)
|
|
623
|
+
elif isinstance(instance, ValidatorInterface):
|
|
624
|
+
return self.register_validator(instance, config=config)
|
|
625
|
+
elif isinstance(instance, ExecutorInterface):
|
|
626
|
+
return self.register_executor(instance, config=config)
|
|
627
|
+
elif isinstance(instance, ContextRouterInterface):
|
|
628
|
+
return self.register_context_router(instance, config=config)
|
|
629
|
+
elif isinstance(instance, PolicyProviderInterface):
|
|
630
|
+
return self.register_policy_provider(instance, config=config)
|
|
631
|
+
elif isinstance(instance, SupervisorInterface):
|
|
632
|
+
return self.register_supervisor(instance, config=config)
|
|
633
|
+
else:
|
|
634
|
+
raise TypeError(f"Unknown plugin type: {type(instance)}")
|
|
635
|
+
|
|
636
|
+
# =========================================================================
|
|
637
|
+
# Plugin Lifecycle
|
|
638
|
+
# =========================================================================
|
|
639
|
+
|
|
640
|
+
def initialize_all(self) -> None:
|
|
641
|
+
"""Initialize all registered plugins"""
|
|
642
|
+
for registration in self._plugins.values():
|
|
643
|
+
if hasattr(registration.instance, 'initialize'):
|
|
644
|
+
registration.instance.initialize()
|
|
645
|
+
logger.info(f"Initialized {len(self._plugins)} plugins")
|
|
646
|
+
|
|
647
|
+
def shutdown_all(self) -> None:
|
|
648
|
+
"""Shutdown all registered plugins"""
|
|
649
|
+
for registration in self._plugins.values():
|
|
650
|
+
if hasattr(registration.instance, 'shutdown'):
|
|
651
|
+
registration.instance.shutdown()
|
|
652
|
+
logger.info("All plugins shut down")
|
|
653
|
+
|
|
654
|
+
def health_check_all(self) -> Dict[str, Dict[str, Any]]:
|
|
655
|
+
"""Run health check on all plugins"""
|
|
656
|
+
results = {}
|
|
657
|
+
for plugin_id, registration in self._plugins.items():
|
|
658
|
+
if hasattr(registration.instance, 'health_check'):
|
|
659
|
+
results[plugin_id] = registration.instance.health_check()
|
|
660
|
+
else:
|
|
661
|
+
results[plugin_id] = {"status": "unknown", "reason": "no health_check method"}
|
|
662
|
+
return results
|
|
663
|
+
|
|
664
|
+
# =========================================================================
|
|
665
|
+
# Utility Methods
|
|
666
|
+
# =========================================================================
|
|
667
|
+
|
|
668
|
+
def _check_forbidden_dependencies(self, instance: Any) -> None:
|
|
669
|
+
"""Check if an instance comes from a forbidden dependency"""
|
|
670
|
+
module = type(instance).__module__
|
|
671
|
+
for forbidden in self.config.forbidden_dependencies:
|
|
672
|
+
if forbidden in module:
|
|
673
|
+
raise ValueError(
|
|
674
|
+
f"Cannot register plugin from forbidden dependency: {forbidden}. "
|
|
675
|
+
f"Plugin module: {module}. "
|
|
676
|
+
f"Forbidden dependencies: {self.config.forbidden_dependencies}"
|
|
677
|
+
)
|
|
678
|
+
|
|
679
|
+
def get_plugin(self, plugin_id: str) -> Optional[Any]:
|
|
680
|
+
"""Get any plugin by ID"""
|
|
681
|
+
if plugin_id in self._plugins:
|
|
682
|
+
return self._plugins[plugin_id].instance
|
|
683
|
+
return None
|
|
684
|
+
|
|
685
|
+
def unregister_plugin(self, plugin_id: str) -> bool:
|
|
686
|
+
"""Unregister a plugin"""
|
|
687
|
+
if plugin_id not in self._plugins:
|
|
688
|
+
return False
|
|
689
|
+
|
|
690
|
+
registration = self._plugins[plugin_id]
|
|
691
|
+
|
|
692
|
+
# Shutdown if possible
|
|
693
|
+
if hasattr(registration.instance, 'shutdown'):
|
|
694
|
+
registration.instance.shutdown()
|
|
695
|
+
|
|
696
|
+
# Remove from mappings
|
|
697
|
+
for action_type, plugin_ids in list(self._validator_mappings.items()):
|
|
698
|
+
if plugin_id in plugin_ids:
|
|
699
|
+
plugin_ids.remove(plugin_id)
|
|
700
|
+
|
|
701
|
+
for action_type, pid in list(self._executor_mappings.items()):
|
|
702
|
+
if pid == plugin_id:
|
|
703
|
+
del self._executor_mappings[action_type]
|
|
704
|
+
|
|
705
|
+
# Clear active kernel if needed
|
|
706
|
+
if self._active_kernel == plugin_id:
|
|
707
|
+
self._active_kernel = None
|
|
708
|
+
|
|
709
|
+
del self._plugins[plugin_id]
|
|
710
|
+
logger.info(f"Unregistered plugin: {plugin_id}")
|
|
711
|
+
return True
|
|
712
|
+
|
|
713
|
+
def list_plugins(self, plugin_type: Optional[PluginType] = None) -> List[Dict[str, Any]]:
|
|
714
|
+
"""List all registered plugins"""
|
|
715
|
+
plugins = []
|
|
716
|
+
for plugin_id, registration in self._plugins.items():
|
|
717
|
+
if plugin_type and registration.plugin_type != plugin_type:
|
|
718
|
+
continue
|
|
719
|
+
|
|
720
|
+
plugins.append({
|
|
721
|
+
"plugin_id": plugin_id,
|
|
722
|
+
"type": registration.plugin_type.value,
|
|
723
|
+
"name": registration.metadata.name,
|
|
724
|
+
"version": registration.metadata.version,
|
|
725
|
+
"is_active": registration.is_active,
|
|
726
|
+
"registered_at": registration.registered_at.isoformat()
|
|
727
|
+
})
|
|
728
|
+
|
|
729
|
+
return plugins
|
|
730
|
+
|
|
731
|
+
def get_statistics(self) -> Dict[str, Any]:
|
|
732
|
+
"""Get registry statistics"""
|
|
733
|
+
type_counts = {}
|
|
734
|
+
for registration in self._plugins.values():
|
|
735
|
+
type_name = registration.plugin_type.value
|
|
736
|
+
type_counts[type_name] = type_counts.get(type_name, 0) + 1
|
|
737
|
+
|
|
738
|
+
return {
|
|
739
|
+
"total_plugins": len(self._plugins),
|
|
740
|
+
"plugins_by_type": type_counts,
|
|
741
|
+
"active_kernel": self._active_kernel,
|
|
742
|
+
"validator_mappings": len(self._validator_mappings),
|
|
743
|
+
"executor_mappings": len(self._executor_mappings)
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
# Convenience function to get the global registry
|
|
748
|
+
def get_registry() -> PluginRegistry:
|
|
749
|
+
"""Get the global plugin registry instance"""
|
|
750
|
+
return PluginRegistry()
|