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
agent_os/escalation.py ADDED
@@ -0,0 +1,276 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """Human-in-the-loop escalation workflows for AI agent governance.
4
+
5
+ Provides approval gates, timeout escalation, and configurable escalation
6
+ policies so agents can't take high-risk actions without human sign-off.
7
+
8
+ This directly addresses the criticism that AGT has "no human escalation
9
+ primitives baked in." Now it does.
10
+
11
+ Usage:
12
+ from agent_os.escalation import EscalationManager, EscalationPolicy
13
+
14
+ policy = EscalationPolicy(
15
+ actions_requiring_approval=["delete_file", "deploy", "send_email"],
16
+ timeout_seconds=300,
17
+ default_on_timeout="deny",
18
+ )
19
+ manager = EscalationManager(policy)
20
+
21
+ decision = await manager.request_approval(
22
+ agent_id="agent-1",
23
+ action="deploy",
24
+ context={"target": "production", "version": "2.1.0"},
25
+ )
26
+ if decision.approved:
27
+ # proceed
28
+ ...
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ import asyncio
34
+ import uuid
35
+ from datetime import datetime, timedelta, timezone
36
+ from enum import Enum
37
+ from typing import Any, Callable, Awaitable
38
+
39
+ from pydantic import BaseModel, Field
40
+
41
+
42
+ class EscalationOutcome(str, Enum):
43
+ """Outcome of an escalation request."""
44
+ APPROVED = "approved"
45
+ DENIED = "denied"
46
+ TIMED_OUT = "timed_out"
47
+ PENDING = "pending"
48
+ AUTO_APPROVED = "auto_approved"
49
+
50
+
51
+ class EscalationRequest(BaseModel):
52
+ """A pending human approval request."""
53
+ request_id: str = Field(default_factory=lambda: uuid.uuid4().hex[:12])
54
+ agent_id: str
55
+ action: str
56
+ context: dict[str, Any] = Field(default_factory=dict)
57
+ reason: str = ""
58
+ urgency: str = Field(default="normal", description="low, normal, high, critical")
59
+ requested_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
60
+ expires_at: datetime | None = None
61
+ outcome: EscalationOutcome = EscalationOutcome.PENDING
62
+ decided_by: str | None = None
63
+ decided_at: datetime | None = None
64
+
65
+
66
+ class EscalationDecision(BaseModel):
67
+ """Result of an escalation request."""
68
+ request_id: str
69
+ approved: bool
70
+ outcome: EscalationOutcome
71
+ decided_by: str
72
+ decided_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
73
+ reason: str = ""
74
+
75
+
76
+ class EscalationPolicy(BaseModel):
77
+ """Policy governing when and how actions are escalated to humans."""
78
+
79
+ actions_requiring_approval: list[str] = Field(
80
+ default_factory=list,
81
+ description="Actions that always require human approval",
82
+ )
83
+ action_patterns_requiring_approval: list[str] = Field(
84
+ default_factory=list,
85
+ description="Regex patterns for actions requiring approval",
86
+ )
87
+ classifications_requiring_approval: list[str] = Field(
88
+ default_factory=list,
89
+ description="Data classifications that trigger escalation (e.g., RESTRICTED, TOP_SECRET)",
90
+ )
91
+ timeout_seconds: int = Field(
92
+ default=300,
93
+ description="Seconds to wait for human response before timeout action",
94
+ )
95
+ default_on_timeout: str = Field(
96
+ default="deny",
97
+ description="Action when timeout: 'deny' (safe default) or 'approve'",
98
+ )
99
+ max_auto_approvals_per_hour: int = Field(
100
+ default=0,
101
+ description="Max actions auto-approved per hour (0 = never auto-approve)",
102
+ )
103
+ escalation_chain: list[str] = Field(
104
+ default_factory=list,
105
+ description="Ordered list of approvers. If first doesn't respond, escalate to next.",
106
+ )
107
+ notify_on_timeout: bool = Field(
108
+ default=True,
109
+ description="Send notification when escalation times out",
110
+ )
111
+
112
+
113
+ class EscalationManager:
114
+ """Manages human-in-the-loop approval workflows.
115
+
116
+ When an agent requests a high-risk action, the manager:
117
+ 1. Checks if the action requires approval (per policy)
118
+ 2. Creates an EscalationRequest
119
+ 3. Notifies the approval handler (webhook, UI, Slack, etc.)
120
+ 4. Waits for human response or timeout
121
+ 5. Returns the decision
122
+
123
+ The approval handler is pluggable — implement your own notification
124
+ system (Slack bot, email, Teams, dashboard, etc.)
125
+ """
126
+
127
+ def __init__(
128
+ self,
129
+ policy: EscalationPolicy,
130
+ approval_handler: Callable[[EscalationRequest], Awaitable[None]] | None = None,
131
+ timeout_handler: Callable[[EscalationRequest], Awaitable[None]] | None = None,
132
+ ) -> None:
133
+ self.policy = policy
134
+ self._pending: dict[str, EscalationRequest] = {}
135
+ self._approval_handler = approval_handler
136
+ self._timeout_handler = timeout_handler
137
+ self._events: list[dict[str, Any]] = []
138
+
139
+ def requires_approval(self, action: str, **context: Any) -> bool:
140
+ """Check if an action requires human approval per policy."""
141
+ import re
142
+
143
+ if action in self.policy.actions_requiring_approval:
144
+ return True
145
+
146
+ for pattern in self.policy.action_patterns_requiring_approval:
147
+ if re.search(pattern, action):
148
+ return True
149
+
150
+ classification = context.get("classification", "")
151
+ if classification in self.policy.classifications_requiring_approval:
152
+ return True
153
+
154
+ return False
155
+
156
+ async def request_approval(
157
+ self,
158
+ agent_id: str,
159
+ action: str,
160
+ context: dict[str, Any] | None = None,
161
+ reason: str = "",
162
+ urgency: str = "normal",
163
+ ) -> EscalationDecision:
164
+ """Request human approval for an action.
165
+
166
+ If the action doesn't require approval, returns auto-approved.
167
+ Otherwise, creates an escalation request and waits for response.
168
+ """
169
+ if not self.requires_approval(action, **(context or {})):
170
+ decision = EscalationDecision(
171
+ request_id="auto",
172
+ approved=True,
173
+ outcome=EscalationOutcome.AUTO_APPROVED,
174
+ decided_by="policy",
175
+ reason="Action does not require approval",
176
+ )
177
+ self._record_event("auto_approved", agent_id, action, decision)
178
+ return decision
179
+
180
+ now = datetime.now(timezone.utc)
181
+ request = EscalationRequest(
182
+ agent_id=agent_id,
183
+ action=action,
184
+ context=context or {},
185
+ reason=reason,
186
+ urgency=urgency,
187
+ expires_at=now + timedelta(seconds=self.policy.timeout_seconds),
188
+ )
189
+ self._pending[request.request_id] = request
190
+
191
+ # Notify approval handler
192
+ if self._approval_handler:
193
+ await self._approval_handler(request)
194
+
195
+ self._record_event("escalated", agent_id, action, request)
196
+
197
+ # Wait for response or timeout
198
+ deadline = request.expires_at
199
+ while datetime.now(timezone.utc) < deadline:
200
+ if request.outcome != EscalationOutcome.PENDING:
201
+ break
202
+ await asyncio.sleep(0.1)
203
+
204
+ # Handle timeout
205
+ if request.outcome == EscalationOutcome.PENDING:
206
+ if self.policy.default_on_timeout == "approve":
207
+ request.outcome = EscalationOutcome.TIMED_OUT
208
+ approved = True
209
+ else:
210
+ request.outcome = EscalationOutcome.TIMED_OUT
211
+ approved = False
212
+
213
+ request.decided_by = "timeout"
214
+ request.decided_at = datetime.now(timezone.utc)
215
+
216
+ if self._timeout_handler and self.policy.notify_on_timeout:
217
+ await self._timeout_handler(request)
218
+
219
+ decision = EscalationDecision(
220
+ request_id=request.request_id,
221
+ approved=approved,
222
+ outcome=EscalationOutcome.TIMED_OUT,
223
+ decided_by="timeout",
224
+ reason=f"Timed out after {self.policy.timeout_seconds}s — default: {self.policy.default_on_timeout}",
225
+ )
226
+ else:
227
+ decision = EscalationDecision(
228
+ request_id=request.request_id,
229
+ approved=request.outcome == EscalationOutcome.APPROVED,
230
+ outcome=request.outcome,
231
+ decided_by=request.decided_by or "unknown",
232
+ decided_at=request.decided_at or datetime.now(timezone.utc),
233
+ )
234
+
235
+ del self._pending[request.request_id]
236
+ self._record_event("decided", agent_id, action, decision)
237
+ return decision
238
+
239
+ def approve(self, request_id: str, decided_by: str = "human", reason: str = "") -> bool:
240
+ """Approve a pending escalation request (called by human/UI)."""
241
+ request = self._pending.get(request_id)
242
+ if not request or request.outcome != EscalationOutcome.PENDING:
243
+ return False
244
+ request.outcome = EscalationOutcome.APPROVED
245
+ request.decided_by = decided_by
246
+ request.decided_at = datetime.now(timezone.utc)
247
+ return True
248
+
249
+ def deny(self, request_id: str, decided_by: str = "human", reason: str = "") -> bool:
250
+ """Deny a pending escalation request (called by human/UI)."""
251
+ request = self._pending.get(request_id)
252
+ if not request or request.outcome != EscalationOutcome.PENDING:
253
+ return False
254
+ request.outcome = EscalationOutcome.DENIED
255
+ request.decided_by = decided_by
256
+ request.decided_at = datetime.now(timezone.utc)
257
+ return True
258
+
259
+ @property
260
+ def pending_requests(self) -> list[EscalationRequest]:
261
+ """Get all pending escalation requests."""
262
+ return [r for r in self._pending.values() if r.outcome == EscalationOutcome.PENDING]
263
+
264
+ @property
265
+ def audit_trail(self) -> list[dict[str, Any]]:
266
+ """Get the escalation audit trail."""
267
+ return list(self._events)
268
+
269
+ def _record_event(self, event_type: str, agent_id: str, action: str, data: Any) -> None:
270
+ self._events.append({
271
+ "event_type": event_type,
272
+ "agent_id": agent_id,
273
+ "action": action,
274
+ "timestamp": datetime.now(timezone.utc).isoformat(),
275
+ "data": data.model_dump(mode="json") if hasattr(data, "model_dump") else str(data),
276
+ })
agent_os/event_bus.py ADDED
@@ -0,0 +1,124 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """Cross-gate event bus for governance layer composition.
4
+
5
+ Enables governance gates (PolicyEvaluator, TrustGate, CircuitBreaker,
6
+ ConversationGuardian) to communicate via events without tight coupling.
7
+
8
+ Example::
9
+
10
+ bus = GovernanceEventBus()
11
+ bus.subscribe("policy.violation", on_violation)
12
+ bus.publish("policy.violation", agent_id="a1", action="delete_db")
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ from collections import defaultdict
19
+ from dataclasses import dataclass, field
20
+ from datetime import datetime, timezone
21
+ from typing import Any, Callable
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ EventHandler = Callable[["GovernanceEvent"], None]
26
+
27
+
28
+ @dataclass
29
+ class GovernanceEvent:
30
+ """A governance event emitted by any gate."""
31
+
32
+ event_type: str
33
+ timestamp: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
34
+ source: str = ""
35
+ agent_id: str = ""
36
+ data: dict[str, Any] = field(default_factory=dict)
37
+
38
+
39
+ # Standard event types
40
+ POLICY_VIOLATION = "policy.violation"
41
+ POLICY_ALLOW = "policy.allow"
42
+ TRUST_PENALTY = "trust.penalty"
43
+ TRUST_BOOST = "trust.boost"
44
+ CIRCUIT_OPEN = "circuit.open"
45
+ CIRCUIT_CLOSE = "circuit.close"
46
+ ESCALATION = "governance.escalation"
47
+ BUDGET_EXCEEDED = "budget.exceeded"
48
+
49
+
50
+ class GovernanceEventBus:
51
+ """Publish/subscribe event bus for governance gate composition.
52
+
53
+ Example::
54
+
55
+ bus = GovernanceEventBus()
56
+
57
+ # Trust gate penalizes on policy violations
58
+ def on_violation(event):
59
+ trust_engine.penalize(event.agent_id, severity=0.3)
60
+ bus.subscribe("policy.violation", on_violation)
61
+
62
+ # Circuit breaker trips on trust penalties
63
+ def on_trust_penalty(event):
64
+ if event.data.get("new_score", 1.0) < 0.3:
65
+ circuit_breaker.trip(event.agent_id)
66
+ bus.subscribe("trust.penalty", on_trust_penalty)
67
+
68
+ # Policy engine publishes violation
69
+ bus.publish("policy.violation", agent_id="agent-1", action="drop_table")
70
+ """
71
+
72
+ def __init__(self) -> None:
73
+ self._handlers: dict[str, list[EventHandler]] = defaultdict(list)
74
+ self._history: list[GovernanceEvent] = []
75
+ self._max_history: int = 1000
76
+
77
+ def subscribe(self, event_type: str, handler: EventHandler) -> None:
78
+ """Subscribe a handler to an event type."""
79
+ self._handlers[event_type].append(handler)
80
+
81
+ def unsubscribe(self, event_type: str, handler: EventHandler) -> None:
82
+ """Remove a handler from an event type."""
83
+ if event_type in self._handlers:
84
+ self._handlers[event_type] = [
85
+ h for h in self._handlers[event_type] if h is not handler
86
+ ]
87
+
88
+ def publish(self, event_type: str, source: str = "", agent_id: str = "", **data: Any) -> GovernanceEvent:
89
+ """Publish an event to all subscribers."""
90
+ event = GovernanceEvent(
91
+ event_type=event_type,
92
+ source=source,
93
+ agent_id=agent_id,
94
+ data=data,
95
+ )
96
+ self._history.append(event)
97
+ if len(self._history) > self._max_history:
98
+ self._history = self._history[-self._max_history:]
99
+
100
+ for handler in self._handlers.get(event_type, []):
101
+ try:
102
+ handler(event)
103
+ except Exception:
104
+ logger.exception("Event handler failed for %s", event_type)
105
+
106
+ # Wildcard subscribers
107
+ for handler in self._handlers.get("*", []):
108
+ try:
109
+ handler(event)
110
+ except Exception:
111
+ logger.exception("Wildcard handler failed for %s", event_type)
112
+
113
+ return event
114
+
115
+ def get_history(self, event_type: str | None = None, limit: int = 100) -> list[GovernanceEvent]:
116
+ """Get recent events, optionally filtered by type."""
117
+ events = self._history
118
+ if event_type:
119
+ events = [e for e in events if e.event_type == event_type]
120
+ return events[-limit:]
121
+
122
+ def clear_history(self) -> None:
123
+ """Clear event history."""
124
+ self._history.clear()
agent_os/exceptions.py ADDED
@@ -0,0 +1,180 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ Agent OS Exception Hierarchy
5
+
6
+ Standardized exceptions with error codes for all Agent OS components.
7
+ Each exception carries an error_code, optional details dict, and timestamp
8
+ for structured error handling and logging.
9
+ """
10
+
11
+ from datetime import datetime, timezone
12
+
13
+
14
+ class AgentOSError(Exception):
15
+ """Base exception for all Agent OS errors."""
16
+
17
+ def __init__(self, message, error_code=None, details=None):
18
+ super().__init__(message)
19
+ self.error_code = error_code or "AGENT_OS_ERROR"
20
+ self.details = details or {}
21
+ self.timestamp = datetime.now(timezone.utc).isoformat()
22
+
23
+ def to_dict(self):
24
+ return {
25
+ "error": self.error_code,
26
+ "message": str(self),
27
+ "details": self.details,
28
+ "timestamp": self.timestamp,
29
+ }
30
+
31
+
32
+ # --- Policy errors ---
33
+
34
+ class PolicyError(AgentOSError):
35
+ """Base exception for policy-related errors."""
36
+
37
+ def __init__(self, message, error_code=None, details=None):
38
+ super().__init__(message, error_code or "POLICY_ERROR", details)
39
+
40
+
41
+ class PolicyViolationError(PolicyError):
42
+ """Raised when a governance policy check fails."""
43
+
44
+ def __init__(self, message, error_code=None, details=None):
45
+ super().__init__(message, error_code or "POLICY_VIOLATION", details)
46
+
47
+
48
+ class PolicyDeniedError(PolicyError):
49
+ """Raised when a policy explicitly denies an action."""
50
+
51
+ def __init__(self, message, error_code=None, details=None):
52
+ super().__init__(message, error_code or "POLICY_DENIED", details)
53
+
54
+
55
+ class PolicyTimeoutError(PolicyError):
56
+ """Raised when a policy evaluation times out."""
57
+
58
+ def __init__(self, message, error_code=None, details=None):
59
+ super().__init__(message, error_code or "POLICY_TIMEOUT", details)
60
+
61
+
62
+ # --- Budget errors ---
63
+
64
+ class BudgetError(AgentOSError):
65
+ """Base exception for budget-related errors."""
66
+
67
+ def __init__(self, message, error_code=None, details=None):
68
+ super().__init__(message, error_code or "BUDGET_ERROR", details)
69
+
70
+
71
+ class BudgetExceededError(BudgetError):
72
+ """Raised when a budget limit is exceeded."""
73
+
74
+ def __init__(self, message, error_code=None, details=None):
75
+ super().__init__(message, error_code or "BUDGET_EXCEEDED", details)
76
+
77
+
78
+ class BudgetWarningError(BudgetError):
79
+ """Raised when approaching a budget limit."""
80
+
81
+ def __init__(self, message, error_code=None, details=None):
82
+ super().__init__(message, error_code or "BUDGET_WARNING", details)
83
+
84
+
85
+ # --- Identity errors ---
86
+
87
+ class IdentityError(AgentOSError):
88
+ """Base exception for identity-related errors."""
89
+
90
+ def __init__(self, message, error_code=None, details=None):
91
+ super().__init__(message, error_code or "IDENTITY_ERROR", details)
92
+
93
+
94
+ class IdentityVerificationError(IdentityError):
95
+ """Raised when identity verification fails."""
96
+
97
+ def __init__(self, message, error_code=None, details=None):
98
+ super().__init__(message, error_code or "IDENTITY_VERIFICATION_FAILED", details)
99
+
100
+
101
+ class CredentialExpiredError(IdentityError):
102
+ """Raised when credentials have expired."""
103
+
104
+ def __init__(self, message, error_code=None, details=None):
105
+ super().__init__(message, error_code or "CREDENTIAL_EXPIRED", details)
106
+
107
+
108
+ # --- Integration errors ---
109
+
110
+ class IntegrationError(AgentOSError):
111
+ """Base exception for integration-related errors."""
112
+
113
+ def __init__(self, message, error_code=None, details=None):
114
+ super().__init__(message, error_code or "INTEGRATION_ERROR", details)
115
+
116
+
117
+ class AdapterNotFoundError(IntegrationError):
118
+ """Raised when a requested adapter is not found."""
119
+
120
+ def __init__(self, message, error_code=None, details=None):
121
+ super().__init__(message, error_code or "ADAPTER_NOT_FOUND", details)
122
+
123
+
124
+ class AdapterTimeoutError(IntegrationError):
125
+ """Raised when an adapter operation times out."""
126
+
127
+ def __init__(self, message, error_code=None, details=None):
128
+ super().__init__(message, error_code or "ADAPTER_TIMEOUT", details)
129
+
130
+
131
+ # --- Configuration errors ---
132
+
133
+ class ConfigurationError(AgentOSError):
134
+ """Base exception for configuration-related errors."""
135
+
136
+ def __init__(self, message, error_code=None, details=None):
137
+ super().__init__(message, error_code or "CONFIGURATION_ERROR", details)
138
+
139
+
140
+ class InvalidPolicyError(ConfigurationError):
141
+ """Raised when a policy definition is invalid."""
142
+
143
+ def __init__(self, message, error_code=None, details=None):
144
+ super().__init__(message, error_code or "INVALID_POLICY", details)
145
+
146
+
147
+ class MissingConfigError(ConfigurationError):
148
+ """Raised when required configuration is missing."""
149
+
150
+ def __init__(self, message, error_code=None, details=None):
151
+ super().__init__(message, error_code or "MISSING_CONFIG", details)
152
+
153
+
154
+ # --- Rate limit errors ---
155
+
156
+ class RateLimitError(AgentOSError):
157
+ """Raised when a rate limit is hit."""
158
+
159
+ def __init__(self, message, error_code=None, details=None):
160
+ super().__init__(message, error_code or "RATE_LIMIT_EXCEEDED", details)
161
+
162
+
163
+ # --- Security errors ---
164
+
165
+
166
+ class SecurityError(AgentOSError):
167
+ """Raised when a sandbox security violation is detected."""
168
+
169
+ def __init__(self, message, error_code=None, details=None):
170
+ super().__init__(message, error_code or "SECURITY_VIOLATION", details)
171
+
172
+
173
+ # --- Serialization errors ---
174
+
175
+
176
+ class SerializationError(AgentOSError):
177
+ """Raised when state serialization or deserialization fails."""
178
+
179
+ def __init__(self, message, error_code=None, details=None):
180
+ super().__init__(message, error_code or "SERIALIZATION_ERROR", details)