clm-kernel 0.0.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 (333) hide show
  1. clm/__init__.py +230 -0
  2. clm/__main__.py +25 -0
  3. clm/cross_cutting/__init__.py +50 -0
  4. clm/cross_cutting/_test_runner.py +36 -0
  5. clm/cross_cutting/async_utils.py +25 -0
  6. clm/cross_cutting/cel_builder.py +123 -0
  7. clm/cross_cutting/cel_converter.py +697 -0
  8. clm/cross_cutting/cel_engine.py +252 -0
  9. clm/cross_cutting/cel_ops.py +72 -0
  10. clm/cross_cutting/cel_ops_db.py +157 -0
  11. clm/cross_cutting/cel_ops_files.py +99 -0
  12. clm/cross_cutting/cel_ops_state.py +71 -0
  13. clm/cross_cutting/cel_ops_strings.py +64 -0
  14. clm/cross_cutting/cel_resolver.py +63 -0
  15. clm/cross_cutting/cel_slices.py +56 -0
  16. clm/cross_cutting/cel_store.py +330 -0
  17. clm/cross_cutting/clm_logger.py +140 -0
  18. clm/cross_cutting/config/__init__.py +155 -0
  19. clm/cross_cutting/config/config_constants.py +392 -0
  20. clm/cross_cutting/config/env_parameters.py +90 -0
  21. clm/cross_cutting/config/logging.py +378 -0
  22. clm/cross_cutting/config/settings.py +504 -0
  23. clm/cross_cutting/context.py +5 -0
  24. clm/cross_cutting/domain_models.py +55 -0
  25. clm/cross_cutting/domain_types.py +61 -0
  26. clm/cross_cutting/effects.py +67 -0
  27. clm/cross_cutting/errors.py +153 -0
  28. clm/cross_cutting/governance.py +331 -0
  29. clm/cross_cutting/guards.py +41 -0
  30. clm/cross_cutting/mcard.py +321 -0
  31. clm/cross_cutting/native.py +185 -0
  32. clm/cross_cutting/observability.py +289 -0
  33. clm/cross_cutting/pcard.py +434 -0
  34. clm/cross_cutting/registry.py +71 -0
  35. clm/cross_cutting/resources.py +84 -0
  36. clm/cross_cutting/secrets.py +44 -0
  37. clm/cross_cutting/subprocess_utils.py +118 -0
  38. clm/cross_cutting/telemetry.py +164 -0
  39. clm/cross_cutting/testing/__init__.py +8 -0
  40. clm/cross_cutting/testing/comparator.py +187 -0
  41. clm/cross_cutting/testing/datasets.py +87 -0
  42. clm/cross_cutting/timeutil.py +20 -0
  43. clm/cross_cutting/types/new_type_check.py +0 -0
  44. clm/cross_cutting/utils/__init__.py +1 -0
  45. clm/cross_cutting/utils/url_safety.py +50 -0
  46. clm/cross_cutting/vcard.py +560 -0
  47. clm/cross_cutting/writer.py +118 -0
  48. clm/layer0/README.md +50 -0
  49. clm/layer0/__init__.py +223 -0
  50. clm/layer0/algebra.py +60 -0
  51. clm/layer0/algebra_baldwin.py +133 -0
  52. clm/layer0/algebra_baldwin_generators.py +36 -0
  53. clm/layer0/algebra_equivalence.py +262 -0
  54. clm/layer0/algebra_ingest.py +306 -0
  55. clm/layer0/algebra_manifest_io.py +156 -0
  56. clm/layer0/assembler.py +481 -0
  57. clm/layer0/cel/__init__.py +23 -0
  58. clm/layer0/cel_eval.py +491 -0
  59. clm/layer0/codec.py +106 -0
  60. clm/layer0/context.py +122 -0
  61. clm/layer0/db.py +160 -0
  62. clm/layer0/exceptions.py +73 -0
  63. clm/layer0/fibration.py +106 -0
  64. clm/layer0/gates.py +50 -0
  65. clm/layer0/hash.py +80 -0
  66. clm/layer0/loader.py +826 -0
  67. clm/layer0/math_utils.py +163 -0
  68. clm/layer0/mcard.py +96 -0
  69. clm/layer0/model/__init__.py +0 -0
  70. clm/layer0/model/action.py +223 -0
  71. clm/layer0/model/card.py +280 -0
  72. clm/layer0/model/card_triad.py +427 -0
  73. clm/layer0/model/compatibility.py +60 -0
  74. clm/layer0/model/dictionary.py +46 -0
  75. clm/layer0/model/dots.py +331 -0
  76. clm/layer0/model/event_producer.py +88 -0
  77. clm/layer0/model/g_time.py +89 -0
  78. clm/layer0/model/handle.py +163 -0
  79. clm/layer0/model/hash/__init__.py +6 -0
  80. clm/layer0/model/hash/algorithms/__init__.py +3 -0
  81. clm/layer0/model/hash/algorithms/custom_hash.py +7 -0
  82. clm/layer0/model/hash/algorithms/local_sha256.py +178 -0
  83. clm/layer0/model/hash/constants.py +53 -0
  84. clm/layer0/model/hash/enums.py +60 -0
  85. clm/layer0/model/hash/validator.py +307 -0
  86. clm/layer0/model/interpreter.py +275 -0
  87. clm/layer0/model/pagination.py +45 -0
  88. clm/layer0/model/pcard.py +716 -0
  89. clm/layer0/model/schema.py +44 -0
  90. clm/layer0/model/utils/__init__.py +1 -0
  91. clm/layer0/model/utils/content_analyzer.py +152 -0
  92. clm/layer0/model/validators/__init__.py +1 -0
  93. clm/layer0/model/validators/base_validator.py +44 -0
  94. clm/layer0/model/validators/binary_validator.py +66 -0
  95. clm/layer0/model/validators/text_validator.py +82 -0
  96. clm/layer0/model/validators/validation_registry.py +49 -0
  97. clm/layer0/model/vcard.py +823 -0
  98. clm/layer0/model/vcard_ext/__init__.py +39 -0
  99. clm/layer0/model/vcard_ext/core.py +60 -0
  100. clm/layer0/model/vcard_ext/network.py +23 -0
  101. clm/layer0/model/vcard_ext/observability.py +63 -0
  102. clm/layer0/model/vcard_ext/storage.py +60 -0
  103. clm/layer0/model/vcard_ext/vendors.py +211 -0
  104. clm/layer0/model/vcard_sandwich.py +119 -0
  105. clm/layer0/model/vcard_vocabulary.py +463 -0
  106. clm/layer0/model/workflow.py +274 -0
  107. clm/layer0/narrative.py +431 -0
  108. clm/layer0/ontology/collection.py +125 -0
  109. clm/layer0/parser.py +429 -0
  110. clm/layer0/relations.py +73 -0
  111. clm/layer0/rule_evaluator.py +251 -0
  112. clm/layer0/schema/__init__.py +38 -0
  113. clm/layer0/schema/ddl.py +97 -0
  114. clm/layer0/templates/abstract.yaml +99 -0
  115. clm/layer0/templates/balanced.yaml +253 -0
  116. clm/layer0/templates/concrete.yaml +172 -0
  117. clm/layer0/type_registry.py +223 -0
  118. clm/layer0/types.py +204 -0
  119. clm/layer0/utils.py +886 -0
  120. clm/layer0/verifier_core.py +262 -0
  121. clm/layer1/__init__.py +31 -0
  122. clm/layer1/action_dispatcher.py +275 -0
  123. clm/layer1/adapter_registry.py +233 -0
  124. clm/layer1/algebra_baldwin_generators.py +192 -0
  125. clm/layer1/arrow_compiler.py +525 -0
  126. clm/layer1/batch_processor.py +152 -0
  127. clm/layer1/cel/__init__.py +27 -0
  128. clm/layer1/cel/builder.py +173 -0
  129. clm/layer1/engine.py +759 -0
  130. clm/layer1/engine_async.py +89 -0
  131. clm/layer1/eval_callback.py +49 -0
  132. clm/layer1/gate_composer.py +229 -0
  133. clm/layer1/hoare_sandwich.py +298 -0
  134. clm/layer1/identity_guard.py +348 -0
  135. clm/layer1/matrix.py +138 -0
  136. clm/layer1/neural_runtime.py +221 -0
  137. clm/layer1/operations/__init__.py +123 -0
  138. clm/layer1/operations/augment.py +156 -0
  139. clm/layer1/operations/base.py +109 -0
  140. clm/layer1/operations/builtins.py +338 -0
  141. clm/layer1/operations/dispatch.py +144 -0
  142. clm/layer1/operations/exclude.py +107 -0
  143. clm/layer1/operations/handle.py +197 -0
  144. clm/layer1/operations/identity.py +139 -0
  145. clm/layer1/operations/invert.py +66 -0
  146. clm/layer1/operations/loader.py +116 -0
  147. clm/layer1/operations/manipulators/__init__.py +23 -0
  148. clm/layer1/operations/manipulators/document.py +211 -0
  149. clm/layer1/operations/manipulators/media.py +134 -0
  150. clm/layer1/operations/manipulators/structured.py +159 -0
  151. clm/layer1/operations/manipulators/tabular.py +334 -0
  152. clm/layer1/operations/port.py +65 -0
  153. clm/layer1/operations/services.py +529 -0
  154. clm/layer1/operations/split.py +117 -0
  155. clm/layer1/operations/substitute.py +75 -0
  156. clm/layer1/petri.py +1052 -0
  157. clm/layer1/pocketflow_orchestrator.py +408 -0
  158. clm/layer1/pocketflow_scheduler.py +519 -0
  159. clm/layer1/protocols.py +197 -0
  160. clm/layer1/runtime_adapter.py +718 -0
  161. clm/layer1/runtimes/__init__.py +71 -0
  162. clm/layer1/runtimes/_generated_assertions.py +125 -0
  163. clm/layer1/runtimes/_generated_types.py +42 -0
  164. clm/layer1/runtimes/base.py +265 -0
  165. clm/layer1/runtimes/binary.py +101 -0
  166. clm/layer1/runtimes/factory.py +203 -0
  167. clm/layer1/runtimes/javascript.py +321 -0
  168. clm/layer1/runtimes/javascript_runtime.js +33 -0
  169. clm/layer1/runtimes/js_scripts/isomorphism.mjs +22 -0
  170. clm/layer1/runtimes/js_scripts/loader.mjs +52 -0
  171. clm/layer1/runtimes/lambda_calc.py +126 -0
  172. clm/layer1/runtimes/python.py +288 -0
  173. clm/layer1/runtimes/python_runtime.py +41 -0
  174. clm/layer1/runtimes/script.py +114 -0
  175. clm/layer1/sandbox.py +334 -0
  176. clm/layer1/savepoint_guard.py +136 -0
  177. clm/layer1/sparse_net.py +122 -0
  178. clm/layer1/spec_tester.py +165 -0
  179. clm/layer1/store.py +295 -0
  180. clm/layer1/test_runner.py +498 -0
  181. clm/layer1/type_inspector.py +166 -0
  182. clm/layer1/verifier.py +772 -0
  183. clm/layer1/vm.py +91 -0
  184. clm/layer2/__init__.py +78 -0
  185. clm/layer2/card_collection.py +678 -0
  186. clm/layer2/classifier.py +479 -0
  187. clm/layer2/engine/__init__.py +1 -0
  188. clm/layer2/engine/abstract_sql_engine.py +320 -0
  189. clm/layer2/engine/base.py +193 -0
  190. clm/layer2/engine/duckdb_engine.py +576 -0
  191. clm/layer2/engine/sqlite_engine.py +518 -0
  192. clm/layer2/fiber/__init__.py +31 -0
  193. clm/layer2/fiber/context.py +89 -0
  194. clm/layer2/fiber/disposable.py +163 -0
  195. clm/layer2/fiber/fiber.py +125 -0
  196. clm/layer2/fiber/hoare.py +191 -0
  197. clm/layer2/file_io.py +376 -0
  198. clm/layer2/file_registrar.py +77 -0
  199. clm/layer2/ingest.py +202 -0
  200. clm/layer2/lineage.py +322 -0
  201. clm/layer2/mcard_fs.py +262 -0
  202. clm/layer2/merkle.py +11 -0
  203. clm/layer2/mime.py +244 -0
  204. clm/layer2/mime_detector.py +245 -0
  205. clm/layer2/private_collection.py +118 -0
  206. clm/layer2/shared_store.py +11 -0
  207. clm/layer2/storage/__init__.py +190 -0
  208. clm/layer2/storage/db_bitemporal.py +141 -0
  209. clm/layer2/storage/db_driver.py +331 -0
  210. clm/layer2/storage/db_hyperlinks.py +214 -0
  211. clm/layer2/storage/db_pool.py +139 -0
  212. clm/layer2/storage/db_repository.py +229 -0
  213. clm/layer2/storage/savepoint.py +78 -0
  214. clm/layer2/storage/sqlite_wal.py +74 -0
  215. clm/layer2/tridb.py +245 -0
  216. clm/layer2/vcard_receipt.py +71 -0
  217. clm/layer2/vfs.py +17 -0
  218. clm/layer3/__init__.py +141 -0
  219. clm/layer3/agency/__init__.py +19 -0
  220. clm/layer3/agency/config.py +220 -0
  221. clm/layer3/agency/providers/__init__.py +15 -0
  222. clm/layer3/agency/providers/base.py +91 -0
  223. clm/layer3/agency/providers/mlc_llm.py +169 -0
  224. clm/layer3/agency/providers/ollama.py +203 -0
  225. clm/layer3/agency/router.py +71 -0
  226. clm/layer3/agency/runtime.py +524 -0
  227. clm/layer3/gateway.py +353 -0
  228. clm/layer3/open_interpreter_adapter.py +159 -0
  229. clm/layer3/rag/__init__.py +70 -0
  230. clm/layer3/rag/cli.py +228 -0
  231. clm/layer3/rag/config.py +153 -0
  232. clm/layer3/rag/embeddings/__init__.py +16 -0
  233. clm/layer3/rag/embeddings/base.py +79 -0
  234. clm/layer3/rag/embeddings/ollama.py +211 -0
  235. clm/layer3/rag/embeddings/vision.py +290 -0
  236. clm/layer3/rag/engine.py +276 -0
  237. clm/layer3/rag/graph/__init__.py +22 -0
  238. clm/layer3/rag/graph/community.py +198 -0
  239. clm/layer3/rag/graph/engine.py +433 -0
  240. clm/layer3/rag/graph/extractor.py +255 -0
  241. clm/layer3/rag/graph/schema.py +115 -0
  242. clm/layer3/rag/graph/store.py +641 -0
  243. clm/layer3/rag/indexer.py +333 -0
  244. clm/layer3/rag/llm_providers.json +52 -0
  245. clm/layer3/rag/semantic_versioning.py +313 -0
  246. clm/layer3/rag/vector/__init__.py +28 -0
  247. clm/layer3/rag/vector/handle_vector_store.py +749 -0
  248. clm/layer3/rag/vector/schema.py +151 -0
  249. clm/layer3/rag/vector/store.py +632 -0
  250. clm/layer3/reticulum/__init__.py +55 -0
  251. clm/layer3/reticulum/bridge.py +74 -0
  252. clm/layer3/reticulum/daemon.py +88 -0
  253. clm/layer3/reticulum/discovery.py +164 -0
  254. clm/layer3/reticulum/identity.py +107 -0
  255. clm/layer3/reticulum/media.py +148 -0
  256. clm/layer3/reticulum/transport.py +133 -0
  257. clm/layer3/satori/__init__.py +209 -0
  258. clm/layer3/satori/alpha_conversion.py +168 -0
  259. clm/layer3/satori/beta_reduction.py +359 -0
  260. clm/layer3/satori/continuation.py +38 -0
  261. clm/layer3/satori/eta_conversion.py +205 -0
  262. clm/layer3/satori/free_variables.py +163 -0
  263. clm/layer3/satori/io_effects.py +370 -0
  264. clm/layer3/satori/lambda_runtime.py +726 -0
  265. clm/layer3/satori/lambda_term.py +230 -0
  266. clm/layer3/satori/sheaf_audit.py +261 -0
  267. clm/layer3/satori/speech_act.py +279 -0
  268. clm/layer4/README.md +9 -0
  269. clm/layer4/__init__.py +67 -0
  270. clm/layer4/_sovereign_executor.py +580 -0
  271. clm/layer4/action_commands.py +719 -0
  272. clm/layer4/api.py +236 -0
  273. clm/layer4/bootstrap/__init__.py +13 -0
  274. clm/layer4/bootstrap/bootstrapper.py +118 -0
  275. clm/layer4/bootstrap/cleanup.py +44 -0
  276. clm/layer4/bootstrap/clm_hooks.py +49 -0
  277. clm/layer4/bootstrap/genesis.py +77 -0
  278. clm/layer4/bootstrap/injection.py +125 -0
  279. clm/layer4/cli.py +549 -0
  280. clm/layer4/collection_manager.py +553 -0
  281. clm/layer4/commands/__init__.py +81 -0
  282. clm/layer4/commands/action_cmd.py +42 -0
  283. clm/layer4/commands/check_cmd.py +82 -0
  284. clm/layer4/commands/envelope.py +73 -0
  285. clm/layer4/commands/evaluate_cmd.py +224 -0
  286. clm/layer4/commands/mcard_cmd.py +24 -0
  287. clm/layer4/commands/petri_cmd.py +92 -0
  288. clm/layer4/commands/tridb_cmd.py +319 -0
  289. clm/layer4/commands/version_cmd.py +27 -0
  290. clm/layer4/diff_commands.py +167 -0
  291. clm/layer4/eoa_sponsor.py +232 -0
  292. clm/layer4/events.py +69 -0
  293. clm/layer4/flux_gateway.py +133 -0
  294. clm/layer4/gateway.py +91 -0
  295. clm/layer4/loader.py +307 -0
  296. clm/layer4/mcard_commands.py +166 -0
  297. clm/layer4/membrane.py +273 -0
  298. clm/layer4/navigation.py +50 -0
  299. clm/layer4/protocol/protocol_entry_python.py +108 -0
  300. clm/layer4/protocol/python_sync.py +126 -0
  301. clm/layer4/runner.py +150 -0
  302. clm/layer4/satori.py +262 -0
  303. clm/layer4/server/python_sync_client.py +150 -0
  304. clm/layer4/server/python_sync_server.py +139 -0
  305. clm/layer4/server/service_api.py +315 -0
  306. clm/layer4/server/start_servers.py +107 -0
  307. clm/layer4/server/stop_servers.py +24 -0
  308. clm/layer4/simulated_optimization_fix.py +0 -0
  309. clm/layer4/storage.py +463 -0
  310. clm/layer4/tridb_admin.py +268 -0
  311. clm/layer4/websocket/test_ws_client.py +104 -0
  312. clm/layer4/websocket/test_ws_server.py +138 -0
  313. clm/layer4/websocket/ws_server_local.py +160 -0
  314. clm/layer5/__init__.py +51 -0
  315. clm/layer5/async_batch_writer.py +133 -0
  316. clm/layer5/learning.py +276 -0
  317. clm/layer5/telemetry_hook.py +107 -0
  318. clm/layer5/type_lattice.py +238 -0
  319. clm/py.typed +0 -0
  320. clm/schemas/__init__.py +652 -0
  321. clm/schemas/abstract_face_schema.yaml +77 -0
  322. clm/schemas/cel_schema.yaml +416 -0
  323. clm/schemas/lifecycle/__init__.py +45 -0
  324. clm/schemas/lifecycle/models.py +123 -0
  325. clm/schemas/lifecycle/service.py +364 -0
  326. clm/schemas/mcard_schema.sql +192 -0
  327. clm/schemas/mcard_vector_schema.sql +283 -0
  328. clm/schemas/mlp-context-v1.json +91 -0
  329. clm_kernel-0.0.0.dist-info/METADATA +121 -0
  330. clm_kernel-0.0.0.dist-info/RECORD +333 -0
  331. clm_kernel-0.0.0.dist-info/WHEEL +4 -0
  332. clm_kernel-0.0.0.dist-info/entry_points.txt +3 -0
  333. clm_kernel-0.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,126 @@
1
+ """
2
+ Lambda Calculus runtime executor.
3
+
4
+ Executes λ-calculus operations (α-β-η conversions) on MCard-stored terms.
5
+ """
6
+
7
+ from typing import Any
8
+
9
+ from clm.layer0.model.card import MCard
10
+
11
+ from .base import RuntimeExecutor, register_runtime
12
+
13
+
14
+ @register_runtime("lambda")
15
+ class LambdaRuntimeExecutor(RuntimeExecutor):
16
+ """Lambda Calculus runtime executor.
17
+
18
+ Executes λ-calculus operations (α-β-η conversions) on MCard-stored terms.
19
+ """
20
+
21
+ def __init__(self, collection=None):
22
+ super().__init__()
23
+ self.collection = collection
24
+ self._lambda_runtime = None
25
+
26
+ def _get_runtime(self):
27
+ """Lazy initialization of LambdaRuntime."""
28
+ if self._lambda_runtime is None:
29
+ from clm.layer1.protocols import get_store
30
+ from clm.layer1.runtimes.factory import get_external_executor
31
+
32
+ if self.collection is None:
33
+ self.collection = get_store(":memory:")
34
+
35
+ lambda_cls = get_external_executor("lambda")
36
+ if lambda_cls is not None:
37
+ self._lambda_runtime = lambda_cls(self.collection)
38
+ return self._lambda_runtime
39
+
40
+ def execute(self, impl: dict[str, Any], target: MCard, ctx: dict[str, Any]) -> Any:
41
+ """Execute Lambda Calculus operation."""
42
+ runtime = self._get_runtime()
43
+
44
+ # Build context from concrete implementation and context
45
+ # Prioritize ctx override, then 'process', then 'action', then 'operation'
46
+ operation = ctx.get(
47
+ "operation",
48
+ impl.get("process", impl.get("action", impl.get("operation", "normalize"))),
49
+ )
50
+ strategy = ctx.get("strategy", impl.get("strategy", "normal"))
51
+ max_steps = ctx.get(
52
+ "max_steps",
53
+ ctx.get("maxSteps", impl.get("max_steps", impl.get("maxSteps", 100))),
54
+ )
55
+
56
+ # Get expression from context or target
57
+ expression = ctx.get("expression")
58
+ if not expression:
59
+ # Try to get from balanced input arguments
60
+ balanced = ctx.get("balanced", {})
61
+ input_args = balanced.get("input_arguments", {})
62
+ expression = input_args.get("expression") or input_args.get("numeral")
63
+
64
+ if not expression or expression == "dummy_target":
65
+ # Check if target content looks like a Lambda expression
66
+ target_content = target.get_content().decode("utf-8", errors="ignore")
67
+ if target_content and ("λ" in target_content or "\\" in target_content):
68
+ expression = target_content
69
+ elif operation in (
70
+ "check-readiness",
71
+ "num-add",
72
+ "num-sub",
73
+ "num-mul",
74
+ "num-div",
75
+ "http-request",
76
+ ):
77
+ expression = "builtin" # Placeholder
78
+ else:
79
+ return "Error: No Lambda expression provided"
80
+
81
+ # Execute through LambdaRuntime
82
+ # Create a full context by merging ctx and any other needed fields
83
+ full_ctx = ctx.copy()
84
+ full_ctx["expression"] = expression
85
+
86
+ # Get io_effects from context (override) or concrete implementation config
87
+ io_effects = impl.get("io_effects", {}).copy()
88
+ if isinstance(ctx.get("io_effects"), dict):
89
+ io_effects.update(ctx.get("io_effects"))
90
+
91
+ result = runtime.execute(
92
+ expression,
93
+ full_ctx,
94
+ {
95
+ "operation": operation,
96
+ "strategy": strategy,
97
+ "max_steps": max_steps,
98
+ "io_effects": io_effects,
99
+ },
100
+ "",
101
+ )
102
+
103
+ if result.success:
104
+ # Return appropriate result based on operation
105
+ if result.pretty_print:
106
+ return result.pretty_print
107
+ elif result.is_closed is not None:
108
+ return result.is_closed
109
+ elif result.free_variables is not None:
110
+ return result.free_variables
111
+ else:
112
+ return result.term_hash
113
+ else:
114
+ return f"Error: {result.error}"
115
+
116
+ def validate_environment(self) -> bool:
117
+ """Lambda runtime is always available (pure Python)."""
118
+ return True
119
+
120
+ def get_runtime_status(self) -> dict[str, Any]:
121
+ return {
122
+ "available": True,
123
+ "version": "1.0.0",
124
+ "command": "lambda",
125
+ "details": "Lambda Calculus α-β-η converter",
126
+ }
@@ -0,0 +1,288 @@
1
+ """
2
+ Python runtime executor.
3
+
4
+ Executes Python code directly in-process with sandboxing.
5
+ """
6
+
7
+ import functools
8
+ import importlib
9
+ from collections.abc import Callable
10
+ from typing import Any
11
+
12
+ from clm.layer0.model.card import MCard
13
+
14
+ from .base import RUNTIME_CONFIG, RuntimeExecutor, register_runtime
15
+
16
+ # Module URI prefix for dynamic module imports
17
+ MODULE_URI_PREFIX = "module://"
18
+
19
+ # Import sandbox configuration
20
+ try:
21
+ from clm.cross_cutting.config.settings import settings as _settings
22
+
23
+ ALLOWED_IMPORTS = _settings.ptr.allowed_imports
24
+ SAFE_BUILTINS = _settings.ptr.safe_builtins
25
+ except ImportError:
26
+ ALLOWED_IMPORTS = {}
27
+ SAFE_BUILTINS = set()
28
+
29
+
30
+ @register_runtime("python")
31
+ class PythonRuntime(RuntimeExecutor):
32
+ """Python runtime executor - executes Python code directly in-process."""
33
+
34
+ # Operation handlers mapping
35
+ OPERATIONS: dict[str, Callable] = {}
36
+
37
+ # Operation handlers mapping
38
+ OPERATIONS: dict[str, Callable] = {}
39
+
40
+ def __init__(self):
41
+ super().__init__()
42
+ # Import operations from the extracted operations module
43
+ from ..operations import DEFAULT_OPERATIONS
44
+
45
+ # Register built-in operations from module
46
+ self.OPERATIONS = DEFAULT_OPERATIONS.copy()
47
+
48
+ # Add custom operation handler (requires self reference for sandboxing)
49
+ self.OPERATIONS["custom"] = self._op_custom
50
+
51
+ def execute(
52
+ self, concrete_impl: dict[str, Any], target: MCard, context: dict[str, Any]
53
+ ) -> Any:
54
+ # Check for module:// syntax first
55
+ code_file = concrete_impl.get("code_file", "")
56
+ if code_file.startswith(MODULE_URI_PREFIX):
57
+ return self._execute_module_logic(code_file, concrete_impl, target, context)
58
+
59
+ # Determine operation robustly without letting dicts/lists cause key errors
60
+ operation = concrete_impl.get("operation")
61
+ if not operation:
62
+ operation = concrete_impl.get("builtin")
63
+ if not operation:
64
+ op_cand = concrete_impl.get("process")
65
+ if isinstance(op_cand, str):
66
+ operation = op_cand
67
+ else:
68
+ op_cand = concrete_impl.get("action")
69
+ if isinstance(op_cand, str):
70
+ operation = op_cand
71
+
72
+ if not operation:
73
+ # Auto-detect custom operation if code or process-script is present
74
+ has_proc_script = False
75
+ proc = concrete_impl.get("process")
76
+ if isinstance(proc, dict) and "script" in proc:
77
+ has_proc_script = True
78
+ elif isinstance(proc, list):
79
+ for p in proc:
80
+ if (
81
+ isinstance(p, dict)
82
+ and p.get("type") == "python"
83
+ and "script" in p
84
+ ):
85
+ has_proc_script = True
86
+ break
87
+
88
+ if (
89
+ "code_file" in concrete_impl
90
+ or "code" in concrete_impl
91
+ or has_proc_script
92
+ ):
93
+ operation = "custom"
94
+ else:
95
+ operation = "identity"
96
+
97
+ handler = self.OPERATIONS.get(operation)
98
+
99
+ if handler:
100
+ return handler(concrete_impl, target, context)
101
+
102
+ # Fallback to custom operation if custom script/code is provided, even with a custom operation name
103
+ has_proc_script = False
104
+ proc = concrete_impl.get("process")
105
+ if isinstance(proc, dict) and "script" in proc:
106
+ has_proc_script = True
107
+ elif isinstance(proc, list):
108
+ for p in proc:
109
+ if isinstance(p, dict) and p.get("type") == "python" and "script" in p:
110
+ has_proc_script = True
111
+ break
112
+
113
+ if "code_file" in concrete_impl or "code" in concrete_impl or has_proc_script:
114
+ return self._op_custom(concrete_impl, target, context)
115
+
116
+ return f"Executed {operation} on {target.hash}"
117
+
118
+ # ─── Custom Operation ──────────────────────────────────────────────────────
119
+
120
+ def _op_custom(self, impl: dict, target: MCard, ctx: dict) -> Any:
121
+ code_file = impl.get("code_file", "")
122
+ if code_file.startswith(MODULE_URI_PREFIX):
123
+ return self._execute_module_logic(code_file, impl, target, ctx)
124
+
125
+ code = impl.get("code", "")
126
+ if not code:
127
+ proc = impl.get("process")
128
+ if isinstance(proc, dict):
129
+ code = proc.get("script", "")
130
+ elif isinstance(proc, list):
131
+ for p in proc:
132
+ if isinstance(p, dict) and p.get("type") == "python":
133
+ code = p.get("script", "")
134
+ break
135
+ if not code:
136
+ return "Error: No code provided"
137
+
138
+ return self._exec_sandboxed(code, impl, target, ctx)
139
+
140
+ # ─── Sandboxed Execution ───────────────────────────────────────────────────
141
+
142
+ def _make_safe_import(self) -> Callable:
143
+ """Create a safe import function."""
144
+
145
+ def safe_import(name, _globals=None, _locals=None, _fromlist=(), _level=0):
146
+ if name in ALLOWED_IMPORTS:
147
+ return importlib.import_module(name)
148
+ raise ImportError(f"Import of '{name}' is not allowed")
149
+
150
+ return safe_import
151
+
152
+ def _make_namespace(self, target: MCard, context: dict) -> dict:
153
+ """Create a sandboxed namespace for code execution."""
154
+ import builtins as builtins_module
155
+ import math
156
+
157
+ # Build safe builtins dict from the builtins module
158
+ safe_builtins = {}
159
+ for name in SAFE_BUILTINS:
160
+ if hasattr(builtins_module, name):
161
+ safe_builtins[name] = getattr(builtins_module, name)
162
+
163
+ safe_builtins["__import__"] = self._make_safe_import()
164
+ safe_builtins["__build_class__"] = builtins_module.__build_class__
165
+
166
+ return {
167
+ "__builtins__": safe_builtins,
168
+ "target": target.get_content(),
169
+ "context": context,
170
+ "result": None,
171
+ "math": math,
172
+ "__name__": "__clm_runtime__",
173
+ }
174
+
175
+ @staticmethod
176
+ @functools.lru_cache(maxsize=1024)
177
+ def _compile_code(code: str) -> Any:
178
+ """Compile Python code with an LRU cache to prevent memory leaks."""
179
+ return compile(code, "<string>", "exec")
180
+
181
+ def _exec_sandboxed(self, code: str, impl: dict, target: MCard, ctx: dict) -> Any:
182
+ """Execute code in a sandboxed namespace with compilation caching."""
183
+ namespace = self._make_namespace(target, ctx)
184
+
185
+ try:
186
+ compiled_code = self._compile_code(code)
187
+ exec(compiled_code, namespace) # nosec B102
188
+
189
+ entry_point = impl.get("entry_point")
190
+ if entry_point:
191
+ return self._call_entry_point(namespace, entry_point, impl, target, ctx)
192
+ return namespace.get("result")
193
+ except Exception as e:
194
+ return f"Error executing Python code: {e}"
195
+
196
+ def _call_entry_point(
197
+ self, ns: dict, entry: str, impl: dict, target: MCard, ctx: dict
198
+ ) -> Any:
199
+ """Call a function defined in namespace."""
200
+ if entry not in ns or not callable(ns[entry]):
201
+ return f"Error: Entry point '{entry}' not found or not callable. Keys: {list(ns.keys())}"
202
+
203
+ func = ns[entry]
204
+ arg = self._prepare_argument(impl, target, ctx)
205
+ return func(arg)
206
+
207
+ def _prepare_argument(self, impl: dict, target: MCard, ctx: dict) -> Any:
208
+ """Prepare argument for entry point function."""
209
+ inputs_def = impl.get("implementation", {}).get("inputs", {})
210
+
211
+ # If context has operation or params keys, the entry point likely expects context
212
+ if ctx.get("operation") or ctx.get("params") or ctx.get("op"):
213
+ combined = ctx.copy()
214
+ content = target.get_content()
215
+ if isinstance(content, bytes):
216
+ try:
217
+ content = content.decode("utf-8")
218
+ except (UnicodeDecodeError, AttributeError):
219
+ pass
220
+ combined["value"] = content
221
+ combined["__input_content__"] = content
222
+ return combined
223
+
224
+ if not inputs_def:
225
+ return target.get_content()
226
+
227
+ input_name = list(inputs_def.keys())[0]
228
+ input_type = inputs_def[input_name]
229
+
230
+ if input_name == "context":
231
+ return ctx
232
+
233
+ raw = target.get_content()
234
+ converters = {
235
+ "float": lambda: float(raw.decode("utf-8")),
236
+ "int": lambda: int(raw.decode("utf-8")),
237
+ "str": lambda: raw.decode("utf-8"),
238
+ }
239
+
240
+ try:
241
+ return converters.get(input_type, lambda: raw)()
242
+ except (ValueError, TypeError, UnicodeDecodeError):
243
+ return raw
244
+
245
+ # ─── Module Logic ──────────────────────────────────────────────────────────
246
+
247
+ def _execute_module_logic(
248
+ self, uri: str, impl: dict, target: MCard, ctx: dict
249
+ ) -> Any:
250
+ """Execute logic imported from a Python module."""
251
+ path = uri.replace(MODULE_URI_PREFIX, "")
252
+ module_name, func_name = (
253
+ path.split(":", 1)
254
+ if ":" in path
255
+ else (path, impl.get("entry_point", "logic"))
256
+ )
257
+
258
+ try:
259
+ module = importlib.import_module(module_name)
260
+ func = getattr(module, func_name)
261
+ if not callable(func):
262
+ return f"Error: {func_name} in {module_name} is not callable"
263
+
264
+ arg = (
265
+ target.get_content().decode("utf-8")
266
+ if hasattr(target, "get_content")
267
+ else target
268
+ )
269
+ return func(arg)
270
+ except ImportError as e:
271
+ return f"Error importing module {module_name}: {e}"
272
+ except AttributeError:
273
+ return f"Error: Function {func_name} not found in {module_name}"
274
+ except (ValueError, TypeError, RuntimeError, OSError) as e:
275
+ return f"Error executing module logic: {e}"
276
+
277
+ def validate_environment(self) -> bool:
278
+ return True
279
+
280
+ def get_runtime_status(self) -> dict[str, Any]:
281
+ import sys
282
+
283
+ return {
284
+ "available": True,
285
+ "version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
286
+ "command": RUNTIME_CONFIG.get("python", {}).get("command", "python3"),
287
+ "details": f"Python {sys.version}",
288
+ }
@@ -0,0 +1,41 @@
1
+ """
2
+ Python Native Sandbox Evaluator
3
+
4
+ Invoked by the Meta Circular Evaluator to execute Python dynamically.
5
+ Expects input as JSON on stdin.
6
+ """
7
+
8
+ import json
9
+ import sys
10
+ import traceback
11
+
12
+
13
+ def main():
14
+ try:
15
+ input_data = sys.stdin.read()
16
+ payload = json.loads(input_data)
17
+
18
+ target = payload.get("target")
19
+ context = payload.get("context", {})
20
+ code = payload.get("code", "")
21
+
22
+ # Execute securely in a restricted dictionary namespace
23
+ safe_globals = context.copy()
24
+
25
+ # Pass the target variable inside for script evaluation
26
+ safe_globals["target"] = target
27
+ safe_globals["context"] = context
28
+
29
+ exec(code, safe_globals)
30
+
31
+ # Scripts must place their output into `result` variable
32
+ output = safe_globals.get("result", None)
33
+
34
+ print(json.dumps(output))
35
+ except Exception as e:
36
+ print(f"Compilation error: {e}\\n{traceback.format_exc()}")
37
+ sys.exit(1)
38
+
39
+
40
+ if __name__ == "__main__":
41
+ main()
@@ -0,0 +1,114 @@
1
+ """
2
+ Script-based runtimes (Lean, R, Julia).
3
+
4
+ These runtimes execute script files via interpreter subprocess.
5
+ """
6
+
7
+ import json
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from clm.cross_cutting.config.config_constants import PTR_LEAN_VALIDATE_TIMEOUT_SECS
12
+ from clm.layer0.model.card import MCard
13
+
14
+ from .base import (
15
+ JULIA_TIMEOUT,
16
+ LEAN_TIMEOUT,
17
+ R_TIMEOUT,
18
+ RUNTIME_CONFIG,
19
+ SubprocessRuntime,
20
+ register_runtime,
21
+ )
22
+
23
+
24
+ class ScriptRuntime(SubprocessRuntime):
25
+ """Base class for runtimes that execute script files."""
26
+
27
+ file_key = "code_file"
28
+ run_args: list[str] = []
29
+
30
+ def execute(self, impl: dict[str, Any], target: MCard, ctx: dict[str, Any]) -> Any:
31
+ code_file = impl.get(self.file_key)
32
+ if not code_file:
33
+ return f"Error: No {self.runtime_name} code file provided"
34
+
35
+ # Normalize command to list
36
+ base_cmd = self.command if isinstance(self.command, list) else [self.command]
37
+
38
+ cmd = base_cmd + self.run_args + [code_file, json.dumps(ctx)]
39
+ return self._run_subprocess(cmd, target, ctx, self.timeout)
40
+
41
+
42
+ @register_runtime("lean")
43
+ class LeanRuntime(ScriptRuntime):
44
+ """Lean 4 runtime executor."""
45
+
46
+ runtime_name = "Lean"
47
+ run_args = ["--run"]
48
+ timeout = LEAN_TIMEOUT
49
+
50
+ def __init__(self):
51
+ super().__init__()
52
+ # Dynamic check for elan to support specific toolchains (e.g. v4.25.2)
53
+ # Matches JS implementation in mcard-js/src/ptr/node/runtimes/lean.ts
54
+ elan_path = Path.home() / ".elan" / "bin" / "elan"
55
+
56
+ # Check explicit environment variable first
57
+ env_lean_cmd = RUNTIME_CONFIG.get("lean", {}).get("command")
58
+
59
+ if env_lean_cmd and env_lean_cmd != "lean":
60
+ # Use configured command if it's specific
61
+ self.command = env_lean_cmd
62
+ elif elan_path.exists():
63
+ # Use elan to ensure we use the same version as JS tests
64
+ # 'elan run' avoids downloading 'stable' if we pin to v4.25.2 match JS
65
+ self.command = [str(elan_path), "run", "leanprover/lean4:v4.25.2", "lean"]
66
+ else:
67
+ # Fallback to system lean (subject to lean-toolchain file)
68
+ self.command = "lean"
69
+
70
+ def validate_environment(self) -> bool:
71
+ # Lean 4 takes longer to initialize, use extended timeout
72
+ return self._check_command(
73
+ self.command, self.version_flag, timeout=PTR_LEAN_VALIDATE_TIMEOUT_SECS
74
+ )
75
+
76
+ def execute(self, impl: dict[str, Any], target: MCard, ctx: dict[str, Any]) -> Any:
77
+ """Execute Lean script, passing input as the argument."""
78
+ code_file = impl.get(self.file_key)
79
+ if not code_file:
80
+ return f"Error: No {self.runtime_name} code file provided"
81
+
82
+ # Determine what to pass as the argument:
83
+ # 1. If context has 'op', 'a', 'b' keys (polyglot mode), use context as JSON
84
+ # 2. Otherwise, use target content (standalone CLM mode)
85
+ if ctx and ("op" in ctx or "a" in ctx or "n" in ctx):
86
+ # Polyglot/advanced mode - context contains the actual input data
87
+ input_data = json.dumps(ctx)
88
+ else:
89
+ # Standalone CLM mode - target content is the JSON input
90
+ input_data = target.get_content().decode("utf-8", errors="ignore")
91
+
92
+ # Normalize command to list
93
+ base_cmd = self.command if isinstance(self.command, list) else [self.command]
94
+
95
+ cmd = base_cmd + self.run_args + [code_file, input_data]
96
+ return self._run_subprocess(cmd, target, ctx, self.timeout)
97
+
98
+
99
+ @register_runtime("r")
100
+ class RRuntime(ScriptRuntime):
101
+ """R runtime executor."""
102
+
103
+ runtime_name = "R"
104
+ command = RUNTIME_CONFIG.get("r", {}).get("command") or "Rscript"
105
+ timeout = R_TIMEOUT
106
+
107
+
108
+ @register_runtime("julia")
109
+ class JuliaRuntime(ScriptRuntime):
110
+ """Julia runtime executor."""
111
+
112
+ runtime_name = "Julia"
113
+ command = RUNTIME_CONFIG.get("julia", {}).get("command") or "julia"
114
+ timeout = JULIA_TIMEOUT