orizu 0.5.19 → 0.5.21

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 (378) hide show
  1. package/README.md +23 -0
  2. package/dist/archive-artifacts-cli.d.ts +50 -0
  3. package/dist/archive-artifacts-cli.d.ts.map +1 -0
  4. package/dist/artifact-archive.d.ts +48 -0
  5. package/dist/artifact-archive.d.ts.map +1 -0
  6. package/dist/artifact-pull.d.ts +22 -0
  7. package/dist/artifact-pull.d.ts.map +1 -0
  8. package/dist/banner.d.ts +3 -0
  9. package/dist/banner.d.ts.map +1 -0
  10. package/dist/connectors-cli.d.ts +31 -0
  11. package/dist/connectors-cli.d.ts.map +1 -0
  12. package/dist/credentials.d.ts +46 -0
  13. package/dist/credentials.d.ts.map +1 -0
  14. package/dist/csv.d.ts +49 -0
  15. package/dist/csv.d.ts.map +1 -0
  16. package/dist/dataset-download.d.ts +6 -0
  17. package/dist/dataset-download.d.ts.map +1 -0
  18. package/dist/dataset-edit-rows.d.ts +10 -0
  19. package/dist/dataset-edit-rows.d.ts.map +1 -0
  20. package/dist/dataset-upload-snapshot.d.ts +13 -0
  21. package/dist/dataset-upload-snapshot.d.ts.map +1 -0
  22. package/dist/daytona-slice-rehearsal.d.ts +89 -0
  23. package/dist/daytona-slice-rehearsal.d.ts.map +1 -0
  24. package/dist/daytona-slice.d.ts +106 -0
  25. package/dist/daytona-slice.d.ts.map +1 -0
  26. package/dist/deploy-key-merge-core.d.ts +121 -0
  27. package/dist/deploy-key-merge-core.d.ts.map +1 -0
  28. package/dist/diff-comments-cli.d.ts +12 -0
  29. package/dist/diff-comments-cli.d.ts.map +1 -0
  30. package/dist/diff-comments-cli.js +21 -2
  31. package/dist/egress-allowlist-cli.d.ts +23 -0
  32. package/dist/egress-allowlist-cli.d.ts.map +1 -0
  33. package/dist/egress-policy.d.ts +108 -0
  34. package/dist/egress-policy.d.ts.map +1 -0
  35. package/dist/error-response.d.ts +9 -0
  36. package/dist/error-response.d.ts.map +1 -0
  37. package/dist/file-parser.d.ts +5 -0
  38. package/dist/file-parser.d.ts.map +1 -0
  39. package/dist/gepa-engine-dispatch.d.ts +9 -0
  40. package/dist/gepa-engine-dispatch.d.ts.map +1 -0
  41. package/dist/gepa-engine-dispatch.js +307 -0
  42. package/dist/gepa-python-command.d.ts +6 -0
  43. package/dist/gepa-python-command.d.ts.map +1 -0
  44. package/dist/gepa-python-command.js +26 -0
  45. package/dist/gepa-python-paths.d.ts +6 -0
  46. package/dist/gepa-python-paths.d.ts.map +1 -0
  47. package/dist/gepa-python-paths.js +42 -0
  48. package/dist/git-credential.d.ts +69 -0
  49. package/dist/git-credential.d.ts.map +1 -0
  50. package/dist/git-recovery-environment.d.ts +31 -0
  51. package/dist/git-recovery-environment.d.ts.map +1 -0
  52. package/dist/github-setup.d.ts +122 -0
  53. package/dist/github-setup.d.ts.map +1 -0
  54. package/dist/global-flags.d.ts +12 -0
  55. package/dist/global-flags.d.ts.map +1 -0
  56. package/dist/help.d.ts +46 -0
  57. package/dist/help.d.ts.map +1 -0
  58. package/dist/help.js +93 -25
  59. package/dist/hosted-boot.d.ts +273 -0
  60. package/dist/hosted-boot.d.ts.map +1 -0
  61. package/dist/hosted-bootstrap-rehearsal.d.ts +86 -0
  62. package/dist/hosted-bootstrap-rehearsal.d.ts.map +1 -0
  63. package/dist/hosted-bootstrap.d.ts +188 -0
  64. package/dist/hosted-bootstrap.d.ts.map +1 -0
  65. package/dist/hosted-broker-server.d.ts +50 -0
  66. package/dist/hosted-broker-server.d.ts.map +1 -0
  67. package/dist/hosted-git-http-server.d.ts +36 -0
  68. package/dist/hosted-git-http-server.d.ts.map +1 -0
  69. package/dist/hosted-harness-claude.d.ts +195 -0
  70. package/dist/hosted-harness-claude.d.ts.map +1 -0
  71. package/dist/hosted-harness-opencode.d.ts +227 -0
  72. package/dist/hosted-harness-opencode.d.ts.map +1 -0
  73. package/dist/hosted-harness.d.ts +118 -0
  74. package/dist/hosted-harness.d.ts.map +1 -0
  75. package/dist/hosted-harvest.d.ts +68 -0
  76. package/dist/hosted-harvest.d.ts.map +1 -0
  77. package/dist/hosted-headless.d.ts +72 -0
  78. package/dist/hosted-headless.d.ts.map +1 -0
  79. package/dist/hosted-loop-lifecycle.d.ts +206 -0
  80. package/dist/hosted-loop-lifecycle.d.ts.map +1 -0
  81. package/dist/hosted-loop.d.ts +170 -0
  82. package/dist/hosted-loop.d.ts.map +1 -0
  83. package/dist/hosted-run-event-sink.d.ts +222 -0
  84. package/dist/hosted-run-event-sink.d.ts.map +1 -0
  85. package/dist/hosted-runtime-assets.d.ts +186 -0
  86. package/dist/hosted-runtime-assets.d.ts.map +1 -0
  87. package/dist/hosted-session-cli.d.ts +258 -0
  88. package/dist/hosted-session-cli.d.ts.map +1 -0
  89. package/dist/hosted-skill-staging.d.ts +73 -0
  90. package/dist/hosted-skill-staging.d.ts.map +1 -0
  91. package/dist/http.d.ts +8 -0
  92. package/dist/http.d.ts.map +1 -0
  93. package/dist/index.d.ts +22 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +119 -129
  96. package/dist/instruction-set-gepa-launch.d.ts +3 -0
  97. package/dist/instruction-set-gepa-launch.d.ts.map +1 -0
  98. package/dist/instruction-set-gepa-launch.js +15 -0
  99. package/dist/instruction-set-loader.d.ts +6 -0
  100. package/dist/instruction-set-loader.d.ts.map +1 -0
  101. package/dist/instruction-set-loader.js +59 -0
  102. package/dist/instruction-set-manifest.d.ts +14 -0
  103. package/dist/instruction-set-manifest.d.ts.map +1 -0
  104. package/dist/instruction-set-manifest.js +162 -0
  105. package/dist/instruction-sets-cli.d.ts +40 -0
  106. package/dist/instruction-sets-cli.d.ts.map +1 -0
  107. package/dist/instruction-sets-cli.js +361 -0
  108. package/dist/json-response.d.ts +4 -0
  109. package/dist/json-response.d.ts.map +1 -0
  110. package/dist/jsonl-stream.d.ts +8 -0
  111. package/dist/jsonl-stream.d.ts.map +1 -0
  112. package/dist/kill-switch-cli.d.ts +30 -0
  113. package/dist/kill-switch-cli.d.ts.map +1 -0
  114. package/dist/loopback-serve.d.ts +25 -0
  115. package/dist/loopback-serve.d.ts.map +1 -0
  116. package/dist/manifests-cli.d.ts +22 -0
  117. package/dist/manifests-cli.d.ts.map +1 -0
  118. package/dist/markdown-report-input.d.ts +7 -0
  119. package/dist/markdown-report-input.d.ts.map +1 -0
  120. package/dist/markdown-report-input.js +15 -1
  121. package/dist/merge-job.d.ts +155 -0
  122. package/dist/merge-job.d.ts.map +1 -0
  123. package/dist/model-configs-cli.d.ts +19 -0
  124. package/dist/model-configs-cli.d.ts.map +1 -0
  125. package/dist/model-configs-cli.js +104 -0
  126. package/dist/optimization-export-cli.d.ts +19 -0
  127. package/dist/optimization-export-cli.d.ts.map +1 -0
  128. package/dist/optimizations-list-cli.d.ts +20 -0
  129. package/dist/optimizations-list-cli.d.ts.map +1 -0
  130. package/dist/optimizations-promote-cli.d.ts +8 -0
  131. package/dist/optimizations-promote-cli.d.ts.map +1 -0
  132. package/dist/optimizations-promote-cli.js +34 -0
  133. package/dist/option-validation.d.ts +15 -0
  134. package/dist/option-validation.d.ts.map +1 -0
  135. package/dist/preview-runtime.d.ts +63 -0
  136. package/dist/preview-runtime.d.ts.map +1 -0
  137. package/dist/prompt-draft-push.d.ts +60 -0
  138. package/dist/prompt-draft-push.d.ts.map +1 -0
  139. package/dist/prompt-label-cli.d.ts +11 -0
  140. package/dist/prompt-label-cli.d.ts.map +1 -0
  141. package/dist/prompt-label-cli.js +29 -0
  142. package/dist/prompt-length-wire.d.ts +28 -0
  143. package/dist/prompt-length-wire.d.ts.map +1 -0
  144. package/dist/prompt-length-wire.js +2 -2
  145. package/dist/prompt-report-cli.d.ts +10 -0
  146. package/dist/prompt-report-cli.d.ts.map +1 -0
  147. package/dist/prompt-report-cli.js +2 -2
  148. package/dist/prompt-summary-table.d.ts +15 -0
  149. package/dist/prompt-summary-table.d.ts.map +1 -0
  150. package/dist/prompt-summary-table.js +6 -0
  151. package/dist/registration-tag-warning.d.ts +32 -0
  152. package/dist/registration-tag-warning.d.ts.map +1 -0
  153. package/dist/report-comments-cli.d.ts +16 -0
  154. package/dist/report-comments-cli.d.ts.map +1 -0
  155. package/dist/report-markdown-blankness.d.ts +2 -0
  156. package/dist/report-markdown-blankness.d.ts.map +1 -0
  157. package/dist/report-markdown-blankness.js +6 -0
  158. package/dist/report-replacement-warning.d.ts +17 -0
  159. package/dist/report-replacement-warning.d.ts.map +1 -0
  160. package/dist/report-replacement-warning.js +31 -0
  161. package/dist/repository-backup-core.d.ts +225 -0
  162. package/dist/repository-backup-core.d.ts.map +1 -0
  163. package/dist/repository-recovery-manifest.d.ts +83 -0
  164. package/dist/repository-recovery-manifest.d.ts.map +1 -0
  165. package/dist/run-event-digest.d.ts +74 -0
  166. package/dist/run-event-digest.d.ts.map +1 -0
  167. package/dist/runner-dir-verify.d.ts +66 -0
  168. package/dist/runner-dir-verify.d.ts.map +1 -0
  169. package/dist/runner-instruction-set-contract.d.ts +24 -0
  170. package/dist/runner-instruction-set-contract.d.ts.map +1 -0
  171. package/dist/runner-instruction-set-contract.js +50 -0
  172. package/dist/sandbox-hygiene.d.ts +45 -0
  173. package/dist/sandbox-hygiene.d.ts.map +1 -0
  174. package/dist/sandbox-provider.d.ts +193 -0
  175. package/dist/sandbox-provider.d.ts.map +1 -0
  176. package/dist/scorer-draft-push.d.ts +50 -0
  177. package/dist/scorer-draft-push.d.ts.map +1 -0
  178. package/dist/scorers-cli.d.ts +20 -0
  179. package/dist/scorers-cli.d.ts.map +1 -0
  180. package/dist/scorers-cli.js +22 -0
  181. package/dist/scorers-verify-parity-bridge.d.ts +16 -0
  182. package/dist/scorers-verify-parity-bridge.d.ts.map +1 -0
  183. package/dist/scorers-verify-parity-bridge.js +90 -0
  184. package/dist/scorers-verify-parity.d.ts +81 -0
  185. package/dist/scorers-verify-parity.d.ts.map +1 -0
  186. package/dist/scorers-verify-parity.js +502 -0
  187. package/dist/scores-accept-cli.d.ts +21 -0
  188. package/dist/scores-accept-cli.d.ts.map +1 -0
  189. package/dist/secret-redaction.d.ts +47 -0
  190. package/dist/secret-redaction.d.ts.map +1 -0
  191. package/dist/session-timeline.d.ts +54 -0
  192. package/dist/session-timeline.d.ts.map +1 -0
  193. package/dist/setup-prompt.d.ts +5 -0
  194. package/dist/setup-prompt.d.ts.map +1 -0
  195. package/dist/skill-installer.d.ts +68 -0
  196. package/dist/skill-installer.d.ts.map +1 -0
  197. package/dist/skilled-proposer-launch.d.ts +7 -0
  198. package/dist/skilled-proposer-launch.d.ts.map +1 -0
  199. package/dist/skilled-proposer-launch.js +60 -0
  200. package/dist/smoke.d.ts +102 -0
  201. package/dist/smoke.d.ts.map +1 -0
  202. package/dist/start-intent.d.ts +12 -0
  203. package/dist/start-intent.d.ts.map +1 -0
  204. package/dist/task-assignment-manifest.d.ts +15 -0
  205. package/dist/task-assignment-manifest.d.ts.map +1 -0
  206. package/dist/task-create-error.d.ts +18 -0
  207. package/dist/task-create-error.d.ts.map +1 -0
  208. package/dist/team-connectors-cli.d.ts +29 -0
  209. package/dist/team-connectors-cli.d.ts.map +1 -0
  210. package/dist/types.d.ts +39 -0
  211. package/dist/types.d.ts.map +1 -0
  212. package/dist/vercel-sandbox-provider.d.ts +156 -0
  213. package/dist/vercel-sandbox-provider.d.ts.map +1 -0
  214. package/dist/workbench-cli.d.ts +233 -0
  215. package/dist/workbench-cli.d.ts.map +1 -0
  216. package/dist/workspace-sync.d.ts +207 -0
  217. package/dist/workspace-sync.d.ts.map +1 -0
  218. package/dist/workspace.d.ts +92 -0
  219. package/dist/workspace.d.ts.map +1 -0
  220. package/dist/zip-draft-push.d.ts +55 -0
  221. package/dist/zip-draft-push.d.ts.map +1 -0
  222. package/package.json +15 -2
  223. package/requirements/README.md +138 -0
  224. package/requirements/skilled-proposer.in +66 -0
  225. package/requirements/skilled-proposer.lock +265 -0
  226. package/scripts/build-cli-dist.mjs +30 -0
  227. package/scripts/ensure-skilled-proposer-venv.mjs +5 -0
  228. package/scripts/orizu-source-checkout.d.mts +1 -0
  229. package/scripts/orizu-source-checkout.mjs +10 -0
  230. package/scripts/refresh-skilled-proposer-lock.mjs +256 -0
  231. package/scripts/vendor-gepa-python.mjs +187 -4
  232. package/src/diff-comments-cli.ts +41 -3
  233. package/src/gepa-engine-dispatch.ts +340 -0
  234. package/src/gepa-python-command.ts +31 -0
  235. package/src/gepa-python-paths.ts +56 -0
  236. package/src/help.ts +95 -25
  237. package/src/index.ts +131 -166
  238. package/src/instruction-set-gepa-launch.ts +28 -0
  239. package/src/instruction-set-loader.ts +37 -0
  240. package/src/instruction-set-manifest.ts +120 -0
  241. package/src/instruction-sets-cli.ts +306 -0
  242. package/src/markdown-report-input.ts +19 -1
  243. package/src/model-configs-cli.ts +119 -0
  244. package/src/optimizations-promote-cli.ts +41 -0
  245. package/src/prompt-label-cli.ts +55 -0
  246. package/src/prompt-length-wire.ts +1 -1
  247. package/src/prompt-report-cli.ts +2 -2
  248. package/src/prompt-summary-table.ts +12 -0
  249. package/src/report-markdown-blankness.ts +6 -0
  250. package/src/report-replacement-warning.ts +35 -0
  251. package/src/runner-instruction-set-contract.ts +64 -0
  252. package/src/scorers-cli.ts +40 -0
  253. package/src/scorers-verify-parity-bridge.ts +90 -0
  254. package/src/scorers-verify-parity.ts +564 -0
  255. package/src/skilled-proposer-launch.ts +89 -0
  256. package/src/skilled-proposer-venv-manager.mjs +757 -0
  257. package/tsconfig.json +2 -0
  258. package/vendor/gepa-python/LICENSE +7 -0
  259. package/vendor/gepa-python/manifest.json +107 -0
  260. package/vendor/gepa-python/src/gepa/__init__.py +22 -0
  261. package/vendor/gepa-python/src/gepa/adapters/__init__.py +0 -0
  262. package/vendor/gepa-python/src/gepa/adapters/anymaths_adapter/__init__.py +1 -0
  263. package/vendor/gepa-python/src/gepa/adapters/anymaths_adapter/anymaths_adapter.py +174 -0
  264. package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/__init__.py +26 -0
  265. package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/confidence_adapter.py +618 -0
  266. package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/scoring.py +206 -0
  267. package/vendor/gepa-python/src/gepa/adapters/default_adapter/__init__.py +0 -0
  268. package/vendor/gepa-python/src/gepa/adapters/default_adapter/default_adapter.py +206 -0
  269. package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/__init__.py +0 -0
  270. package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/dspy_adapter.py +525 -0
  271. package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/instruction_proposal.py +500 -0
  272. package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/__init__.py +6 -0
  273. package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/dspy_program_proposal_signature.py +137 -0
  274. package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/full_program_adapter.py +269 -0
  275. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/__init__.py +56 -0
  276. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/evaluation_metrics.py +226 -0
  277. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/generic_rag_adapter.py +496 -0
  278. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/rag_pipeline.py +238 -0
  279. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_store_interface.py +212 -0
  280. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/__init__.py +2 -0
  281. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/chroma_store.py +196 -0
  282. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/lancedb_store.py +422 -0
  283. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/milvus_store.py +409 -0
  284. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/qdrant_store.py +368 -0
  285. package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/weaviate_store.py +418 -0
  286. package/vendor/gepa-python/src/gepa/adapters/langchain_adapter/__init__.py +11 -0
  287. package/vendor/gepa-python/src/gepa/adapters/langchain_adapter/langchain_adapter.py +261 -0
  288. package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/__init__.py +37 -0
  289. package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/mcp_adapter.py +693 -0
  290. package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/mcp_client.py +364 -0
  291. package/vendor/gepa-python/src/gepa/adapters/optimize_anything_adapter/optimize_anything_adapter.py +879 -0
  292. package/vendor/gepa-python/src/gepa/adapters/terminal_bench_adapter/__init__.py +0 -0
  293. package/vendor/gepa-python/src/gepa/adapters/terminal_bench_adapter/terminal_bench_adapter.py +217 -0
  294. package/vendor/gepa-python/src/gepa/api.py +468 -0
  295. package/vendor/gepa-python/src/gepa/core/__init__.py +0 -0
  296. package/vendor/gepa-python/src/gepa/core/adapter.py +227 -0
  297. package/vendor/gepa-python/src/gepa/core/callbacks.py +551 -0
  298. package/vendor/gepa-python/src/gepa/core/data_loader.py +74 -0
  299. package/vendor/gepa-python/src/gepa/core/engine.py +1025 -0
  300. package/vendor/gepa-python/src/gepa/core/result.py +271 -0
  301. package/vendor/gepa-python/src/gepa/core/state.py +706 -0
  302. package/vendor/gepa-python/src/gepa/examples/__init__.py +0 -0
  303. package/vendor/gepa-python/src/gepa/examples/aime.py +24 -0
  304. package/vendor/gepa-python/src/gepa/examples/anymaths-bench/eval_default.py +111 -0
  305. package/vendor/gepa-python/src/gepa/examples/anymaths-bench/train_anymaths.py +177 -0
  306. package/vendor/gepa-python/src/gepa/examples/mcp_adapter/__init__.py +4 -0
  307. package/vendor/gepa-python/src/gepa/examples/mcp_adapter/mcp_optimization_example.py +456 -0
  308. package/vendor/gepa-python/src/gepa/examples/rag_adapter/__init__.py +9 -0
  309. package/vendor/gepa-python/src/gepa/examples/rag_adapter/rag_optimization.py +824 -0
  310. package/vendor/gepa-python/src/gepa/examples/terminal-bench/train_terminus.py +161 -0
  311. package/vendor/gepa-python/src/gepa/gepa_utils.py +117 -0
  312. package/vendor/gepa-python/src/gepa/gskill/__init__.py +1 -0
  313. package/vendor/gepa-python/src/gepa/gskill/gskill/__init__.py +0 -0
  314. package/vendor/gepa-python/src/gepa/gskill/gskill/cost_tracker.py +194 -0
  315. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/__init__.py +0 -0
  316. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/claude_code.py +1117 -0
  317. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/claude_code_skills.py +613 -0
  318. package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/mini_swe_agent.py +440 -0
  319. package/vendor/gepa-python/src/gepa/gskill/gskill/experiment_logger.py +367 -0
  320. package/vendor/gepa-python/src/gepa/gskill/gskill/swe_fitness_fn.py +209 -0
  321. package/vendor/gepa-python/src/gepa/gskill/gskill/swe_harness.py +352 -0
  322. package/vendor/gepa-python/src/gepa/gskill/gskill/train_optimize_anything.py +830 -0
  323. package/vendor/gepa-python/src/gepa/image.py +104 -0
  324. package/vendor/gepa-python/src/gepa/lm.py +261 -0
  325. package/vendor/gepa-python/src/gepa/logging/__init__.py +0 -0
  326. package/vendor/gepa-python/src/gepa/logging/experiment_tracker.py +457 -0
  327. package/vendor/gepa-python/src/gepa/logging/logger.py +75 -0
  328. package/vendor/gepa-python/src/gepa/logging/utils.py +130 -0
  329. package/vendor/gepa-python/src/gepa/optimize_anything.py +1701 -0
  330. package/vendor/gepa-python/src/gepa/proposer/__init__.py +0 -0
  331. package/vendor/gepa-python/src/gepa/proposer/base.py +53 -0
  332. package/vendor/gepa-python/src/gepa/proposer/merge.py +403 -0
  333. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/__init__.py +0 -0
  334. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/base.py +64 -0
  335. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/reflection_lm.py +178 -0
  336. package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/reflective_mutation.py +641 -0
  337. package/vendor/gepa-python/src/gepa/py.typed +0 -0
  338. package/vendor/gepa-python/src/gepa/strategies/__init__.py +0 -0
  339. package/vendor/gepa-python/src/gepa/strategies/acceptance.py +66 -0
  340. package/vendor/gepa-python/src/gepa/strategies/batch_sampler.py +103 -0
  341. package/vendor/gepa-python/src/gepa/strategies/candidate_selector.py +82 -0
  342. package/vendor/gepa-python/src/gepa/strategies/component_selector.py +36 -0
  343. package/vendor/gepa-python/src/gepa/strategies/eval_policy.py +64 -0
  344. package/vendor/gepa-python/src/gepa/strategies/instruction_proposal.py +153 -0
  345. package/vendor/gepa-python/src/gepa/strategies/proposal_sampling.py +128 -0
  346. package/vendor/gepa-python/src/gepa/strategies/proposal_selection.py +84 -0
  347. package/vendor/gepa-python/src/gepa/utils/__init__.py +63 -0
  348. package/vendor/gepa-python/src/gepa/utils/code_execution.py +626 -0
  349. package/vendor/gepa-python/src/gepa/utils/stdio_capture.py +145 -0
  350. package/vendor/gepa-python/src/gepa/utils/stop_condition.py +230 -0
  351. package/vendor/gepa-python/src/gepa/visualization.py +359 -0
  352. package/vendor/orizu-gepa/pyproject.toml +18 -0
  353. package/vendor/orizu-gepa/src/orizu_gepa_connector/__init__.py +9 -0
  354. package/vendor/orizu-gepa/src/orizu_gepa_connector/__main__.py +5 -0
  355. package/vendor/orizu-gepa/src/orizu_gepa_connector/adapter.py +138 -0
  356. package/vendor/orizu-gepa/src/orizu_gepa_connector/callbacks.py +666 -0
  357. package/vendor/orizu-gepa/src/orizu_gepa_connector/cli.py +7 -0
  358. package/vendor/orizu-gepa/src/orizu_gepa_connector/engine.py +269 -0
  359. package/vendor/orizu-gepa/src/orizu_gepa_connector/instruction_set_loader.py +52 -0
  360. package/vendor/orizu-gepa/src/orizu_gepa_connector/preflight.py +64 -0
  361. package/vendor/orizu-gepa/src/orizu_gepa_connector/reflection.py +186 -0
  362. package/vendor/orizu-gepa/src/orizu_gepa_connector/runtime.py +721 -0
  363. package/vendor/orizu-gepa/src/orizu_gepa_connector/skilled_proposer_bridge.py +381 -0
  364. package/vendor/orizu-gepa/src/orizu_gepa_connector/stop_conditions.py +55 -0
  365. package/vendor/orizu-gepa/src/orizu_gepa_connector/translator.py +203 -0
  366. package/vendor/orizu-gepa-python/pyproject.toml +1 -1
  367. package/vendor/orizu-gepa-python/src/orizu_gepa/cli.py +1 -0
  368. package/vendor/orizu-gepa-python/src/orizu_gepa/client.py +52 -7
  369. package/vendor/orizu-gepa-python/src/orizu_gepa/local_log.py +52 -0
  370. package/vendor/orizu-gepa-python/src/orizu_gepa/optimizer.py +10 -5
  371. package/vendor/orizu-gepa-python/src/orizu_gepa/reflection.py +323 -68
  372. package/vendor/orizu-gepa-python/src/orizu_gepa/runner.py +207 -13
  373. package/vendor/skills/orizu-cli/SKILL.md +3 -1
  374. package/vendor/skills/orizu-cli/references/cli-reference.md +85 -1
  375. package/vendor/skills/orizu-cli/references/migrate-existing-gepa-setup.md +303 -0
  376. package/vendor/skills/orizu-cli/references/optimization-reports.md +1 -1
  377. package/vendor/skills/orizu-cli/references/optimization-with-gepa.md +26 -1
  378. package/vendor/skills/orizu-cli/references/prompt-control-plane.md +113 -10
@@ -0,0 +1,626 @@
1
+ """
2
+ Code execution utilities for GEPA optimization.
3
+
4
+ This module provides safe, sandboxed code execution with timeout support,
5
+ stdout/stderr capture, and structured result handling. These utilities are
6
+ designed to simplify implementing fitness functions for code evolution tasks.
7
+
8
+ Example usage:
9
+
10
+ from gepa.utils.code_execution import execute_code, ExecutionMode
11
+
12
+ # Simple in-process execution (fast, for trusted code)
13
+ result = execute_code(
14
+ code="x = 42\\nprint('hello')",
15
+ timeout=5,
16
+ mode=ExecutionMode.IN_PROCESS,
17
+ )
18
+ print(result.variables.get("x")) # 42
19
+ print(result.stdout) # "hello\\n"
20
+
21
+ # Subprocess execution (safe, for untrusted code)
22
+ result = execute_code(
23
+ code=user_generated_code,
24
+ timeout=30,
25
+ mode=ExecutionMode.SUBPROCESS,
26
+ global_vars={"input_data": [1, 2, 3]},
27
+ )
28
+ if result.success:
29
+ print(f"Result: {result.variables.get('output')}")
30
+ else:
31
+ print(f"Error: {result.error}")
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import hashlib
37
+ import io
38
+ import os
39
+ import pickle
40
+ import signal
41
+ import subprocess
42
+ import sys
43
+ import tempfile
44
+ import time
45
+ import traceback
46
+ from contextlib import redirect_stderr, redirect_stdout
47
+ from dataclasses import dataclass, field
48
+ from enum import Enum
49
+ from typing import Any
50
+
51
+ # Module-level setting for cloudpickle usage (set by optimize_anything.py)
52
+ _USE_CLOUDPICKLE: bool = False
53
+
54
+
55
+ def set_use_cloudpickle(value: bool) -> None:
56
+ """Configure whether subprocess execution uses cloudpickle or pickle."""
57
+ global _USE_CLOUDPICKLE
58
+ _USE_CLOUDPICKLE = value
59
+
60
+
61
+ class ExecutionMode(Enum):
62
+ """Execution mode for code execution."""
63
+
64
+ IN_PROCESS = "in_process"
65
+ """Execute code in the current process using exec(). Fast but less isolated."""
66
+
67
+ SUBPROCESS = "subprocess"
68
+ """Execute code in a separate subprocess. Safer but slower."""
69
+
70
+
71
+ class TimeLimitError(Exception):
72
+ """Raised when code execution exceeds the timeout."""
73
+
74
+ pass
75
+
76
+
77
+ @dataclass
78
+ class CodeExecutionResult:
79
+ """
80
+ Result of code execution.
81
+
82
+ Attributes:
83
+ success: Whether execution completed without errors
84
+ stdout: Captured standard output
85
+ stderr: Captured standard error / logs
86
+ error: Error message if execution failed
87
+ traceback: Full traceback if an exception occurred
88
+ variables: Variables from the execution context (for extracting results)
89
+ execution_time: Time taken for execution in seconds
90
+ code_hash: MD5 hash of the executed code (useful for caching)
91
+ """
92
+
93
+ success: bool
94
+ stdout: str = ""
95
+ stderr: str = ""
96
+ error: str = ""
97
+ traceback: str = ""
98
+ variables: dict[str, Any] = field(default_factory=dict)
99
+ execution_time: float = 0.0
100
+ code_hash: str = ""
101
+
102
+ def get_variable(self, name: str, default: Any = None) -> Any:
103
+ """Get a variable from the execution context."""
104
+ return self.variables.get(name, default)
105
+
106
+ def to_side_info_dict(self) -> dict[str, Any]:
107
+ """
108
+ Convert execution result to a dict suitable for side_info.
109
+
110
+ Returns a dict with standardized keys that can be included in side_info
111
+ for LLM reflection.
112
+ """
113
+ info = {
114
+ "Stdout": self.stdout,
115
+ "Stderr": self.stderr,
116
+ }
117
+ if self.error:
118
+ info["Error"] = self.error
119
+ if self.traceback:
120
+ info["Traceback"] = self.traceback
121
+ return info
122
+
123
+
124
+ def _alarm_handler(signum, frame):
125
+ """Signal handler for timeout."""
126
+ raise TimeLimitError("Code execution timed out")
127
+
128
+
129
+ def _compute_code_hash(code: str) -> str:
130
+ """Compute MD5 hash of code for caching/deduplication."""
131
+ normalized = "\n".join(line.rstrip() for line in code.strip().split("\n"))
132
+ return hashlib.sha256(normalized.encode()).hexdigest()
133
+
134
+
135
+ def execute_code(
136
+ code: str,
137
+ timeout: float = 30.0,
138
+ mode: ExecutionMode = ExecutionMode.IN_PROCESS,
139
+ global_vars: dict[str, Any] | None = None,
140
+ entry_point: str | None = None,
141
+ entry_point_args: tuple = (),
142
+ entry_point_kwargs: dict[str, Any] | None = None,
143
+ capture_variables: list[str] | None = None,
144
+ seed: int | None = None,
145
+ kill_child_processes: bool = True,
146
+ ) -> CodeExecutionResult:
147
+ """
148
+ Execute Python code safely with timeout and output capture.
149
+
150
+ This function provides a unified interface for executing Python code strings
151
+ with configurable isolation level, timeout handling, and result capture.
152
+
153
+ Args:
154
+ code: Python code string to execute
155
+ timeout: Maximum execution time in seconds (default: 30)
156
+ mode: Execution mode - IN_PROCESS (fast) or SUBPROCESS (safe)
157
+ global_vars: Variables to inject into the execution context.
158
+ These are accessible to the code being executed.
159
+ entry_point: Optional function name to call after executing the code.
160
+ If provided, the function will be called and its return value
161
+ stored in variables["__return__"].
162
+ entry_point_args: Positional arguments to pass to entry_point function
163
+ entry_point_kwargs: Keyword arguments to pass to entry_point function
164
+ capture_variables: List of variable names to extract from the execution
165
+ context. If None, all non-private variables are captured.
166
+ seed: Optional random seed to set before execution for reproducibility.
167
+ Sets seeds for random, numpy.random, and torch if available.
168
+ kill_child_processes: If True, attempt to kill any child processes spawned
169
+ by the executed code when a timeout occurs. Requires psutil to be
170
+ installed for full functionality. Default is True.
171
+
172
+ Returns:
173
+ CodeExecutionResult with execution outcome, captured output, and variables
174
+
175
+ Example:
176
+ # Execute code and extract result variable
177
+ result = execute_code(
178
+ code="def solve(x): return x * 2\\nresult = solve(21)",
179
+ timeout=5,
180
+ capture_variables=["result"],
181
+ )
182
+ print(result.variables["result"]) # 42
183
+
184
+ # Execute with entry point function
185
+ result = execute_code(
186
+ code="def optimize(bounds): return sum(bounds) / 2",
187
+ entry_point="optimize",
188
+ entry_point_args=([0, 10],),
189
+ )
190
+ print(result.variables["__return__"]) # 5.0
191
+
192
+ # Execute with injected variables
193
+ result = execute_code(
194
+ code="output = input_value * 2",
195
+ global_vars={"input_value": 21},
196
+ )
197
+ print(result.variables["output"]) # 42
198
+ """
199
+ if mode == ExecutionMode.IN_PROCESS:
200
+ return _execute_in_process(
201
+ code=code,
202
+ timeout=timeout,
203
+ global_vars=global_vars,
204
+ entry_point=entry_point,
205
+ entry_point_args=entry_point_args,
206
+ entry_point_kwargs=entry_point_kwargs,
207
+ capture_variables=capture_variables,
208
+ seed=seed,
209
+ kill_child_processes=kill_child_processes,
210
+ )
211
+ else:
212
+ return _execute_subprocess(
213
+ code=code,
214
+ timeout=timeout,
215
+ global_vars=global_vars,
216
+ entry_point=entry_point,
217
+ entry_point_args=entry_point_args,
218
+ entry_point_kwargs=entry_point_kwargs,
219
+ capture_variables=capture_variables,
220
+ seed=seed,
221
+ kill_child_processes=kill_child_processes,
222
+ )
223
+
224
+
225
+ def _set_random_seeds(seed: int) -> None:
226
+ """Set random seeds for reproducibility."""
227
+ import random
228
+
229
+ random.seed(seed)
230
+
231
+ try:
232
+ import numpy as np
233
+
234
+ np.random.seed(seed)
235
+ except ImportError:
236
+ pass
237
+
238
+ try:
239
+ import torch # type: ignore[import-not-found]
240
+
241
+ torch.manual_seed(seed)
242
+ if torch.cuda.is_available():
243
+ torch.cuda.manual_seed_all(seed)
244
+ except ImportError:
245
+ pass
246
+
247
+
248
+ def _kill_child_processes(current_pid: int) -> None:
249
+ """Kill all child processes of the current process using psutil if available."""
250
+ try:
251
+ import psutil # type: ignore[import-not-found]
252
+
253
+ try:
254
+ parent = psutil.Process(current_pid)
255
+ # Kill all children recursively
256
+ for child in parent.children(recursive=True):
257
+ try:
258
+ child.kill()
259
+ except psutil.NoSuchProcess:
260
+ pass
261
+ except psutil.NoSuchProcess:
262
+ pass
263
+ except ImportError:
264
+ pass # psutil not available, skip child process cleanup
265
+ except Exception:
266
+ pass # Ignore errors in cleanup
267
+
268
+
269
+ def _execute_in_process(
270
+ code: str,
271
+ timeout: float,
272
+ global_vars: dict[str, Any] | None,
273
+ entry_point: str | None,
274
+ entry_point_args: tuple,
275
+ entry_point_kwargs: dict[str, Any] | None,
276
+ capture_variables: list[str] | None,
277
+ seed: int | None,
278
+ kill_child_processes: bool,
279
+ ) -> CodeExecutionResult:
280
+ """Execute code in the current process using exec()."""
281
+ start_time = time.time()
282
+ code_hash = _compute_code_hash(code)
283
+ current_pid = os.getpid()
284
+
285
+ # Set up execution context
286
+ context: dict[str, Any] = {"__name__": "__main__"}
287
+ if global_vars:
288
+ context.update(global_vars)
289
+
290
+ # Set random seeds if specified
291
+ if seed is not None:
292
+ _set_random_seeds(seed)
293
+
294
+ # Capture stdout/stderr
295
+ stdout_capture = io.StringIO()
296
+ stderr_capture = io.StringIO()
297
+
298
+ error = ""
299
+ tb = ""
300
+ success = True
301
+
302
+ # Set up timeout using signal (Unix only)
303
+ old_handler = None
304
+ has_signal = hasattr(signal, "SIGALRM")
305
+
306
+ if timeout > 0 and has_signal:
307
+ old_handler = signal.signal(signal.SIGALRM, _alarm_handler)
308
+ # Use setitimer for sub-second precision if available
309
+ try:
310
+ signal.setitimer(signal.ITIMER_REAL, timeout)
311
+ except AttributeError:
312
+ signal.alarm(int(timeout))
313
+
314
+ try:
315
+ with redirect_stdout(stdout_capture), redirect_stderr(stderr_capture):
316
+ exec(code, context)
317
+
318
+ # Call entry point if specified
319
+ if entry_point and entry_point in context:
320
+ kwargs = entry_point_kwargs or {}
321
+ result = context[entry_point](*entry_point_args, **kwargs)
322
+ context["__return__"] = result
323
+
324
+ except TimeLimitError:
325
+ error = f"TimeLimitError: Code execution exceeded {timeout} seconds."
326
+ success = False
327
+ # Try to kill any child processes spawned by the code
328
+ if kill_child_processes:
329
+ _kill_child_processes(current_pid)
330
+ except Exception as e:
331
+ error = str(e)
332
+ tb = traceback.format_exc()
333
+ success = False
334
+ finally:
335
+ # Disable timeout
336
+ if timeout > 0 and has_signal:
337
+ try:
338
+ signal.setitimer(signal.ITIMER_REAL, 0)
339
+ except AttributeError:
340
+ signal.alarm(0)
341
+ if old_handler is not None:
342
+ signal.signal(signal.SIGALRM, old_handler)
343
+
344
+ # Double-check: if we've exceeded timeout but no exception was raised, kill children
345
+ elapsed = time.time() - start_time
346
+ if kill_child_processes and timeout > 0 and elapsed > timeout and not error:
347
+ error = f"TimeLimitError: Code execution exceeded {timeout} seconds (elapsed: {elapsed:.2f}s)."
348
+ success = False
349
+ _kill_child_processes(current_pid)
350
+
351
+ execution_time = time.time() - start_time
352
+
353
+ # Extract variables
354
+ if capture_variables:
355
+ variables = {k: context.get(k) for k in capture_variables}
356
+ else:
357
+ # Capture all variables except Python dunder variables (e.g., __name__, __builtins__)
358
+ # Note: User-defined private variables (single _) are preserved for backwards compatibility
359
+ variables = {
360
+ k: v for k, v in context.items() if not k.startswith("__")
361
+ }
362
+
363
+ # Always include __return__ if it exists
364
+ if "__return__" in context:
365
+ variables["__return__"] = context["__return__"]
366
+
367
+ return CodeExecutionResult(
368
+ success=success,
369
+ stdout=stdout_capture.getvalue(),
370
+ stderr=stderr_capture.getvalue(),
371
+ error=error,
372
+ traceback=tb,
373
+ variables=variables,
374
+ execution_time=execution_time,
375
+ code_hash=code_hash,
376
+ )
377
+
378
+
379
+ def _execute_subprocess(
380
+ code: str,
381
+ timeout: float,
382
+ global_vars: dict[str, Any] | None,
383
+ entry_point: str | None,
384
+ entry_point_args: tuple,
385
+ entry_point_kwargs: dict[str, Any] | None,
386
+ capture_variables: list[str] | None,
387
+ seed: int | None,
388
+ kill_child_processes: bool,
389
+ ) -> CodeExecutionResult:
390
+ """Execute code in a separate subprocess for isolation."""
391
+ start_time = time.time()
392
+ code_hash = _compute_code_hash(code)
393
+
394
+ # Create temp files for communication
395
+ with tempfile.NamedTemporaryFile(mode="wb", suffix=".pkl", delete=False) as args_file:
396
+ args_path = args_file.name
397
+ if _USE_CLOUDPICKLE:
398
+ import cloudpickle
399
+ cloudpickle.dump(
400
+ {
401
+ "code": code, # Pass code through pickle to avoid escaping issues
402
+ "global_vars": global_vars or {},
403
+ "entry_point": entry_point,
404
+ "entry_point_args": entry_point_args,
405
+ "entry_point_kwargs": entry_point_kwargs or {},
406
+ "capture_variables": capture_variables,
407
+ "seed": seed,
408
+ },
409
+ args_file,
410
+ )
411
+ else:
412
+ pickle.dump(
413
+ {
414
+ "code": code,
415
+ "global_vars": global_vars or {},
416
+ "entry_point": entry_point,
417
+ "entry_point_args": entry_point_args,
418
+ "entry_point_kwargs": entry_point_kwargs or {},
419
+ "capture_variables": capture_variables,
420
+ "seed": seed,
421
+ },
422
+ args_file,
423
+ )
424
+
425
+ results_path = args_path + ".results"
426
+
427
+ # Choose pickle module for subprocess
428
+ pickle_import = "import cloudpickle as _pickle" if _USE_CLOUDPICKLE else "import pickle as _pickle"
429
+
430
+ # Build wrapper script
431
+ wrapper_script = f"""
432
+ import sys
433
+ {pickle_import}
434
+ import traceback
435
+ import random
436
+
437
+ # Load arguments
438
+ with open({args_path!r}, 'rb') as f:
439
+ _args = _pickle.load(f)
440
+
441
+ _code = _args['code']
442
+ _global_vars = _args['global_vars']
443
+ _entry_point = _args['entry_point']
444
+ _entry_point_args = _args['entry_point_args']
445
+ _entry_point_kwargs = _args['entry_point_kwargs']
446
+ _capture_variables = _args['capture_variables']
447
+ _seed = _args['seed']
448
+
449
+ # Set random seeds
450
+ if _seed is not None:
451
+ random.seed(_seed)
452
+ try:
453
+ import numpy as np
454
+ np.random.seed(_seed)
455
+ except ImportError:
456
+ pass
457
+ try:
458
+ import torch
459
+ torch.manual_seed(_seed)
460
+ if torch.cuda.is_available():
461
+ torch.cuda.manual_seed_all(_seed)
462
+ except ImportError:
463
+ pass
464
+
465
+ # Set up execution context
466
+ _context = {{"__name__": "__main__"}}
467
+ _context.update(_global_vars)
468
+
469
+ _output = {{"success": False, "error": "Code did not complete"}}
470
+
471
+ try:
472
+ # Execute user code (loaded from pickle to avoid escaping issues)
473
+ exec(_code, _context)
474
+
475
+ # Call entry point if specified
476
+ if _entry_point and _entry_point in _context:
477
+ _result = _context[_entry_point](*_entry_point_args, **_entry_point_kwargs)
478
+ _context["__return__"] = _result
479
+
480
+ # Extract variables (exclude Python dunder variables, but keep user private vars)
481
+ import types
482
+ def _is_picklable(v):
483
+ return not isinstance(v, (types.ModuleType, types.FunctionType, type))
484
+
485
+ if _capture_variables:
486
+ _variables = {{k: _context.get(k) for k in _capture_variables if _is_picklable(_context.get(k))}}
487
+ else:
488
+ _variables = {{k: v for k, v in _context.items() if not k.startswith("__") and _is_picklable(v)}}
489
+
490
+ if "__return__" in _context:
491
+ _variables["__return__"] = _context["__return__"]
492
+
493
+ _output = {{"success": True, "variables": _variables}}
494
+
495
+ except Exception as _e:
496
+ _output = {{
497
+ "success": False,
498
+ "error": str(_e),
499
+ "traceback": traceback.format_exc(),
500
+ }}
501
+
502
+ with open({results_path!r}, 'wb') as f:
503
+ _pickle.dump(_output, f)
504
+ """
505
+
506
+ # Write wrapper script
507
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as script_file:
508
+ script_path = script_file.name
509
+ script_file.write(wrapper_script)
510
+
511
+ try:
512
+ # Find Python executable
513
+ python_executable = sys.executable
514
+ venv_python = os.path.join(os.getcwd(), ".venv", "bin", "python")
515
+ if os.path.exists(venv_python):
516
+ python_executable = venv_python
517
+
518
+ # Run subprocess
519
+ process = subprocess.Popen(
520
+ [python_executable, script_path],
521
+ stdout=subprocess.PIPE,
522
+ stderr=subprocess.PIPE,
523
+ )
524
+
525
+ try:
526
+ stdout, stderr = process.communicate(timeout=timeout)
527
+ stdout_str = stdout.decode("utf-8", errors="replace")
528
+ stderr_str = stderr.decode("utf-8", errors="replace")
529
+
530
+ execution_time = time.time() - start_time
531
+
532
+ # Load results
533
+ if os.path.exists(results_path):
534
+ try:
535
+ if _USE_CLOUDPICKLE:
536
+ import cloudpickle
537
+ with open(results_path, "rb") as f:
538
+ output = cloudpickle.load(f)
539
+ else:
540
+ with open(results_path, "rb") as f:
541
+ output = pickle.load(f)
542
+ except (EOFError, Exception) as e:
543
+ return CodeExecutionResult(
544
+ success=False,
545
+ stdout=stdout_str,
546
+ stderr=stderr_str,
547
+ error=f"Failed to load results: {e}",
548
+ traceback=stderr_str,
549
+ execution_time=execution_time,
550
+ code_hash=code_hash,
551
+ )
552
+
553
+ return CodeExecutionResult(
554
+ success=output.get("success", False),
555
+ stdout=stdout_str,
556
+ stderr=stderr_str,
557
+ error=output.get("error", ""),
558
+ traceback=output.get("traceback", ""),
559
+ variables=output.get("variables", {}),
560
+ execution_time=execution_time,
561
+ code_hash=code_hash,
562
+ )
563
+ else:
564
+ return CodeExecutionResult(
565
+ success=False,
566
+ stdout=stdout_str,
567
+ stderr=stderr_str,
568
+ error="Script crashed before completing",
569
+ traceback=stderr_str,
570
+ execution_time=execution_time,
571
+ code_hash=code_hash,
572
+ )
573
+
574
+ except subprocess.TimeoutExpired:
575
+ process.kill()
576
+ process.wait()
577
+ execution_time = time.time() - start_time
578
+
579
+ # Try to kill child processes if requested and psutil available
580
+ if kill_child_processes:
581
+ try:
582
+ import psutil # type: ignore[import-not-found]
583
+
584
+ try:
585
+ parent = psutil.Process(process.pid)
586
+ for child in parent.children(recursive=True):
587
+ try:
588
+ child.kill()
589
+ except psutil.NoSuchProcess:
590
+ pass
591
+ except psutil.NoSuchProcess:
592
+ pass
593
+ except ImportError:
594
+ pass
595
+
596
+ return CodeExecutionResult(
597
+ success=False,
598
+ error=f"Timeout: execution exceeded {timeout} seconds",
599
+ execution_time=execution_time,
600
+ code_hash=code_hash,
601
+ )
602
+
603
+ finally:
604
+ # Cleanup temp files
605
+ for path in [args_path, results_path, script_path]:
606
+ if os.path.exists(path):
607
+ try:
608
+ os.unlink(path)
609
+ except OSError:
610
+ pass
611
+
612
+
613
+ def get_code_hash(code: str, length: int = 8) -> str:
614
+ """
615
+ Get a hash of code for caching/deduplication.
616
+
617
+ The hash is computed from normalized code (trailing whitespace removed).
618
+
619
+ Args:
620
+ code: Python code string
621
+ length: Number of characters to return from the hash (default: 8)
622
+
623
+ Returns:
624
+ MD5 hash string (first `length` characters)
625
+ """
626
+ return _compute_code_hash(code)[:length]