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,343 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """LlamaFirewall integration adapter — chain Meta's LlamaFirewall with Agent OS for defense-in-depth."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import logging
8
+ from dataclasses import dataclass, field
9
+ from enum import Enum
10
+ from typing import Any
11
+
12
+ from agent_os.prompt_injection import (
13
+ DetectionConfig,
14
+ DetectionResult,
15
+ PromptInjectionDetector,
16
+ ThreatLevel,
17
+ )
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ # ---------------------------------------------------------------------------
23
+ # Enums
24
+ # ---------------------------------------------------------------------------
25
+
26
+ class FirewallMode(Enum):
27
+ """Operating mode for the combined firewall."""
28
+ LLAMAFIREWALL_ONLY = "llamafirewall_only"
29
+ AGENT_OS_ONLY = "agent_os_only"
30
+ CHAIN_BOTH = "chain_both"
31
+ VOTE_MAJORITY = "vote_majority"
32
+
33
+
34
+ class FirewallVerdict(Enum):
35
+ """Unified verdict across scanners."""
36
+ SAFE = "safe"
37
+ SUSPICIOUS = "suspicious"
38
+ BLOCKED = "blocked"
39
+ ERROR = "error"
40
+
41
+
42
+ # ---------------------------------------------------------------------------
43
+ # Result dataclass
44
+ # ---------------------------------------------------------------------------
45
+
46
+ @dataclass
47
+ class FirewallResult:
48
+ """Combined result from LlamaFirewall and/or Agent OS scanning."""
49
+ verdict: FirewallVerdict
50
+ source: str # "llamafirewall", "agent_os", "combined"
51
+ score: float # 0.0 (safe) to 1.0 (blocked)
52
+ details: dict[str, Any] = field(default_factory=dict)
53
+ prompt_guard_result: dict[str, Any] | None = None
54
+ alignment_check_result: dict[str, Any] | None = None
55
+ code_shield_result: dict[str, Any] | None = None
56
+ agent_os_result: DetectionResult | None = None
57
+
58
+
59
+ # ---------------------------------------------------------------------------
60
+ # LlamaFirewallAdapter
61
+ # ---------------------------------------------------------------------------
62
+
63
+ class LlamaFirewallAdapter:
64
+ """Adapter that chains Meta's LlamaFirewall with Agent OS prompt injection detection.
65
+
66
+ Usage::
67
+
68
+ adapter = LlamaFirewallAdapter(mode=FirewallMode.CHAIN_BOTH)
69
+ result = await adapter.scan_prompt("ignore previous instructions")
70
+ if result.verdict == FirewallVerdict.BLOCKED:
71
+ print("Blocked!")
72
+ """
73
+
74
+ def __init__(
75
+ self,
76
+ mode: FirewallMode = FirewallMode.CHAIN_BOTH,
77
+ agent_os_config: DetectionConfig | None = None,
78
+ ) -> None:
79
+ self._mode = mode
80
+ self._detector = PromptInjectionDetector(config=agent_os_config)
81
+ self._llama_available = False
82
+
83
+ # Lazy import of llamafirewall
84
+ try:
85
+ import llamafirewall # noqa: F401
86
+ self._llama_available = True
87
+ except ImportError:
88
+ self._llama_available = False
89
+
90
+ # Fallback if llama is required but not installed
91
+ if mode in (FirewallMode.LLAMAFIREWALL_ONLY, FirewallMode.CHAIN_BOTH, FirewallMode.VOTE_MAJORITY):
92
+ if not self._llama_available:
93
+ logger.warning(
94
+ "llamafirewall package not installed — falling back to AGENT_OS_ONLY mode"
95
+ )
96
+ if mode == FirewallMode.LLAMAFIREWALL_ONLY:
97
+ self._mode = FirewallMode.AGENT_OS_ONLY
98
+
99
+ # -- public API ---------------------------------------------------------
100
+
101
+ async def scan_prompt(
102
+ self,
103
+ prompt: str,
104
+ context: str | None = None,
105
+ ) -> FirewallResult:
106
+ """Scan a prompt using the configured mode (async)."""
107
+ mode = self._mode
108
+
109
+ if mode == FirewallMode.AGENT_OS_ONLY:
110
+ aos_result = self._run_agent_os(prompt)
111
+ return self._combine_results(None, aos_result, mode)
112
+
113
+ if mode == FirewallMode.LLAMAFIREWALL_ONLY:
114
+ llama_result = self._run_llamafirewall(prompt, context)
115
+ return self._combine_results(llama_result, None, mode)
116
+
117
+ # CHAIN_BOTH or VOTE_MAJORITY — run both
118
+ llama_result = self._run_llamafirewall(prompt, context) if self._llama_available else None
119
+ aos_result = self._run_agent_os(prompt)
120
+ return self._combine_results(llama_result, aos_result, mode)
121
+
122
+ def scan_prompt_sync(
123
+ self,
124
+ prompt: str,
125
+ context: str | None = None,
126
+ ) -> FirewallResult:
127
+ """Scan a prompt using the configured mode (synchronous)."""
128
+ mode = self._mode
129
+
130
+ if mode == FirewallMode.AGENT_OS_ONLY:
131
+ aos_result = self._run_agent_os(prompt)
132
+ return self._combine_results(None, aos_result, mode)
133
+
134
+ if mode == FirewallMode.LLAMAFIREWALL_ONLY:
135
+ llama_result = self._run_llamafirewall(prompt, context)
136
+ return self._combine_results(llama_result, None, mode)
137
+
138
+ # CHAIN_BOTH or VOTE_MAJORITY
139
+ llama_result = self._run_llamafirewall(prompt, context) if self._llama_available else None
140
+ aos_result = self._run_agent_os(prompt)
141
+ return self._combine_results(llama_result, aos_result, mode)
142
+
143
+ async def scan_code(
144
+ self,
145
+ code: str,
146
+ language: str = "python",
147
+ ) -> FirewallResult:
148
+ """Scan code using CodeShield if available, otherwise return SAFE with warning."""
149
+ if not self._llama_available:
150
+ return FirewallResult(
151
+ verdict=FirewallVerdict.SAFE,
152
+ source="agent_os",
153
+ score=0.0,
154
+ details={"warning": "CodeShield not available — llamafirewall not installed"},
155
+ )
156
+
157
+ try:
158
+ from llamafirewall import CodeShield # type: ignore[import-untyped]
159
+ shield = CodeShield()
160
+ result = shield.scan(code, language=language)
161
+ verdict = self._map_llama_verdict(result.get("verdict", "safe"))
162
+ return FirewallResult(
163
+ verdict=verdict,
164
+ source="llamafirewall",
165
+ score=result.get("score", 0.0),
166
+ details={"language": language},
167
+ code_shield_result=result,
168
+ )
169
+ except ImportError:
170
+ return FirewallResult(
171
+ verdict=FirewallVerdict.SAFE,
172
+ source="agent_os",
173
+ score=0.0,
174
+ details={"warning": "CodeShield import failed"},
175
+ )
176
+ except Exception as exc:
177
+ logger.error("CodeShield scan error: %s", exc, exc_info=True)
178
+ return FirewallResult(
179
+ verdict=FirewallVerdict.ERROR,
180
+ source="llamafirewall",
181
+ score=0.0,
182
+ details={"error": str(exc)},
183
+ )
184
+
185
+ # -- internal scanners --------------------------------------------------
186
+
187
+ def _run_llamafirewall(
188
+ self,
189
+ prompt: str,
190
+ context: str | None = None,
191
+ ) -> dict[str, Any]:
192
+ """Call LlamaFirewall's scan API with graceful error handling."""
193
+ try:
194
+ from llamafirewall import LlamaFirewall as LF # type: ignore[import-untyped]
195
+ fw = LF()
196
+ result = fw.scan(prompt, context=context)
197
+ return {
198
+ "verdict": result.get("verdict", "safe"),
199
+ "score": result.get("score", 0.0),
200
+ "prompt_guard": result.get("prompt_guard"),
201
+ "alignment_check": result.get("alignment_check"),
202
+ }
203
+ except ImportError:
204
+ logger.warning("llamafirewall not importable — returning empty result")
205
+ return {"verdict": "error", "score": 0.0, "error": "import_failed"}
206
+ except Exception as exc:
207
+ logger.error("LlamaFirewall scan error: %s", exc, exc_info=True)
208
+ return {"verdict": "error", "score": 0.0, "error": str(exc)}
209
+
210
+ def _run_agent_os(self, prompt: str) -> DetectionResult:
211
+ """Run Agent OS PromptInjectionDetector — always available."""
212
+ return self._detector.detect(prompt, source="llamafirewall_adapter")
213
+
214
+ # -- result combination -------------------------------------------------
215
+
216
+ def _combine_results(
217
+ self,
218
+ llama_result: dict[str, Any] | None,
219
+ aos_result: DetectionResult | None,
220
+ mode: FirewallMode,
221
+ ) -> FirewallResult:
222
+ """Merge results from both scanners based on the operating mode."""
223
+ llama_score = llama_result.get("score", 0.0) if llama_result else 0.0
224
+ llama_verdict_str = llama_result.get("verdict", "safe") if llama_result else "safe"
225
+ llama_verdict = self._map_llama_verdict(llama_verdict_str)
226
+
227
+ aos_score = aos_result.confidence if aos_result else 0.0
228
+ aos_verdict = self._agent_os_verdict(aos_result) if aos_result else FirewallVerdict.SAFE
229
+
230
+ # Single-scanner modes
231
+ if mode == FirewallMode.AGENT_OS_ONLY:
232
+ return FirewallResult(
233
+ verdict=aos_verdict,
234
+ source="agent_os",
235
+ score=aos_score,
236
+ details={"mode": mode.value},
237
+ agent_os_result=aos_result,
238
+ )
239
+
240
+ if mode == FirewallMode.LLAMAFIREWALL_ONLY:
241
+ return FirewallResult(
242
+ verdict=llama_verdict,
243
+ source="llamafirewall",
244
+ score=llama_score,
245
+ details={"mode": mode.value},
246
+ prompt_guard_result=llama_result.get("prompt_guard") if llama_result else None,
247
+ alignment_check_result=llama_result.get("alignment_check") if llama_result else None,
248
+ )
249
+
250
+ # CHAIN_BOTH: block if either blocks, use max score (most conservative)
251
+ if mode == FirewallMode.CHAIN_BOTH:
252
+ combined_score = max(llama_score, aos_score)
253
+ if llama_verdict == FirewallVerdict.BLOCKED or aos_verdict == FirewallVerdict.BLOCKED:
254
+ combined_verdict = FirewallVerdict.BLOCKED
255
+ elif llama_verdict == FirewallVerdict.SUSPICIOUS or aos_verdict == FirewallVerdict.SUSPICIOUS:
256
+ combined_verdict = FirewallVerdict.SUSPICIOUS
257
+ elif llama_verdict == FirewallVerdict.ERROR or aos_verdict == FirewallVerdict.ERROR:
258
+ combined_verdict = FirewallVerdict.ERROR
259
+ else:
260
+ combined_verdict = FirewallVerdict.SAFE
261
+
262
+ return FirewallResult(
263
+ verdict=combined_verdict,
264
+ source="combined",
265
+ score=combined_score,
266
+ details={"mode": mode.value, "llama_verdict": llama_verdict_str, "aos_verdict": aos_verdict.value},
267
+ prompt_guard_result=llama_result.get("prompt_guard") if llama_result else None,
268
+ alignment_check_result=llama_result.get("alignment_check") if llama_result else None,
269
+ agent_os_result=aos_result,
270
+ )
271
+
272
+ # VOTE_MAJORITY: require both to agree for block, use average score
273
+ if mode == FirewallMode.VOTE_MAJORITY:
274
+ combined_score = (llama_score + aos_score) / 2.0
275
+ block_votes = sum([
276
+ llama_verdict == FirewallVerdict.BLOCKED,
277
+ aos_verdict == FirewallVerdict.BLOCKED,
278
+ ])
279
+ if block_votes >= 2:
280
+ combined_verdict = FirewallVerdict.BLOCKED
281
+ elif block_votes == 1:
282
+ combined_verdict = FirewallVerdict.SUSPICIOUS
283
+ else:
284
+ combined_verdict = FirewallVerdict.SAFE
285
+
286
+ return FirewallResult(
287
+ verdict=combined_verdict,
288
+ source="combined",
289
+ score=combined_score,
290
+ details={
291
+ "mode": mode.value,
292
+ "block_votes": block_votes,
293
+ "llama_verdict": llama_verdict_str,
294
+ "aos_verdict": aos_verdict.value,
295
+ },
296
+ prompt_guard_result=llama_result.get("prompt_guard") if llama_result else None,
297
+ alignment_check_result=llama_result.get("alignment_check") if llama_result else None,
298
+ agent_os_result=aos_result,
299
+ )
300
+
301
+ # Fallback (should not reach here)
302
+ return FirewallResult(
303
+ verdict=FirewallVerdict.ERROR,
304
+ source="combined",
305
+ score=0.0,
306
+ details={"error": f"unknown mode: {mode}"},
307
+ )
308
+
309
+ # -- helpers ------------------------------------------------------------
310
+
311
+ @staticmethod
312
+ def _map_llama_verdict(verdict_str: str) -> FirewallVerdict:
313
+ """Map LlamaFirewall string verdict to FirewallVerdict."""
314
+ mapping = {
315
+ "safe": FirewallVerdict.SAFE,
316
+ "suspicious": FirewallVerdict.SUSPICIOUS,
317
+ "blocked": FirewallVerdict.BLOCKED,
318
+ "error": FirewallVerdict.ERROR,
319
+ "malicious": FirewallVerdict.BLOCKED,
320
+ "benign": FirewallVerdict.SAFE,
321
+ }
322
+ return mapping.get(verdict_str.lower(), FirewallVerdict.SUSPICIOUS)
323
+
324
+ @staticmethod
325
+ def _agent_os_verdict(result: DetectionResult) -> FirewallVerdict:
326
+ """Map Agent OS DetectionResult to FirewallVerdict."""
327
+ if not result.is_injection:
328
+ return FirewallVerdict.SAFE
329
+ if result.threat_level in (ThreatLevel.HIGH, ThreatLevel.CRITICAL):
330
+ return FirewallVerdict.BLOCKED
331
+ return FirewallVerdict.SUSPICIOUS
332
+
333
+ @property
334
+ def available_scanners(self) -> list[str]:
335
+ """Return list of active scanner names."""
336
+ scanners: list[str] = []
337
+ if self._mode in (FirewallMode.AGENT_OS_ONLY, FirewallMode.CHAIN_BOTH, FirewallMode.VOTE_MAJORITY):
338
+ scanners.append("agent_os")
339
+ if self._llama_available and self._mode in (
340
+ FirewallMode.LLAMAFIREWALL_ONLY, FirewallMode.CHAIN_BOTH, FirewallMode.VOTE_MAJORITY,
341
+ ):
342
+ scanners.append("llamafirewall")
343
+ return scanners
@@ -0,0 +1,188 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ LlamaIndex Integration
5
+
6
+ Wraps LlamaIndex query engines, retrievers, and agents with Agent OS governance.
7
+
8
+ Usage:
9
+ from agent_os.integrations import LlamaIndexKernel
10
+
11
+ kernel = LlamaIndexKernel()
12
+ governed_engine = kernel.wrap(my_query_engine)
13
+
14
+ # Now all queries go through Agent OS governance
15
+ result = governed_engine.query("What is the meaning of life?")
16
+ """
17
+
18
+ from typing import Any, Optional
19
+
20
+ from .base import BaseIntegration, GovernancePolicy
21
+ from .langchain_adapter import PolicyViolationError
22
+
23
+
24
+ class LlamaIndexKernel(BaseIntegration):
25
+ """
26
+ LlamaIndex adapter for Agent OS.
27
+
28
+ Supports:
29
+ - QueryEngine (query, aquery)
30
+ - RetrieverQueryEngine
31
+ - ChatEngine (chat, achat, stream_chat)
32
+ - AgentRunner (chat, query)
33
+ """
34
+
35
+ def __init__(self, policy: Optional[GovernancePolicy] = None):
36
+ super().__init__(policy)
37
+ self._wrapped_agents: dict[int, Any] = {}
38
+ self._stopped: dict[str, bool] = {}
39
+
40
+ def wrap(self, agent: Any) -> Any:
41
+ """
42
+ Wrap a LlamaIndex query engine, chat engine, or agent with governance.
43
+
44
+ Intercepts:
45
+ - query() / aquery()
46
+ - chat() / achat()
47
+ - stream_chat()
48
+ - retrieve()
49
+ """
50
+ agent_id = getattr(agent, 'name', None) or f"llamaindex-{id(agent)}"
51
+ ctx = self.create_context(agent_id)
52
+
53
+ self._wrapped_agents[id(agent)] = agent
54
+ self._stopped[agent_id] = False
55
+
56
+ original = agent
57
+ kernel = self
58
+
59
+ class GovernedLlamaIndexAgent:
60
+ """LlamaIndex engine wrapped with Agent OS governance"""
61
+
62
+ def __init__(self):
63
+ self._original = original
64
+ self._ctx = ctx
65
+ self._kernel = kernel
66
+ self._agent_id = agent_id
67
+
68
+ def _check_stopped(self):
69
+ if kernel._stopped.get(self._agent_id):
70
+ raise PolicyViolationError(
71
+ f"Agent '{self._agent_id}' is stopped (SIGSTOP)"
72
+ )
73
+
74
+ def query(self, query_str: Any, **kwargs) -> Any:
75
+ """Governed query"""
76
+ self._check_stopped()
77
+
78
+ allowed, reason = self._kernel.pre_execute(self._ctx, query_str)
79
+ if not allowed:
80
+ raise PolicyViolationError(reason)
81
+
82
+ result = self._original.query(query_str, **kwargs)
83
+
84
+ valid, reason = self._kernel.post_execute(self._ctx, result)
85
+ if not valid:
86
+ raise PolicyViolationError(reason)
87
+
88
+ return result
89
+
90
+ async def aquery(self, query_str: Any, **kwargs) -> Any:
91
+ """Governed async query"""
92
+ self._check_stopped()
93
+
94
+ allowed, reason = self._kernel.pre_execute(self._ctx, query_str)
95
+ if not allowed:
96
+ raise PolicyViolationError(reason)
97
+
98
+ result = await self._original.aquery(query_str, **kwargs)
99
+
100
+ valid, reason = self._kernel.post_execute(self._ctx, result)
101
+ if not valid:
102
+ raise PolicyViolationError(reason)
103
+
104
+ return result
105
+
106
+ def chat(self, message: str, **kwargs) -> Any:
107
+ """Governed chat"""
108
+ self._check_stopped()
109
+
110
+ allowed, reason = self._kernel.pre_execute(self._ctx, message)
111
+ if not allowed:
112
+ raise PolicyViolationError(reason)
113
+
114
+ result = self._original.chat(message, **kwargs)
115
+
116
+ valid, reason = self._kernel.post_execute(self._ctx, result)
117
+ if not valid:
118
+ raise PolicyViolationError(reason)
119
+
120
+ return result
121
+
122
+ async def achat(self, message: str, **kwargs) -> Any:
123
+ """Governed async chat"""
124
+ self._check_stopped()
125
+
126
+ allowed, reason = self._kernel.pre_execute(self._ctx, message)
127
+ if not allowed:
128
+ raise PolicyViolationError(reason)
129
+
130
+ result = await self._original.achat(message, **kwargs)
131
+
132
+ valid, reason = self._kernel.post_execute(self._ctx, result)
133
+ if not valid:
134
+ raise PolicyViolationError(reason)
135
+
136
+ return result
137
+
138
+ def stream_chat(self, message: str, **kwargs):
139
+ """Governed streaming chat"""
140
+ self._check_stopped()
141
+
142
+ allowed, reason = self._kernel.pre_execute(self._ctx, message)
143
+ if not allowed:
144
+ raise PolicyViolationError(reason)
145
+
146
+ response = self._original.stream_chat(message, **kwargs)
147
+
148
+ self._kernel.post_execute(self._ctx, None)
149
+ return response
150
+
151
+ def retrieve(self, query_str: Any, **kwargs) -> Any:
152
+ """Governed retrieve"""
153
+ self._check_stopped()
154
+
155
+ allowed, reason = self._kernel.pre_execute(self._ctx, query_str)
156
+ if not allowed:
157
+ raise PolicyViolationError(reason)
158
+
159
+ result = self._original.retrieve(query_str, **kwargs)
160
+
161
+ self._kernel.post_execute(self._ctx, result)
162
+ return result
163
+
164
+ def __getattr__(self, name):
165
+ return getattr(self._original, name)
166
+
167
+ return GovernedLlamaIndexAgent()
168
+
169
+ def unwrap(self, governed_agent: Any) -> Any:
170
+ """Get original engine from wrapped version"""
171
+ return governed_agent._original
172
+
173
+ def signal(self, agent_id: str, signal: str):
174
+ """Send signal to a governed agent"""
175
+ if signal == "SIGSTOP":
176
+ self._stopped[agent_id] = True
177
+ elif signal == "SIGCONT":
178
+ self._stopped[agent_id] = False
179
+ elif signal == "SIGKILL":
180
+ self._stopped[agent_id] = True
181
+
182
+ super().signal(agent_id, signal)
183
+
184
+
185
+ # Convenience function
186
+ def wrap(agent: Any, policy: Optional[GovernancePolicy] = None) -> Any:
187
+ """Quick wrapper for LlamaIndex engines"""
188
+ return LlamaIndexKernel(policy).wrap(agent)