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
|
@@ -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)
|