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.
Files changed (337) hide show
  1. agent_control_plane/__init__.py +662 -0
  2. agent_control_plane/a2a_adapter.py +543 -0
  3. agent_control_plane/adapter.py +417 -0
  4. agent_control_plane/agent_hibernation.py +394 -0
  5. agent_control_plane/agent_kernel.py +470 -0
  6. agent_control_plane/compliance.py +720 -0
  7. agent_control_plane/constraint_graphs.py +478 -0
  8. agent_control_plane/control_plane.py +854 -0
  9. agent_control_plane/example_executors.py +195 -0
  10. agent_control_plane/execution_engine.py +231 -0
  11. agent_control_plane/flight_recorder.py +846 -0
  12. agent_control_plane/governance_layer.py +435 -0
  13. agent_control_plane/hf_utils.py +563 -0
  14. agent_control_plane/interfaces/__init__.py +55 -0
  15. agent_control_plane/interfaces/kernel_interface.py +361 -0
  16. agent_control_plane/interfaces/plugin_interface.py +497 -0
  17. agent_control_plane/interfaces/protocol_interfaces.py +387 -0
  18. agent_control_plane/kernel_space.py +1009 -0
  19. agent_control_plane/langchain_adapter.py +424 -0
  20. agent_control_plane/lifecycle.py +3113 -0
  21. agent_control_plane/mcp_adapter.py +653 -0
  22. agent_control_plane/ml_safety.py +563 -0
  23. agent_control_plane/multimodal.py +727 -0
  24. agent_control_plane/mute_agent.py +422 -0
  25. agent_control_plane/observability.py +787 -0
  26. agent_control_plane/orchestrator.py +482 -0
  27. agent_control_plane/plugin_registry.py +750 -0
  28. agent_control_plane/policy_engine.py +954 -0
  29. agent_control_plane/process_isolation.py +777 -0
  30. agent_control_plane/shadow_mode.py +310 -0
  31. agent_control_plane/signals.py +493 -0
  32. agent_control_plane/supervisor_agents.py +430 -0
  33. agent_control_plane/time_travel_debugger.py +557 -0
  34. agent_control_plane/tool_registry.py +452 -0
  35. agent_control_plane/vfs.py +697 -0
  36. agent_kernel/__init__.py +69 -0
  37. agent_kernel/analyzer.py +435 -0
  38. agent_kernel/auditor.py +36 -0
  39. agent_kernel/completeness_auditor.py +237 -0
  40. agent_kernel/detector.py +203 -0
  41. agent_kernel/kernel.py +744 -0
  42. agent_kernel/memory_manager.py +85 -0
  43. agent_kernel/models.py +374 -0
  44. agent_kernel/nudge_mechanism.py +263 -0
  45. agent_kernel/outcome_analyzer.py +338 -0
  46. agent_kernel/patcher.py +582 -0
  47. agent_kernel/semantic_analyzer.py +316 -0
  48. agent_kernel/semantic_purge.py +349 -0
  49. agent_kernel/simulator.py +449 -0
  50. agent_kernel/teacher.py +85 -0
  51. agent_kernel/triage.py +152 -0
  52. agent_os/__init__.py +409 -0
  53. agent_os/_adversarial_impl.py +200 -0
  54. agent_os/_circuit_breaker_impl.py +232 -0
  55. agent_os/_mcp_metrics.py +193 -0
  56. agent_os/adversarial.py +20 -0
  57. agent_os/agents_compat.py +490 -0
  58. agent_os/audit_logger.py +135 -0
  59. agent_os/base_agent.py +651 -0
  60. agent_os/circuit_breaker.py +34 -0
  61. agent_os/cli/__init__.py +659 -0
  62. agent_os/cli/cmd_audit.py +128 -0
  63. agent_os/cli/cmd_init.py +152 -0
  64. agent_os/cli/cmd_policy.py +41 -0
  65. agent_os/cli/cmd_policy_gen.py +180 -0
  66. agent_os/cli/cmd_validate.py +258 -0
  67. agent_os/cli/mcp_scan.py +265 -0
  68. agent_os/cli/output.py +192 -0
  69. agent_os/cli/policy_checker.py +330 -0
  70. agent_os/compat.py +74 -0
  71. agent_os/constraint_graph.py +234 -0
  72. agent_os/content_governance.py +140 -0
  73. agent_os/context_budget.py +305 -0
  74. agent_os/credential_redactor.py +224 -0
  75. agent_os/diff_policy.py +89 -0
  76. agent_os/egress_policy.py +159 -0
  77. agent_os/escalation.py +276 -0
  78. agent_os/event_bus.py +124 -0
  79. agent_os/exceptions.py +180 -0
  80. agent_os/execution_context_policy.py +141 -0
  81. agent_os/github_enterprise.py +96 -0
  82. agent_os/health.py +20 -0
  83. agent_os/integrations/__init__.py +279 -0
  84. agent_os/integrations/a2a_adapter.py +279 -0
  85. agent_os/integrations/agent_lightning/__init__.py +30 -0
  86. agent_os/integrations/anthropic_adapter.py +420 -0
  87. agent_os/integrations/autogen_adapter.py +620 -0
  88. agent_os/integrations/base.py +1137 -0
  89. agent_os/integrations/compat.py +229 -0
  90. agent_os/integrations/config.py +98 -0
  91. agent_os/integrations/conversation_guardian.py +957 -0
  92. agent_os/integrations/crewai_adapter.py +467 -0
  93. agent_os/integrations/drift_detector.py +425 -0
  94. agent_os/integrations/dry_run.py +124 -0
  95. agent_os/integrations/escalation.py +582 -0
  96. agent_os/integrations/gemini_adapter.py +364 -0
  97. agent_os/integrations/google_adk_adapter.py +633 -0
  98. agent_os/integrations/guardrails_adapter.py +394 -0
  99. agent_os/integrations/health.py +197 -0
  100. agent_os/integrations/langchain_adapter.py +654 -0
  101. agent_os/integrations/llamafirewall.py +343 -0
  102. agent_os/integrations/llamaindex_adapter.py +188 -0
  103. agent_os/integrations/logging.py +191 -0
  104. agent_os/integrations/maf_adapter.py +631 -0
  105. agent_os/integrations/mistral_adapter.py +365 -0
  106. agent_os/integrations/openai_adapter.py +816 -0
  107. agent_os/integrations/openai_agents_sdk.py +406 -0
  108. agent_os/integrations/policy_compose.py +171 -0
  109. agent_os/integrations/profiling.py +144 -0
  110. agent_os/integrations/pydantic_ai_adapter.py +420 -0
  111. agent_os/integrations/rate_limiter.py +130 -0
  112. agent_os/integrations/rbac.py +143 -0
  113. agent_os/integrations/registry.py +113 -0
  114. agent_os/integrations/scope_guard.py +303 -0
  115. agent_os/integrations/semantic_kernel_adapter.py +769 -0
  116. agent_os/integrations/smolagents_adapter.py +629 -0
  117. agent_os/integrations/templates.py +178 -0
  118. agent_os/integrations/token_budget.py +134 -0
  119. agent_os/integrations/tool_aliases.py +190 -0
  120. agent_os/integrations/webhooks.py +177 -0
  121. agent_os/lite.py +208 -0
  122. agent_os/mcp_gateway.py +385 -0
  123. agent_os/mcp_message_signer.py +273 -0
  124. agent_os/mcp_protocols.py +161 -0
  125. agent_os/mcp_response_scanner.py +232 -0
  126. agent_os/mcp_security.py +924 -0
  127. agent_os/mcp_session_auth.py +231 -0
  128. agent_os/mcp_sliding_rate_limiter.py +184 -0
  129. agent_os/memory_guard.py +409 -0
  130. agent_os/metrics.py +134 -0
  131. agent_os/mute.py +428 -0
  132. agent_os/mute_agent.py +209 -0
  133. agent_os/policies/__init__.py +77 -0
  134. agent_os/policies/async_evaluator.py +275 -0
  135. agent_os/policies/backends.py +670 -0
  136. agent_os/policies/bridge.py +169 -0
  137. agent_os/policies/budget.py +85 -0
  138. agent_os/policies/cli.py +294 -0
  139. agent_os/policies/conflict_resolution.py +270 -0
  140. agent_os/policies/data_classification.py +252 -0
  141. agent_os/policies/evaluator.py +239 -0
  142. agent_os/policies/policy_schema.json +228 -0
  143. agent_os/policies/rate_limiting.py +145 -0
  144. agent_os/policies/schema.py +115 -0
  145. agent_os/policies/shared.py +331 -0
  146. agent_os/prompt_injection.py +694 -0
  147. agent_os/providers.py +182 -0
  148. agent_os/py.typed +0 -0
  149. agent_os/retry.py +81 -0
  150. agent_os/reversibility.py +251 -0
  151. agent_os/sandbox.py +432 -0
  152. agent_os/sandbox_provider.py +140 -0
  153. agent_os/secure_codegen.py +525 -0
  154. agent_os/security_skills.py +538 -0
  155. agent_os/semantic_policy.py +422 -0
  156. agent_os/server/__init__.py +15 -0
  157. agent_os/server/__main__.py +25 -0
  158. agent_os/server/app.py +277 -0
  159. agent_os/server/models.py +104 -0
  160. agent_os/shift_left_metrics.py +130 -0
  161. agent_os/stateless.py +742 -0
  162. agent_os/supervisor.py +148 -0
  163. agent_os/task_outcome.py +148 -0
  164. agent_os/transparency.py +181 -0
  165. agent_os/trust_root.py +128 -0
  166. agent_os_kernel-3.1.0.dist-info/METADATA +1269 -0
  167. agent_os_kernel-3.1.0.dist-info/RECORD +337 -0
  168. agent_os_kernel-3.1.0.dist-info/WHEEL +4 -0
  169. agent_os_kernel-3.1.0.dist-info/entry_points.txt +2 -0
  170. agent_os_kernel-3.1.0.dist-info/licenses/LICENSE +21 -0
  171. agent_os_observability/__init__.py +27 -0
  172. agent_os_observability/dashboards.py +898 -0
  173. agent_os_observability/metrics.py +398 -0
  174. agent_os_observability/server.py +223 -0
  175. agent_os_observability/tracer.py +232 -0
  176. agent_primitives/__init__.py +24 -0
  177. agent_primitives/failures.py +84 -0
  178. agent_primitives/py.typed +0 -0
  179. amb_core/__init__.py +177 -0
  180. amb_core/adapters/__init__.py +57 -0
  181. amb_core/adapters/aws_sqs_broker.py +376 -0
  182. amb_core/adapters/azure_servicebus_broker.py +340 -0
  183. amb_core/adapters/kafka_broker.py +260 -0
  184. amb_core/adapters/nats_broker.py +285 -0
  185. amb_core/adapters/rabbitmq_broker.py +235 -0
  186. amb_core/adapters/redis_broker.py +262 -0
  187. amb_core/broker.py +145 -0
  188. amb_core/bus.py +481 -0
  189. amb_core/cloudevents.py +509 -0
  190. amb_core/dlq.py +345 -0
  191. amb_core/hf_utils.py +536 -0
  192. amb_core/memory_broker.py +410 -0
  193. amb_core/models.py +141 -0
  194. amb_core/persistence.py +529 -0
  195. amb_core/schema.py +294 -0
  196. amb_core/tracing.py +358 -0
  197. atr/__init__.py +640 -0
  198. atr/access.py +348 -0
  199. atr/composition.py +645 -0
  200. atr/decorator.py +357 -0
  201. atr/executor.py +384 -0
  202. atr/health.py +557 -0
  203. atr/hf_utils.py +449 -0
  204. atr/injection.py +422 -0
  205. atr/metrics.py +440 -0
  206. atr/policies.py +403 -0
  207. atr/py.typed +2 -0
  208. atr/registry.py +452 -0
  209. atr/schema.py +480 -0
  210. atr/tools/safe/__init__.py +75 -0
  211. atr/tools/safe/calculator.py +467 -0
  212. atr/tools/safe/datetime_tool.py +443 -0
  213. atr/tools/safe/file_reader.py +402 -0
  214. atr/tools/safe/http_client.py +316 -0
  215. atr/tools/safe/json_parser.py +374 -0
  216. atr/tools/safe/text_tool.py +537 -0
  217. atr/tools/safe/toolkit.py +175 -0
  218. caas/__init__.py +162 -0
  219. caas/api/__init__.py +7 -0
  220. caas/api/server.py +1328 -0
  221. caas/caching.py +834 -0
  222. caas/cli.py +210 -0
  223. caas/conversation.py +223 -0
  224. caas/decay.py +72 -0
  225. caas/detection/__init__.py +9 -0
  226. caas/detection/detector.py +238 -0
  227. caas/enrichment.py +130 -0
  228. caas/gateway/__init__.py +27 -0
  229. caas/gateway/trust_gateway.py +474 -0
  230. caas/hf_utils.py +479 -0
  231. caas/ingestion/__init__.py +23 -0
  232. caas/ingestion/processors.py +253 -0
  233. caas/ingestion/structure_parser.py +188 -0
  234. caas/models.py +356 -0
  235. caas/pragmatic_truth.py +444 -0
  236. caas/routing/__init__.py +10 -0
  237. caas/routing/heuristic_router.py +58 -0
  238. caas/storage/__init__.py +9 -0
  239. caas/storage/store.py +389 -0
  240. caas/triad.py +213 -0
  241. caas/tuning/__init__.py +9 -0
  242. caas/tuning/tuner.py +329 -0
  243. caas/vfs/__init__.py +14 -0
  244. caas/vfs/filesystem.py +452 -0
  245. cmvk/__init__.py +218 -0
  246. cmvk/audit.py +402 -0
  247. cmvk/benchmarks.py +478 -0
  248. cmvk/constitutional.py +904 -0
  249. cmvk/hf_utils.py +301 -0
  250. cmvk/metrics.py +473 -0
  251. cmvk/profiles.py +300 -0
  252. cmvk/py.typed +0 -0
  253. cmvk/types.py +12 -0
  254. cmvk/verification.py +956 -0
  255. emk/__init__.py +89 -0
  256. emk/causal.py +352 -0
  257. emk/hf_utils.py +421 -0
  258. emk/indexer.py +83 -0
  259. emk/py.typed +0 -0
  260. emk/schema.py +204 -0
  261. emk/sleep_cycle.py +347 -0
  262. emk/store.py +281 -0
  263. iatp/__init__.py +166 -0
  264. iatp/attestation.py +461 -0
  265. iatp/cli.py +317 -0
  266. iatp/hf_utils.py +472 -0
  267. iatp/ipc_pipes.py +580 -0
  268. iatp/main.py +412 -0
  269. iatp/models/__init__.py +447 -0
  270. iatp/policy_engine.py +337 -0
  271. iatp/py.typed +2 -0
  272. iatp/recovery.py +321 -0
  273. iatp/security/__init__.py +270 -0
  274. iatp/sidecar/__init__.py +519 -0
  275. iatp/telemetry/__init__.py +164 -0
  276. iatp/tests/__init__.py +1 -0
  277. iatp/tests/test_attestation.py +370 -0
  278. iatp/tests/test_cli.py +131 -0
  279. iatp/tests/test_ed25519_attestation.py +211 -0
  280. iatp/tests/test_models.py +130 -0
  281. iatp/tests/test_policy_engine.py +347 -0
  282. iatp/tests/test_recovery.py +281 -0
  283. iatp/tests/test_security.py +222 -0
  284. iatp/tests/test_sidecar.py +167 -0
  285. iatp/tests/test_telemetry.py +175 -0
  286. mcp_kernel_server/__init__.py +28 -0
  287. mcp_kernel_server/cli.py +274 -0
  288. mcp_kernel_server/resources.py +217 -0
  289. mcp_kernel_server/server.py +564 -0
  290. mcp_kernel_server/tools.py +1174 -0
  291. mute_agent/__init__.py +68 -0
  292. mute_agent/core/__init__.py +1 -0
  293. mute_agent/core/execution_agent.py +166 -0
  294. mute_agent/core/handshake_protocol.py +201 -0
  295. mute_agent/core/reasoning_agent.py +238 -0
  296. mute_agent/knowledge_graph/__init__.py +1 -0
  297. mute_agent/knowledge_graph/graph_elements.py +65 -0
  298. mute_agent/knowledge_graph/multidimensional_graph.py +170 -0
  299. mute_agent/knowledge_graph/subgraph.py +224 -0
  300. mute_agent/listener/__init__.py +43 -0
  301. mute_agent/listener/adapters/__init__.py +31 -0
  302. mute_agent/listener/adapters/base_adapter.py +189 -0
  303. mute_agent/listener/adapters/caas_adapter.py +344 -0
  304. mute_agent/listener/adapters/control_plane_adapter.py +436 -0
  305. mute_agent/listener/adapters/iatp_adapter.py +332 -0
  306. mute_agent/listener/adapters/scak_adapter.py +251 -0
  307. mute_agent/listener/listener.py +610 -0
  308. mute_agent/listener/state_observer.py +436 -0
  309. mute_agent/listener/threshold_config.py +313 -0
  310. mute_agent/super_system/__init__.py +1 -0
  311. mute_agent/super_system/router.py +204 -0
  312. mute_agent/visualization/__init__.py +10 -0
  313. mute_agent/visualization/graph_debugger.py +502 -0
  314. nexus/README.md +60 -0
  315. nexus/__init__.py +51 -0
  316. nexus/arbiter.py +359 -0
  317. nexus/client.py +466 -0
  318. nexus/dmz.py +444 -0
  319. nexus/escrow.py +430 -0
  320. nexus/exceptions.py +286 -0
  321. nexus/pyproject.toml +36 -0
  322. nexus/registry.py +393 -0
  323. nexus/reputation.py +425 -0
  324. nexus/schemas/__init__.py +51 -0
  325. nexus/schemas/compliance.py +276 -0
  326. nexus/schemas/escrow.py +251 -0
  327. nexus/schemas/manifest.py +225 -0
  328. nexus/schemas/receipt.py +208 -0
  329. nexus/tests/__init__.py +0 -0
  330. nexus/tests/conftest.py +146 -0
  331. nexus/tests/test_arbiter.py +192 -0
  332. nexus/tests/test_dmz.py +194 -0
  333. nexus/tests/test_escrow.py +276 -0
  334. nexus/tests/test_exceptions.py +225 -0
  335. nexus/tests/test_registry.py +232 -0
  336. nexus/tests/test_reputation.py +328 -0
  337. nexus/tests/test_schemas.py +295 -0
@@ -0,0 +1,631 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ Microsoft Agent Framework (MAF) Governance Adapter
5
+
6
+ Bridges the Agent OS governance toolkit into MAF's native middleware system.
7
+ Four composable middleware layers enforce policy, capability guards, audit
8
+ trails, and rogue-agent detection at every level of the agent stack:
9
+
10
+ - GovernancePolicyMiddleware (AgentMiddleware): Declarative policy enforcement
11
+ - CapabilityGuardMiddleware (FunctionMiddleware): Tool allow/deny lists
12
+ - AuditTrailMiddleware (AgentMiddleware): Tamper-proof audit logging
13
+ - RogueDetectionMiddleware (FunctionMiddleware): Behavioral anomaly detection
14
+
15
+ Each middleware works independently and can be composed in any combination.
16
+
17
+ Usage::
18
+
19
+ from agent_framework import Agent
20
+ from agent_os.integrations.maf_adapter import create_governance_middleware
21
+
22
+ middleware = create_governance_middleware(
23
+ policy_directory="policies/",
24
+ allowed_tools=["web_search", "file_read"],
25
+ enable_rogue_detection=True,
26
+ )
27
+
28
+ agent = Agent(
29
+ name="researcher",
30
+ instructions="You are a research assistant.",
31
+ middleware=middleware,
32
+ )
33
+ """
34
+
35
+ from __future__ import annotations
36
+
37
+ import logging
38
+ import time
39
+ from pathlib import Path
40
+ from typing import Any, Awaitable, Callable
41
+
42
+ from agent_os.policies import PolicyDecision, PolicyEvaluator
43
+ from agentmesh.governance import AuditEntry, AuditLog
44
+ from agent_sre.anomaly import RiskLevel, RogueAgentDetector, RogueDetectorConfig
45
+
46
+ logger = logging.getLogger(__name__)
47
+
48
+ # ---------------------------------------------------------------------------
49
+ # Conditional MAF imports — fall back to local stubs when agent_framework
50
+ # is not installed so the module remains importable for testing / linting.
51
+ # ---------------------------------------------------------------------------
52
+ try:
53
+ from agent_framework import (
54
+ AgentContext,
55
+ AgentMiddleware,
56
+ AgentResponse,
57
+ FunctionInvocationContext,
58
+ FunctionMiddleware,
59
+ Message,
60
+ MiddlewareTermination,
61
+ )
62
+ except ImportError: # pragma: no cover
63
+ logger.debug(
64
+ "agent_framework is not installed; MAF middleware classes will use "
65
+ "protocol-only base stubs."
66
+ )
67
+
68
+ class AgentMiddleware: # type: ignore[no-redef]
69
+ """Stub base class when agent_framework is absent."""
70
+
71
+ class FunctionMiddleware: # type: ignore[no-redef]
72
+ """Stub base class when agent_framework is absent."""
73
+
74
+ class AgentContext: # type: ignore[no-redef]
75
+ """Stub for type hints."""
76
+
77
+ class FunctionInvocationContext: # type: ignore[no-redef]
78
+ """Stub for type hints."""
79
+
80
+ class AgentResponse: # type: ignore[no-redef]
81
+ def __init__(self, *, messages: list[Any] | None = None) -> None:
82
+ self.messages = messages or []
83
+
84
+ class Message: # type: ignore[no-redef]
85
+ def __init__(self, role: str, contents: list[str] | None = None) -> None:
86
+ self.role = role
87
+ self.contents = contents or []
88
+
89
+ @property
90
+ def text(self) -> str:
91
+ return str(self.contents[0]) if self.contents else ""
92
+
93
+ class MiddlewareTermination(Exception): # type: ignore[no-redef]
94
+ """Local fallback when agent_framework is not installed."""
95
+
96
+
97
+ # ═══════════════════════════════════════════════════════════════════════════
98
+ # 1. GovernancePolicyMiddleware
99
+ # ═══════════════════════════════════════════════════════════════════════════
100
+
101
+
102
+ class GovernancePolicyMiddleware(AgentMiddleware):
103
+ """AgentMiddleware that evaluates declarative governance policies.
104
+
105
+ Intercepts every agent invocation, builds a context dict from the
106
+ incoming messages and agent metadata, and evaluates it against loaded
107
+ :class:`~agent_os.policies.PolicyEvaluator` rules. Denied requests
108
+ are short-circuited with an ``AgentResponse`` explaining the
109
+ violation and a ``MiddlewareTermination`` is raised.
110
+
111
+ Args:
112
+ evaluator: Pre-configured :class:`PolicyEvaluator` with loaded
113
+ policy documents.
114
+ audit_log: Optional :class:`AuditLog` for recording decisions.
115
+ """
116
+
117
+ def __init__(
118
+ self,
119
+ evaluator: PolicyEvaluator,
120
+ audit_log: AuditLog | None = None,
121
+ ) -> None:
122
+ self.evaluator = evaluator
123
+ self.audit_log = audit_log
124
+
125
+ async def process(
126
+ self,
127
+ context: AgentContext,
128
+ call_next: Callable[[], Awaitable[None]],
129
+ ) -> None:
130
+ """Evaluate governance policy before agent execution."""
131
+ agent_name = getattr(context.agent, "name", "unknown")
132
+
133
+ # Extract the last user message text (handle empty conversations).
134
+ last_message_text = ""
135
+ messages: list[Any] = getattr(context, "messages", None) or []
136
+ if messages:
137
+ last_msg = messages[-1]
138
+ # Message.text is the MAF accessor; fall back to str()
139
+ last_message_text = (
140
+ getattr(last_msg, "text", None) or str(last_msg)
141
+ )
142
+
143
+ # Build context dict for the policy evaluator.
144
+ eval_context: dict[str, Any] = {
145
+ "agent": agent_name,
146
+ "message": last_message_text,
147
+ "timestamp": time.time(),
148
+ "stream": getattr(context, "stream", False),
149
+ "message_count": len(messages),
150
+ }
151
+
152
+ decision: PolicyDecision = self.evaluator.evaluate(eval_context)
153
+
154
+ # Persist the decision in the MAF metadata for downstream middleware.
155
+ metadata: dict[str, Any] = getattr(context, "metadata", {})
156
+ metadata["governance_decision"] = decision
157
+
158
+ if not decision.allowed:
159
+ logger.info(
160
+ "Policy DENY for agent '%s': %s (rule=%s)",
161
+ agent_name,
162
+ decision.reason,
163
+ decision.matched_rule,
164
+ )
165
+
166
+ # Set a user-visible response explaining the denial.
167
+ context.result = AgentResponse(
168
+ messages=[
169
+ Message(
170
+ "assistant",
171
+ [f"⛔ Policy violation: {decision.reason}"],
172
+ )
173
+ ]
174
+ )
175
+
176
+ if self.audit_log:
177
+ self.audit_log.log(
178
+ event_type="policy_violation",
179
+ agent_did=agent_name,
180
+ action="deny",
181
+ data={
182
+ "reason": decision.reason,
183
+ "matched_rule": decision.matched_rule,
184
+ "message_preview": last_message_text[:200],
185
+ },
186
+ outcome="denied",
187
+ policy_decision=decision.action,
188
+ )
189
+
190
+ raise MiddlewareTermination(decision.reason)
191
+
192
+ # Policy allowed — log and continue the pipeline.
193
+ logger.debug(
194
+ "Policy ALLOW for agent '%s' (rule=%s)",
195
+ agent_name,
196
+ decision.matched_rule,
197
+ )
198
+
199
+ if self.audit_log:
200
+ self.audit_log.log(
201
+ event_type="policy_evaluation",
202
+ agent_did=agent_name,
203
+ action="allow",
204
+ data={
205
+ "matched_rule": decision.matched_rule,
206
+ "message_preview": last_message_text[:200],
207
+ },
208
+ outcome="success",
209
+ policy_decision=decision.action,
210
+ )
211
+
212
+ await call_next()
213
+
214
+
215
+ # ═══════════════════════════════════════════════════════════════════════════
216
+ # 2. CapabilityGuardMiddleware
217
+ # ═══════════════════════════════════════════════════════════════════════════
218
+
219
+
220
+ class CapabilityGuardMiddleware(FunctionMiddleware):
221
+ """FunctionMiddleware that enforces tool allow/deny lists.
222
+
223
+ Each tool invocation is checked against explicit ``allowed_tools``
224
+ and ``denied_tools`` lists. If a tool is not permitted, the
225
+ function result is set to an error string and
226
+ ``MiddlewareTermination`` is raised.
227
+
228
+ When both ``allowed_tools`` and ``denied_tools`` are provided,
229
+ ``denied_tools`` takes precedence (a tool in both lists is denied).
230
+
231
+ Args:
232
+ allowed_tools: Whitelist of permitted tool names. If ``None``,
233
+ all tools are allowed unless explicitly denied.
234
+ denied_tools: Blacklist of forbidden tool names.
235
+ audit_log: Optional :class:`AuditLog` for recording tool
236
+ invocations.
237
+ """
238
+
239
+ def __init__(
240
+ self,
241
+ allowed_tools: list[str] | None = None,
242
+ denied_tools: list[str] | None = None,
243
+ audit_log: AuditLog | None = None,
244
+ ) -> None:
245
+ self.allowed_tools = allowed_tools
246
+ self.denied_tools = denied_tools
247
+ self.audit_log = audit_log
248
+
249
+ def _is_denied(self, tool_name: str) -> bool:
250
+ """Return ``True`` if *tool_name* should be blocked."""
251
+ # Explicit deny list takes precedence.
252
+ if self.denied_tools and tool_name in self.denied_tools:
253
+ return True
254
+ # If an allow list is set, anything not in it is denied.
255
+ if self.allowed_tools is not None and tool_name not in self.allowed_tools:
256
+ return True
257
+ return False
258
+
259
+ async def process(
260
+ self,
261
+ context: FunctionInvocationContext,
262
+ call_next: Callable[[], Awaitable[None]],
263
+ ) -> None:
264
+ """Guard tool invocations against capability policy."""
265
+ func_name = getattr(
266
+ getattr(context, "function", None), "name", "unknown"
267
+ )
268
+
269
+ if self._is_denied(func_name):
270
+ logger.info("Capability DENY: tool '%s' blocked by policy", func_name)
271
+
272
+ context.result = (
273
+ f"⛔ Tool '{func_name}' is not permitted by governance policy"
274
+ )
275
+
276
+ if self.audit_log:
277
+ self.audit_log.log(
278
+ event_type="tool_blocked",
279
+ agent_did="capability-guard",
280
+ action="deny",
281
+ resource=func_name,
282
+ data={"tool": func_name},
283
+ outcome="denied",
284
+ )
285
+
286
+ raise MiddlewareTermination(
287
+ f"Tool '{func_name}' is not permitted by governance policy"
288
+ )
289
+
290
+ # Tool is allowed — log start, execute, log completion.
291
+ if self.audit_log:
292
+ self.audit_log.log(
293
+ event_type="tool_invocation",
294
+ agent_did="capability-guard",
295
+ action="start",
296
+ resource=func_name,
297
+ data={"tool": func_name},
298
+ outcome="success",
299
+ )
300
+
301
+ logger.debug("Capability ALLOW: invoking tool '%s'", func_name)
302
+
303
+ await call_next()
304
+
305
+ # Log completion with a truncated result summary.
306
+ result_summary = str(getattr(context, "result", ""))[:500]
307
+ if self.audit_log:
308
+ self.audit_log.log(
309
+ event_type="tool_invocation",
310
+ agent_did="capability-guard",
311
+ action="complete",
312
+ resource=func_name,
313
+ data={
314
+ "tool": func_name,
315
+ "result_preview": result_summary,
316
+ },
317
+ outcome="success",
318
+ )
319
+
320
+
321
+ # ═══════════════════════════════════════════════════════════════════════════
322
+ # 3. AuditTrailMiddleware
323
+ # ═══════════════════════════════════════════════════════════════════════════
324
+
325
+
326
+ class AuditTrailMiddleware(AgentMiddleware):
327
+ """AgentMiddleware that records tamper-proof audit entries.
328
+
329
+ Wraps every agent invocation with pre- and post-execution audit
330
+ entries, capturing timing information and the execution outcome.
331
+ The resulting :class:`AuditEntry` ID is stored in
332
+ ``context.metadata["audit_entry_id"]`` for downstream correlation.
333
+
334
+ Args:
335
+ audit_log: :class:`AuditLog` instance for recording entries.
336
+ agent_did: Optional decentralised identifier for the agent.
337
+ Defaults to the MAF agent name when not provided.
338
+ """
339
+
340
+ def __init__(
341
+ self,
342
+ audit_log: AuditLog,
343
+ agent_did: str | None = None,
344
+ ) -> None:
345
+ self.audit_log = audit_log
346
+ self.agent_did = agent_did
347
+
348
+ async def process(
349
+ self,
350
+ context: AgentContext,
351
+ call_next: Callable[[], Awaitable[None]],
352
+ ) -> None:
353
+ """Record pre/post execution audit entries with timing."""
354
+ agent_name = getattr(context.agent, "name", "unknown")
355
+ did = self.agent_did or agent_name
356
+
357
+ messages: list[Any] = getattr(context, "messages", None) or []
358
+ metadata: dict[str, Any] = getattr(context, "metadata", {})
359
+
360
+ # Pre-execution audit entry.
361
+ start_entry: AuditEntry = self.audit_log.log(
362
+ event_type="agent_invocation",
363
+ agent_did=did,
364
+ action="start",
365
+ data={
366
+ "agent_name": agent_name,
367
+ "message_count": len(messages),
368
+ "stream": getattr(context, "stream", False),
369
+ },
370
+ outcome="success",
371
+ )
372
+
373
+ # Store the entry ID for downstream middleware / callers.
374
+ metadata["audit_entry_id"] = start_entry.entry_id
375
+
376
+ start_time = time.time()
377
+ outcome = "success"
378
+ error_detail: str | None = None
379
+
380
+ try:
381
+ await call_next()
382
+ except Exception as exc:
383
+ outcome = "error"
384
+ error_detail = f"{type(exc).__name__}: {exc}"
385
+ raise
386
+ finally:
387
+ elapsed = time.time() - start_time
388
+
389
+ # Post-execution audit entry.
390
+ self.audit_log.log(
391
+ event_type="agent_invocation",
392
+ agent_did=did,
393
+ action="complete",
394
+ data={
395
+ "agent_name": agent_name,
396
+ "elapsed_seconds": round(elapsed, 4),
397
+ "start_entry_id": start_entry.entry_id,
398
+ **({"error": error_detail} if error_detail else {}),
399
+ },
400
+ outcome=outcome,
401
+ )
402
+
403
+ logger.debug(
404
+ "Audit: agent '%s' completed in %.3fs (outcome=%s)",
405
+ agent_name,
406
+ elapsed,
407
+ outcome,
408
+ )
409
+
410
+
411
+ # ═══════════════════════════════════════════════════════════════════════════
412
+ # 4. RogueDetectionMiddleware
413
+ # ═══════════════════════════════════════════════════════════════════════════
414
+
415
+
416
+ class RogueDetectionMiddleware(FunctionMiddleware):
417
+ """FunctionMiddleware that detects rogue agent behaviour.
418
+
419
+ Feeds every tool invocation into a
420
+ :class:`~agent_sre.anomaly.RogueAgentDetector` and checks the
421
+ resulting risk assessment. High-risk agents are blocked with a
422
+ ``MiddlewareTermination``; medium-risk invocations proceed with a
423
+ warning logged to the audit trail.
424
+
425
+ Args:
426
+ detector: Pre-configured :class:`RogueAgentDetector`.
427
+ agent_id: Identifier for the agent being monitored.
428
+ capability_profile: Optional dict mapping ``"allowed_tools"``
429
+ to a list of expected tool names. Registered with the
430
+ detector on construction.
431
+ audit_log: Optional :class:`AuditLog` for recording detections.
432
+ """
433
+
434
+ def __init__(
435
+ self,
436
+ detector: RogueAgentDetector,
437
+ agent_id: str,
438
+ capability_profile: dict[str, Any] | None = None,
439
+ audit_log: AuditLog | None = None,
440
+ ) -> None:
441
+ self.detector = detector
442
+ self.agent_id = agent_id
443
+ self.audit_log = audit_log
444
+
445
+ # Register the expected capability profile if provided.
446
+ if capability_profile and "allowed_tools" in capability_profile:
447
+ self.detector.register_capability_profile(
448
+ agent_id,
449
+ capability_profile["allowed_tools"],
450
+ )
451
+
452
+ async def process(
453
+ self,
454
+ context: FunctionInvocationContext,
455
+ call_next: Callable[[], Awaitable[None]],
456
+ ) -> None:
457
+ """Assess rogue risk before allowing tool execution."""
458
+ func_name = getattr(
459
+ getattr(context, "function", None), "name", "unknown"
460
+ )
461
+ now = time.time()
462
+
463
+ # Feed the observation into the detector's analyzers.
464
+ self.detector.record_action(
465
+ agent_id=self.agent_id,
466
+ action=func_name,
467
+ tool_name=func_name,
468
+ timestamp=now,
469
+ )
470
+
471
+ # Produce a composite risk assessment.
472
+ assessment = self.detector.assess(self.agent_id, timestamp=now)
473
+
474
+ if assessment.quarantine_recommended:
475
+ logger.warning(
476
+ "Rogue QUARANTINE for agent '%s': risk=%s score=%.2f",
477
+ self.agent_id,
478
+ assessment.risk_level.value,
479
+ assessment.composite_score,
480
+ )
481
+
482
+ context.result = (
483
+ f"⛔ Agent '{self.agent_id}' has been quarantined due to "
484
+ f"anomalous behaviour (risk={assessment.risk_level.value}, "
485
+ f"score={assessment.composite_score:.2f})"
486
+ )
487
+
488
+ if self.audit_log:
489
+ self.audit_log.log(
490
+ event_type="rogue_detection",
491
+ agent_did=self.agent_id,
492
+ action="quarantine",
493
+ resource=func_name,
494
+ data=assessment.to_dict(),
495
+ outcome="denied",
496
+ )
497
+
498
+ raise MiddlewareTermination(
499
+ f"Agent '{self.agent_id}' quarantined: "
500
+ f"risk={assessment.risk_level.value}"
501
+ )
502
+
503
+ # Log a warning for MEDIUM or above but allow execution.
504
+ if assessment.risk_level in (RiskLevel.MEDIUM, RiskLevel.HIGH):
505
+ logger.warning(
506
+ "Rogue WARNING for agent '%s': risk=%s score=%.2f "
507
+ "(tool=%s)",
508
+ self.agent_id,
509
+ assessment.risk_level.value,
510
+ assessment.composite_score,
511
+ func_name,
512
+ )
513
+
514
+ if self.audit_log:
515
+ self.audit_log.log(
516
+ event_type="rogue_detection",
517
+ agent_did=self.agent_id,
518
+ action="warning",
519
+ resource=func_name,
520
+ data=assessment.to_dict(),
521
+ outcome="success",
522
+ )
523
+
524
+ await call_next()
525
+
526
+
527
+ # ═══════════════════════════════════════════════════════════════════════════
528
+ # Convenience factory
529
+ # ═══════════════════════════════════════════════════════════════════════════
530
+
531
+
532
+ def create_governance_middleware(
533
+ policy_directory: str | Path | None = None,
534
+ allowed_tools: list[str] | None = None,
535
+ denied_tools: list[str] | None = None,
536
+ agent_id: str = "default-agent",
537
+ enable_rogue_detection: bool = True,
538
+ audit_log: AuditLog | None = None,
539
+ ) -> list:
540
+ """Create a complete governance middleware stack for a MAF agent.
541
+
542
+ Assembles and returns an ordered list of middleware instances ready
543
+ to pass directly to a MAF ``Agent(middleware=...)`` constructor.
544
+
545
+ The stack is built bottom-up:
546
+
547
+ 1. :class:`AuditTrailMiddleware` (if *audit_log* provided)
548
+ 2. :class:`GovernancePolicyMiddleware` (if *policy_directory* provided)
549
+ 3. :class:`CapabilityGuardMiddleware` (if allow/deny lists provided)
550
+ 4. :class:`RogueDetectionMiddleware` (if *enable_rogue_detection*)
551
+
552
+ Args:
553
+ policy_directory: Path to a directory of YAML policy files.
554
+ When provided, a :class:`PolicyEvaluator` is created and
555
+ loaded with all ``*.yaml`` / ``*.yml`` files found.
556
+ allowed_tools: Whitelist of permitted tool names.
557
+ denied_tools: Blacklist of forbidden tool names.
558
+ agent_id: Identifier for the agent (used by audit and rogue
559
+ detection).
560
+ enable_rogue_detection: Whether to include the
561
+ :class:`RogueDetectionMiddleware`.
562
+ audit_log: Shared :class:`AuditLog` instance. When ``None``,
563
+ a fresh in-memory log is created if any auditing middleware
564
+ is needed.
565
+
566
+ Returns:
567
+ List of middleware instances in recommended execution order.
568
+
569
+ Example::
570
+
571
+ from agent_framework import Agent
572
+ from agent_os.integrations.maf_adapter import create_governance_middleware
573
+
574
+ stack = create_governance_middleware(
575
+ policy_directory="policies/",
576
+ allowed_tools=["search", "read_file"],
577
+ agent_id="my-researcher",
578
+ )
579
+ agent = Agent(name="researcher", middleware=stack)
580
+ """
581
+ stack: list[Any] = []
582
+
583
+ # Determine whether we need an audit log for any layer.
584
+ needs_audit = (
585
+ audit_log is not None
586
+ or policy_directory is not None
587
+ or allowed_tools is not None
588
+ or denied_tools is not None
589
+ or enable_rogue_detection
590
+ )
591
+ if needs_audit and audit_log is None:
592
+ audit_log = AuditLog()
593
+
594
+ # 1. Audit trail (outermost — captures everything).
595
+ if audit_log is not None:
596
+ stack.append(AuditTrailMiddleware(audit_log=audit_log, agent_did=agent_id))
597
+
598
+ # 2. Governance policy enforcement.
599
+ if policy_directory is not None:
600
+ evaluator = PolicyEvaluator()
601
+ evaluator.load_policies(policy_directory)
602
+ stack.append(
603
+ GovernancePolicyMiddleware(evaluator=evaluator, audit_log=audit_log)
604
+ )
605
+
606
+ # 3. Capability guard.
607
+ if allowed_tools is not None or denied_tools is not None:
608
+ stack.append(
609
+ CapabilityGuardMiddleware(
610
+ allowed_tools=allowed_tools,
611
+ denied_tools=denied_tools,
612
+ audit_log=audit_log,
613
+ )
614
+ )
615
+
616
+ # 4. Rogue detection (innermost — closest to actual tool execution).
617
+ if enable_rogue_detection:
618
+ detector = RogueAgentDetector(config=RogueDetectorConfig())
619
+ capability_profile: dict[str, Any] | None = None
620
+ if allowed_tools:
621
+ capability_profile = {"allowed_tools": allowed_tools}
622
+ stack.append(
623
+ RogueDetectionMiddleware(
624
+ detector=detector,
625
+ agent_id=agent_id,
626
+ capability_profile=capability_profile,
627
+ audit_log=audit_log,
628
+ )
629
+ )
630
+
631
+ return stack