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,490 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ AGENTS.md Compatibility for Agent OS.
5
+
6
+ Parses OpenAI/Anthropic standard .agents/ directory structure
7
+ and maps to Agent OS kernel policies.
8
+
9
+ Also provides generation utilities for producing AGENTS.md files
10
+ from AgentMdConfig dataclasses (GitHub Copilot / Cursor / Codex format).
11
+ """
12
+
13
+ import re
14
+ from dataclasses import dataclass, field
15
+ from pathlib import Path
16
+ from typing import Any, Optional
17
+
18
+ import yaml
19
+
20
+ from agent_os.integrations.base import GovernancePolicy
21
+
22
+
23
+ @dataclass
24
+ class AgentSkill:
25
+ """Parsed agent skill/capability."""
26
+ name: str
27
+ description: str
28
+ allowed: bool = True
29
+ requires_approval: bool = False
30
+ read_only: bool = False
31
+ constraints: dict[str, Any] = field(default_factory=dict)
32
+
33
+
34
+ @dataclass
35
+ class AgentConfig:
36
+ """Parsed agent configuration from AGENTS.md."""
37
+ name: str
38
+ description: str
39
+ skills: list[AgentSkill]
40
+ policies: list[str]
41
+ instructions: str
42
+ security_config: dict[str, Any] = field(default_factory=dict)
43
+
44
+
45
+ class AgentsParser:
46
+ """
47
+ Parse .agents/ directory structure.
48
+
49
+ Supports:
50
+ - agents.md (OpenAI/Anthropic standard)
51
+ - security.md (Agent OS extension)
52
+ - YAML front matter
53
+
54
+ Usage:
55
+ parser = AgentsParser()
56
+ config = parser.parse_directory("./my-project/.agents")
57
+
58
+ # Convert to kernel policies
59
+ policies = parser.to_kernel_policies(config)
60
+ """
61
+
62
+ def __init__(self):
63
+ self.skill_patterns = [
64
+ r"^[-*]\s+(.+)$", # - skill or * skill
65
+ r"^(\d+)\.\s+(.+)$", # 1. skill
66
+ ]
67
+
68
+ def parse_directory(self, path: str) -> AgentConfig:
69
+ """Parse .agents/ directory."""
70
+ agents_dir = Path(path)
71
+
72
+ if not agents_dir.exists():
73
+ raise FileNotFoundError(f"Agents directory not found: {path}")
74
+
75
+ # Parse main agents.md
76
+ agents_md = agents_dir / "agents.md"
77
+ if not agents_md.exists():
78
+ agents_md = agents_dir / "AGENTS.md"
79
+
80
+ config = self._parse_agents_md(agents_md) if agents_md.exists() else AgentConfig(
81
+ name="default",
82
+ description="",
83
+ skills=[],
84
+ policies=[],
85
+ instructions=""
86
+ )
87
+
88
+ # Parse security.md (Agent OS extension)
89
+ security_md = agents_dir / "security.md"
90
+ if security_md.exists():
91
+ config.security_config = self._parse_security_md(security_md)
92
+
93
+ return config
94
+
95
+ def _parse_agents_md(self, path: Path) -> AgentConfig:
96
+ """Parse agents.md file."""
97
+ content = path.read_text(encoding="utf-8")
98
+
99
+ # Extract YAML front matter if present
100
+ front_matter = {}
101
+ if content.startswith("---"):
102
+ end = content.find("---", 3)
103
+ if end != -1:
104
+ yaml_content = content[3:end]
105
+ front_matter = yaml.safe_load(yaml_content) or {}
106
+ content = content[end + 3:].strip()
107
+
108
+ # Parse sections
109
+ name = front_matter.get("name", "agent")
110
+ description = ""
111
+ skills = []
112
+ instructions = content
113
+
114
+ # Find "You can:" or "Capabilities:" section
115
+ can_match = re.search(r"(?:You can|Capabilities|Skills):\s*\n((?:[-*\d].*\n?)+)", content, re.IGNORECASE)
116
+ if can_match:
117
+ skills_text = can_match.group(1)
118
+ skills = self._parse_skills(skills_text)
119
+
120
+ # Find description (first paragraph)
121
+ lines = content.split("\n")
122
+ for line in lines:
123
+ line = line.strip()
124
+ if line and not line.startswith(("#", "-", "*", "You can", "Capabilities")):
125
+ description = line
126
+ break
127
+
128
+ return AgentConfig(
129
+ name=name,
130
+ description=description,
131
+ skills=skills,
132
+ policies=front_matter.get("policies", []),
133
+ instructions=instructions,
134
+ security_config=front_matter.get("security", {})
135
+ )
136
+
137
+ def _parse_skills(self, text: str) -> list[AgentSkill]:
138
+ """Parse skills from bullet list."""
139
+ skills = []
140
+
141
+ for line in text.strip().split("\n"):
142
+ line = line.strip()
143
+ if not line:
144
+ continue
145
+
146
+ # Extract skill text
147
+ skill_text = re.sub(r"^[-*\d.]+\s*", "", line)
148
+
149
+ # Parse constraints from parentheses
150
+ constraints = {}
151
+ read_only = False
152
+ requires_approval = False
153
+
154
+ # Check for (read-only), (requires approval), etc.
155
+ if "(read-only)" in skill_text.lower() or "(read only)" in skill_text.lower():
156
+ read_only = True
157
+ skill_text = re.sub(r"\s*\(read[- ]?only\)", "", skill_text, flags=re.IGNORECASE)
158
+
159
+ if "(requires approval)" in skill_text.lower():
160
+ requires_approval = True
161
+ skill_text = re.sub(r"\s*\(requires approval\)", "", skill_text, flags=re.IGNORECASE)
162
+
163
+ skills.append(AgentSkill(
164
+ name=self._skill_to_action(skill_text),
165
+ description=skill_text.strip(),
166
+ read_only=read_only,
167
+ requires_approval=requires_approval,
168
+ constraints=constraints
169
+ ))
170
+
171
+ return skills
172
+
173
+ def _skill_to_action(self, skill: str) -> str:
174
+ """Convert skill description to action name."""
175
+ skill_lower = skill.lower()
176
+
177
+ # Map common patterns
178
+ mappings = {
179
+ "query database": "database_query",
180
+ "read database": "database_query",
181
+ "write to database": "database_write",
182
+ "send email": "send_email",
183
+ "write file": "file_write",
184
+ "read file": "file_read",
185
+ "call api": "api_call",
186
+ "execute code": "code_execution",
187
+ "search": "search",
188
+ "browse": "web_browse",
189
+ }
190
+
191
+ for pattern, action in mappings.items():
192
+ if pattern in skill_lower:
193
+ return action
194
+
195
+ # Default: snake_case the skill
196
+ return re.sub(r"[^a-z0-9]+", "_", skill_lower).strip("_")
197
+
198
+ def _parse_security_md(self, path: Path) -> dict[str, Any]:
199
+ """Parse security.md (Agent OS extension)."""
200
+ content = path.read_text(encoding="utf-8")
201
+
202
+ # Try YAML front matter first
203
+ if content.startswith("---"):
204
+ end = content.find("---", 3)
205
+ if end != -1:
206
+ yaml_content = content[3:end]
207
+ return yaml.safe_load(yaml_content) or {}
208
+
209
+ # Try full YAML
210
+ try:
211
+ return yaml.safe_load(content) or {}
212
+ except yaml.YAMLError:
213
+ pass
214
+
215
+ return {}
216
+
217
+ def to_kernel_policies(self, config: AgentConfig) -> dict[str, Any]:
218
+ """
219
+ Convert AgentConfig to Agent OS kernel policies.
220
+
221
+ Returns policy configuration for Control Plane.
222
+ """
223
+ policies = {
224
+ "name": config.name,
225
+ "version": "1.0",
226
+ "rules": []
227
+ }
228
+
229
+ # Convert skills to rules
230
+ for skill in config.skills:
231
+ rule = {
232
+ "action": skill.name,
233
+ "effect": "allow" if skill.allowed else "deny",
234
+ }
235
+
236
+ if skill.read_only:
237
+ rule["mode"] = "read_only"
238
+
239
+ if skill.requires_approval:
240
+ rule["requires_approval"] = True
241
+
242
+ if skill.constraints:
243
+ rule["constraints"] = skill.constraints
244
+
245
+ policies["rules"].append(rule)
246
+
247
+ # Add security config
248
+ if config.security_config:
249
+ sec = config.security_config
250
+
251
+ if "signals" in sec:
252
+ policies["allowed_signals"] = sec["signals"]
253
+
254
+ if "max_tokens" in sec:
255
+ policies["limits"] = {"max_tokens": sec["max_tokens"]}
256
+
257
+ return policies
258
+
259
+
260
+ def discover_agents(root_dir: str = ".") -> list[AgentConfig]:
261
+ """
262
+ Discover all agent configurations in a repository.
263
+
264
+ Looks for:
265
+ - .agents/agents.md
266
+ - .agents/AGENTS.md
267
+ - agents.md (root)
268
+ - AGENTS.md (root)
269
+
270
+ Returns list of parsed configurations.
271
+ """
272
+ parser = AgentsParser()
273
+ configs = []
274
+ root = Path(root_dir)
275
+
276
+ # Check .agents/ directory
277
+ agents_dir = root / ".agents"
278
+ if agents_dir.exists():
279
+ try:
280
+ configs.append(parser.parse_directory(str(agents_dir)))
281
+ except Exception:
282
+ pass
283
+
284
+ # Check root agents.md
285
+ for name in ["agents.md", "AGENTS.md"]:
286
+ agents_md = root / name
287
+ if agents_md.exists():
288
+ try:
289
+ config = parser._parse_agents_md(agents_md)
290
+ configs.append(config)
291
+ except Exception:
292
+ pass
293
+
294
+ return configs
295
+
296
+
297
+ # ── AGENTS.md Generator ──────────────────────────────────────────────────────
298
+
299
+
300
+ _AGENTS_MD_VERSION = "1.0"
301
+
302
+
303
+ @dataclass
304
+ class AgentMdConfig:
305
+ """Configuration for generating an AGENTS.md file.
306
+
307
+ Maps Agent OS concepts (governance policy, RBAC role, tools) into the
308
+ standard AGENTS.md format consumed by GitHub Copilot, Cursor, Codex, etc.
309
+ """
310
+
311
+ name: str
312
+ description: str = ""
313
+ tools: list[str] = field(default_factory=list)
314
+ policy: Optional[GovernancePolicy] = None
315
+ role: Optional[str] = None
316
+ build_commands: list[str] = field(default_factory=list)
317
+ test_commands: list[str] = field(default_factory=list)
318
+ lint_commands: list[str] = field(default_factory=list)
319
+ boundaries: list[str] = field(default_factory=list)
320
+ code_style: dict[str, str] = field(default_factory=dict)
321
+
322
+
323
+ def generate_agents_md(config: AgentMdConfig) -> str:
324
+ """Generate a valid AGENTS.md string from *config*.
325
+
326
+ The output includes YAML frontmatter followed by Markdown sections for
327
+ project overview, build & test commands, code style, governance,
328
+ boundaries, and commit style.
329
+ """
330
+
331
+ parts: list[str] = []
332
+
333
+ # ── YAML frontmatter ─────────────────────────────────────────────────
334
+ fm: dict[str, Any] = {
335
+ "name": config.name,
336
+ "version": _AGENTS_MD_VERSION,
337
+ }
338
+ if config.description:
339
+ fm["description"] = config.description
340
+ if config.tools:
341
+ fm["tools"] = config.tools
342
+ if config.role:
343
+ fm["role"] = config.role
344
+
345
+ parts.append("---")
346
+ parts.append(yaml.dump(fm, default_flow_style=False, sort_keys=False).rstrip())
347
+ parts.append("---")
348
+ parts.append("")
349
+
350
+ # ── Title ────────────────────────────────────────────────────────────
351
+ parts.append(f"# {config.name} — Coding Agent Instructions")
352
+ parts.append("")
353
+
354
+ # ── Project Overview ─────────────────────────────────────────────────
355
+ if config.description:
356
+ parts.append("## Project Overview")
357
+ parts.append("")
358
+ parts.append(config.description)
359
+ parts.append("")
360
+
361
+ # ── Build & Test Commands ────────────────────────────────────────────
362
+ has_commands = config.build_commands or config.test_commands or config.lint_commands
363
+ if has_commands:
364
+ parts.append("## Build & Test Commands")
365
+ parts.append("")
366
+ parts.append("```bash")
367
+ for cmd in config.build_commands:
368
+ parts.append(cmd)
369
+ for cmd in config.test_commands:
370
+ parts.append(cmd)
371
+ for cmd in config.lint_commands:
372
+ parts.append(cmd)
373
+ parts.append("```")
374
+ parts.append("")
375
+
376
+ # ── Code Style ───────────────────────────────────────────────────────
377
+ if config.code_style:
378
+ parts.append("## Code Style")
379
+ parts.append("")
380
+ for key, value in config.code_style.items():
381
+ parts.append(f"- **{key}:** {value}")
382
+ parts.append("")
383
+
384
+ # ── Governance ───────────────────────────────────────────────────────
385
+ if config.policy is not None:
386
+ parts.append("## Governance")
387
+ parts.append("")
388
+ parts.append("```yaml")
389
+ parts.append(config.policy.to_yaml().rstrip())
390
+ parts.append("```")
391
+ parts.append("")
392
+
393
+ # ── Boundaries ───────────────────────────────────────────────────────
394
+ if config.boundaries:
395
+ parts.append("## Boundaries")
396
+ parts.append("")
397
+ for boundary in config.boundaries:
398
+ parts.append(f"- {boundary}")
399
+ parts.append("")
400
+
401
+ # ── Commit Style ─────────────────────────────────────────────────────
402
+ parts.append("## Commit Style")
403
+ parts.append("")
404
+ parts.append(
405
+ "Use conventional commits: `feat:`, `fix:`, `docs:`, `test:`, `refactor:`, `chore:`"
406
+ )
407
+ parts.append("")
408
+
409
+ return "\n".join(parts)
410
+
411
+
412
+ def save_agents_md(config: AgentMdConfig, path: str) -> None:
413
+ """Write the generated AGENTS.md to *path*."""
414
+
415
+ content = generate_agents_md(config)
416
+ Path(path).write_text(content, encoding="utf-8")
417
+
418
+
419
+ def load_agents_md(path: str) -> AgentMdConfig:
420
+ """Parse an AGENTS.md file back into an *AgentMdConfig*.
421
+
422
+ Extracts YAML frontmatter for metadata and scans Markdown sections for
423
+ build/test/lint commands, code style, governance policy, and boundaries.
424
+ """
425
+
426
+ text = Path(path).read_text(encoding="utf-8")
427
+
428
+ # ── Parse YAML frontmatter ───────────────────────────────────────────
429
+ fm: dict[str, Any] = {}
430
+ body = text
431
+ if text.startswith("---"):
432
+ end = text.find("---", 3)
433
+ if end != -1:
434
+ fm = yaml.safe_load(text[3:end]) or {}
435
+ body = text[end + 3:].strip()
436
+
437
+ config = AgentMdConfig(
438
+ name=fm.get("name", "agent"),
439
+ description=fm.get("description", ""),
440
+ tools=fm.get("tools", []),
441
+ role=fm.get("role"),
442
+ )
443
+
444
+ # ── Section regex (## Heading) ───────────────────────────────────────
445
+ section_re = re.compile(r"^##\s+(.+)$", re.MULTILINE)
446
+ sections: dict[str, str] = {}
447
+ matches = list(section_re.finditer(body))
448
+ for i, m in enumerate(matches):
449
+ heading = m.group(1).strip()
450
+ start = m.end()
451
+ end_pos = matches[i + 1].start() if i + 1 < len(matches) else len(body)
452
+ sections[heading] = body[start:end_pos].strip()
453
+
454
+ # ── Build & Test Commands ────────────────────────────────────────────
455
+ bt_section = sections.get("Build & Test Commands", "")
456
+ code_block = re.search(r"```(?:bash)?\s*\n(.*?)```", bt_section, re.DOTALL)
457
+ if code_block:
458
+ lines = [ln for ln in code_block.group(1).strip().splitlines() if ln.strip()]
459
+ # Simple heuristic: commands containing "test" → test, "lint"/"check"/"format" → lint, rest → build
460
+ for ln in lines:
461
+ low = ln.lower()
462
+ if "test" in low or "pytest" in low:
463
+ config.test_commands.append(ln)
464
+ elif any(kw in low for kw in ("lint", "check", "format", "ruff", "mypy")):
465
+ config.lint_commands.append(ln)
466
+ else:
467
+ config.build_commands.append(ln)
468
+
469
+ # ── Code Style ───────────────────────────────────────────────────────
470
+ cs_section = sections.get("Code Style", "")
471
+ for line in cs_section.splitlines():
472
+ # Matches both `**key:** value` and `**key**: value`
473
+ m = re.match(r"^-\s+\*\*(.+?):?\*\*:?\s*(.+)$", line.strip())
474
+ if m:
475
+ config.code_style[m.group(1).rstrip(":")] = m.group(2)
476
+
477
+ # ── Governance ───────────────────────────────────────────────────────
478
+ gov_section = sections.get("Governance", "")
479
+ gov_block = re.search(r"```(?:yaml)?\s*\n(.*?)```", gov_section, re.DOTALL)
480
+ if gov_block:
481
+ config.policy = GovernancePolicy.from_yaml(gov_block.group(1))
482
+
483
+ # ── Boundaries ───────────────────────────────────────────────────────
484
+ bd_section = sections.get("Boundaries", "")
485
+ for line in bd_section.splitlines():
486
+ stripped = line.strip()
487
+ if stripped.startswith("- "):
488
+ config.boundaries.append(stripped[2:])
489
+
490
+ return config
@@ -0,0 +1,135 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """Standard governance audit logger with pluggable backends."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import json
8
+ import logging
9
+ from dataclasses import asdict, dataclass, field
10
+ from datetime import datetime, timezone
11
+ from pathlib import Path
12
+ from typing import Any, Protocol
13
+
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @dataclass
19
+ class AuditEntry:
20
+ """A governance audit log entry."""
21
+
22
+ timestamp: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
23
+ event_type: str = ""
24
+ agent_id: str = ""
25
+ action: str = ""
26
+ decision: str = ""
27
+ reason: str = ""
28
+ latency_ms: float = 0.0
29
+ metadata: dict[str, Any] = field(default_factory=dict)
30
+
31
+ def to_dict(self) -> dict[str, Any]:
32
+ return asdict(self)
33
+
34
+ def to_json(self) -> str:
35
+ return json.dumps(self.to_dict(), default=str)
36
+
37
+
38
+ class AuditBackend(Protocol):
39
+ """Protocol for audit log backends."""
40
+
41
+ def write(self, entry: AuditEntry) -> None: ...
42
+ def flush(self) -> None: ...
43
+
44
+
45
+ class JsonlFileBackend:
46
+ """Writes audit entries as JSONL to a file."""
47
+
48
+ def __init__(self, path: str | Path) -> None:
49
+ self.path = Path(path)
50
+ self.path.parent.mkdir(parents=True, exist_ok=True)
51
+ self._file = open(self.path, "a", encoding="utf-8")
52
+
53
+ def write(self, entry: AuditEntry) -> None:
54
+ self._file.write(entry.to_json() + "\n")
55
+
56
+ def flush(self) -> None:
57
+ self._file.flush()
58
+
59
+ def close(self) -> None:
60
+ self._file.close()
61
+
62
+
63
+ class InMemoryBackend:
64
+ """Stores audit entries in memory (useful for testing)."""
65
+
66
+ def __init__(self) -> None:
67
+ self.entries: list[AuditEntry] = []
68
+
69
+ def write(self, entry: AuditEntry) -> None:
70
+ self.entries.append(entry)
71
+
72
+ def flush(self) -> None:
73
+ pass
74
+
75
+
76
+ class LoggingBackend:
77
+ """Writes audit entries via Python logging."""
78
+
79
+ def __init__(self, logger_name: str = "agent_os.audit") -> None:
80
+ self._logger = logging.getLogger(logger_name)
81
+
82
+ def write(self, entry: AuditEntry) -> None:
83
+ self._logger.info(
84
+ "[%s] agent=%s action=%s decision=%s latency=%.1fms",
85
+ entry.event_type, entry.agent_id, entry.action,
86
+ entry.decision, entry.latency_ms,
87
+ )
88
+
89
+ def flush(self) -> None:
90
+ pass
91
+
92
+
93
+ class GovernanceAuditLogger:
94
+ """Standard audit logger with pluggable backends.
95
+
96
+ Example::
97
+
98
+ audit = GovernanceAuditLogger()
99
+ audit.add_backend(InMemoryBackend())
100
+ audit.log_decision(agent_id="a1", action="search", decision="allow")
101
+ """
102
+
103
+ def __init__(self) -> None:
104
+ self._backends: list[Any] = []
105
+
106
+ def add_backend(self, backend: Any) -> None:
107
+ self._backends.append(backend)
108
+
109
+ def log(self, entry: AuditEntry) -> None:
110
+ for backend in self._backends:
111
+ backend.write(entry)
112
+
113
+ def log_decision(
114
+ self,
115
+ agent_id: str,
116
+ action: str,
117
+ decision: str,
118
+ reason: str = "",
119
+ latency_ms: float = 0.0,
120
+ **metadata: Any,
121
+ ) -> None:
122
+ entry = AuditEntry(
123
+ event_type="governance_decision",
124
+ agent_id=agent_id,
125
+ action=action,
126
+ decision=decision,
127
+ reason=reason,
128
+ latency_ms=latency_ms,
129
+ metadata=metadata,
130
+ )
131
+ self.log(entry)
132
+
133
+ def flush(self) -> None:
134
+ for backend in self._backends:
135
+ backend.flush()