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.
- package/README.md +23 -0
- package/dist/archive-artifacts-cli.d.ts +50 -0
- package/dist/archive-artifacts-cli.d.ts.map +1 -0
- package/dist/artifact-archive.d.ts +48 -0
- package/dist/artifact-archive.d.ts.map +1 -0
- package/dist/artifact-pull.d.ts +22 -0
- package/dist/artifact-pull.d.ts.map +1 -0
- package/dist/banner.d.ts +3 -0
- package/dist/banner.d.ts.map +1 -0
- package/dist/connectors-cli.d.ts +31 -0
- package/dist/connectors-cli.d.ts.map +1 -0
- package/dist/credentials.d.ts +46 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/csv.d.ts +49 -0
- package/dist/csv.d.ts.map +1 -0
- package/dist/dataset-download.d.ts +6 -0
- package/dist/dataset-download.d.ts.map +1 -0
- package/dist/dataset-edit-rows.d.ts +10 -0
- package/dist/dataset-edit-rows.d.ts.map +1 -0
- package/dist/dataset-upload-snapshot.d.ts +13 -0
- package/dist/dataset-upload-snapshot.d.ts.map +1 -0
- package/dist/daytona-slice-rehearsal.d.ts +89 -0
- package/dist/daytona-slice-rehearsal.d.ts.map +1 -0
- package/dist/daytona-slice.d.ts +106 -0
- package/dist/daytona-slice.d.ts.map +1 -0
- package/dist/deploy-key-merge-core.d.ts +121 -0
- package/dist/deploy-key-merge-core.d.ts.map +1 -0
- package/dist/diff-comments-cli.d.ts +12 -0
- package/dist/diff-comments-cli.d.ts.map +1 -0
- package/dist/diff-comments-cli.js +21 -2
- package/dist/egress-allowlist-cli.d.ts +23 -0
- package/dist/egress-allowlist-cli.d.ts.map +1 -0
- package/dist/egress-policy.d.ts +108 -0
- package/dist/egress-policy.d.ts.map +1 -0
- package/dist/error-response.d.ts +9 -0
- package/dist/error-response.d.ts.map +1 -0
- package/dist/file-parser.d.ts +5 -0
- package/dist/file-parser.d.ts.map +1 -0
- package/dist/gepa-engine-dispatch.d.ts +9 -0
- package/dist/gepa-engine-dispatch.d.ts.map +1 -0
- package/dist/gepa-engine-dispatch.js +307 -0
- package/dist/gepa-python-command.d.ts +6 -0
- package/dist/gepa-python-command.d.ts.map +1 -0
- package/dist/gepa-python-command.js +26 -0
- package/dist/gepa-python-paths.d.ts +6 -0
- package/dist/gepa-python-paths.d.ts.map +1 -0
- package/dist/gepa-python-paths.js +42 -0
- package/dist/git-credential.d.ts +69 -0
- package/dist/git-credential.d.ts.map +1 -0
- package/dist/git-recovery-environment.d.ts +31 -0
- package/dist/git-recovery-environment.d.ts.map +1 -0
- package/dist/github-setup.d.ts +122 -0
- package/dist/github-setup.d.ts.map +1 -0
- package/dist/global-flags.d.ts +12 -0
- package/dist/global-flags.d.ts.map +1 -0
- package/dist/help.d.ts +46 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +93 -25
- package/dist/hosted-boot.d.ts +273 -0
- package/dist/hosted-boot.d.ts.map +1 -0
- package/dist/hosted-bootstrap-rehearsal.d.ts +86 -0
- package/dist/hosted-bootstrap-rehearsal.d.ts.map +1 -0
- package/dist/hosted-bootstrap.d.ts +188 -0
- package/dist/hosted-bootstrap.d.ts.map +1 -0
- package/dist/hosted-broker-server.d.ts +50 -0
- package/dist/hosted-broker-server.d.ts.map +1 -0
- package/dist/hosted-git-http-server.d.ts +36 -0
- package/dist/hosted-git-http-server.d.ts.map +1 -0
- package/dist/hosted-harness-claude.d.ts +195 -0
- package/dist/hosted-harness-claude.d.ts.map +1 -0
- package/dist/hosted-harness-opencode.d.ts +227 -0
- package/dist/hosted-harness-opencode.d.ts.map +1 -0
- package/dist/hosted-harness.d.ts +118 -0
- package/dist/hosted-harness.d.ts.map +1 -0
- package/dist/hosted-harvest.d.ts +68 -0
- package/dist/hosted-harvest.d.ts.map +1 -0
- package/dist/hosted-headless.d.ts +72 -0
- package/dist/hosted-headless.d.ts.map +1 -0
- package/dist/hosted-loop-lifecycle.d.ts +206 -0
- package/dist/hosted-loop-lifecycle.d.ts.map +1 -0
- package/dist/hosted-loop.d.ts +170 -0
- package/dist/hosted-loop.d.ts.map +1 -0
- package/dist/hosted-run-event-sink.d.ts +222 -0
- package/dist/hosted-run-event-sink.d.ts.map +1 -0
- package/dist/hosted-runtime-assets.d.ts +186 -0
- package/dist/hosted-runtime-assets.d.ts.map +1 -0
- package/dist/hosted-session-cli.d.ts +258 -0
- package/dist/hosted-session-cli.d.ts.map +1 -0
- package/dist/hosted-skill-staging.d.ts +73 -0
- package/dist/hosted-skill-staging.d.ts.map +1 -0
- package/dist/http.d.ts +8 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +119 -129
- package/dist/instruction-set-gepa-launch.d.ts +3 -0
- package/dist/instruction-set-gepa-launch.d.ts.map +1 -0
- package/dist/instruction-set-gepa-launch.js +15 -0
- package/dist/instruction-set-loader.d.ts +6 -0
- package/dist/instruction-set-loader.d.ts.map +1 -0
- package/dist/instruction-set-loader.js +59 -0
- package/dist/instruction-set-manifest.d.ts +14 -0
- package/dist/instruction-set-manifest.d.ts.map +1 -0
- package/dist/instruction-set-manifest.js +162 -0
- package/dist/instruction-sets-cli.d.ts +40 -0
- package/dist/instruction-sets-cli.d.ts.map +1 -0
- package/dist/instruction-sets-cli.js +361 -0
- package/dist/json-response.d.ts +4 -0
- package/dist/json-response.d.ts.map +1 -0
- package/dist/jsonl-stream.d.ts +8 -0
- package/dist/jsonl-stream.d.ts.map +1 -0
- package/dist/kill-switch-cli.d.ts +30 -0
- package/dist/kill-switch-cli.d.ts.map +1 -0
- package/dist/loopback-serve.d.ts +25 -0
- package/dist/loopback-serve.d.ts.map +1 -0
- package/dist/manifests-cli.d.ts +22 -0
- package/dist/manifests-cli.d.ts.map +1 -0
- package/dist/markdown-report-input.d.ts +7 -0
- package/dist/markdown-report-input.d.ts.map +1 -0
- package/dist/markdown-report-input.js +15 -1
- package/dist/merge-job.d.ts +155 -0
- package/dist/merge-job.d.ts.map +1 -0
- package/dist/model-configs-cli.d.ts +19 -0
- package/dist/model-configs-cli.d.ts.map +1 -0
- package/dist/model-configs-cli.js +104 -0
- package/dist/optimization-export-cli.d.ts +19 -0
- package/dist/optimization-export-cli.d.ts.map +1 -0
- package/dist/optimizations-list-cli.d.ts +20 -0
- package/dist/optimizations-list-cli.d.ts.map +1 -0
- package/dist/optimizations-promote-cli.d.ts +8 -0
- package/dist/optimizations-promote-cli.d.ts.map +1 -0
- package/dist/optimizations-promote-cli.js +34 -0
- package/dist/option-validation.d.ts +15 -0
- package/dist/option-validation.d.ts.map +1 -0
- package/dist/preview-runtime.d.ts +63 -0
- package/dist/preview-runtime.d.ts.map +1 -0
- package/dist/prompt-draft-push.d.ts +60 -0
- package/dist/prompt-draft-push.d.ts.map +1 -0
- package/dist/prompt-label-cli.d.ts +11 -0
- package/dist/prompt-label-cli.d.ts.map +1 -0
- package/dist/prompt-label-cli.js +29 -0
- package/dist/prompt-length-wire.d.ts +28 -0
- package/dist/prompt-length-wire.d.ts.map +1 -0
- package/dist/prompt-length-wire.js +2 -2
- package/dist/prompt-report-cli.d.ts +10 -0
- package/dist/prompt-report-cli.d.ts.map +1 -0
- package/dist/prompt-report-cli.js +2 -2
- package/dist/prompt-summary-table.d.ts +15 -0
- package/dist/prompt-summary-table.d.ts.map +1 -0
- package/dist/prompt-summary-table.js +6 -0
- package/dist/registration-tag-warning.d.ts +32 -0
- package/dist/registration-tag-warning.d.ts.map +1 -0
- package/dist/report-comments-cli.d.ts +16 -0
- package/dist/report-comments-cli.d.ts.map +1 -0
- package/dist/report-markdown-blankness.d.ts +2 -0
- package/dist/report-markdown-blankness.d.ts.map +1 -0
- package/dist/report-markdown-blankness.js +6 -0
- package/dist/report-replacement-warning.d.ts +17 -0
- package/dist/report-replacement-warning.d.ts.map +1 -0
- package/dist/report-replacement-warning.js +31 -0
- package/dist/repository-backup-core.d.ts +225 -0
- package/dist/repository-backup-core.d.ts.map +1 -0
- package/dist/repository-recovery-manifest.d.ts +83 -0
- package/dist/repository-recovery-manifest.d.ts.map +1 -0
- package/dist/run-event-digest.d.ts +74 -0
- package/dist/run-event-digest.d.ts.map +1 -0
- package/dist/runner-dir-verify.d.ts +66 -0
- package/dist/runner-dir-verify.d.ts.map +1 -0
- package/dist/runner-instruction-set-contract.d.ts +24 -0
- package/dist/runner-instruction-set-contract.d.ts.map +1 -0
- package/dist/runner-instruction-set-contract.js +50 -0
- package/dist/sandbox-hygiene.d.ts +45 -0
- package/dist/sandbox-hygiene.d.ts.map +1 -0
- package/dist/sandbox-provider.d.ts +193 -0
- package/dist/sandbox-provider.d.ts.map +1 -0
- package/dist/scorer-draft-push.d.ts +50 -0
- package/dist/scorer-draft-push.d.ts.map +1 -0
- package/dist/scorers-cli.d.ts +20 -0
- package/dist/scorers-cli.d.ts.map +1 -0
- package/dist/scorers-cli.js +22 -0
- package/dist/scorers-verify-parity-bridge.d.ts +16 -0
- package/dist/scorers-verify-parity-bridge.d.ts.map +1 -0
- package/dist/scorers-verify-parity-bridge.js +90 -0
- package/dist/scorers-verify-parity.d.ts +81 -0
- package/dist/scorers-verify-parity.d.ts.map +1 -0
- package/dist/scorers-verify-parity.js +502 -0
- package/dist/scores-accept-cli.d.ts +21 -0
- package/dist/scores-accept-cli.d.ts.map +1 -0
- package/dist/secret-redaction.d.ts +47 -0
- package/dist/secret-redaction.d.ts.map +1 -0
- package/dist/session-timeline.d.ts +54 -0
- package/dist/session-timeline.d.ts.map +1 -0
- package/dist/setup-prompt.d.ts +5 -0
- package/dist/setup-prompt.d.ts.map +1 -0
- package/dist/skill-installer.d.ts +68 -0
- package/dist/skill-installer.d.ts.map +1 -0
- package/dist/skilled-proposer-launch.d.ts +7 -0
- package/dist/skilled-proposer-launch.d.ts.map +1 -0
- package/dist/skilled-proposer-launch.js +60 -0
- package/dist/smoke.d.ts +102 -0
- package/dist/smoke.d.ts.map +1 -0
- package/dist/start-intent.d.ts +12 -0
- package/dist/start-intent.d.ts.map +1 -0
- package/dist/task-assignment-manifest.d.ts +15 -0
- package/dist/task-assignment-manifest.d.ts.map +1 -0
- package/dist/task-create-error.d.ts +18 -0
- package/dist/task-create-error.d.ts.map +1 -0
- package/dist/team-connectors-cli.d.ts +29 -0
- package/dist/team-connectors-cli.d.ts.map +1 -0
- package/dist/types.d.ts +39 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/vercel-sandbox-provider.d.ts +156 -0
- package/dist/vercel-sandbox-provider.d.ts.map +1 -0
- package/dist/workbench-cli.d.ts +233 -0
- package/dist/workbench-cli.d.ts.map +1 -0
- package/dist/workspace-sync.d.ts +207 -0
- package/dist/workspace-sync.d.ts.map +1 -0
- package/dist/workspace.d.ts +92 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/zip-draft-push.d.ts +55 -0
- package/dist/zip-draft-push.d.ts.map +1 -0
- package/package.json +15 -2
- package/requirements/README.md +138 -0
- package/requirements/skilled-proposer.in +66 -0
- package/requirements/skilled-proposer.lock +265 -0
- package/scripts/build-cli-dist.mjs +30 -0
- package/scripts/ensure-skilled-proposer-venv.mjs +5 -0
- package/scripts/orizu-source-checkout.d.mts +1 -0
- package/scripts/orizu-source-checkout.mjs +10 -0
- package/scripts/refresh-skilled-proposer-lock.mjs +256 -0
- package/scripts/vendor-gepa-python.mjs +187 -4
- package/src/diff-comments-cli.ts +41 -3
- package/src/gepa-engine-dispatch.ts +340 -0
- package/src/gepa-python-command.ts +31 -0
- package/src/gepa-python-paths.ts +56 -0
- package/src/help.ts +95 -25
- package/src/index.ts +131 -166
- package/src/instruction-set-gepa-launch.ts +28 -0
- package/src/instruction-set-loader.ts +37 -0
- package/src/instruction-set-manifest.ts +120 -0
- package/src/instruction-sets-cli.ts +306 -0
- package/src/markdown-report-input.ts +19 -1
- package/src/model-configs-cli.ts +119 -0
- package/src/optimizations-promote-cli.ts +41 -0
- package/src/prompt-label-cli.ts +55 -0
- package/src/prompt-length-wire.ts +1 -1
- package/src/prompt-report-cli.ts +2 -2
- package/src/prompt-summary-table.ts +12 -0
- package/src/report-markdown-blankness.ts +6 -0
- package/src/report-replacement-warning.ts +35 -0
- package/src/runner-instruction-set-contract.ts +64 -0
- package/src/scorers-cli.ts +40 -0
- package/src/scorers-verify-parity-bridge.ts +90 -0
- package/src/scorers-verify-parity.ts +564 -0
- package/src/skilled-proposer-launch.ts +89 -0
- package/src/skilled-proposer-venv-manager.mjs +757 -0
- package/tsconfig.json +2 -0
- package/vendor/gepa-python/LICENSE +7 -0
- package/vendor/gepa-python/manifest.json +107 -0
- package/vendor/gepa-python/src/gepa/__init__.py +22 -0
- package/vendor/gepa-python/src/gepa/adapters/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/adapters/anymaths_adapter/__init__.py +1 -0
- package/vendor/gepa-python/src/gepa/adapters/anymaths_adapter/anymaths_adapter.py +174 -0
- package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/__init__.py +26 -0
- package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/confidence_adapter.py +618 -0
- package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/scoring.py +206 -0
- package/vendor/gepa-python/src/gepa/adapters/default_adapter/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/adapters/default_adapter/default_adapter.py +206 -0
- package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/dspy_adapter.py +525 -0
- package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/instruction_proposal.py +500 -0
- package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/__init__.py +6 -0
- package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/dspy_program_proposal_signature.py +137 -0
- package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/full_program_adapter.py +269 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/__init__.py +56 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/evaluation_metrics.py +226 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/generic_rag_adapter.py +496 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/rag_pipeline.py +238 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_store_interface.py +212 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/__init__.py +2 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/chroma_store.py +196 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/lancedb_store.py +422 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/milvus_store.py +409 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/qdrant_store.py +368 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/weaviate_store.py +418 -0
- package/vendor/gepa-python/src/gepa/adapters/langchain_adapter/__init__.py +11 -0
- package/vendor/gepa-python/src/gepa/adapters/langchain_adapter/langchain_adapter.py +261 -0
- package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/__init__.py +37 -0
- package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/mcp_adapter.py +693 -0
- package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/mcp_client.py +364 -0
- package/vendor/gepa-python/src/gepa/adapters/optimize_anything_adapter/optimize_anything_adapter.py +879 -0
- package/vendor/gepa-python/src/gepa/adapters/terminal_bench_adapter/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/adapters/terminal_bench_adapter/terminal_bench_adapter.py +217 -0
- package/vendor/gepa-python/src/gepa/api.py +468 -0
- package/vendor/gepa-python/src/gepa/core/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/core/adapter.py +227 -0
- package/vendor/gepa-python/src/gepa/core/callbacks.py +551 -0
- package/vendor/gepa-python/src/gepa/core/data_loader.py +74 -0
- package/vendor/gepa-python/src/gepa/core/engine.py +1025 -0
- package/vendor/gepa-python/src/gepa/core/result.py +271 -0
- package/vendor/gepa-python/src/gepa/core/state.py +706 -0
- package/vendor/gepa-python/src/gepa/examples/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/examples/aime.py +24 -0
- package/vendor/gepa-python/src/gepa/examples/anymaths-bench/eval_default.py +111 -0
- package/vendor/gepa-python/src/gepa/examples/anymaths-bench/train_anymaths.py +177 -0
- package/vendor/gepa-python/src/gepa/examples/mcp_adapter/__init__.py +4 -0
- package/vendor/gepa-python/src/gepa/examples/mcp_adapter/mcp_optimization_example.py +456 -0
- package/vendor/gepa-python/src/gepa/examples/rag_adapter/__init__.py +9 -0
- package/vendor/gepa-python/src/gepa/examples/rag_adapter/rag_optimization.py +824 -0
- package/vendor/gepa-python/src/gepa/examples/terminal-bench/train_terminus.py +161 -0
- package/vendor/gepa-python/src/gepa/gepa_utils.py +117 -0
- package/vendor/gepa-python/src/gepa/gskill/__init__.py +1 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/cost_tracker.py +194 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/claude_code.py +1117 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/claude_code_skills.py +613 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/mini_swe_agent.py +440 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/experiment_logger.py +367 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/swe_fitness_fn.py +209 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/swe_harness.py +352 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/train_optimize_anything.py +830 -0
- package/vendor/gepa-python/src/gepa/image.py +104 -0
- package/vendor/gepa-python/src/gepa/lm.py +261 -0
- package/vendor/gepa-python/src/gepa/logging/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/logging/experiment_tracker.py +457 -0
- package/vendor/gepa-python/src/gepa/logging/logger.py +75 -0
- package/vendor/gepa-python/src/gepa/logging/utils.py +130 -0
- package/vendor/gepa-python/src/gepa/optimize_anything.py +1701 -0
- package/vendor/gepa-python/src/gepa/proposer/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/proposer/base.py +53 -0
- package/vendor/gepa-python/src/gepa/proposer/merge.py +403 -0
- package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/base.py +64 -0
- package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/reflection_lm.py +178 -0
- package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/reflective_mutation.py +641 -0
- package/vendor/gepa-python/src/gepa/py.typed +0 -0
- package/vendor/gepa-python/src/gepa/strategies/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/strategies/acceptance.py +66 -0
- package/vendor/gepa-python/src/gepa/strategies/batch_sampler.py +103 -0
- package/vendor/gepa-python/src/gepa/strategies/candidate_selector.py +82 -0
- package/vendor/gepa-python/src/gepa/strategies/component_selector.py +36 -0
- package/vendor/gepa-python/src/gepa/strategies/eval_policy.py +64 -0
- package/vendor/gepa-python/src/gepa/strategies/instruction_proposal.py +153 -0
- package/vendor/gepa-python/src/gepa/strategies/proposal_sampling.py +128 -0
- package/vendor/gepa-python/src/gepa/strategies/proposal_selection.py +84 -0
- package/vendor/gepa-python/src/gepa/utils/__init__.py +63 -0
- package/vendor/gepa-python/src/gepa/utils/code_execution.py +626 -0
- package/vendor/gepa-python/src/gepa/utils/stdio_capture.py +145 -0
- package/vendor/gepa-python/src/gepa/utils/stop_condition.py +230 -0
- package/vendor/gepa-python/src/gepa/visualization.py +359 -0
- package/vendor/orizu-gepa/pyproject.toml +18 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/__init__.py +9 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/__main__.py +5 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/adapter.py +138 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/callbacks.py +666 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/cli.py +7 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/engine.py +269 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/instruction_set_loader.py +52 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/preflight.py +64 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/reflection.py +186 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/runtime.py +721 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/skilled_proposer_bridge.py +381 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/stop_conditions.py +55 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/translator.py +203 -0
- package/vendor/orizu-gepa-python/pyproject.toml +1 -1
- package/vendor/orizu-gepa-python/src/orizu_gepa/cli.py +1 -0
- package/vendor/orizu-gepa-python/src/orizu_gepa/client.py +52 -7
- package/vendor/orizu-gepa-python/src/orizu_gepa/local_log.py +52 -0
- package/vendor/orizu-gepa-python/src/orizu_gepa/optimizer.py +10 -5
- package/vendor/orizu-gepa-python/src/orizu_gepa/reflection.py +323 -68
- package/vendor/orizu-gepa-python/src/orizu_gepa/runner.py +207 -13
- package/vendor/skills/orizu-cli/SKILL.md +3 -1
- package/vendor/skills/orizu-cli/references/cli-reference.md +85 -1
- package/vendor/skills/orizu-cli/references/migrate-existing-gepa-setup.md +303 -0
- package/vendor/skills/orizu-cli/references/optimization-reports.md +1 -1
- package/vendor/skills/orizu-cli/references/optimization-with-gepa.md +26 -1
- 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]
|