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,620 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ AutoGen Integration
5
+
6
+ Wraps Microsoft AutoGen agents with Agent OS governance.
7
+
8
+ Usage:
9
+ from agent_os.integrations import AutoGenKernel
10
+
11
+ kernel = AutoGenKernel()
12
+ kernel.govern(agent1, agent2, agent3)
13
+
14
+ # Now all conversations are governed
15
+ agent1.initiate_chat(agent2, message="...")
16
+ """
17
+
18
+ import functools
19
+ import logging
20
+ import re
21
+ import time
22
+ from datetime import datetime
23
+ from typing import Any, Callable, Optional
24
+
25
+ from .base import BaseIntegration, ExecutionContext, GovernancePolicy, PolicyViolationError
26
+
27
+ logger = logging.getLogger("agent_os.autogen")
28
+
29
+ # Patterns used to detect potential PII / secrets in state changes
30
+ _PII_PATTERNS = [
31
+ re.compile(r"\b\d{3}-\d{2}-\d{4}\b"), # SSN
32
+ re.compile(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b"), # email
33
+ re.compile(r"\b(?:password|passwd|secret|token|api[_-]?key)\s*[:=]\s*\S+", re.IGNORECASE),
34
+ ]
35
+
36
+
37
+ class AutoGenKernel(BaseIntegration):
38
+ """
39
+ AutoGen adapter for Agent OS.
40
+
41
+ Supports:
42
+ - AssistantAgent
43
+ - UserProxyAgent
44
+ - GroupChat
45
+ - Conversation flows
46
+ - Deep hooks: function call pipeline interception, GroupChat message
47
+ routing, and agent state tracking (when ``deep_hooks_enabled`` is True).
48
+ """
49
+
50
+ def __init__(
51
+ self,
52
+ policy: Optional[GovernancePolicy] = None,
53
+ timeout_seconds: float = 300.0,
54
+ on_error: Optional[Callable[[Exception, str], Any]] = None,
55
+ deep_hooks_enabled: bool = True,
56
+ ):
57
+ """Initialise the AutoGen governance kernel.
58
+
59
+ Args:
60
+ policy: Governance policy to enforce. When ``None`` the default
61
+ ``GovernancePolicy`` is used.
62
+ timeout_seconds: Default timeout in seconds (default 300).
63
+ on_error: Optional callback invoked on errors with ``(exception,
64
+ agent_id)`` arguments. When ``None``, errors propagate
65
+ normally.
66
+ deep_hooks_enabled: When ``True`` (default), apply deep
67
+ integration hooks — function call pipeline interception,
68
+ GroupChat message routing, and state change tracking.
69
+ """
70
+ super().__init__(policy)
71
+ self.timeout_seconds = timeout_seconds
72
+ self.on_error = on_error
73
+ self.deep_hooks_enabled = deep_hooks_enabled
74
+ self._governed_agents: dict[str, Any] = {}
75
+ self._original_methods: dict[str, dict[str, Any]] = {}
76
+ self._stopped: dict[str, bool] = {}
77
+ self._start_time = time.monotonic()
78
+ self._last_error: Optional[str] = None
79
+ self._function_call_log: list[dict[str, Any]] = []
80
+ self._groupchat_message_log: list[dict[str, Any]] = []
81
+ self._state_change_log: list[dict[str, Any]] = []
82
+
83
+ def wrap(self, agent: Any) -> Any:
84
+ """Wrap a single AutoGen agent with governance.
85
+
86
+ Convenience method that delegates to :meth:`govern` for a single
87
+ agent.
88
+
89
+ Args:
90
+ agent: An AutoGen agent (``AssistantAgent``, ``UserProxyAgent``,
91
+ etc.).
92
+
93
+ Returns:
94
+ The same agent object with its key methods monkey-patched for
95
+ governance.
96
+ """
97
+ return self.govern(agent)[0]
98
+
99
+ def govern(self, *agents: Any) -> list[Any]:
100
+ """Add governance to one or more AutoGen agents.
101
+
102
+ Monkey-patches ``initiate_chat``, ``generate_reply``, and
103
+ ``receive`` on each agent so that every message exchange is
104
+ validated against the active policy.
105
+
106
+ The original methods are stored internally so they can be restored
107
+ later via :meth:`unwrap`.
108
+
109
+ Args:
110
+ *agents: AutoGen agents to govern.
111
+
112
+ Returns:
113
+ The same agent objects (in-place patched) as a list.
114
+
115
+ Example:
116
+ >>> kernel = AutoGenKernel(policy=GovernancePolicy(
117
+ ... blocked_patterns=["password"]
118
+ ... ))
119
+ >>> kernel.govern(assistant, user_proxy)
120
+ >>> assistant.initiate_chat(user_proxy, message="hello")
121
+ """
122
+ governed = []
123
+
124
+ for agent in agents:
125
+ agent_id = getattr(agent, 'name', f"autogen-{id(agent)}")
126
+ ctx = self.create_context(agent_id)
127
+
128
+ # Store reference
129
+ self._governed_agents[agent_id] = agent
130
+ self._stopped[agent_id] = False
131
+
132
+ # Store original methods before wrapping
133
+ self._original_methods[agent_id] = {}
134
+ for method_name in ('initiate_chat', 'generate_reply', 'receive'):
135
+ if hasattr(agent, method_name):
136
+ self._original_methods[agent_id][method_name] = getattr(agent, method_name)
137
+
138
+ # Wrap key methods
139
+ self._wrap_initiate_chat(agent, ctx, agent_id)
140
+ self._wrap_generate_reply(agent, ctx, agent_id)
141
+ self._wrap_receive(agent, ctx, agent_id)
142
+
143
+ # Apply deep hooks
144
+ if self.deep_hooks_enabled:
145
+ try:
146
+ self._intercept_function_calls(agent, ctx, agent_id)
147
+ except Exception as exc:
148
+ logger.warning("Function call interception failed for %s: %s", agent_id, exc)
149
+ try:
150
+ self._intercept_groupchat(agent, ctx, agent_id)
151
+ except Exception as exc:
152
+ logger.warning("GroupChat interception failed for %s: %s", agent_id, exc)
153
+ try:
154
+ self._intercept_state_changes(agent, ctx, agent_id)
155
+ except Exception as exc:
156
+ logger.warning("State change interception failed for %s: %s", agent_id, exc)
157
+
158
+ governed.append(agent)
159
+
160
+ return governed
161
+
162
+ def _wrap_initiate_chat(self, agent: Any, ctx: ExecutionContext, agent_id: str):
163
+ """Wrap ``initiate_chat`` with pre-/post-execution governance.
164
+
165
+ Args:
166
+ agent: The AutoGen agent to patch.
167
+ ctx: Execution context for this agent.
168
+ agent_id: Unique identifier for audit logging.
169
+ """
170
+ if not hasattr(agent, 'initiate_chat'):
171
+ return
172
+
173
+ original = agent.initiate_chat
174
+ kernel = self
175
+
176
+ def governed_initiate_chat(recipient, message=None, **kwargs):
177
+ if kernel._stopped.get(agent_id):
178
+ raise PolicyViolationError(f"Agent '{agent_id}' is stopped (SIGSTOP)")
179
+
180
+ try:
181
+ allowed, reason = kernel.pre_execute(ctx, {"recipient": str(recipient), "message": message})
182
+ if not allowed:
183
+ logger.info("Policy DENY on initiate_chat for %s: %s", agent_id, reason)
184
+ raise PolicyViolationError(reason)
185
+ except PolicyViolationError:
186
+ raise
187
+ except Exception as exc:
188
+ logger.error("Governance check failed for %s: %s", agent_id, exc)
189
+ kernel._last_error = str(exc)
190
+ if kernel.on_error:
191
+ kernel.on_error(exc, agent_id)
192
+ return None
193
+ raise
194
+
195
+ try:
196
+ result = original(recipient, message=message, **kwargs)
197
+ except Exception as exc:
198
+ logger.error("initiate_chat failed for %s: %s", agent_id, exc)
199
+ kernel._last_error = str(exc)
200
+ if kernel.on_error:
201
+ kernel.on_error(exc, agent_id)
202
+ return None
203
+ raise
204
+
205
+ kernel.post_execute(ctx, result)
206
+ return result
207
+
208
+ agent.initiate_chat = governed_initiate_chat
209
+
210
+ def _wrap_generate_reply(self, agent: Any, ctx: ExecutionContext, agent_id: str):
211
+ """Wrap ``generate_reply`` with message interception and governance.
212
+
213
+ Unlike ``initiate_chat``, violations in ``generate_reply`` return a
214
+ ``[BLOCKED: ...]`` string rather than raising an exception, so that
215
+ multi-agent conversations can continue with the violation visible
216
+ in the message stream.
217
+
218
+ Args:
219
+ agent: The AutoGen agent to patch.
220
+ ctx: Execution context for this agent.
221
+ agent_id: Unique identifier for audit logging.
222
+ """
223
+ if not hasattr(agent, 'generate_reply'):
224
+ return
225
+
226
+ original = agent.generate_reply
227
+ kernel = self
228
+
229
+ def governed_generate_reply(messages=None, sender=None, **kwargs):
230
+ if kernel._stopped.get(agent_id):
231
+ return f"[BLOCKED: Agent '{agent_id}' is stopped (SIGSTOP)]"
232
+
233
+ try:
234
+ allowed, reason = kernel.pre_execute(ctx, {"messages": messages, "sender": str(sender)})
235
+ if not allowed:
236
+ logger.info("Policy DENY on generate_reply for %s: %s", agent_id, reason)
237
+ return f"[BLOCKED: {reason}]"
238
+ except Exception as exc:
239
+ logger.error("Governance check failed for %s: %s", agent_id, exc)
240
+ kernel._last_error = str(exc)
241
+ if kernel.on_error:
242
+ kernel.on_error(exc, agent_id)
243
+ return "[ERROR: governance check failed]"
244
+
245
+ try:
246
+ result = original(messages=messages, sender=sender, **kwargs)
247
+ except Exception as exc:
248
+ logger.error("generate_reply failed for %s: %s", agent_id, exc)
249
+ kernel._last_error = str(exc)
250
+ if kernel.on_error:
251
+ kernel.on_error(exc, agent_id)
252
+ return f"[ERROR: {exc}]"
253
+
254
+ valid, reason = kernel.post_execute(ctx, result)
255
+ if not valid:
256
+ return f"[BLOCKED: {reason}]"
257
+
258
+ return result
259
+
260
+ agent.generate_reply = governed_generate_reply
261
+
262
+ def _wrap_receive(self, agent: Any, ctx: ExecutionContext, agent_id: str):
263
+ """Wrap ``receive`` with inbound message governance.
264
+
265
+ Intercepts messages arriving at this agent and validates them
266
+ against the active policy before forwarding to the original
267
+ ``receive`` implementation.
268
+
269
+ Args:
270
+ agent: The AutoGen agent to patch.
271
+ ctx: Execution context for this agent.
272
+ agent_id: Unique identifier for audit logging.
273
+ """
274
+ if not hasattr(agent, 'receive'):
275
+ return
276
+
277
+ original = agent.receive
278
+ kernel = self
279
+
280
+ def governed_receive(message, sender, **kwargs):
281
+ if kernel._stopped.get(agent_id):
282
+ raise PolicyViolationError(f"Agent '{agent_id}' is stopped (SIGSTOP)")
283
+
284
+ try:
285
+ allowed, reason = kernel.pre_execute(ctx, {"message": message, "sender": str(sender)})
286
+ if not allowed:
287
+ logger.info("Policy DENY on receive for %s: %s", agent_id, reason)
288
+ raise PolicyViolationError(reason)
289
+ except PolicyViolationError:
290
+ raise
291
+ except Exception as exc:
292
+ logger.error("Governance check failed on receive for %s: %s", agent_id, exc)
293
+ kernel._last_error = str(exc)
294
+ if kernel.on_error:
295
+ kernel.on_error(exc, agent_id)
296
+ return None
297
+ raise
298
+
299
+ try:
300
+ result = original(message, sender, **kwargs)
301
+ except Exception as exc:
302
+ logger.error("receive failed for %s: %s", agent_id, exc)
303
+ kernel._last_error = str(exc)
304
+ if kernel.on_error:
305
+ kernel.on_error(exc, agent_id)
306
+ return None
307
+ raise
308
+
309
+ kernel.post_execute(ctx, result)
310
+ return result
311
+
312
+ agent.receive = governed_receive
313
+
314
+ # ── Deep Integration Hooks ────────────────────────────────────
315
+
316
+ def _intercept_function_calls(
317
+ self, agent: Any, ctx: ExecutionContext, agent_id: str
318
+ ) -> None:
319
+ """Wrap the function_map on an AutoGen AssistantAgent.
320
+
321
+ AutoGen agents store callable functions in a ``function_map`` dict.
322
+ This method wraps each function so that every invocation is
323
+ validated against the governance policy before execution.
324
+
325
+ Blocked functions are prevented from running and a
326
+ ``PolicyViolationError`` is raised.
327
+
328
+ Args:
329
+ agent: The AutoGen agent to instrument.
330
+ ctx: Execution context for governance checks.
331
+ agent_id: Unique identifier for audit logging.
332
+ """
333
+ function_map = getattr(agent, "function_map", None)
334
+ if not function_map or not isinstance(function_map, dict):
335
+ return
336
+
337
+ kernel = self
338
+
339
+ for func_name, func in list(function_map.items()):
340
+ if getattr(func, "_fn_governed", False) is True:
341
+ continue
342
+
343
+ @functools.wraps(func)
344
+ def governed_function(
345
+ *args: Any,
346
+ _orig=func,
347
+ _name=func_name,
348
+ **kwargs: Any,
349
+ ) -> Any:
350
+ """Governed wrapper around an AutoGen function_map entry."""
351
+ # Check allowed tools
352
+ if kernel.policy.allowed_tools and _name not in kernel.policy.allowed_tools:
353
+ raise PolicyViolationError(
354
+ f"Function '{_name}' not in allowed list: {kernel.policy.allowed_tools}"
355
+ )
356
+
357
+ # Check blocked patterns on function name + arguments
358
+ combined = _name + str(args) + str(kwargs)
359
+ matched = kernel.policy.matches_pattern(combined)
360
+ if matched:
361
+ raise PolicyViolationError(
362
+ f"Function '{_name}' blocked: pattern '{matched[0]}' detected"
363
+ )
364
+
365
+ # Record the call
366
+ record = {
367
+ "agent_id": agent_id,
368
+ "function_name": _name,
369
+ "args_summary": str(args)[:200],
370
+ "timestamp": datetime.now().isoformat(),
371
+ }
372
+ kernel._function_call_log.append(record)
373
+ logger.info("Function call governed: agent=%s function=%s", agent_id, _name)
374
+
375
+ return _orig(*args, **kwargs)
376
+
377
+ governed_function._fn_governed = True
378
+ function_map[func_name] = governed_function
379
+
380
+ def _intercept_groupchat(
381
+ self, agent: Any, ctx: ExecutionContext, agent_id: str
382
+ ) -> None:
383
+ """Hook into GroupChat's select_speaker and message routing.
384
+
385
+ If the agent is a GroupChat manager (has a ``groupchat`` attribute),
386
+ this method wraps ``select_speaker`` and ``_process_message`` to
387
+ validate each speaker selection and track conversation patterns.
388
+
389
+ Args:
390
+ agent: The AutoGen agent (potentially a GroupChatManager).
391
+ ctx: Execution context for governance checks.
392
+ agent_id: Unique identifier for audit logging.
393
+ """
394
+ groupchat = getattr(agent, "groupchat", None)
395
+ if groupchat is None:
396
+ return
397
+
398
+ kernel = self
399
+
400
+ # Wrap select_speaker
401
+ original_select = getattr(groupchat, "select_speaker", None)
402
+ if original_select and getattr(original_select, "_gc_governed", False) is not True:
403
+
404
+ @functools.wraps(original_select)
405
+ def governed_select_speaker(*args: Any, **kwargs: Any) -> Any:
406
+ result = original_select(*args, **kwargs)
407
+ speaker_name = getattr(result, "name", str(result))
408
+
409
+ record = {
410
+ "groupchat_manager": agent_id,
411
+ "selected_speaker": speaker_name,
412
+ "timestamp": datetime.now().isoformat(),
413
+ }
414
+ kernel._groupchat_message_log.append(record)
415
+
416
+ # Validate speaker selection against blocked patterns
417
+ matched = kernel.policy.matches_pattern(speaker_name)
418
+ if matched:
419
+ raise PolicyViolationError(
420
+ f"Speaker '{speaker_name}' blocked: "
421
+ f"pattern '{matched[0]}' detected"
422
+ )
423
+
424
+ logger.debug(
425
+ "GroupChat speaker selected: manager=%s speaker=%s",
426
+ agent_id, speaker_name,
427
+ )
428
+ return result
429
+
430
+ governed_select_speaker._gc_governed = True
431
+ groupchat.select_speaker = governed_select_speaker
432
+
433
+ # Wrap message sending/routing if available
434
+ for route_attr in ("send", "_broadcast"):
435
+ original_route = getattr(groupchat, route_attr, None)
436
+ if original_route and getattr(original_route, "_gc_governed", False) is not True:
437
+
438
+ @functools.wraps(original_route)
439
+ def governed_route(
440
+ *args: Any, _orig=original_route, _attr=route_attr, **kwargs: Any
441
+ ) -> Any:
442
+ message_str = str(args[0]) if args else str(kwargs)
443
+ matched = kernel.policy.matches_pattern(message_str)
444
+ if matched:
445
+ raise PolicyViolationError(
446
+ f"GroupChat message blocked: pattern '{matched[0]}' detected"
447
+ )
448
+
449
+ kernel._groupchat_message_log.append({
450
+ "groupchat_manager": agent_id,
451
+ "route_method": _attr,
452
+ "message_summary": message_str[:200],
453
+ "timestamp": datetime.now().isoformat(),
454
+ })
455
+ return _orig(*args, **kwargs)
456
+
457
+ governed_route._gc_governed = True
458
+ setattr(groupchat, route_attr, governed_route)
459
+
460
+ def _intercept_state_changes(
461
+ self, agent: Any, ctx: ExecutionContext, agent_id: str
462
+ ) -> None:
463
+ """Track agent state changes for governance audit.
464
+
465
+ Wraps ``update_system_message`` and ``reset`` (if present) to
466
+ monitor and validate state mutations. State changes that contain
467
+ PII or blocked patterns are rejected.
468
+
469
+ Args:
470
+ agent: The AutoGen agent to instrument.
471
+ ctx: Execution context for governance checks.
472
+ agent_id: Unique identifier for audit logging.
473
+ """
474
+ kernel = self
475
+
476
+ # Wrap update_system_message
477
+ original_update = getattr(agent, "update_system_message", None)
478
+ if original_update and getattr(original_update, "_state_governed", False) is not True:
479
+
480
+ @functools.wraps(original_update)
481
+ def governed_update(*args: Any, **kwargs: Any) -> Any:
482
+ content = str(args[0]) if args else str(kwargs)
483
+
484
+ # PII check
485
+ for pattern in _PII_PATTERNS:
486
+ if pattern.search(content):
487
+ raise PolicyViolationError(
488
+ f"State update blocked for '{agent_id}': "
489
+ f"sensitive data detected (pattern: {pattern.pattern})"
490
+ )
491
+
492
+ # Blocked patterns check
493
+ matched = kernel.policy.matches_pattern(content)
494
+ if matched:
495
+ raise PolicyViolationError(
496
+ f"State update blocked for '{agent_id}': "
497
+ f"pattern '{matched[0]}' detected"
498
+ )
499
+
500
+ kernel._state_change_log.append({
501
+ "agent_id": agent_id,
502
+ "action": "update_system_message",
503
+ "content_summary": content[:200],
504
+ "timestamp": datetime.now().isoformat(),
505
+ })
506
+ return original_update(*args, **kwargs)
507
+
508
+ governed_update._state_governed = True
509
+ agent.update_system_message = governed_update
510
+
511
+ # Wrap reset
512
+ original_reset = getattr(agent, "reset", None)
513
+ if original_reset and getattr(original_reset, "_state_governed", False) is not True:
514
+
515
+ @functools.wraps(original_reset)
516
+ def governed_reset(*args: Any, **kwargs: Any) -> Any:
517
+ kernel._state_change_log.append({
518
+ "agent_id": agent_id,
519
+ "action": "reset",
520
+ "timestamp": datetime.now().isoformat(),
521
+ })
522
+ logger.info("Agent state reset: agent=%s", agent_id)
523
+ return original_reset(*args, **kwargs)
524
+
525
+ governed_reset._state_governed = True
526
+ agent.reset = governed_reset
527
+
528
+ def unwrap(self, governed_agent: Any) -> Any:
529
+ """Restore original methods on a governed AutoGen agent.
530
+
531
+ Removes all monkey-patches applied by :meth:`govern` and clears
532
+ the agent from internal tracking.
533
+
534
+ Args:
535
+ governed_agent: A previously governed AutoGen agent.
536
+
537
+ Returns:
538
+ The agent with its original, un-governed methods restored.
539
+ """
540
+ agent_id = getattr(governed_agent, 'name', f"autogen-{id(governed_agent)}")
541
+ originals = self._original_methods.get(agent_id, {})
542
+
543
+ for method_name, original_method in originals.items():
544
+ setattr(governed_agent, method_name, original_method)
545
+
546
+ self._governed_agents.pop(agent_id, None)
547
+ self._original_methods.pop(agent_id, None)
548
+ self._stopped.pop(agent_id, None)
549
+
550
+ return governed_agent
551
+
552
+ def signal(self, agent_id: str, signal: str):
553
+ """Send a POSIX-style signal to a governed agent.
554
+
555
+ Supported signals:
556
+
557
+ * ``SIGSTOP`` — pause the agent; all intercepted methods will
558
+ raise ``PolicyViolationError`` or return a blocked message.
559
+ * ``SIGCONT`` — resume a previously stopped agent.
560
+ * ``SIGKILL`` — permanently remove governance (calls
561
+ :meth:`unwrap`).
562
+
563
+ Args:
564
+ agent_id: Identifier of the target agent.
565
+ signal: One of ``"SIGSTOP"``, ``"SIGCONT"``, or ``"SIGKILL"``.
566
+ """
567
+ if signal == "SIGSTOP":
568
+ self._stopped[agent_id] = True
569
+ elif signal == "SIGCONT":
570
+ self._stopped[agent_id] = False
571
+ elif signal == "SIGKILL":
572
+ if agent_id in self._governed_agents:
573
+ agent = self._governed_agents[agent_id]
574
+ self.unwrap(agent)
575
+
576
+ super().signal(agent_id, signal)
577
+
578
+ def health_check(self) -> dict[str, Any]:
579
+ """Return adapter health status.
580
+
581
+ Returns:
582
+ A dict with ``status``, ``backend``, ``last_error``, and
583
+ ``uptime_seconds`` keys.
584
+ """
585
+ uptime = time.monotonic() - self._start_time
586
+ status = "degraded" if self._last_error else "healthy"
587
+ return {
588
+ "status": status,
589
+ "backend": "autogen",
590
+ "backend_connected": bool(self._governed_agents),
591
+ "last_error": self._last_error,
592
+ "uptime_seconds": round(uptime, 2),
593
+ }
594
+
595
+
596
+ # Convenience function
597
+ def govern(
598
+ *agents: Any,
599
+ policy: Optional[GovernancePolicy] = None,
600
+ timeout_seconds: float = 300.0,
601
+ on_error: Optional[Callable[[Exception, str], Any]] = None,
602
+ ) -> list[Any]:
603
+ """Convenience function to add governance to AutoGen agents.
604
+
605
+ Args:
606
+ *agents: AutoGen agents to govern.
607
+ policy: Optional governance policy (uses defaults when ``None``).
608
+ timeout_seconds: Default timeout in seconds (default 300).
609
+ on_error: Optional error callback ``(exception, agent_id)``.
610
+
611
+ Returns:
612
+ The governed agents as a list.
613
+
614
+ Example:
615
+ >>> from agent_os.integrations.autogen_adapter import govern
616
+ >>> governed_agents = govern(assistant, user_proxy)
617
+ """
618
+ return AutoGenKernel(
619
+ policy, timeout_seconds=timeout_seconds, on_error=on_error
620
+ ).govern(*agents)