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/schema.py
ADDED
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Schema definitions for Agent Tool Registry.
|
|
5
|
+
|
|
6
|
+
Defines the rigorous JSON/Pydantic schema for tool specifications,
|
|
7
|
+
similar to OpenAI Function Calling spec.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import asyncio
|
|
13
|
+
import time
|
|
14
|
+
from enum import Enum
|
|
15
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
16
|
+
|
|
17
|
+
from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, field_validator
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ParameterType(str, Enum):
|
|
24
|
+
"""Supported parameter types for tool inputs/outputs."""
|
|
25
|
+
|
|
26
|
+
STRING = "string"
|
|
27
|
+
INTEGER = "integer"
|
|
28
|
+
NUMBER = "number"
|
|
29
|
+
BOOLEAN = "boolean"
|
|
30
|
+
ARRAY = "array"
|
|
31
|
+
OBJECT = "object"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ParameterSpec(BaseModel):
|
|
35
|
+
"""Specification for a single parameter."""
|
|
36
|
+
|
|
37
|
+
name: str = Field(..., description="Parameter name")
|
|
38
|
+
type: ParameterType = Field(..., description="Parameter type")
|
|
39
|
+
description: str = Field(..., description="Human-readable description")
|
|
40
|
+
required: bool = Field(default=True, description="Whether parameter is required")
|
|
41
|
+
default: Optional[Any] = Field(default=None, description="Default value if not required")
|
|
42
|
+
enum: Optional[List[Any]] = Field(default=None, description="Allowed values (for enum types)")
|
|
43
|
+
items: Optional[Dict[str, Any]] = Field(
|
|
44
|
+
default=None, description="Array item schema (for array type)"
|
|
45
|
+
)
|
|
46
|
+
properties: Optional[Dict[str, Any]] = Field(
|
|
47
|
+
default=None, description="Object properties (for object type)"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
@field_validator("default")
|
|
51
|
+
@classmethod
|
|
52
|
+
def validate_default(cls, v, info):
|
|
53
|
+
"""Ensure default is only set for non-required parameters."""
|
|
54
|
+
if v is not None and info.data.get("required", True):
|
|
55
|
+
raise ValueError("Cannot set default value for required parameter")
|
|
56
|
+
return v
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class SideEffect(str, Enum):
|
|
60
|
+
"""Types of side effects a tool may have."""
|
|
61
|
+
|
|
62
|
+
NONE = "none"
|
|
63
|
+
READ = "read"
|
|
64
|
+
WRITE = "write"
|
|
65
|
+
DELETE = "delete"
|
|
66
|
+
NETWORK = "network"
|
|
67
|
+
FILESYSTEM = "filesystem"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class CostLevel(str, Enum):
|
|
71
|
+
"""Cost level for tool execution."""
|
|
72
|
+
|
|
73
|
+
FREE = "free"
|
|
74
|
+
LOW = "low"
|
|
75
|
+
MEDIUM = "medium"
|
|
76
|
+
HIGH = "high"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class ToolMetadata(BaseModel):
|
|
80
|
+
"""Metadata about a tool."""
|
|
81
|
+
|
|
82
|
+
name: str = Field(..., description="Unique tool identifier")
|
|
83
|
+
description: str = Field(..., description="Human-readable tool description")
|
|
84
|
+
version: str = Field(default="1.0.0", description="Semantic version (e.g., '1.0.0')")
|
|
85
|
+
author: Optional[str] = Field(default=None, description="Tool author")
|
|
86
|
+
cost: CostLevel = Field(default=CostLevel.FREE, description="Estimated execution cost")
|
|
87
|
+
side_effects: List[SideEffect] = Field(
|
|
88
|
+
default_factory=lambda: [SideEffect.NONE], description="Tool side effects"
|
|
89
|
+
)
|
|
90
|
+
tags: List[str] = Field(default_factory=list, description="Searchable tags")
|
|
91
|
+
|
|
92
|
+
# New fields for enhanced functionality
|
|
93
|
+
is_async: bool = Field(default=False, description="Whether tool supports async execution")
|
|
94
|
+
permissions: List[str] = Field(
|
|
95
|
+
default_factory=list, description="Required permissions/roles to access"
|
|
96
|
+
)
|
|
97
|
+
rate_limit: Optional[str] = Field(
|
|
98
|
+
default=None, description="Rate limit string (e.g., '10/minute')"
|
|
99
|
+
)
|
|
100
|
+
deprecated: bool = Field(default=False, description="Whether this tool version is deprecated")
|
|
101
|
+
deprecated_message: Optional[str] = Field(
|
|
102
|
+
default=None, description="Deprecation message/migration guide"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
@field_validator("version")
|
|
106
|
+
@classmethod
|
|
107
|
+
def validate_version(cls, v: str) -> str:
|
|
108
|
+
"""Validate semantic version format."""
|
|
109
|
+
import re
|
|
110
|
+
|
|
111
|
+
# Basic semver pattern
|
|
112
|
+
pattern = r"^\d+\.\d+\.\d+(?:-[\w.]+)?(?:\+[\w.]+)?$"
|
|
113
|
+
if not re.match(pattern, v):
|
|
114
|
+
raise ValueError(f"Invalid version format: {v}. Expected semver (e.g., '1.0.0')")
|
|
115
|
+
return v
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def version_tuple(self) -> tuple:
|
|
119
|
+
"""Get version as a comparable tuple."""
|
|
120
|
+
import re
|
|
121
|
+
|
|
122
|
+
# Extract major.minor.patch
|
|
123
|
+
match = re.match(r"^(\d+)\.(\d+)\.(\d+)", self.version)
|
|
124
|
+
if match:
|
|
125
|
+
return (int(match.group(1)), int(match.group(2)), int(match.group(3)))
|
|
126
|
+
return (0, 0, 0)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class ToolSpec(BaseModel):
|
|
130
|
+
"""Complete specification for a tool.
|
|
131
|
+
|
|
132
|
+
This is the core schema that defines what a tool looks like in the registry.
|
|
133
|
+
It does NOT execute the tool - it just describes it.
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
137
|
+
|
|
138
|
+
metadata: ToolMetadata = Field(..., description="Tool metadata")
|
|
139
|
+
parameters: List[ParameterSpec] = Field(default_factory=list, description="Input parameters")
|
|
140
|
+
returns: Optional[ParameterSpec] = Field(default=None, description="Return value specification")
|
|
141
|
+
|
|
142
|
+
# The actual callable - stored but never executed by the registry
|
|
143
|
+
# Use PrivateAttr for internal state that shouldn't be validated
|
|
144
|
+
_callable_func: Optional[Any] = PrivateAttr(default=None)
|
|
145
|
+
|
|
146
|
+
# Enhanced execution configuration
|
|
147
|
+
_retry_policy: Optional[Any] = PrivateAttr(default=None) # RetryPolicy
|
|
148
|
+
_rate_limit_policy: Optional[Any] = PrivateAttr(default=None) # RateLimitPolicy
|
|
149
|
+
_health_check: Optional[Any] = PrivateAttr(default=None) # HealthCheck
|
|
150
|
+
_access_policy: Optional[Any] = PrivateAttr(default=None) # AccessPolicy
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def name(self) -> str:
|
|
154
|
+
"""Convenience property for tool name."""
|
|
155
|
+
return self.metadata.name
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def version(self) -> str:
|
|
159
|
+
"""Convenience property for tool version."""
|
|
160
|
+
return self.metadata.version
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def is_async(self) -> bool:
|
|
164
|
+
"""Check if tool supports async execution."""
|
|
165
|
+
return self.metadata.is_async
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def retry_policy(self) -> Optional[Any]:
|
|
169
|
+
"""Get the retry policy if set."""
|
|
170
|
+
return self._retry_policy
|
|
171
|
+
|
|
172
|
+
@retry_policy.setter
|
|
173
|
+
def retry_policy(self, policy: Any) -> None:
|
|
174
|
+
"""Set the retry policy."""
|
|
175
|
+
self._retry_policy = policy
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def rate_limit_policy(self) -> Optional[Any]:
|
|
179
|
+
"""Get the rate limit policy if set."""
|
|
180
|
+
return self._rate_limit_policy
|
|
181
|
+
|
|
182
|
+
@rate_limit_policy.setter
|
|
183
|
+
def rate_limit_policy(self, policy: Any) -> None:
|
|
184
|
+
"""Set the rate limit policy."""
|
|
185
|
+
self._rate_limit_policy = policy
|
|
186
|
+
|
|
187
|
+
@property
|
|
188
|
+
def health_check(self) -> Optional[Any]:
|
|
189
|
+
"""Get the health check if set."""
|
|
190
|
+
return self._health_check
|
|
191
|
+
|
|
192
|
+
@health_check.setter
|
|
193
|
+
def health_check(self, check: Any) -> None:
|
|
194
|
+
"""Set the health check."""
|
|
195
|
+
self._health_check = check
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def access_policy(self) -> Optional[Any]:
|
|
199
|
+
"""Get the access policy if set."""
|
|
200
|
+
return self._access_policy
|
|
201
|
+
|
|
202
|
+
@access_policy.setter
|
|
203
|
+
def access_policy(self, policy: Any) -> None:
|
|
204
|
+
"""Set the access policy."""
|
|
205
|
+
self._access_policy = policy
|
|
206
|
+
|
|
207
|
+
def to_openai_function_schema(self) -> Dict[str, Any]:
|
|
208
|
+
"""Convert to OpenAI function calling format.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Dictionary in OpenAI function calling format
|
|
212
|
+
"""
|
|
213
|
+
properties = {}
|
|
214
|
+
required = []
|
|
215
|
+
|
|
216
|
+
for param in self.parameters:
|
|
217
|
+
prop_schema = {
|
|
218
|
+
"type": param.type.value,
|
|
219
|
+
"description": param.description,
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if param.enum:
|
|
223
|
+
prop_schema["enum"] = param.enum
|
|
224
|
+
if param.items:
|
|
225
|
+
prop_schema["items"] = param.items
|
|
226
|
+
if param.properties:
|
|
227
|
+
prop_schema["properties"] = param.properties
|
|
228
|
+
|
|
229
|
+
properties[param.name] = prop_schema
|
|
230
|
+
|
|
231
|
+
if param.required:
|
|
232
|
+
required.append(param.name)
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
"name": self.metadata.name,
|
|
236
|
+
"description": self.metadata.description,
|
|
237
|
+
"parameters": {
|
|
238
|
+
"type": "object",
|
|
239
|
+
"properties": properties,
|
|
240
|
+
"required": required,
|
|
241
|
+
},
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
def to_anthropic_tool_schema(self) -> Dict[str, Any]:
|
|
245
|
+
"""Convert to Anthropic tool use format.
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
Dictionary in Anthropic tool use format.
|
|
249
|
+
"""
|
|
250
|
+
return {
|
|
251
|
+
"name": self.metadata.name,
|
|
252
|
+
"description": self.metadata.description,
|
|
253
|
+
"input_schema": {
|
|
254
|
+
"type": "object",
|
|
255
|
+
"properties": {
|
|
256
|
+
param.name: {
|
|
257
|
+
"type": param.type.value,
|
|
258
|
+
"description": param.description,
|
|
259
|
+
**({"enum": param.enum} if param.enum else {}),
|
|
260
|
+
**({"items": param.items} if param.items else {}),
|
|
261
|
+
}
|
|
262
|
+
for param in self.parameters
|
|
263
|
+
},
|
|
264
|
+
"required": [p.name for p in self.parameters if p.required],
|
|
265
|
+
},
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class ToolHandle:
|
|
270
|
+
"""Handle for executing a registered tool with all policies applied.
|
|
271
|
+
|
|
272
|
+
This is the public interface for tool execution, applying rate limiting,
|
|
273
|
+
retries, metrics collection, and access control automatically.
|
|
274
|
+
|
|
275
|
+
Example:
|
|
276
|
+
>>> tool = atr.get_tool("pdf_parser", version=">=1.0.0")
|
|
277
|
+
>>> result = await tool.call_async(file_path="doc.pdf")
|
|
278
|
+
>>> # or synchronously
|
|
279
|
+
>>> result = tool.call(file_path="doc.pdf")
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
def __init__(
|
|
283
|
+
self,
|
|
284
|
+
spec: ToolSpec,
|
|
285
|
+
container: Optional[Any] = None, # DependencyContainer
|
|
286
|
+
metrics_collector: Optional[Any] = None, # MetricsCollector
|
|
287
|
+
access_manager: Optional[Any] = None, # AccessControlManager
|
|
288
|
+
):
|
|
289
|
+
"""Initialize tool handle.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
spec: The tool specification.
|
|
293
|
+
container: Optional dependency container for injection.
|
|
294
|
+
metrics_collector: Optional metrics collector.
|
|
295
|
+
access_manager: Optional access control manager.
|
|
296
|
+
"""
|
|
297
|
+
self._spec = spec
|
|
298
|
+
self._container = container
|
|
299
|
+
self._metrics = metrics_collector
|
|
300
|
+
self._access_manager = access_manager
|
|
301
|
+
|
|
302
|
+
@property
|
|
303
|
+
def spec(self) -> ToolSpec:
|
|
304
|
+
"""Get the underlying tool specification."""
|
|
305
|
+
return self._spec
|
|
306
|
+
|
|
307
|
+
@property
|
|
308
|
+
def name(self) -> str:
|
|
309
|
+
"""Get tool name."""
|
|
310
|
+
return self._spec.name
|
|
311
|
+
|
|
312
|
+
@property
|
|
313
|
+
def version(self) -> str:
|
|
314
|
+
"""Get tool version."""
|
|
315
|
+
return self._spec.version
|
|
316
|
+
|
|
317
|
+
@property
|
|
318
|
+
def is_async(self) -> bool:
|
|
319
|
+
"""Check if tool supports async."""
|
|
320
|
+
return self._spec.is_async
|
|
321
|
+
|
|
322
|
+
def call(self, *args: Any, **kwargs: Any) -> Any:
|
|
323
|
+
"""Execute the tool synchronously with all policies.
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
*args: Positional arguments.
|
|
327
|
+
**kwargs: Keyword arguments.
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
The tool's return value.
|
|
331
|
+
|
|
332
|
+
Raises:
|
|
333
|
+
ValueError: If tool has no callable.
|
|
334
|
+
RateLimitExceeded: If rate limited.
|
|
335
|
+
RetryExhausted: If all retries fail.
|
|
336
|
+
AccessDeniedError: If access is denied.
|
|
337
|
+
"""
|
|
338
|
+
if self._spec._callable_func is None:
|
|
339
|
+
raise ValueError(f"Tool '{self.name}' has no callable function")
|
|
340
|
+
|
|
341
|
+
start_time = time.perf_counter()
|
|
342
|
+
error = None
|
|
343
|
+
rate_limited = False
|
|
344
|
+
|
|
345
|
+
try:
|
|
346
|
+
# Apply rate limiting
|
|
347
|
+
if self._spec._rate_limit_policy and not self._spec._rate_limit_policy.acquire(
|
|
348
|
+
blocking=True, timeout=30
|
|
349
|
+
):
|
|
350
|
+
rate_limited = True
|
|
351
|
+
from atr.policies import RateLimitExceeded
|
|
352
|
+
|
|
353
|
+
raise RateLimitExceeded(f"Rate limit exceeded for tool '{self.name}'")
|
|
354
|
+
|
|
355
|
+
# Inject dependencies if container available
|
|
356
|
+
if self._container:
|
|
357
|
+
from atr.injection import InjectionResolver
|
|
358
|
+
|
|
359
|
+
resolver = InjectionResolver(self._container)
|
|
360
|
+
kwargs = resolver.resolve_parameters(self._spec._callable_func, args, kwargs)
|
|
361
|
+
args = ()
|
|
362
|
+
|
|
363
|
+
# Execute with retry policy if configured
|
|
364
|
+
if self._spec._retry_policy:
|
|
365
|
+
from atr.policies import with_retry
|
|
366
|
+
|
|
367
|
+
result = with_retry(
|
|
368
|
+
self._spec._retry_policy, self._spec._callable_func, *args, **kwargs
|
|
369
|
+
)
|
|
370
|
+
else:
|
|
371
|
+
result = self._spec._callable_func(*args, **kwargs)
|
|
372
|
+
|
|
373
|
+
return result
|
|
374
|
+
|
|
375
|
+
except Exception as e:
|
|
376
|
+
error = e
|
|
377
|
+
raise
|
|
378
|
+
finally:
|
|
379
|
+
# Record metrics
|
|
380
|
+
if self._metrics:
|
|
381
|
+
latency_ms = (time.perf_counter() - start_time) * 1000
|
|
382
|
+
self._metrics.record_call(
|
|
383
|
+
tool_name=self.name,
|
|
384
|
+
latency_ms=latency_ms,
|
|
385
|
+
success=(error is None),
|
|
386
|
+
error=error,
|
|
387
|
+
rate_limited=rate_limited,
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
async def call_async(self, *args: Any, **kwargs: Any) -> Any:
|
|
391
|
+
"""Execute the tool asynchronously with all policies.
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
*args: Positional arguments.
|
|
395
|
+
**kwargs: Keyword arguments.
|
|
396
|
+
|
|
397
|
+
Returns:
|
|
398
|
+
The tool's return value.
|
|
399
|
+
|
|
400
|
+
Raises:
|
|
401
|
+
ValueError: If tool has no callable.
|
|
402
|
+
RateLimitExceeded: If rate limited.
|
|
403
|
+
RetryExhausted: If all retries fail.
|
|
404
|
+
AccessDeniedError: If access is denied.
|
|
405
|
+
"""
|
|
406
|
+
if self._spec._callable_func is None:
|
|
407
|
+
raise ValueError(f"Tool '{self.name}' has no callable function")
|
|
408
|
+
|
|
409
|
+
start_time = time.perf_counter()
|
|
410
|
+
error = None
|
|
411
|
+
rate_limited = False
|
|
412
|
+
|
|
413
|
+
try:
|
|
414
|
+
# Apply rate limiting
|
|
415
|
+
if (
|
|
416
|
+
self._spec._rate_limit_policy
|
|
417
|
+
and not await self._spec._rate_limit_policy.acquire_async(blocking=True, timeout=30)
|
|
418
|
+
):
|
|
419
|
+
rate_limited = True
|
|
420
|
+
from atr.policies import RateLimitExceeded
|
|
421
|
+
|
|
422
|
+
raise RateLimitExceeded(f"Rate limit exceeded for tool '{self.name}'")
|
|
423
|
+
|
|
424
|
+
# Inject dependencies if container available
|
|
425
|
+
if self._container:
|
|
426
|
+
from atr.injection import InjectionResolver
|
|
427
|
+
|
|
428
|
+
resolver = InjectionResolver(self._container)
|
|
429
|
+
kwargs = resolver.resolve_parameters(self._spec._callable_func, args, kwargs)
|
|
430
|
+
args = ()
|
|
431
|
+
|
|
432
|
+
# Execute with retry policy if configured
|
|
433
|
+
if self._spec._retry_policy:
|
|
434
|
+
from atr.policies import with_retry_async
|
|
435
|
+
|
|
436
|
+
result = await with_retry_async(
|
|
437
|
+
self._spec._retry_policy, self._spec._callable_func, *args, **kwargs
|
|
438
|
+
)
|
|
439
|
+
else:
|
|
440
|
+
func = self._spec._callable_func
|
|
441
|
+
result = func(*args, **kwargs)
|
|
442
|
+
if asyncio.iscoroutine(result):
|
|
443
|
+
result = await result
|
|
444
|
+
|
|
445
|
+
return result
|
|
446
|
+
|
|
447
|
+
except Exception as e:
|
|
448
|
+
error = e
|
|
449
|
+
raise
|
|
450
|
+
finally:
|
|
451
|
+
# Record metrics
|
|
452
|
+
if self._metrics:
|
|
453
|
+
latency_ms = (time.perf_counter() - start_time) * 1000
|
|
454
|
+
self._metrics.record_call(
|
|
455
|
+
tool_name=self.name,
|
|
456
|
+
latency_ms=latency_ms,
|
|
457
|
+
success=(error is None),
|
|
458
|
+
error=error,
|
|
459
|
+
rate_limited=rate_limited,
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
def check_health(self) -> Optional[Any]:
|
|
463
|
+
"""Run health check if configured.
|
|
464
|
+
|
|
465
|
+
Returns:
|
|
466
|
+
HealthCheckResult or None if no health check configured.
|
|
467
|
+
"""
|
|
468
|
+
if self._spec._health_check:
|
|
469
|
+
return self._spec._health_check.check()
|
|
470
|
+
return None
|
|
471
|
+
|
|
472
|
+
async def check_health_async(self) -> Optional[Any]:
|
|
473
|
+
"""Run health check asynchronously.
|
|
474
|
+
|
|
475
|
+
Returns:
|
|
476
|
+
HealthCheckResult or None if no health check configured.
|
|
477
|
+
"""
|
|
478
|
+
if self._spec._health_check:
|
|
479
|
+
return await self._spec._health_check.check_async()
|
|
480
|
+
return None
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Safe Tool Plugins for Agent Tool Registry (ATR).
|
|
5
|
+
|
|
6
|
+
This package provides pre-built, security-hardened tools that agents can use
|
|
7
|
+
safely without risk of unauthorized access or dangerous operations.
|
|
8
|
+
|
|
9
|
+
All tools in this package follow the principle of least privilege:
|
|
10
|
+
- Read-only operations where possible
|
|
11
|
+
- Sandboxed file access
|
|
12
|
+
- Rate limiting on network operations
|
|
13
|
+
- Input validation and sanitization
|
|
14
|
+
- No shell execution
|
|
15
|
+
|
|
16
|
+
Available Tools:
|
|
17
|
+
- HttpClientTool: Safe HTTP requests with URL whitelisting
|
|
18
|
+
- FileReaderTool: Read-only file access with path sandboxing
|
|
19
|
+
- JsonParserTool: Safe JSON/YAML parsing
|
|
20
|
+
- CalculatorTool: Safe mathematical operations
|
|
21
|
+
- DateTimeTool: Timezone-aware datetime operations
|
|
22
|
+
- TextTool: Safe text processing operations
|
|
23
|
+
|
|
24
|
+
Example:
|
|
25
|
+
>>> from atr.tools.safe import HttpClientTool, FileReaderTool
|
|
26
|
+
>>>
|
|
27
|
+
>>> # Create tools with restrictions
|
|
28
|
+
>>> http = HttpClientTool(
|
|
29
|
+
... allowed_domains=["api.example.com"],
|
|
30
|
+
... rate_limit=10 # requests per minute
|
|
31
|
+
... )
|
|
32
|
+
>>>
|
|
33
|
+
>>> reader = FileReaderTool(
|
|
34
|
+
... sandbox_path="/data/safe",
|
|
35
|
+
... max_file_size=1_000_000 # 1MB
|
|
36
|
+
... )
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
from typing import List
|
|
40
|
+
|
|
41
|
+
__all__: List[str] = [
|
|
42
|
+
"HttpClientTool",
|
|
43
|
+
"FileReaderTool",
|
|
44
|
+
"JsonParserTool",
|
|
45
|
+
"CalculatorTool",
|
|
46
|
+
"DateTimeTool",
|
|
47
|
+
"TextTool",
|
|
48
|
+
"create_safe_toolkit",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def __getattr__(name: str):
|
|
53
|
+
"""Lazy import tools."""
|
|
54
|
+
if name == "HttpClientTool":
|
|
55
|
+
from atr.tools.safe.http_client import HttpClientTool
|
|
56
|
+
return HttpClientTool
|
|
57
|
+
elif name == "FileReaderTool":
|
|
58
|
+
from atr.tools.safe.file_reader import FileReaderTool
|
|
59
|
+
return FileReaderTool
|
|
60
|
+
elif name == "JsonParserTool":
|
|
61
|
+
from atr.tools.safe.json_parser import JsonParserTool
|
|
62
|
+
return JsonParserTool
|
|
63
|
+
elif name == "CalculatorTool":
|
|
64
|
+
from atr.tools.safe.calculator import CalculatorTool
|
|
65
|
+
return CalculatorTool
|
|
66
|
+
elif name == "DateTimeTool":
|
|
67
|
+
from atr.tools.safe.datetime_tool import DateTimeTool
|
|
68
|
+
return DateTimeTool
|
|
69
|
+
elif name == "TextTool":
|
|
70
|
+
from atr.tools.safe.text_tool import TextTool
|
|
71
|
+
return TextTool
|
|
72
|
+
elif name == "create_safe_toolkit":
|
|
73
|
+
from atr.tools.safe.toolkit import create_safe_toolkit
|
|
74
|
+
return create_safe_toolkit
|
|
75
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|