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/supervisor.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Supervisor Hierarchy — Enforces layered supervision with a deterministic trust root.
|
|
5
|
+
|
|
6
|
+
Level 0 (root) MUST be a deterministic (non-LLM) trust root.
|
|
7
|
+
Middle levels (1–N) may be agent-based supervisors.
|
|
8
|
+
Escalation always terminates at the trust root.
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
>>> from agent_os.trust_root import TrustRoot
|
|
12
|
+
>>> from agent_os.supervisor import SupervisorHierarchy
|
|
13
|
+
>>> from agent_os.integrations.base import GovernancePolicy
|
|
14
|
+
>>>
|
|
15
|
+
>>> root = TrustRoot(policies=[GovernancePolicy()])
|
|
16
|
+
>>> hierarchy = SupervisorHierarchy(trust_root=root)
|
|
17
|
+
>>> hierarchy.register_supervisor("trust-root", level=0, is_agent=False)
|
|
18
|
+
>>> hierarchy.register_supervisor("safety-agent", level=1, is_agent=True)
|
|
19
|
+
>>> hierarchy.validate_hierarchy()
|
|
20
|
+
[]
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
from dataclasses import dataclass
|
|
26
|
+
from typing import Any
|
|
27
|
+
|
|
28
|
+
from agent_os.trust_root import TrustDecision, TrustRoot
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class _Supervisor:
|
|
33
|
+
"""Internal record for a registered supervisor."""
|
|
34
|
+
|
|
35
|
+
name: str
|
|
36
|
+
level: int
|
|
37
|
+
is_agent: bool = True
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class SupervisorHierarchy:
|
|
41
|
+
"""Manages the layered supervisor chain with a deterministic trust root.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
trust_root: The deterministic TrustRoot that serves as level-0 authority.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(self, trust_root: TrustRoot) -> None:
|
|
48
|
+
self.trust_root = trust_root
|
|
49
|
+
self._supervisors: list[_Supervisor] = []
|
|
50
|
+
|
|
51
|
+
# ------------------------------------------------------------------
|
|
52
|
+
# Registration
|
|
53
|
+
# ------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
def register_supervisor(
|
|
56
|
+
self,
|
|
57
|
+
name: str,
|
|
58
|
+
level: int,
|
|
59
|
+
is_agent: bool = True,
|
|
60
|
+
) -> None:
|
|
61
|
+
"""Register a supervisor at a given level.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
name: Unique supervisor name.
|
|
65
|
+
level: Hierarchy level (0 = root, higher = closer to workers).
|
|
66
|
+
is_agent: Whether this supervisor is an LLM-based agent.
|
|
67
|
+
"""
|
|
68
|
+
self._supervisors.append(_Supervisor(name=name, level=level, is_agent=is_agent))
|
|
69
|
+
|
|
70
|
+
# ------------------------------------------------------------------
|
|
71
|
+
# Validation
|
|
72
|
+
# ------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
def validate_hierarchy(self) -> list[str]:
|
|
75
|
+
"""Check hierarchy rules and return a list of violations (empty = valid).
|
|
76
|
+
|
|
77
|
+
Rules:
|
|
78
|
+
- Level 0 MUST exist and MUST be deterministic (not an LLM agent).
|
|
79
|
+
- Middle levels (1–N) may be agent-based.
|
|
80
|
+
- Each level present must have at least one supervisor.
|
|
81
|
+
"""
|
|
82
|
+
violations: list[str] = []
|
|
83
|
+
|
|
84
|
+
level_0 = [s for s in self._supervisors if s.level == 0]
|
|
85
|
+
if not level_0:
|
|
86
|
+
violations.append("Level 0 (root) has no registered supervisor")
|
|
87
|
+
else:
|
|
88
|
+
for s in level_0:
|
|
89
|
+
if s.is_agent:
|
|
90
|
+
violations.append(
|
|
91
|
+
f"Level 0 supervisor '{s.name}' must be deterministic, not an LLM agent"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Ensure no gaps in levels (every level between 0 and max has a supervisor)
|
|
95
|
+
if self._supervisors:
|
|
96
|
+
max_level = max(s.level for s in self._supervisors)
|
|
97
|
+
for lvl in range(1, max_level + 1):
|
|
98
|
+
if not any(s.level == lvl for s in self._supervisors):
|
|
99
|
+
violations.append(f"Level {lvl} has no registered supervisor")
|
|
100
|
+
|
|
101
|
+
return violations
|
|
102
|
+
|
|
103
|
+
# ------------------------------------------------------------------
|
|
104
|
+
# Authority chain & escalation
|
|
105
|
+
# ------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
def get_authority_chain(self, action: dict[str, Any]) -> list[str]:
|
|
108
|
+
"""Return the ordered chain of supervisor names that would evaluate *action*.
|
|
109
|
+
|
|
110
|
+
The chain goes from the lowest (closest to workers) up to the trust root.
|
|
111
|
+
"""
|
|
112
|
+
sorted_supervisors = sorted(self._supervisors, key=lambda s: s.level, reverse=True)
|
|
113
|
+
return [s.name for s in sorted_supervisors]
|
|
114
|
+
|
|
115
|
+
def escalate(
|
|
116
|
+
self,
|
|
117
|
+
action: dict[str, Any],
|
|
118
|
+
from_level: int,
|
|
119
|
+
) -> TrustDecision:
|
|
120
|
+
"""Escalate *action* up the hierarchy starting above *from_level*.
|
|
121
|
+
|
|
122
|
+
Each level is consulted in descending order. If the action reaches
|
|
123
|
+
level 0 the trust root makes the **final, non-overridable** decision.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
action: Dict with ``tool`` and ``arguments``.
|
|
127
|
+
from_level: The level that initiated escalation.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
TrustDecision from the trust root (always deterministic).
|
|
131
|
+
"""
|
|
132
|
+
levels_above = sorted(
|
|
133
|
+
{s.level for s in self._supervisors if s.level < from_level},
|
|
134
|
+
reverse=True,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
depth = 0
|
|
138
|
+
for _level in levels_above:
|
|
139
|
+
depth += 1
|
|
140
|
+
if depth > self.trust_root.max_escalation_depth:
|
|
141
|
+
return TrustDecision(
|
|
142
|
+
allowed=False,
|
|
143
|
+
reason="Max escalation depth exceeded",
|
|
144
|
+
policy_name="escalation_limit",
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Final decision always comes from the deterministic trust root
|
|
148
|
+
return self.trust_root.validate_action(action)
|
agent_os/task_outcome.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""Task outcome recording for RewardEngine trust scoring.
|
|
4
|
+
|
|
5
|
+
Provides severity-based scoring with diminishing returns and
|
|
6
|
+
time-based recovery for agent trust management.
|
|
7
|
+
|
|
8
|
+
Example::
|
|
9
|
+
|
|
10
|
+
recorder = TaskOutcomeRecorder()
|
|
11
|
+
recorder.record(agent_id="a1", outcome="success")
|
|
12
|
+
recorder.record(agent_id="a1", outcome="failure", severity=0.8)
|
|
13
|
+
score = recorder.get_score("a1")
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import time
|
|
19
|
+
from dataclasses import dataclass, field
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class TaskOutcome:
|
|
25
|
+
"""A recorded task outcome."""
|
|
26
|
+
|
|
27
|
+
agent_id: str
|
|
28
|
+
outcome: str # "success" | "failure"
|
|
29
|
+
severity: float = 0.5
|
|
30
|
+
timestamp: float = field(default_factory=time.time)
|
|
31
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class AgentScoreState:
|
|
36
|
+
"""Running score state for an agent."""
|
|
37
|
+
|
|
38
|
+
score: float = 0.7 # Start at neutral-positive
|
|
39
|
+
total_tasks: int = 0
|
|
40
|
+
successes: int = 0
|
|
41
|
+
failures: int = 0
|
|
42
|
+
last_updated: float = field(default_factory=time.time)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class TaskOutcomeRecorder:
|
|
46
|
+
"""Records task outcomes and computes trust scores.
|
|
47
|
+
|
|
48
|
+
Features:
|
|
49
|
+
- Success boost with diminishing returns
|
|
50
|
+
- Severity-based failure penalties
|
|
51
|
+
- Time-based recovery (scores drift toward neutral over time)
|
|
52
|
+
- Per-agent score tracking
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
success_boost: float = 0.05,
|
|
58
|
+
failure_base_penalty: float = 0.1,
|
|
59
|
+
recovery_rate: float = 0.01,
|
|
60
|
+
recovery_interval_seconds: float = 3600.0,
|
|
61
|
+
min_score: float = 0.0,
|
|
62
|
+
max_score: float = 1.0,
|
|
63
|
+
) -> None:
|
|
64
|
+
self.success_boost = success_boost
|
|
65
|
+
self.failure_base_penalty = failure_base_penalty
|
|
66
|
+
self.recovery_rate = recovery_rate
|
|
67
|
+
self.recovery_interval = recovery_interval_seconds
|
|
68
|
+
self.min_score = min_score
|
|
69
|
+
self.max_score = max_score
|
|
70
|
+
self._agents: dict[str, AgentScoreState] = {}
|
|
71
|
+
self._history: list[TaskOutcome] = []
|
|
72
|
+
|
|
73
|
+
def record(
|
|
74
|
+
self,
|
|
75
|
+
agent_id: str,
|
|
76
|
+
outcome: str,
|
|
77
|
+
severity: float = 0.5,
|
|
78
|
+
**metadata: Any,
|
|
79
|
+
) -> float:
|
|
80
|
+
"""Record a task outcome and return updated score.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
agent_id: The agent identifier.
|
|
84
|
+
outcome: "success" or "failure".
|
|
85
|
+
severity: 0.0-1.0, how severe (for failures) or impactful (for successes).
|
|
86
|
+
**metadata: Additional context.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Updated trust score for the agent.
|
|
90
|
+
"""
|
|
91
|
+
state = self._agents.setdefault(agent_id, AgentScoreState())
|
|
92
|
+
|
|
93
|
+
# Apply time-based recovery first
|
|
94
|
+
self._apply_recovery(state)
|
|
95
|
+
|
|
96
|
+
state.total_tasks += 1
|
|
97
|
+
entry = TaskOutcome(
|
|
98
|
+
agent_id=agent_id,
|
|
99
|
+
outcome=outcome,
|
|
100
|
+
severity=severity,
|
|
101
|
+
metadata=metadata,
|
|
102
|
+
)
|
|
103
|
+
self._history.append(entry)
|
|
104
|
+
|
|
105
|
+
if outcome == "success":
|
|
106
|
+
state.successes += 1
|
|
107
|
+
# Diminishing returns: boost decreases as score approaches max
|
|
108
|
+
headroom = self.max_score - state.score
|
|
109
|
+
boost = self.success_boost * severity * (headroom / self.max_score)
|
|
110
|
+
state.score = min(self.max_score, state.score + boost)
|
|
111
|
+
elif outcome == "failure":
|
|
112
|
+
state.failures += 1
|
|
113
|
+
penalty = self.failure_base_penalty * severity
|
|
114
|
+
state.score = max(self.min_score, state.score - penalty)
|
|
115
|
+
|
|
116
|
+
state.last_updated = time.time()
|
|
117
|
+
return state.score
|
|
118
|
+
|
|
119
|
+
def get_score(self, agent_id: str) -> float:
|
|
120
|
+
"""Get current trust score for an agent."""
|
|
121
|
+
state = self._agents.get(agent_id)
|
|
122
|
+
if state is None:
|
|
123
|
+
return 0.7 # Default for unknown agents
|
|
124
|
+
self._apply_recovery(state)
|
|
125
|
+
return round(state.score, 4)
|
|
126
|
+
|
|
127
|
+
def get_stats(self, agent_id: str) -> dict[str, Any]:
|
|
128
|
+
"""Get detailed stats for an agent."""
|
|
129
|
+
state = self._agents.get(agent_id)
|
|
130
|
+
if state is None:
|
|
131
|
+
return {"agent_id": agent_id, "score": 0.7, "total_tasks": 0}
|
|
132
|
+
return {
|
|
133
|
+
"agent_id": agent_id,
|
|
134
|
+
"score": round(state.score, 4),
|
|
135
|
+
"total_tasks": state.total_tasks,
|
|
136
|
+
"successes": state.successes,
|
|
137
|
+
"failures": state.failures,
|
|
138
|
+
"success_rate": round(state.successes / max(1, state.total_tasks), 3),
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
def _apply_recovery(self, state: AgentScoreState) -> None:
|
|
142
|
+
"""Apply time-based score recovery toward neutral (0.7)."""
|
|
143
|
+
elapsed = time.time() - state.last_updated
|
|
144
|
+
intervals = elapsed / self.recovery_interval
|
|
145
|
+
if intervals > 0 and state.score < 0.7:
|
|
146
|
+
recovery = self.recovery_rate * intervals
|
|
147
|
+
state.score = min(0.7, state.score + recovery)
|
|
148
|
+
state.last_updated = time.time()
|
agent_os/transparency.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""EU AI Act Art. 13/50 transparency enforcement interceptor.
|
|
4
|
+
|
|
5
|
+
Ensures AI disclosure is delivered to users before tool execution,
|
|
6
|
+
supporting Art. 50(1) (AI interaction notice), Art. 50(3) (emotion
|
|
7
|
+
recognition notice), and Art. 13 (interpretable output documentation).
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import logging
|
|
13
|
+
import time
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from enum import Enum
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TransparencyLevel(str, Enum):
|
|
22
|
+
"""Disclosure level per EU AI Act risk classification."""
|
|
23
|
+
|
|
24
|
+
NONE = "none"
|
|
25
|
+
BASIC = "basic"
|
|
26
|
+
ENHANCED = "enhanced"
|
|
27
|
+
FULL = "full"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class ToolCallRequest:
|
|
32
|
+
"""Minimal shim — real class imported from integrations.base at runtime."""
|
|
33
|
+
|
|
34
|
+
tool_name: str
|
|
35
|
+
arguments: dict[str, Any] = field(default_factory=dict)
|
|
36
|
+
call_id: str = ""
|
|
37
|
+
agent_id: str = ""
|
|
38
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class ToolCallResult:
|
|
43
|
+
"""Minimal shim — real class imported from integrations.base at runtime."""
|
|
44
|
+
|
|
45
|
+
allowed: bool
|
|
46
|
+
reason: str | None = None
|
|
47
|
+
modified_arguments: dict[str, Any] | None = None
|
|
48
|
+
audit_entry: dict[str, Any] | None = None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
DISCLOSURE_TEXTS = {
|
|
52
|
+
TransparencyLevel.BASIC: (
|
|
53
|
+
"You are interacting with an AI system. Outputs are machine-generated "
|
|
54
|
+
"and may contain errors. (EU AI Act Art. 50(1))"
|
|
55
|
+
),
|
|
56
|
+
TransparencyLevel.ENHANCED: (
|
|
57
|
+
"You are interacting with a high-risk AI system. Outputs are "
|
|
58
|
+
"machine-generated, subject to governance policy enforcement, and "
|
|
59
|
+
"logged for regulatory audit. Interpretability documentation is "
|
|
60
|
+
"available on request. (EU AI Act Art. 13, Art. 50(1))"
|
|
61
|
+
),
|
|
62
|
+
TransparencyLevel.FULL: (
|
|
63
|
+
"You are interacting with a high-risk AI system under full "
|
|
64
|
+
"transparency obligations. All tool calls are policy-governed, "
|
|
65
|
+
"audited, and subject to human oversight. System accuracy "
|
|
66
|
+
"declarations and technical documentation are available. "
|
|
67
|
+
"(EU AI Act Art. 13, Art. 14, Art. 50)"
|
|
68
|
+
),
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
EMOTION_RECOGNITION_NOTICE = (
|
|
72
|
+
"This system uses emotion recognition technology. You have the right "
|
|
73
|
+
"to be informed when such processing takes place. (EU AI Act Art. 50(3))"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class TransparencyInterceptor:
|
|
78
|
+
"""EU AI Act Art. 13/50 transparency enforcement interceptor.
|
|
79
|
+
|
|
80
|
+
Blocks tool execution when required AI disclosure has not been
|
|
81
|
+
confirmed, and injects disclosure metadata into allowed results.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
default_level: Transparency level applied when none is specified
|
|
85
|
+
in the request context.
|
|
86
|
+
require_disclosure_confirmation: If ``True``, tool calls are
|
|
87
|
+
blocked until ``confirm_disclosure`` is called for the session.
|
|
88
|
+
emotion_recognition_notice: If ``True``, requires emotion
|
|
89
|
+
recognition acknowledgement per Art. 50(3).
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
def __init__(
|
|
93
|
+
self,
|
|
94
|
+
default_level: TransparencyLevel = TransparencyLevel.BASIC,
|
|
95
|
+
require_disclosure_confirmation: bool = True,
|
|
96
|
+
emotion_recognition_notice: bool = False,
|
|
97
|
+
) -> None:
|
|
98
|
+
self.default_level = default_level
|
|
99
|
+
self.require_disclosure_confirmation = require_disclosure_confirmation
|
|
100
|
+
self.emotion_recognition_notice = emotion_recognition_notice
|
|
101
|
+
self._confirmed_sessions: dict[str, float] = {}
|
|
102
|
+
self._emotion_acknowledged: dict[str, float] = {}
|
|
103
|
+
|
|
104
|
+
def intercept(self, request: ToolCallRequest) -> ToolCallResult:
|
|
105
|
+
"""Check transparency requirements before allowing a tool call."""
|
|
106
|
+
session_id = request.metadata.get("session_id", request.agent_id or "default")
|
|
107
|
+
level = request.metadata.get("transparency_level", self.default_level)
|
|
108
|
+
if isinstance(level, str):
|
|
109
|
+
try:
|
|
110
|
+
level = TransparencyLevel(level)
|
|
111
|
+
except ValueError:
|
|
112
|
+
level = self.default_level
|
|
113
|
+
|
|
114
|
+
if level == TransparencyLevel.NONE:
|
|
115
|
+
return ToolCallResult(allowed=True)
|
|
116
|
+
|
|
117
|
+
# Check disclosure confirmation
|
|
118
|
+
if self.require_disclosure_confirmation:
|
|
119
|
+
if session_id not in self._confirmed_sessions:
|
|
120
|
+
logger.warning(
|
|
121
|
+
"Blocked %s: AI disclosure not confirmed for session %s",
|
|
122
|
+
request.tool_name,
|
|
123
|
+
session_id,
|
|
124
|
+
)
|
|
125
|
+
return ToolCallResult(
|
|
126
|
+
allowed=False,
|
|
127
|
+
reason=(
|
|
128
|
+
f"AI disclosure must be confirmed before tool execution. "
|
|
129
|
+
f"Required level: {level.value}. "
|
|
130
|
+
f"Call confirm_disclosure(session_id) first."
|
|
131
|
+
),
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Check emotion recognition acknowledgement
|
|
135
|
+
if self.emotion_recognition_notice:
|
|
136
|
+
if session_id not in self._emotion_acknowledged:
|
|
137
|
+
logger.warning(
|
|
138
|
+
"Blocked %s: emotion recognition notice not acknowledged for %s",
|
|
139
|
+
request.tool_name,
|
|
140
|
+
session_id,
|
|
141
|
+
)
|
|
142
|
+
return ToolCallResult(
|
|
143
|
+
allowed=False,
|
|
144
|
+
reason=(
|
|
145
|
+
"Emotion recognition notice must be acknowledged "
|
|
146
|
+
"before tool execution. (Art. 50(3))"
|
|
147
|
+
),
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Inject disclosure metadata
|
|
151
|
+
disclosure = {
|
|
152
|
+
"_ai_disclosure": {
|
|
153
|
+
"level": level.value,
|
|
154
|
+
"text": self.get_disclosure_text(level),
|
|
155
|
+
"confirmed_at": self._confirmed_sessions.get(session_id),
|
|
156
|
+
"emotion_recognition": self.emotion_recognition_notice,
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return ToolCallResult(
|
|
161
|
+
allowed=True,
|
|
162
|
+
audit_entry=disclosure,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
def confirm_disclosure(self, session_id: str) -> None:
|
|
166
|
+
"""Mark AI disclosure as confirmed for a session."""
|
|
167
|
+
self._confirmed_sessions[session_id] = time.time()
|
|
168
|
+
logger.info("AI disclosure confirmed for session %s", session_id)
|
|
169
|
+
|
|
170
|
+
def acknowledge_emotion_recognition(self, session_id: str) -> None:
|
|
171
|
+
"""Mark emotion recognition notice as acknowledged for a session."""
|
|
172
|
+
self._emotion_acknowledged[session_id] = time.time()
|
|
173
|
+
logger.info("Emotion recognition notice acknowledged for session %s", session_id)
|
|
174
|
+
|
|
175
|
+
def get_disclosure_text(self, level: TransparencyLevel) -> str:
|
|
176
|
+
"""Get standard disclosure text for the given transparency level."""
|
|
177
|
+
return DISCLOSURE_TEXTS.get(level, DISCLOSURE_TEXTS[TransparencyLevel.BASIC])
|
|
178
|
+
|
|
179
|
+
def is_disclosure_confirmed(self, session_id: str) -> bool:
|
|
180
|
+
"""Check if disclosure has been confirmed for a session."""
|
|
181
|
+
return session_id in self._confirmed_sessions
|
agent_os/trust_root.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Deterministic Trust Root — Final authority for the supervisor hierarchy.
|
|
5
|
+
|
|
6
|
+
The trust root is a pure-code (non-LLM) policy checkpoint that sits at
|
|
7
|
+
the top of the supervisor chain. It evaluates actions using
|
|
8
|
+
GovernancePolicy rules and cannot be overridden by any agent.
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
>>> from agent_os.trust_root import TrustRoot, TrustDecision
|
|
12
|
+
>>> from agent_os.integrations.base import GovernancePolicy
|
|
13
|
+
>>>
|
|
14
|
+
>>> policy = GovernancePolicy(allowed_tools=["read_file"])
|
|
15
|
+
>>> root = TrustRoot(policies=[policy])
|
|
16
|
+
>>> decision = root.validate_action({"tool": "delete_file", "arguments": {}})
|
|
17
|
+
>>> decision.allowed # False
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from dataclasses import dataclass
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
from agent_os.integrations.base import GovernancePolicy
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class TrustDecision:
|
|
30
|
+
"""Result of a deterministic trust-root evaluation."""
|
|
31
|
+
|
|
32
|
+
allowed: bool
|
|
33
|
+
reason: str
|
|
34
|
+
policy_name: str
|
|
35
|
+
deterministic: bool = True
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TrustRoot:
|
|
39
|
+
"""Deterministic (non-LLM) policy authority at the top of the supervisor hierarchy.
|
|
40
|
+
|
|
41
|
+
The trust root is the FINAL authority — it cannot be overridden by any agent.
|
|
42
|
+
All evaluations use pure code logic; no model inference is involved.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
policies: List of GovernancePolicy instances to enforce.
|
|
46
|
+
max_escalation_depth: Maximum supervisor levels before forced rejection.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
policies: list[GovernancePolicy],
|
|
52
|
+
max_escalation_depth: int = 3,
|
|
53
|
+
) -> None:
|
|
54
|
+
if not policies:
|
|
55
|
+
raise ValueError("TrustRoot requires at least one policy")
|
|
56
|
+
self.policies = policies
|
|
57
|
+
self.max_escalation_depth = max_escalation_depth
|
|
58
|
+
|
|
59
|
+
# ------------------------------------------------------------------
|
|
60
|
+
# Public API
|
|
61
|
+
# ------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
def validate_action(self, action: dict[str, Any]) -> TrustDecision:
|
|
64
|
+
"""Deterministic policy check against all registered policies.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
action: Dict with at least ``tool`` (str) and ``arguments`` (dict).
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
TrustDecision indicating whether the action is allowed.
|
|
71
|
+
"""
|
|
72
|
+
tool = action.get("tool", "")
|
|
73
|
+
arguments = action.get("arguments", {})
|
|
74
|
+
args_str = str(arguments)
|
|
75
|
+
|
|
76
|
+
for policy in self.policies:
|
|
77
|
+
# Check allowed tools
|
|
78
|
+
if policy.allowed_tools and tool not in policy.allowed_tools:
|
|
79
|
+
return TrustDecision(
|
|
80
|
+
allowed=False,
|
|
81
|
+
reason=(
|
|
82
|
+
f"Tool '{tool}' not in allowed list: {policy.allowed_tools}"
|
|
83
|
+
),
|
|
84
|
+
policy_name=policy.name,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Check blocked patterns
|
|
88
|
+
matched = policy.matches_pattern(args_str)
|
|
89
|
+
if matched:
|
|
90
|
+
return TrustDecision(
|
|
91
|
+
allowed=False,
|
|
92
|
+
reason=f"Blocked pattern '{matched[0]}' detected in arguments",
|
|
93
|
+
policy_name=policy.name,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return TrustDecision(
|
|
97
|
+
allowed=True,
|
|
98
|
+
reason="All policies passed",
|
|
99
|
+
policy_name="aggregate",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def validate_supervisor(self, supervisor_config: dict[str, Any]) -> bool:
|
|
103
|
+
"""Verify a supervisor agent meets trust requirements.
|
|
104
|
+
|
|
105
|
+
A supervisor at any level must declare a ``name`` and ``level``.
|
|
106
|
+
Level-0 supervisors **must not** be agent-based (``is_agent`` must be False).
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
supervisor_config: Dict with ``name``, ``level``, and optionally ``is_agent``.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
True if the supervisor configuration is acceptable.
|
|
113
|
+
"""
|
|
114
|
+
level = supervisor_config.get("level")
|
|
115
|
+
is_agent = supervisor_config.get("is_agent", True)
|
|
116
|
+
|
|
117
|
+
if level is None or not supervisor_config.get("name"):
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
# Root level must be deterministic — not an LLM agent
|
|
121
|
+
if level == 0 and is_agent:
|
|
122
|
+
return False
|
|
123
|
+
|
|
124
|
+
return True
|
|
125
|
+
|
|
126
|
+
def is_deterministic(self) -> bool:
|
|
127
|
+
"""Guarantee that this trust root uses only deterministic logic."""
|
|
128
|
+
return True
|