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
atr/injection.py
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Dependency Injection for ATR tools.
|
|
5
|
+
|
|
6
|
+
Provides a mechanism for injecting configuration, credentials, and other
|
|
7
|
+
dependencies into tool functions at execution time.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import inspect
|
|
13
|
+
import threading
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from typing import (
|
|
16
|
+
Any,
|
|
17
|
+
Callable,
|
|
18
|
+
Dict,
|
|
19
|
+
Generic,
|
|
20
|
+
Optional,
|
|
21
|
+
Type,
|
|
22
|
+
TypeVar,
|
|
23
|
+
Union,
|
|
24
|
+
get_type_hints,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
T = TypeVar("T")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class InjectionToken(Generic[T]):
|
|
31
|
+
"""Token for identifying injectable dependencies.
|
|
32
|
+
|
|
33
|
+
Example:
|
|
34
|
+
>>> CONFIG_TOKEN = InjectionToken[Config]("config")
|
|
35
|
+
>>> @atr.register()
|
|
36
|
+
... def my_tool(config: Config = inject(CONFIG_TOKEN)) -> str:
|
|
37
|
+
... return config.api_key
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, name: str, default: Optional[T] = None):
|
|
41
|
+
"""Initialize injection token.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
name: Unique name for this token.
|
|
45
|
+
default: Default value if not provided.
|
|
46
|
+
"""
|
|
47
|
+
self.name = name
|
|
48
|
+
self.default = default
|
|
49
|
+
|
|
50
|
+
def __repr__(self) -> str:
|
|
51
|
+
return f"InjectionToken({self.name!r})"
|
|
52
|
+
|
|
53
|
+
def __hash__(self) -> int:
|
|
54
|
+
return hash(self.name)
|
|
55
|
+
|
|
56
|
+
def __eq__(self, other: object) -> bool:
|
|
57
|
+
if isinstance(other, InjectionToken):
|
|
58
|
+
return self.name == other.name
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass
|
|
63
|
+
class InjectionMarker:
|
|
64
|
+
"""Marker class to identify parameters that need injection.
|
|
65
|
+
|
|
66
|
+
Used as a default value for parameters that should be injected.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
token: Optional[Union[InjectionToken, str, Type]] = None
|
|
70
|
+
optional: bool = False
|
|
71
|
+
default: Any = None
|
|
72
|
+
|
|
73
|
+
def __repr__(self) -> str:
|
|
74
|
+
if self.token:
|
|
75
|
+
return f"inject({self.token!r})"
|
|
76
|
+
return "inject()"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def inject(
|
|
80
|
+
token: Optional[Union[InjectionToken, str, Type]] = None,
|
|
81
|
+
*,
|
|
82
|
+
optional: bool = False,
|
|
83
|
+
default: Any = None,
|
|
84
|
+
) -> Any:
|
|
85
|
+
"""Mark a parameter for dependency injection.
|
|
86
|
+
|
|
87
|
+
Use this as a default value for parameters that should be injected
|
|
88
|
+
by the runtime when the tool is executed.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
token: Optional injection token, type, or name string.
|
|
92
|
+
If None, uses the parameter's type annotation.
|
|
93
|
+
optional: If True, allow None when dependency isn't available.
|
|
94
|
+
default: Default value if dependency isn't available.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
InjectionMarker instance (used as parameter default).
|
|
98
|
+
|
|
99
|
+
Example:
|
|
100
|
+
>>> @atr.register()
|
|
101
|
+
... def pdf_parser(
|
|
102
|
+
... file_path: str,
|
|
103
|
+
... config: Config = inject(), # Inject by type
|
|
104
|
+
... api_key: str = inject("api_key"), # Inject by name
|
|
105
|
+
... ) -> dict:
|
|
106
|
+
... ...
|
|
107
|
+
"""
|
|
108
|
+
return InjectionMarker(token=token, optional=optional, default=default)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class DependencyContainer:
|
|
112
|
+
"""Container for managing injectable dependencies.
|
|
113
|
+
|
|
114
|
+
Provides a thread-safe container for registering and resolving
|
|
115
|
+
dependencies used by tools.
|
|
116
|
+
|
|
117
|
+
Example:
|
|
118
|
+
>>> container = DependencyContainer()
|
|
119
|
+
>>> container.register(Config, Config(api_key="secret"))
|
|
120
|
+
>>> container.register("database", db_connection)
|
|
121
|
+
>>>
|
|
122
|
+
>>> config = container.resolve(Config)
|
|
123
|
+
>>> db = container.resolve("database")
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
def __init__(self):
|
|
127
|
+
"""Initialize empty container."""
|
|
128
|
+
self._by_type: Dict[Type, Any] = {}
|
|
129
|
+
self._by_name: Dict[str, Any] = {}
|
|
130
|
+
self._by_token: Dict[InjectionToken, Any] = {}
|
|
131
|
+
self._factories: Dict[Any, Callable[[], Any]] = {}
|
|
132
|
+
self._lock = threading.RLock()
|
|
133
|
+
|
|
134
|
+
def register(
|
|
135
|
+
self,
|
|
136
|
+
key: Union[Type, str, InjectionToken],
|
|
137
|
+
value: Any = None,
|
|
138
|
+
*,
|
|
139
|
+
factory: Optional[Callable[[], Any]] = None,
|
|
140
|
+
singleton: bool = True,
|
|
141
|
+
) -> "DependencyContainer":
|
|
142
|
+
"""Register a dependency.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
key: Type, name string, or InjectionToken.
|
|
146
|
+
value: The value to inject (mutually exclusive with factory).
|
|
147
|
+
factory: Factory function to create the value.
|
|
148
|
+
singleton: If using factory, whether to cache the result.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Self for chaining.
|
|
152
|
+
|
|
153
|
+
Raises:
|
|
154
|
+
ValueError: If both value and factory are provided.
|
|
155
|
+
"""
|
|
156
|
+
if value is not None and factory is not None:
|
|
157
|
+
raise ValueError("Cannot provide both value and factory")
|
|
158
|
+
|
|
159
|
+
with self._lock:
|
|
160
|
+
if factory is not None:
|
|
161
|
+
if singleton:
|
|
162
|
+
# Wrap factory to cache result
|
|
163
|
+
_cached = {}
|
|
164
|
+
|
|
165
|
+
def cached_factory():
|
|
166
|
+
if "value" not in _cached:
|
|
167
|
+
_cached["value"] = factory()
|
|
168
|
+
return _cached["value"]
|
|
169
|
+
|
|
170
|
+
self._factories[key] = cached_factory
|
|
171
|
+
else:
|
|
172
|
+
self._factories[key] = factory
|
|
173
|
+
elif isinstance(key, type):
|
|
174
|
+
self._by_type[key] = value
|
|
175
|
+
elif isinstance(key, str):
|
|
176
|
+
self._by_name[key] = value
|
|
177
|
+
elif isinstance(key, InjectionToken):
|
|
178
|
+
self._by_token[key] = value
|
|
179
|
+
else:
|
|
180
|
+
raise TypeError(f"Unsupported key type: {type(key)}")
|
|
181
|
+
|
|
182
|
+
return self
|
|
183
|
+
|
|
184
|
+
def register_instance(self, instance: Any) -> "DependencyContainer":
|
|
185
|
+
"""Register an instance by its type.
|
|
186
|
+
|
|
187
|
+
Convenience method that registers the instance using its type as key.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
instance: The instance to register.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
Self for chaining.
|
|
194
|
+
"""
|
|
195
|
+
return self.register(type(instance), instance)
|
|
196
|
+
|
|
197
|
+
def resolve(
|
|
198
|
+
self, key: Union[Type[T], str, InjectionToken[T]], default: Any = None
|
|
199
|
+
) -> Optional[T]:
|
|
200
|
+
"""Resolve a dependency.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
key: Type, name string, or InjectionToken to resolve.
|
|
204
|
+
default: Default value if not found.
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
The resolved dependency or default.
|
|
208
|
+
"""
|
|
209
|
+
with self._lock:
|
|
210
|
+
# Check factories first
|
|
211
|
+
if key in self._factories:
|
|
212
|
+
return self._factories[key]()
|
|
213
|
+
|
|
214
|
+
# Then check direct registrations
|
|
215
|
+
if isinstance(key, type):
|
|
216
|
+
if key in self._by_type:
|
|
217
|
+
return self._by_type[key]
|
|
218
|
+
# Check subclasses
|
|
219
|
+
for _registered_type, value in self._by_type.items():
|
|
220
|
+
if isinstance(value, key):
|
|
221
|
+
return value
|
|
222
|
+
elif isinstance(key, str):
|
|
223
|
+
if key in self._by_name:
|
|
224
|
+
return self._by_name[key]
|
|
225
|
+
elif isinstance(key, InjectionToken):
|
|
226
|
+
if key in self._by_token:
|
|
227
|
+
return self._by_token[key]
|
|
228
|
+
# Fall back to token's default
|
|
229
|
+
if key.default is not None:
|
|
230
|
+
return key.default
|
|
231
|
+
|
|
232
|
+
return default
|
|
233
|
+
|
|
234
|
+
def has(self, key: Union[Type, str, InjectionToken]) -> bool:
|
|
235
|
+
"""Check if a dependency is registered.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
key: The key to check.
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
True if registered, False otherwise.
|
|
242
|
+
"""
|
|
243
|
+
with self._lock:
|
|
244
|
+
if key in self._factories:
|
|
245
|
+
return True
|
|
246
|
+
if isinstance(key, type):
|
|
247
|
+
return key in self._by_type
|
|
248
|
+
elif isinstance(key, str):
|
|
249
|
+
return key in self._by_name
|
|
250
|
+
elif isinstance(key, InjectionToken):
|
|
251
|
+
return key in self._by_token
|
|
252
|
+
return False
|
|
253
|
+
|
|
254
|
+
def unregister(self, key: Union[Type, str, InjectionToken]) -> bool:
|
|
255
|
+
"""Unregister a dependency.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
key: The key to unregister.
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
True if was registered, False otherwise.
|
|
262
|
+
"""
|
|
263
|
+
with self._lock:
|
|
264
|
+
if key in self._factories:
|
|
265
|
+
del self._factories[key]
|
|
266
|
+
return True
|
|
267
|
+
if isinstance(key, type) and key in self._by_type:
|
|
268
|
+
del self._by_type[key]
|
|
269
|
+
return True
|
|
270
|
+
elif isinstance(key, str) and key in self._by_name:
|
|
271
|
+
del self._by_name[key]
|
|
272
|
+
return True
|
|
273
|
+
elif isinstance(key, InjectionToken) and key in self._by_token:
|
|
274
|
+
del self._by_token[key]
|
|
275
|
+
return True
|
|
276
|
+
return False
|
|
277
|
+
|
|
278
|
+
def clear(self) -> None:
|
|
279
|
+
"""Clear all registered dependencies."""
|
|
280
|
+
with self._lock:
|
|
281
|
+
self._by_type.clear()
|
|
282
|
+
self._by_name.clear()
|
|
283
|
+
self._by_token.clear()
|
|
284
|
+
self._factories.clear()
|
|
285
|
+
|
|
286
|
+
def create_child(self) -> "DependencyContainer":
|
|
287
|
+
"""Create a child container that inherits from this one.
|
|
288
|
+
|
|
289
|
+
The child can override dependencies without affecting the parent.
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
New child container.
|
|
293
|
+
"""
|
|
294
|
+
child = ChildContainer(self)
|
|
295
|
+
return child
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class ChildContainer(DependencyContainer):
|
|
299
|
+
"""Child container that inherits from a parent."""
|
|
300
|
+
|
|
301
|
+
def __init__(self, parent: DependencyContainer):
|
|
302
|
+
super().__init__()
|
|
303
|
+
self._parent = parent
|
|
304
|
+
|
|
305
|
+
def resolve(
|
|
306
|
+
self, key: Union[Type[T], str, InjectionToken[T]], default: Any = None
|
|
307
|
+
) -> Optional[T]:
|
|
308
|
+
"""Resolve from self first, then parent."""
|
|
309
|
+
# Try self first
|
|
310
|
+
result = super().resolve(key, None)
|
|
311
|
+
if result is not None:
|
|
312
|
+
return result
|
|
313
|
+
|
|
314
|
+
# Fall back to parent
|
|
315
|
+
return self._parent.resolve(key, default)
|
|
316
|
+
|
|
317
|
+
def has(self, key: Union[Type, str, InjectionToken]) -> bool:
|
|
318
|
+
"""Check self and parent."""
|
|
319
|
+
return super().has(key) or self._parent.has(key)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
class InjectionResolver:
|
|
323
|
+
"""Resolves injection markers in function calls.
|
|
324
|
+
|
|
325
|
+
Used by the runtime to inject dependencies into tool functions.
|
|
326
|
+
"""
|
|
327
|
+
|
|
328
|
+
def __init__(self, container: DependencyContainer):
|
|
329
|
+
"""Initialize resolver with a container.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
container: The dependency container to use.
|
|
333
|
+
"""
|
|
334
|
+
self.container = container
|
|
335
|
+
|
|
336
|
+
def resolve_parameters(
|
|
337
|
+
self, func: Callable, args: tuple, kwargs: Dict[str, Any]
|
|
338
|
+
) -> Dict[str, Any]:
|
|
339
|
+
"""Resolve injection markers in function parameters.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
func: The function being called.
|
|
343
|
+
args: Positional arguments provided.
|
|
344
|
+
kwargs: Keyword arguments provided.
|
|
345
|
+
|
|
346
|
+
Returns:
|
|
347
|
+
Updated kwargs with injected values.
|
|
348
|
+
|
|
349
|
+
Raises:
|
|
350
|
+
InjectionError: If a required dependency cannot be resolved.
|
|
351
|
+
"""
|
|
352
|
+
sig = inspect.signature(func)
|
|
353
|
+
type_hints = get_type_hints(func) if hasattr(func, "__annotations__") else {}
|
|
354
|
+
|
|
355
|
+
resolved_kwargs = dict(kwargs)
|
|
356
|
+
|
|
357
|
+
# Convert positional args to kwargs
|
|
358
|
+
params = list(sig.parameters.items())
|
|
359
|
+
for i, arg in enumerate(args):
|
|
360
|
+
if i < len(params):
|
|
361
|
+
param_name = params[i][0]
|
|
362
|
+
resolved_kwargs[param_name] = arg
|
|
363
|
+
|
|
364
|
+
# Check each parameter for injection markers
|
|
365
|
+
for param_name, param in sig.parameters.items():
|
|
366
|
+
# Skip if already provided
|
|
367
|
+
if param_name in resolved_kwargs:
|
|
368
|
+
continue
|
|
369
|
+
|
|
370
|
+
# Check if default is an injection marker
|
|
371
|
+
if isinstance(param.default, InjectionMarker):
|
|
372
|
+
marker = param.default
|
|
373
|
+
|
|
374
|
+
# Determine the key to use
|
|
375
|
+
if marker.token is not None:
|
|
376
|
+
key = marker.token
|
|
377
|
+
elif param_name in type_hints:
|
|
378
|
+
key = type_hints[param_name]
|
|
379
|
+
else:
|
|
380
|
+
key = param_name
|
|
381
|
+
|
|
382
|
+
# Resolve the dependency
|
|
383
|
+
value = self.container.resolve(key, marker.default)
|
|
384
|
+
|
|
385
|
+
if value is None and not marker.optional:
|
|
386
|
+
raise InjectionError(
|
|
387
|
+
f"Cannot resolve dependency for parameter '{param_name}' "
|
|
388
|
+
f"with key {key!r}"
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
resolved_kwargs[param_name] = value
|
|
392
|
+
|
|
393
|
+
return resolved_kwargs
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
class InjectionError(Exception):
|
|
397
|
+
"""Raised when dependency injection fails."""
|
|
398
|
+
|
|
399
|
+
pass
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
# Global container instance
|
|
403
|
+
_global_container: DependencyContainer = DependencyContainer()
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def get_container() -> DependencyContainer:
|
|
407
|
+
"""Get the global dependency container.
|
|
408
|
+
|
|
409
|
+
Returns:
|
|
410
|
+
The global DependencyContainer instance.
|
|
411
|
+
"""
|
|
412
|
+
return _global_container
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def set_container(container: DependencyContainer) -> None:
|
|
416
|
+
"""Set the global dependency container.
|
|
417
|
+
|
|
418
|
+
Args:
|
|
419
|
+
container: The container to use globally.
|
|
420
|
+
"""
|
|
421
|
+
global _global_container
|
|
422
|
+
_global_container = container
|