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
agent_os/providers.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Provider Discovery System
|
|
5
|
+
|
|
6
|
+
Enables plug-and-play upgrades from Public Preview to Advanced implementations.
|
|
7
|
+
When an advanced provider package is installed (e.g., agent-governance-providers),
|
|
8
|
+
factory functions automatically return the advanced implementation. Otherwise,
|
|
9
|
+
they return the built-in Public Preview.
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
from agent_os.providers import get_verification_engine, get_self_correction_kernel
|
|
13
|
+
|
|
14
|
+
engine = get_verification_engine() # Advanced if available, else CE
|
|
15
|
+
kernel = get_self_correction_kernel() # Advanced if available, else CE
|
|
16
|
+
|
|
17
|
+
Advanced: pip install agent-governance-providers (from PyPI)
|
|
18
|
+
Community: pip install agent-os-kernel (from PyPI) — works out of the box
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import logging
|
|
24
|
+
from importlib.metadata import entry_points
|
|
25
|
+
from typing import Any
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
# Entry point group names — internal packages register under these
|
|
30
|
+
PROVIDER_GROUPS = {
|
|
31
|
+
"verification": "agent_os.providers.verification",
|
|
32
|
+
"self_correction": "agent_os.providers.self_correction",
|
|
33
|
+
"policy_engine": "agent_os.providers.policy_engine",
|
|
34
|
+
"context_service": "agent_os.providers.context_service",
|
|
35
|
+
"memory": "agent_os.providers.memory",
|
|
36
|
+
"trust_protocol": "agent_os.providers.trust_protocol",
|
|
37
|
+
"mute_agent": "agent_os.providers.mute_agent",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Cache loaded providers to avoid repeated discovery
|
|
41
|
+
_provider_cache: dict[str, Any] = {}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _discover_provider(group: str) -> type | None:
|
|
45
|
+
"""Discover an advanced provider via entry_points.
|
|
46
|
+
|
|
47
|
+
Returns the provider class if found, None otherwise.
|
|
48
|
+
"""
|
|
49
|
+
if group in _provider_cache:
|
|
50
|
+
return _provider_cache[group]
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
eps = entry_points(group=group)
|
|
54
|
+
if eps:
|
|
55
|
+
# Use the first registered provider (highest priority)
|
|
56
|
+
ep = next(iter(eps))
|
|
57
|
+
provider_cls = ep.load()
|
|
58
|
+
_provider_cache[group] = provider_cls
|
|
59
|
+
logger.info(
|
|
60
|
+
"Advanced provider loaded: %s from %s", ep.name, ep.value
|
|
61
|
+
)
|
|
62
|
+
return provider_cls
|
|
63
|
+
except Exception:
|
|
64
|
+
logger.debug("Provider discovery failed for %s", group, exc_info=True)
|
|
65
|
+
|
|
66
|
+
_provider_cache[group] = None
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_verification_engine(**kwargs: Any):
|
|
71
|
+
"""Get the best available verification engine.
|
|
72
|
+
|
|
73
|
+
Advanced: Cross-model adversarial verification with strategy banning.
|
|
74
|
+
Community: Single-model self-check using difflib comparison.
|
|
75
|
+
"""
|
|
76
|
+
provider = _discover_provider(PROVIDER_GROUPS["verification"])
|
|
77
|
+
if provider is not None:
|
|
78
|
+
return provider(**kwargs)
|
|
79
|
+
|
|
80
|
+
from cmvk.verification import VerificationEngine
|
|
81
|
+
return VerificationEngine(**kwargs)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def get_self_correction_kernel(**kwargs: Any):
|
|
85
|
+
"""Get the best available self-correction kernel.
|
|
86
|
+
|
|
87
|
+
Advanced: Dual-loop OODA with differential auditing and semantic purge.
|
|
88
|
+
Community: Simple retry with exponential backoff.
|
|
89
|
+
"""
|
|
90
|
+
provider = _discover_provider(PROVIDER_GROUPS["self_correction"])
|
|
91
|
+
if provider is not None:
|
|
92
|
+
return provider(**kwargs)
|
|
93
|
+
|
|
94
|
+
from agent_kernel.kernel import SelfCorrectingAgentKernel
|
|
95
|
+
return SelfCorrectingAgentKernel(**kwargs)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def get_policy_engine(**kwargs: Any):
|
|
99
|
+
"""Get the best available policy engine.
|
|
100
|
+
|
|
101
|
+
Advanced: ABAC with attribute evaluation, constraint graphs, shadow mode.
|
|
102
|
+
Community: YAML-driven allow/deny rules with first-match semantics.
|
|
103
|
+
"""
|
|
104
|
+
provider = _discover_provider(PROVIDER_GROUPS["policy_engine"])
|
|
105
|
+
if provider is not None:
|
|
106
|
+
return provider(**kwargs)
|
|
107
|
+
|
|
108
|
+
from agent_os.integrations.base import GovernancePolicy
|
|
109
|
+
return GovernancePolicy(**kwargs)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def get_context_service(**kwargs: Any):
|
|
113
|
+
"""Get the best available context service.
|
|
114
|
+
|
|
115
|
+
Advanced: Hot/Warm/Cold tiers with heuristic routing and pragmatic truth.
|
|
116
|
+
Community: Single-tier context with TTL-based expiry.
|
|
117
|
+
"""
|
|
118
|
+
provider = _discover_provider(PROVIDER_GROUPS["context_service"])
|
|
119
|
+
if provider is not None:
|
|
120
|
+
return provider(**kwargs)
|
|
121
|
+
|
|
122
|
+
from caas.triad import ContextTriadManager
|
|
123
|
+
return ContextTriadManager(**kwargs)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def get_memory_store(**kwargs: Any):
|
|
127
|
+
"""Get the best available episodic memory store.
|
|
128
|
+
|
|
129
|
+
Advanced: Immutable append-only store with hash chaining (GARR).
|
|
130
|
+
Community: Mutable JSON file-based episode store.
|
|
131
|
+
"""
|
|
132
|
+
provider = _discover_provider(PROVIDER_GROUPS["memory"])
|
|
133
|
+
if provider is not None:
|
|
134
|
+
return provider(**kwargs)
|
|
135
|
+
|
|
136
|
+
from emk.store import EpisodicMemoryStore
|
|
137
|
+
return EpisodicMemoryStore(**kwargs)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def get_trust_protocol(**kwargs: Any):
|
|
141
|
+
"""Get the best available trust protocol engine.
|
|
142
|
+
|
|
143
|
+
Advanced: Full IATP with sidecar attestation and capability handshake.
|
|
144
|
+
Community: Basic policy engine with nonce-based verification.
|
|
145
|
+
"""
|
|
146
|
+
provider = _discover_provider(PROVIDER_GROUPS["trust_protocol"])
|
|
147
|
+
if provider is not None:
|
|
148
|
+
return provider(**kwargs)
|
|
149
|
+
|
|
150
|
+
from iatp.policy_engine import IATPPolicyEngine
|
|
151
|
+
return IATPPolicyEngine(**kwargs)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def get_mute_agent(**kwargs: Any):
|
|
155
|
+
"""Get the best available mute agent implementation.
|
|
156
|
+
|
|
157
|
+
Advanced: NULL response pattern with zero information leakage.
|
|
158
|
+
Community: Simple empty-string response on policy block.
|
|
159
|
+
"""
|
|
160
|
+
provider = _discover_provider(PROVIDER_GROUPS["mute_agent"])
|
|
161
|
+
if provider is not None:
|
|
162
|
+
return provider(**kwargs)
|
|
163
|
+
|
|
164
|
+
from agent_os.mute_agent import MuteAgent
|
|
165
|
+
return MuteAgent(**kwargs)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def list_providers() -> dict[str, str]:
|
|
169
|
+
"""List all provider slots and their current implementations.
|
|
170
|
+
|
|
171
|
+
Returns a dict of {slot_name: "advanced" | "community"}.
|
|
172
|
+
"""
|
|
173
|
+
result = {}
|
|
174
|
+
for name, group in PROVIDER_GROUPS.items():
|
|
175
|
+
provider = _discover_provider(group)
|
|
176
|
+
result[name] = "advanced" if provider is not None else "community"
|
|
177
|
+
return result
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def clear_cache() -> None:
|
|
181
|
+
"""Clear the provider cache. Useful for testing."""
|
|
182
|
+
_provider_cache.clear()
|
agent_os/py.typed
ADDED
|
File without changes
|
agent_os/retry.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""Shared retry utilities for governance toolkit components."""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import asyncio
|
|
7
|
+
import functools
|
|
8
|
+
import logging
|
|
9
|
+
import time
|
|
10
|
+
from typing import Any, Callable, Sequence, TypeVar
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
T = TypeVar("T")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def retry(
|
|
18
|
+
max_attempts: int = 3,
|
|
19
|
+
backoff_base: float = 1.0,
|
|
20
|
+
exceptions: Sequence[type[BaseException]] = (Exception,),
|
|
21
|
+
on_retry: Callable[[int, BaseException], None] | None = None,
|
|
22
|
+
) -> Callable:
|
|
23
|
+
"""Decorator for retrying functions with exponential backoff.
|
|
24
|
+
|
|
25
|
+
Works with both sync and async functions.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
max_attempts: Maximum number of attempts (including first try).
|
|
29
|
+
backoff_base: Base delay in seconds (doubled each retry).
|
|
30
|
+
exceptions: Tuple of exception types to catch and retry.
|
|
31
|
+
on_retry: Optional callback(attempt, exception) called before each retry.
|
|
32
|
+
|
|
33
|
+
Example:
|
|
34
|
+
@retry(max_attempts=3, exceptions=(ConnectionError, TimeoutError))
|
|
35
|
+
async def fetch_data(url: str) -> dict:
|
|
36
|
+
...
|
|
37
|
+
"""
|
|
38
|
+
def decorator(func: Callable) -> Callable:
|
|
39
|
+
if asyncio.iscoroutinefunction(func):
|
|
40
|
+
@functools.wraps(func)
|
|
41
|
+
async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
42
|
+
last_exc: BaseException | None = None
|
|
43
|
+
for attempt in range(1, max_attempts + 1):
|
|
44
|
+
try:
|
|
45
|
+
return await func(*args, **kwargs)
|
|
46
|
+
except tuple(exceptions) as exc:
|
|
47
|
+
last_exc = exc
|
|
48
|
+
if attempt == max_attempts:
|
|
49
|
+
raise
|
|
50
|
+
delay = backoff_base * (2 ** (attempt - 1))
|
|
51
|
+
if on_retry:
|
|
52
|
+
on_retry(attempt, exc)
|
|
53
|
+
logger.warning(
|
|
54
|
+
"Retry %d/%d for %s after %s: %s",
|
|
55
|
+
attempt, max_attempts, func.__name__, type(exc).__name__, exc,
|
|
56
|
+
)
|
|
57
|
+
await asyncio.sleep(delay)
|
|
58
|
+
raise last_exc # unreachable but satisfies type checker
|
|
59
|
+
return async_wrapper
|
|
60
|
+
else:
|
|
61
|
+
@functools.wraps(func)
|
|
62
|
+
def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
63
|
+
last_exc: BaseException | None = None
|
|
64
|
+
for attempt in range(1, max_attempts + 1):
|
|
65
|
+
try:
|
|
66
|
+
return func(*args, **kwargs)
|
|
67
|
+
except tuple(exceptions) as exc:
|
|
68
|
+
last_exc = exc
|
|
69
|
+
if attempt == max_attempts:
|
|
70
|
+
raise
|
|
71
|
+
delay = backoff_base * (2 ** (attempt - 1))
|
|
72
|
+
if on_retry:
|
|
73
|
+
on_retry(attempt, exc)
|
|
74
|
+
logger.warning(
|
|
75
|
+
"Retry %d/%d for %s after %s: %s",
|
|
76
|
+
attempt, max_attempts, func.__name__, type(exc).__name__, exc,
|
|
77
|
+
)
|
|
78
|
+
time.sleep(delay)
|
|
79
|
+
raise last_exc # unreachable but satisfies type checker
|
|
80
|
+
return sync_wrapper
|
|
81
|
+
return decorator
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""Action reversibility assessment and compensation primitives.
|
|
4
|
+
|
|
5
|
+
Pre-execution check: is this action reversible? If not, require
|
|
6
|
+
additional approval or block entirely. Post-execution: provide
|
|
7
|
+
compensation actions to undo effects.
|
|
8
|
+
|
|
9
|
+
Addresses the criticism that AGT has no "rollback/reversibility
|
|
10
|
+
guarantees." Now every action can be assessed for reversibility
|
|
11
|
+
before execution, and compensation plans are generated for
|
|
12
|
+
irreversible operations.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
|
+
from enum import Enum
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
from pydantic import BaseModel, Field
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ReversibilityLevel(str, Enum):
|
|
25
|
+
"""How reversible an action is."""
|
|
26
|
+
FULLY_REVERSIBLE = "fully_reversible" # Can be undone completely (e.g., write a file)
|
|
27
|
+
PARTIALLY_REVERSIBLE = "partially_reversible" # Can be partially undone (e.g., send email — recall possible)
|
|
28
|
+
IRREVERSIBLE = "irreversible" # Cannot be undone (e.g., delete, deploy, send to external)
|
|
29
|
+
UNKNOWN = "unknown" # Reversibility cannot be determined
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class CompensatingAction(BaseModel):
|
|
33
|
+
"""An action that can undo or mitigate a previous action."""
|
|
34
|
+
description: str
|
|
35
|
+
action: str
|
|
36
|
+
parameters: dict[str, Any] = Field(default_factory=dict)
|
|
37
|
+
effectiveness: str = Field(
|
|
38
|
+
default="full",
|
|
39
|
+
description="full, partial, or mitigation-only",
|
|
40
|
+
)
|
|
41
|
+
time_window: str = Field(
|
|
42
|
+
default="",
|
|
43
|
+
description="Time window in which compensation is possible (e.g., '30 minutes')",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ReversibilityAssessment(BaseModel):
|
|
48
|
+
"""Pre-execution assessment of an action's reversibility."""
|
|
49
|
+
action: str
|
|
50
|
+
level: ReversibilityLevel
|
|
51
|
+
reason: str
|
|
52
|
+
compensating_actions: list[CompensatingAction] = Field(default_factory=list)
|
|
53
|
+
requires_extra_approval: bool = False
|
|
54
|
+
assessed_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# Default reversibility classifications
|
|
58
|
+
_REVERSIBILITY_MAP: dict[str, dict[str, Any]] = {
|
|
59
|
+
# Fully reversible
|
|
60
|
+
"write_file": {
|
|
61
|
+
"level": ReversibilityLevel.FULLY_REVERSIBLE,
|
|
62
|
+
"reason": "File writes can be reverted by restoring previous version",
|
|
63
|
+
"compensating": [
|
|
64
|
+
CompensatingAction(
|
|
65
|
+
description="Restore previous file version",
|
|
66
|
+
action="restore_file_backup",
|
|
67
|
+
effectiveness="full",
|
|
68
|
+
)
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
"create_file": {
|
|
72
|
+
"level": ReversibilityLevel.FULLY_REVERSIBLE,
|
|
73
|
+
"reason": "Created files can be deleted",
|
|
74
|
+
"compensating": [
|
|
75
|
+
CompensatingAction(
|
|
76
|
+
description="Delete the created file",
|
|
77
|
+
action="delete_file",
|
|
78
|
+
effectiveness="full",
|
|
79
|
+
)
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
"database_write": {
|
|
83
|
+
"level": ReversibilityLevel.FULLY_REVERSIBLE,
|
|
84
|
+
"reason": "Database writes can be rolled back within transaction",
|
|
85
|
+
"compensating": [
|
|
86
|
+
CompensatingAction(
|
|
87
|
+
description="Rollback transaction",
|
|
88
|
+
action="rollback_transaction",
|
|
89
|
+
effectiveness="full",
|
|
90
|
+
time_window="within transaction scope",
|
|
91
|
+
)
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
"create_pr": {
|
|
95
|
+
"level": ReversibilityLevel.FULLY_REVERSIBLE,
|
|
96
|
+
"reason": "Pull requests can be closed",
|
|
97
|
+
"compensating": [
|
|
98
|
+
CompensatingAction(
|
|
99
|
+
description="Close the pull request",
|
|
100
|
+
action="close_pr",
|
|
101
|
+
effectiveness="full",
|
|
102
|
+
)
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
# Partially reversible
|
|
107
|
+
"send_email": {
|
|
108
|
+
"level": ReversibilityLevel.PARTIALLY_REVERSIBLE,
|
|
109
|
+
"reason": "Email recall may work within org, but external delivery cannot be undone",
|
|
110
|
+
"compensating": [
|
|
111
|
+
CompensatingAction(
|
|
112
|
+
description="Recall email (internal only)",
|
|
113
|
+
action="recall_email",
|
|
114
|
+
effectiveness="partial",
|
|
115
|
+
time_window="30 minutes",
|
|
116
|
+
),
|
|
117
|
+
CompensatingAction(
|
|
118
|
+
description="Send correction/retraction",
|
|
119
|
+
action="send_correction",
|
|
120
|
+
effectiveness="mitigation-only",
|
|
121
|
+
),
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
"update_record": {
|
|
125
|
+
"level": ReversibilityLevel.PARTIALLY_REVERSIBLE,
|
|
126
|
+
"reason": "Previous value may be recoverable from audit log",
|
|
127
|
+
"compensating": [
|
|
128
|
+
CompensatingAction(
|
|
129
|
+
description="Restore from audit trail",
|
|
130
|
+
action="restore_from_audit",
|
|
131
|
+
effectiveness="partial",
|
|
132
|
+
)
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
# Irreversible
|
|
137
|
+
"deploy": {
|
|
138
|
+
"level": ReversibilityLevel.IRREVERSIBLE,
|
|
139
|
+
"reason": "Production deployments affect live users immediately",
|
|
140
|
+
"compensating": [
|
|
141
|
+
CompensatingAction(
|
|
142
|
+
description="Rollback deployment",
|
|
143
|
+
action="rollback_deploy",
|
|
144
|
+
effectiveness="partial",
|
|
145
|
+
time_window="depends on deployment pipeline",
|
|
146
|
+
)
|
|
147
|
+
],
|
|
148
|
+
"requires_extra_approval": True,
|
|
149
|
+
},
|
|
150
|
+
"delete_file": {
|
|
151
|
+
"level": ReversibilityLevel.IRREVERSIBLE,
|
|
152
|
+
"reason": "Deleted files may not be recoverable without backups",
|
|
153
|
+
"compensating": [
|
|
154
|
+
CompensatingAction(
|
|
155
|
+
description="Restore from backup if available",
|
|
156
|
+
action="restore_from_backup",
|
|
157
|
+
effectiveness="partial",
|
|
158
|
+
)
|
|
159
|
+
],
|
|
160
|
+
"requires_extra_approval": True,
|
|
161
|
+
},
|
|
162
|
+
"delete_record": {
|
|
163
|
+
"level": ReversibilityLevel.IRREVERSIBLE,
|
|
164
|
+
"reason": "Deleted records may not be recoverable",
|
|
165
|
+
"compensating": [],
|
|
166
|
+
"requires_extra_approval": True,
|
|
167
|
+
},
|
|
168
|
+
"execute_trade": {
|
|
169
|
+
"level": ReversibilityLevel.IRREVERSIBLE,
|
|
170
|
+
"reason": "Executed trades are settled and cannot be undone",
|
|
171
|
+
"compensating": [
|
|
172
|
+
CompensatingAction(
|
|
173
|
+
description="Execute offsetting trade",
|
|
174
|
+
action="offsetting_trade",
|
|
175
|
+
effectiveness="mitigation-only",
|
|
176
|
+
)
|
|
177
|
+
],
|
|
178
|
+
"requires_extra_approval": True,
|
|
179
|
+
},
|
|
180
|
+
"ssh_connect": {
|
|
181
|
+
"level": ReversibilityLevel.IRREVERSIBLE,
|
|
182
|
+
"reason": "Remote commands may have irreversible effects",
|
|
183
|
+
"compensating": [],
|
|
184
|
+
"requires_extra_approval": True,
|
|
185
|
+
},
|
|
186
|
+
"execute_code": {
|
|
187
|
+
"level": ReversibilityLevel.IRREVERSIBLE,
|
|
188
|
+
"reason": "Arbitrary code execution effects are unpredictable",
|
|
189
|
+
"compensating": [],
|
|
190
|
+
"requires_extra_approval": True,
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class ReversibilityChecker:
|
|
196
|
+
"""Assess action reversibility before execution.
|
|
197
|
+
|
|
198
|
+
Usage:
|
|
199
|
+
checker = ReversibilityChecker()
|
|
200
|
+
assessment = checker.assess("deploy")
|
|
201
|
+
if assessment.level == ReversibilityLevel.IRREVERSIBLE:
|
|
202
|
+
# require extra approval
|
|
203
|
+
...
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
def __init__(
|
|
207
|
+
self,
|
|
208
|
+
custom_rules: dict[str, dict[str, Any]] | None = None,
|
|
209
|
+
block_irreversible: bool = False,
|
|
210
|
+
) -> None:
|
|
211
|
+
self._rules = dict(_REVERSIBILITY_MAP)
|
|
212
|
+
if custom_rules:
|
|
213
|
+
self._rules.update(custom_rules)
|
|
214
|
+
self._block_irreversible = block_irreversible
|
|
215
|
+
|
|
216
|
+
def assess(self, action: str) -> ReversibilityAssessment:
|
|
217
|
+
"""Assess the reversibility of an action before execution."""
|
|
218
|
+
rule = self._rules.get(action)
|
|
219
|
+
|
|
220
|
+
if not rule:
|
|
221
|
+
return ReversibilityAssessment(
|
|
222
|
+
action=action,
|
|
223
|
+
level=ReversibilityLevel.UNKNOWN,
|
|
224
|
+
reason=f"No reversibility data for action '{action}'",
|
|
225
|
+
requires_extra_approval=True,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
return ReversibilityAssessment(
|
|
229
|
+
action=action,
|
|
230
|
+
level=rule["level"],
|
|
231
|
+
reason=rule["reason"],
|
|
232
|
+
compensating_actions=rule.get("compensating", []),
|
|
233
|
+
requires_extra_approval=rule.get("requires_extra_approval", False),
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
def is_safe(self, action: str) -> bool:
|
|
237
|
+
"""Quick check: is this action safely reversible?"""
|
|
238
|
+
assessment = self.assess(action)
|
|
239
|
+
return assessment.level == ReversibilityLevel.FULLY_REVERSIBLE
|
|
240
|
+
|
|
241
|
+
def should_block(self, action: str) -> bool:
|
|
242
|
+
"""Check if action should be blocked per policy."""
|
|
243
|
+
if not self._block_irreversible:
|
|
244
|
+
return False
|
|
245
|
+
assessment = self.assess(action)
|
|
246
|
+
return assessment.level == ReversibilityLevel.IRREVERSIBLE
|
|
247
|
+
|
|
248
|
+
def get_compensation_plan(self, action: str) -> list[CompensatingAction]:
|
|
249
|
+
"""Get the compensation plan for an action."""
|
|
250
|
+
assessment = self.assess(action)
|
|
251
|
+
return assessment.compensating_actions
|