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/registry.py
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Registry for storing and retrieving tool specifications.
|
|
5
|
+
|
|
6
|
+
The registry is a lightweight lookup mechanism that stores tool specs
|
|
7
|
+
but does NOT execute them. Execution is the responsibility of the
|
|
8
|
+
Agent Runtime (Control Plane).
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import re
|
|
14
|
+
import warnings
|
|
15
|
+
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple
|
|
16
|
+
|
|
17
|
+
from .schema import CostLevel, SideEffect, ToolHandle, ToolSpec
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class RegistryError(Exception):
|
|
24
|
+
"""Base exception for registry errors."""
|
|
25
|
+
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ToolNotFoundError(RegistryError):
|
|
30
|
+
"""Raised when a tool is not found in the registry."""
|
|
31
|
+
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ToolAlreadyExistsError(RegistryError):
|
|
36
|
+
"""Raised when attempting to register a tool that already exists."""
|
|
37
|
+
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class VersionConstraintError(RegistryError):
|
|
42
|
+
"""Raised when no tool version matches the constraint."""
|
|
43
|
+
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def parse_version(version: str) -> Tuple[int, int, int]:
|
|
48
|
+
"""Parse a semantic version string into a tuple.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
version: Version string (e.g., "1.2.3").
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
Tuple of (major, minor, patch).
|
|
55
|
+
"""
|
|
56
|
+
match = re.match(r"^(\d+)\.(\d+)\.(\d+)", version)
|
|
57
|
+
if match:
|
|
58
|
+
return (int(match.group(1)), int(match.group(2)), int(match.group(3)))
|
|
59
|
+
return (0, 0, 0)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def version_matches(version: str, constraint: str) -> bool:
|
|
63
|
+
"""Check if a version matches a constraint.
|
|
64
|
+
|
|
65
|
+
Supports constraints like:
|
|
66
|
+
- "1.0.0" - exact match
|
|
67
|
+
- ">=1.0.0" - greater than or equal
|
|
68
|
+
- ">1.0.0" - greater than
|
|
69
|
+
- "<=1.0.0" - less than or equal
|
|
70
|
+
- "<1.0.0" - less than
|
|
71
|
+
- "^1.0.0" - compatible with (same major version)
|
|
72
|
+
- "~1.0.0" - approximately (same major.minor)
|
|
73
|
+
- "*" - any version
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
version: The version to check.
|
|
77
|
+
constraint: The version constraint.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
True if version matches constraint.
|
|
81
|
+
"""
|
|
82
|
+
if constraint == "*" or constraint == "":
|
|
83
|
+
return True
|
|
84
|
+
|
|
85
|
+
v = parse_version(version)
|
|
86
|
+
|
|
87
|
+
# Handle comparison operators
|
|
88
|
+
if constraint.startswith(">="):
|
|
89
|
+
c = parse_version(constraint[2:])
|
|
90
|
+
return v >= c
|
|
91
|
+
elif constraint.startswith("<="):
|
|
92
|
+
c = parse_version(constraint[2:])
|
|
93
|
+
return v <= c
|
|
94
|
+
elif constraint.startswith(">"):
|
|
95
|
+
c = parse_version(constraint[1:])
|
|
96
|
+
return v > c
|
|
97
|
+
elif constraint.startswith("<"):
|
|
98
|
+
c = parse_version(constraint[1:])
|
|
99
|
+
return v < c
|
|
100
|
+
elif constraint.startswith("^"):
|
|
101
|
+
# Caret: compatible with major version
|
|
102
|
+
c = parse_version(constraint[1:])
|
|
103
|
+
return v[0] == c[0] and v >= c
|
|
104
|
+
elif constraint.startswith("~"):
|
|
105
|
+
# Tilde: compatible with major.minor
|
|
106
|
+
c = parse_version(constraint[1:])
|
|
107
|
+
return v[0] == c[0] and v[1] == c[1] and v >= c
|
|
108
|
+
else:
|
|
109
|
+
# Exact match
|
|
110
|
+
c = parse_version(constraint)
|
|
111
|
+
return v == c
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class Registry:
|
|
115
|
+
"""Lightweight tool registry using a local dictionary store.
|
|
116
|
+
|
|
117
|
+
This registry stores tool specifications and their callables but does NOT
|
|
118
|
+
execute them. It's purely a lookup and discovery mechanism.
|
|
119
|
+
|
|
120
|
+
The actual execution is handled by the Agent Runtime (Control Plane).
|
|
121
|
+
|
|
122
|
+
Supports versioning: multiple versions of the same tool can be registered.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
def __init__(
|
|
126
|
+
self,
|
|
127
|
+
container: Optional[Any] = None, # DependencyContainer
|
|
128
|
+
metrics_collector: Optional[Any] = None, # MetricsCollector
|
|
129
|
+
access_manager: Optional[Any] = None, # AccessControlManager
|
|
130
|
+
):
|
|
131
|
+
"""Initialize an empty registry.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
container: Optional dependency container for injection.
|
|
135
|
+
metrics_collector: Optional metrics collector.
|
|
136
|
+
access_manager: Optional access control manager.
|
|
137
|
+
"""
|
|
138
|
+
# Key: tool_name, Value: dict of version -> ToolSpec
|
|
139
|
+
self._tools: Dict[str, Dict[str, ToolSpec]] = {}
|
|
140
|
+
self._container = container
|
|
141
|
+
self._metrics = metrics_collector
|
|
142
|
+
self._access_manager = access_manager
|
|
143
|
+
|
|
144
|
+
def register_tool(
|
|
145
|
+
self, spec: ToolSpec, callable_func: Optional[Callable] = None, replace: bool = False
|
|
146
|
+
) -> None:
|
|
147
|
+
"""Register a tool in the registry.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
spec: The tool specification
|
|
151
|
+
callable_func: The actual callable function (stored but not executed)
|
|
152
|
+
replace: Whether to replace if tool version already exists
|
|
153
|
+
|
|
154
|
+
Raises:
|
|
155
|
+
ToolAlreadyExistsError: If tool version exists and replace=False
|
|
156
|
+
"""
|
|
157
|
+
tool_name = spec.metadata.name
|
|
158
|
+
tool_version = spec.metadata.version
|
|
159
|
+
|
|
160
|
+
# Initialize version dict if needed
|
|
161
|
+
if tool_name not in self._tools:
|
|
162
|
+
self._tools[tool_name] = {}
|
|
163
|
+
|
|
164
|
+
if tool_version in self._tools[tool_name] and not replace:
|
|
165
|
+
raise ToolAlreadyExistsError(
|
|
166
|
+
f"Tool '{tool_name}' version '{tool_version}' already exists. "
|
|
167
|
+
"Use replace=True to overwrite."
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# Store the callable but NEVER execute it
|
|
171
|
+
if callable_func is not None:
|
|
172
|
+
spec._callable_func = callable_func
|
|
173
|
+
|
|
174
|
+
self._tools[tool_name][tool_version] = spec
|
|
175
|
+
|
|
176
|
+
def get_tool(
|
|
177
|
+
self, name: str, version: Optional[str] = None, include_deprecated: bool = False
|
|
178
|
+
) -> ToolSpec:
|
|
179
|
+
"""Retrieve a tool specification by name and optional version constraint.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
name: The tool name
|
|
183
|
+
version: Version constraint (e.g., ">=1.0.0", "^1.0.0", "1.2.3")
|
|
184
|
+
If None, returns the latest version.
|
|
185
|
+
include_deprecated: Whether to include deprecated versions
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
The tool specification (includes the callable but doesn't execute it)
|
|
189
|
+
|
|
190
|
+
Raises:
|
|
191
|
+
ToolNotFoundError: If tool is not found
|
|
192
|
+
VersionConstraintError: If no version matches constraint
|
|
193
|
+
"""
|
|
194
|
+
if name not in self._tools:
|
|
195
|
+
raise ToolNotFoundError(f"Tool '{name}' not found in registry")
|
|
196
|
+
|
|
197
|
+
versions = self._tools[name]
|
|
198
|
+
|
|
199
|
+
if not versions:
|
|
200
|
+
raise ToolNotFoundError(f"Tool '{name}' has no registered versions")
|
|
201
|
+
|
|
202
|
+
# Filter out deprecated if needed
|
|
203
|
+
available = {
|
|
204
|
+
v: spec
|
|
205
|
+
for v, spec in versions.items()
|
|
206
|
+
if include_deprecated or not spec.metadata.deprecated
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if not available:
|
|
210
|
+
raise ToolNotFoundError(
|
|
211
|
+
f"Tool '{name}' has no non-deprecated versions. "
|
|
212
|
+
"Use include_deprecated=True to access deprecated versions."
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
if version is None:
|
|
216
|
+
# Return latest version
|
|
217
|
+
latest_version = max(available.keys(), key=parse_version)
|
|
218
|
+
return available[latest_version]
|
|
219
|
+
|
|
220
|
+
# Find matching versions
|
|
221
|
+
matching = [(v, spec) for v, spec in available.items() if version_matches(v, version)]
|
|
222
|
+
|
|
223
|
+
if not matching:
|
|
224
|
+
raise VersionConstraintError(
|
|
225
|
+
f"No version of '{name}' matches constraint '{version}'. "
|
|
226
|
+
f"Available versions: {list(available.keys())}"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
# Return the highest matching version
|
|
230
|
+
best_version = max(matching, key=lambda x: parse_version(x[0]))
|
|
231
|
+
return best_version[1]
|
|
232
|
+
|
|
233
|
+
def get_tool_handle(
|
|
234
|
+
self, name: str, version: Optional[str] = None, include_deprecated: bool = False
|
|
235
|
+
) -> ToolHandle:
|
|
236
|
+
"""Get a ToolHandle for executing a tool with all policies applied.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
name: The tool name
|
|
240
|
+
version: Version constraint
|
|
241
|
+
include_deprecated: Whether to include deprecated versions
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
ToolHandle ready for execution
|
|
245
|
+
"""
|
|
246
|
+
spec = self.get_tool(name, version, include_deprecated)
|
|
247
|
+
|
|
248
|
+
# Warn if deprecated
|
|
249
|
+
if spec.metadata.deprecated:
|
|
250
|
+
msg = f"Tool '{name}' version '{spec.version}' is deprecated."
|
|
251
|
+
if spec.metadata.deprecated_message:
|
|
252
|
+
msg += f" {spec.metadata.deprecated_message}"
|
|
253
|
+
warnings.warn(msg, DeprecationWarning, stacklevel=2)
|
|
254
|
+
|
|
255
|
+
return ToolHandle(
|
|
256
|
+
spec=spec,
|
|
257
|
+
container=self._container,
|
|
258
|
+
metrics_collector=self._metrics,
|
|
259
|
+
access_manager=self._access_manager,
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
def get_all_versions(self, name: str) -> List[str]:
|
|
263
|
+
"""Get all registered versions of a tool.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
name: The tool name
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
List of version strings, sorted newest first
|
|
270
|
+
|
|
271
|
+
Raises:
|
|
272
|
+
ToolNotFoundError: If tool is not found
|
|
273
|
+
"""
|
|
274
|
+
if name not in self._tools:
|
|
275
|
+
raise ToolNotFoundError(f"Tool '{name}' not found in registry")
|
|
276
|
+
|
|
277
|
+
versions = list(self._tools[name].keys())
|
|
278
|
+
return sorted(versions, key=parse_version, reverse=True)
|
|
279
|
+
|
|
280
|
+
def get_callable(self, name: str, version: Optional[str] = None) -> Callable:
|
|
281
|
+
"""Get the callable function for a tool.
|
|
282
|
+
|
|
283
|
+
This returns the function object but does NOT execute it.
|
|
284
|
+
The caller (Agent Runtime) is responsible for execution.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
name: The tool name
|
|
288
|
+
version: Optional version constraint
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
The callable function object
|
|
292
|
+
|
|
293
|
+
Raises:
|
|
294
|
+
ToolNotFoundError: If tool is not found
|
|
295
|
+
ValueError: If tool has no callable
|
|
296
|
+
"""
|
|
297
|
+
tool = self.get_tool(name, version)
|
|
298
|
+
|
|
299
|
+
if tool._callable_func is None:
|
|
300
|
+
raise ValueError(f"Tool '{name}' has no callable function")
|
|
301
|
+
|
|
302
|
+
return tool._callable_func
|
|
303
|
+
|
|
304
|
+
def list_tools(
|
|
305
|
+
self,
|
|
306
|
+
tag: Optional[str] = None,
|
|
307
|
+
cost: Optional[CostLevel] = None,
|
|
308
|
+
side_effect: Optional[SideEffect] = None,
|
|
309
|
+
include_all_versions: bool = False,
|
|
310
|
+
include_deprecated: bool = False,
|
|
311
|
+
) -> List[ToolSpec]:
|
|
312
|
+
"""List all registered tools with optional filtering.
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
tag: Filter by tag
|
|
316
|
+
cost: Filter by cost level
|
|
317
|
+
side_effect: Filter by side effect
|
|
318
|
+
include_all_versions: If True, return all versions. If False, only latest.
|
|
319
|
+
include_deprecated: Whether to include deprecated tools
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
List of matching tool specifications
|
|
323
|
+
"""
|
|
324
|
+
tools: List[ToolSpec] = []
|
|
325
|
+
|
|
326
|
+
for _name, versions in self._tools.items():
|
|
327
|
+
if include_all_versions:
|
|
328
|
+
specs = list(versions.values())
|
|
329
|
+
else:
|
|
330
|
+
# Get latest version
|
|
331
|
+
if versions:
|
|
332
|
+
latest_version = max(versions.keys(), key=parse_version)
|
|
333
|
+
specs = [versions[latest_version]]
|
|
334
|
+
else:
|
|
335
|
+
specs = []
|
|
336
|
+
|
|
337
|
+
for spec in specs:
|
|
338
|
+
# Filter deprecated
|
|
339
|
+
if not include_deprecated and spec.metadata.deprecated:
|
|
340
|
+
continue
|
|
341
|
+
|
|
342
|
+
# Apply filters
|
|
343
|
+
if tag is not None and tag not in spec.metadata.tags:
|
|
344
|
+
continue
|
|
345
|
+
if cost is not None and spec.metadata.cost != cost:
|
|
346
|
+
continue
|
|
347
|
+
if side_effect is not None and side_effect not in spec.metadata.side_effects:
|
|
348
|
+
continue
|
|
349
|
+
|
|
350
|
+
tools.append(spec)
|
|
351
|
+
|
|
352
|
+
return tools
|
|
353
|
+
|
|
354
|
+
def search_tools(self, query: str, include_all_versions: bool = False) -> List[ToolSpec]:
|
|
355
|
+
"""Search tools by name, description, or tags.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
query: Search query string
|
|
359
|
+
include_all_versions: Whether to search all versions
|
|
360
|
+
|
|
361
|
+
Returns:
|
|
362
|
+
List of matching tool specifications
|
|
363
|
+
"""
|
|
364
|
+
query_lower = query.lower()
|
|
365
|
+
results = []
|
|
366
|
+
|
|
367
|
+
for _name, versions in self._tools.items():
|
|
368
|
+
if include_all_versions:
|
|
369
|
+
specs = list(versions.values())
|
|
370
|
+
else:
|
|
371
|
+
if versions:
|
|
372
|
+
latest_version = max(versions.keys(), key=parse_version)
|
|
373
|
+
specs = [versions[latest_version]]
|
|
374
|
+
else:
|
|
375
|
+
specs = []
|
|
376
|
+
|
|
377
|
+
for tool in specs:
|
|
378
|
+
# Check name
|
|
379
|
+
if query_lower in tool.metadata.name.lower():
|
|
380
|
+
results.append(tool)
|
|
381
|
+
continue
|
|
382
|
+
|
|
383
|
+
# Check description
|
|
384
|
+
if query_lower in tool.metadata.description.lower():
|
|
385
|
+
results.append(tool)
|
|
386
|
+
continue
|
|
387
|
+
|
|
388
|
+
# Check tags
|
|
389
|
+
if any(query_lower in tag.lower() for tag in tool.metadata.tags):
|
|
390
|
+
results.append(tool)
|
|
391
|
+
continue
|
|
392
|
+
|
|
393
|
+
return results
|
|
394
|
+
|
|
395
|
+
def unregister_tool(self, name: str, version: Optional[str] = None) -> None:
|
|
396
|
+
"""Remove a tool from the registry.
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
name: The tool name
|
|
400
|
+
version: Specific version to remove, or None to remove all versions
|
|
401
|
+
|
|
402
|
+
Raises:
|
|
403
|
+
ToolNotFoundError: If tool is not found
|
|
404
|
+
"""
|
|
405
|
+
if name not in self._tools:
|
|
406
|
+
raise ToolNotFoundError(f"Tool '{name}' not found in registry")
|
|
407
|
+
|
|
408
|
+
if version is None:
|
|
409
|
+
# Remove all versions
|
|
410
|
+
del self._tools[name]
|
|
411
|
+
else:
|
|
412
|
+
if version not in self._tools[name]:
|
|
413
|
+
raise ToolNotFoundError(f"Tool '{name}' version '{version}' not found in registry")
|
|
414
|
+
del self._tools[name][version]
|
|
415
|
+
|
|
416
|
+
# Clean up if no versions left
|
|
417
|
+
if not self._tools[name]:
|
|
418
|
+
del self._tools[name]
|
|
419
|
+
|
|
420
|
+
def deprecate_tool(self, name: str, version: str, message: Optional[str] = None) -> None:
|
|
421
|
+
"""Mark a tool version as deprecated.
|
|
422
|
+
|
|
423
|
+
Args:
|
|
424
|
+
name: Tool name
|
|
425
|
+
version: Version to deprecate
|
|
426
|
+
message: Optional deprecation message/migration guide
|
|
427
|
+
|
|
428
|
+
Raises:
|
|
429
|
+
ToolNotFoundError: If tool/version not found
|
|
430
|
+
"""
|
|
431
|
+
if name not in self._tools or version not in self._tools[name]:
|
|
432
|
+
raise ToolNotFoundError(f"Tool '{name}' version '{version}' not found")
|
|
433
|
+
|
|
434
|
+
spec = self._tools[name][version]
|
|
435
|
+
spec.metadata.deprecated = True
|
|
436
|
+
spec.metadata.deprecated_message = message
|
|
437
|
+
|
|
438
|
+
def clear(self) -> None:
|
|
439
|
+
"""Remove all tools from the registry."""
|
|
440
|
+
self._tools.clear()
|
|
441
|
+
|
|
442
|
+
def __len__(self) -> int:
|
|
443
|
+
"""Return the number of registered tools (unique names)."""
|
|
444
|
+
return len(self._tools)
|
|
445
|
+
|
|
446
|
+
def total_versions(self) -> int:
|
|
447
|
+
"""Return the total number of registered tool versions."""
|
|
448
|
+
return sum(len(versions) for versions in self._tools.values())
|
|
449
|
+
|
|
450
|
+
def __contains__(self, name: str) -> bool:
|
|
451
|
+
"""Check if a tool is registered."""
|
|
452
|
+
return name in self._tools
|