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
atr/executor.py ADDED
@@ -0,0 +1,384 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ Execution layer for Agent Tool Registry.
5
+
6
+ Provides sandboxed execution of tools using Docker containers.
7
+ This module handles the actual execution of registered tools, with support
8
+ for both local (unsafe) and Docker-based (safe) sandboxed execution.
9
+ """
10
+
11
+ from abc import ABC, abstractmethod
12
+ from typing import Any, Callable, Dict, Optional
13
+ import tempfile
14
+ import os
15
+ import json
16
+
17
+
18
+ class ExecutorError(Exception):
19
+ """Base exception for executor errors."""
20
+ pass
21
+
22
+
23
+ class ExecutionTimeoutError(ExecutorError):
24
+ """Raised when execution exceeds timeout."""
25
+ pass
26
+
27
+
28
+ class Executor(ABC):
29
+ """Abstract base class for tool executors.
30
+
31
+ Executors handle the actual execution of registered tools,
32
+ providing different execution environments (local, Docker, etc.).
33
+ """
34
+
35
+ @abstractmethod
36
+ def execute(
37
+ self,
38
+ func: Callable[..., Any],
39
+ args: Optional[Dict[str, Any]] = None,
40
+ timeout: Optional[int] = None,
41
+ ) -> Any:
42
+ """Execute a callable function.
43
+
44
+ Args:
45
+ func: The callable function to execute.
46
+ args: Dictionary of arguments to pass to the function.
47
+ timeout: Execution timeout in seconds (None for no timeout).
48
+
49
+ Returns:
50
+ The result of the function execution.
51
+
52
+ Raises:
53
+ ExecutorError: If execution fails.
54
+ ExecutionTimeoutError: If execution exceeds timeout.
55
+ """
56
+ pass
57
+
58
+
59
+ class LocalExecutor(Executor):
60
+ """Executor that runs tools directly on the host machine.
61
+
62
+ WARNING: This executor provides no sandboxing and should only be used
63
+ with trusted code. For untrusted code, use DockerExecutor.
64
+ """
65
+
66
+ def execute(
67
+ self,
68
+ func: Callable[..., Any],
69
+ args: Optional[Dict[str, Any]] = None,
70
+ timeout: Optional[int] = None,
71
+ ) -> Any:
72
+ """Execute a callable function directly on the host.
73
+
74
+ Args:
75
+ func: The callable function to execute.
76
+ args: Dictionary of arguments to pass to the function.
77
+ timeout: Execution timeout in seconds (ignored for local execution).
78
+
79
+ Returns:
80
+ The result of the function execution.
81
+
82
+ Raises:
83
+ ExecutorError: If execution fails.
84
+ """
85
+ if args is None:
86
+ args = {}
87
+
88
+ try:
89
+ return func(**args)
90
+ except Exception as e:
91
+ raise ExecutorError(f"Local execution failed: {str(e)}") from e
92
+
93
+
94
+ class DockerExecutor(Executor):
95
+ """Executor that runs tools in isolated Docker containers.
96
+
97
+ This executor provides sandboxed execution by running tools inside
98
+ ephemeral Docker containers. Containers are automatically cleaned up
99
+ after execution completes or fails.
100
+
101
+ Attributes:
102
+ image: Docker image to use for execution (default: python:3.9-slim).
103
+ auto_pull: Whether to automatically pull the image if not available.
104
+ """
105
+
106
+ def __init__(
107
+ self,
108
+ image: str = "python:3.9-slim",
109
+ auto_pull: bool = True,
110
+ ):
111
+ """Initialize Docker executor.
112
+
113
+ Args:
114
+ image: Docker image to use for execution.
115
+ auto_pull: Whether to automatically pull the image if not available.
116
+
117
+ Raises:
118
+ ImportError: If docker package is not installed.
119
+ ExecutorError: If Docker daemon is not accessible.
120
+ """
121
+ try:
122
+ import docker
123
+ except ImportError:
124
+ raise ImportError(
125
+ "docker package is required for DockerExecutor. "
126
+ "Install it with: pip install docker"
127
+ )
128
+
129
+ self.image = image
130
+ self.auto_pull = auto_pull
131
+
132
+ try:
133
+ self._client = docker.from_env()
134
+ # Test Docker connection
135
+ self._client.ping()
136
+ except Exception as e:
137
+ raise ExecutorError(
138
+ f"Failed to connect to Docker daemon: {str(e)}. "
139
+ "Make sure Docker is installed and running."
140
+ ) from e
141
+
142
+ # Pull image if needed
143
+ if self.auto_pull:
144
+ self._ensure_image()
145
+
146
+ def _ensure_image(self) -> None:
147
+ """Ensure the Docker image is available, pulling if necessary."""
148
+ try:
149
+ self._client.images.get(self.image)
150
+ except Exception:
151
+ # Image not found, try to pull it
152
+ try:
153
+ self._client.images.pull(self.image)
154
+ except Exception as e:
155
+ raise ExecutorError(
156
+ f"Failed to pull Docker image '{self.image}': {str(e)}"
157
+ ) from e
158
+
159
+ def execute(
160
+ self,
161
+ func: Callable[..., Any],
162
+ args: Optional[Dict[str, Any]] = None,
163
+ timeout: Optional[int] = None,
164
+ ) -> Any:
165
+ """Execute a callable function in a Docker container.
166
+
167
+ The function is serialized and executed inside an ephemeral container.
168
+ The container is automatically removed after execution.
169
+
170
+ Args:
171
+ func: The callable function to execute.
172
+ args: Dictionary of arguments to pass to the function.
173
+ timeout: Execution timeout in seconds (None for no timeout).
174
+
175
+ Returns:
176
+ The result of the function execution.
177
+
178
+ Raises:
179
+ ExecutorError: If execution fails.
180
+ ExecutionTimeoutError: If execution exceeds timeout.
181
+ """
182
+ if args is None:
183
+ args = {}
184
+
185
+ # Import required modules
186
+ import docker
187
+ import inspect
188
+ import textwrap
189
+
190
+ container = None
191
+ try:
192
+ # Get the function source
193
+ try:
194
+ full_source = inspect.getsource(func)
195
+ except (OSError, TypeError):
196
+ raise ExecutorError(
197
+ "Cannot execute function in Docker: source code unavailable. "
198
+ "This typically happens with built-in functions or lambdas."
199
+ )
200
+
201
+ func_name = func.__name__
202
+
203
+ # Extract just the function definition (skip decorators)
204
+ # Split into lines and find where the def statement starts
205
+ lines = full_source.split('\n')
206
+ func_start_idx = 0
207
+ for i, line in enumerate(lines):
208
+ if line.strip().startswith('def '):
209
+ func_start_idx = i
210
+ break
211
+
212
+ # Get the function definition without decorators
213
+ func_lines = lines[func_start_idx:]
214
+
215
+ # Dedent to remove any leading indentation
216
+ func_source = textwrap.dedent('\n'.join(func_lines))
217
+
218
+ # Create execution script
219
+ script = self._create_execution_script(func_source, func_name, args)
220
+
221
+ # Create temporary directory for script
222
+ with tempfile.TemporaryDirectory() as temp_dir:
223
+ script_path = os.path.join(temp_dir, "execute.py")
224
+ with open(script_path, "w") as f:
225
+ f.write(script)
226
+
227
+ # Create container with volume mount
228
+ container = self._client.containers.create(
229
+ image=self.image,
230
+ command=["python", "/app/execute.py"],
231
+ volumes={temp_dir: {"bind": "/app", "mode": "ro"}},
232
+ network_mode="none", # Disable network for security
233
+ mem_limit="512m", # Limit memory
234
+ detach=True,
235
+ auto_remove=False, # We'll remove manually after getting logs
236
+ )
237
+
238
+ # Start container
239
+ container.start()
240
+
241
+ # Wait for completion with timeout
242
+ try:
243
+ exit_code = container.wait(timeout=timeout)
244
+
245
+ # Get container status
246
+ if isinstance(exit_code, dict):
247
+ exit_code = exit_code.get("StatusCode", 0)
248
+
249
+ # Get logs
250
+ logs = container.logs().decode("utf-8")
251
+
252
+ if exit_code != 0:
253
+ raise ExecutorError(
254
+ f"Container execution failed with exit code {exit_code}:\n{logs}"
255
+ )
256
+
257
+ # Parse result from logs
258
+ result = self._parse_result(logs)
259
+ return result
260
+
261
+ except Exception as e:
262
+ # Check if it's a timeout
263
+ error_str = str(e).lower()
264
+ if "timeout" in error_str or "timed out" in error_str:
265
+ raise ExecutionTimeoutError(
266
+ f"Execution exceeded timeout of {timeout} seconds"
267
+ ) from e
268
+ # Re-raise if it's already one of our exception types
269
+ if isinstance(e, (ExecutorError, ExecutionTimeoutError)):
270
+ raise
271
+ # Wrap other exceptions
272
+ raise ExecutorError(f"Docker execution failed: {str(e)}") from e
273
+
274
+ except ExecutorError:
275
+ raise
276
+ except ExecutionTimeoutError:
277
+ raise
278
+ except Exception as e:
279
+ raise ExecutorError(f"Docker execution failed: {str(e)}") from e
280
+ finally:
281
+ # Clean up container
282
+ if container is not None:
283
+ try:
284
+ container.stop(timeout=1)
285
+ except Exception:
286
+ pass
287
+ try:
288
+ container.remove(force=True)
289
+ except Exception:
290
+ pass
291
+
292
+ def _create_execution_script(
293
+ self,
294
+ func_source: str,
295
+ func_name: str,
296
+ args: Dict[str, Any],
297
+ ) -> str:
298
+ """Create Python script for container execution.
299
+
300
+ Args:
301
+ func_source: Source code of the function.
302
+ func_name: Name of the function.
303
+ args: Arguments to pass to the function.
304
+
305
+ Returns:
306
+ Complete Python script as string.
307
+ """
308
+ # Serialize args to JSON and escape for embedding in script
309
+ args_json = json.dumps(args).replace('\\', '\\\\').replace("'", "\\'")
310
+
311
+ # Build the script with common imports
312
+ script_parts = [
313
+ "import json",
314
+ "import sys",
315
+ "from typing import List, Dict, Optional, Any, Tuple, Set", # Common type hints
316
+ "",
317
+ "# Define the function",
318
+ func_source,
319
+ "",
320
+ "# Parse arguments",
321
+ f"args = json.loads('{args_json}')",
322
+ "",
323
+ "# Execute function",
324
+ "try:",
325
+ f" result = {func_name}(**args)",
326
+ " # Print result with marker for parsing",
327
+ ' print("__RESULT_START__")',
328
+ ' print(json.dumps({"success": True, "result": result}))',
329
+ ' print("__RESULT_END__")',
330
+ "except Exception as e:",
331
+ ' print("__RESULT_START__")',
332
+ ' print(json.dumps({"success": False, "error": str(e)}))',
333
+ ' print("__RESULT_END__")',
334
+ " sys.exit(1)",
335
+ ]
336
+
337
+ return "\n".join(script_parts)
338
+
339
+ def _parse_result(self, logs: str) -> Any:
340
+ """Parse execution result from container logs.
341
+
342
+ Args:
343
+ logs: Container logs output.
344
+
345
+ Returns:
346
+ The execution result.
347
+
348
+ Raises:
349
+ ExecutorError: If result parsing fails.
350
+ """
351
+ try:
352
+ # Find result between markers
353
+ start_marker = "__RESULT_START__"
354
+ end_marker = "__RESULT_END__"
355
+
356
+ if start_marker not in logs or end_marker not in logs:
357
+ raise ExecutorError(f"Could not find result markers in logs:\n{logs}")
358
+
359
+ start_idx = logs.index(start_marker) + len(start_marker)
360
+ end_idx = logs.index(end_marker)
361
+ result_json = logs[start_idx:end_idx].strip()
362
+
363
+ result_data = json.loads(result_json)
364
+
365
+ if not result_data.get("success"):
366
+ error = result_data.get("error", "Unknown error")
367
+ raise ExecutorError(f"Function execution failed: {error}")
368
+
369
+ return result_data.get("result")
370
+
371
+ except json.JSONDecodeError as e:
372
+ raise ExecutorError(f"Failed to parse result JSON: {str(e)}") from e
373
+ except ExecutorError:
374
+ raise
375
+ except Exception as e:
376
+ raise ExecutorError(f"Failed to parse result: {str(e)}") from e
377
+
378
+ def __del__(self):
379
+ """Clean up Docker client."""
380
+ if hasattr(self, "_client"):
381
+ try:
382
+ self._client.close()
383
+ except Exception:
384
+ pass