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,830 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Training script using GEPA optimize_anything API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
import logging
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from dotenv import load_dotenv
|
|
13
|
+
|
|
14
|
+
# Suppress verbose LiteLLM logging
|
|
15
|
+
logging.getLogger("LiteLLM").setLevel(logging.WARNING)
|
|
16
|
+
logging.getLogger("litellm").setLevel(logging.WARNING)
|
|
17
|
+
|
|
18
|
+
# Load environment variables
|
|
19
|
+
load_dotenv()
|
|
20
|
+
|
|
21
|
+
import re
|
|
22
|
+
|
|
23
|
+
from datasets import load_dataset
|
|
24
|
+
from gskill.cost_tracker import reset_tracker
|
|
25
|
+
from gskill.experiment_logger import ExperimentLogger, set_logger
|
|
26
|
+
from gskill.swe_fitness_fn import create_swe_fitness_fn
|
|
27
|
+
|
|
28
|
+
from gepa.optimize_anything import EngineConfig, GEPAConfig, ReflectionConfig, TrackingConfig, optimize_anything
|
|
29
|
+
from gepa.utils.stop_condition import TimeoutStopCondition
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TeeOutput:
|
|
33
|
+
"""Duplicate stdout/stderr to both terminal and a log file."""
|
|
34
|
+
|
|
35
|
+
def __init__(self, log_path: Path):
|
|
36
|
+
self.log_path = log_path
|
|
37
|
+
self.log_file = None
|
|
38
|
+
self.original_stdout = None
|
|
39
|
+
self.original_stderr = None
|
|
40
|
+
|
|
41
|
+
def start(self):
|
|
42
|
+
"""Start capturing output."""
|
|
43
|
+
self.log_file = open(self.log_path, "w", buffering=1) # Line buffered
|
|
44
|
+
self.original_stdout = sys.stdout
|
|
45
|
+
self.original_stderr = sys.stderr
|
|
46
|
+
sys.stdout = self._TeeStream(self.original_stdout, self.log_file)
|
|
47
|
+
sys.stderr = self._TeeStream(self.original_stderr, self.log_file)
|
|
48
|
+
print(f"[Logging terminal output to: {self.log_path}]")
|
|
49
|
+
|
|
50
|
+
def stop(self):
|
|
51
|
+
"""Stop capturing and restore original streams."""
|
|
52
|
+
if self.original_stdout:
|
|
53
|
+
sys.stdout = self.original_stdout
|
|
54
|
+
if self.original_stderr:
|
|
55
|
+
sys.stderr = self.original_stderr
|
|
56
|
+
if self.log_file:
|
|
57
|
+
self.log_file.close()
|
|
58
|
+
|
|
59
|
+
class _TeeStream:
|
|
60
|
+
"""Stream wrapper that writes to both original stream and file."""
|
|
61
|
+
|
|
62
|
+
def __init__(self, original, log_file):
|
|
63
|
+
self.original = original
|
|
64
|
+
self.log_file = log_file
|
|
65
|
+
|
|
66
|
+
def write(self, data):
|
|
67
|
+
self.original.write(data)
|
|
68
|
+
self.original.flush()
|
|
69
|
+
self.log_file.write(data)
|
|
70
|
+
self.log_file.flush()
|
|
71
|
+
|
|
72
|
+
def flush(self):
|
|
73
|
+
self.original.flush()
|
|
74
|
+
self.log_file.flush()
|
|
75
|
+
|
|
76
|
+
def fileno(self):
|
|
77
|
+
return self.original.fileno()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class LoggingProposer:
|
|
81
|
+
"""Base proposer class that logs all inputs/outputs to separate files.
|
|
82
|
+
|
|
83
|
+
Can be inherited to create custom proposers with different strategies.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
# Custom prompt for learning terminal and repo-specific skills
|
|
87
|
+
DEFAULT_PROMPT_TEMPLATE = """You are helping an AI coding agent learn skills for fixing bugs in a software repository.
|
|
88
|
+
|
|
89
|
+
The agent operates inside a Docker container with:
|
|
90
|
+
- The repository cloned at /testbed
|
|
91
|
+
- Access to bash commands (grep, find, cat, sed, python, pytest, git, etc.)
|
|
92
|
+
- The ability to read, edit, and create files
|
|
93
|
+
|
|
94
|
+
## Current Skills
|
|
95
|
+
The agent currently has these learned skills:
|
|
96
|
+
```
|
|
97
|
+
{curr_skills}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Evaluation Results
|
|
101
|
+
Below are results from the agent attempting to fix bugs using the current skills. Each entry shows:
|
|
102
|
+
- The problem statement (bug description)
|
|
103
|
+
- The agent's actions and reasoning
|
|
104
|
+
- Whether the fix succeeded or failed
|
|
105
|
+
- Test output and error messages
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
{evaluation_data}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Your Task
|
|
112
|
+
Analyze the evaluation results and propose IMPROVED SKILLS that will help the agent:
|
|
113
|
+
|
|
114
|
+
1. **Terminal/Bash Skills**: Common command patterns, file navigation, searching code, running tests
|
|
115
|
+
2. **Repository-Specific Knowledge**: Project structure, key modules, common patterns in this codebase
|
|
116
|
+
3. **Debugging Strategies**: How to locate bugs, understand test failures, verify fixes
|
|
117
|
+
4. **Code Editing Patterns**: Safe ways to modify files, handle imports, avoid syntax errors
|
|
118
|
+
|
|
119
|
+
Focus on:
|
|
120
|
+
- Patterns that led to SUCCESS - reinforce these
|
|
121
|
+
- Patterns that led to FAILURE - what should the agent do differently?
|
|
122
|
+
- Missing knowledge that would have helped
|
|
123
|
+
- Common mistakes to avoid
|
|
124
|
+
|
|
125
|
+
Write the improved skills as clear, actionable instructions. Be specific and concrete. Remember the agent will not be evaluated on the same task, but they are expected to use the skills to fix other tasks in the SAME repository.
|
|
126
|
+
If any older skills are still helpful, include them as well. However, always keep the overall skills concise and comprehensive.
|
|
127
|
+
Adding skills blindly will not help the agent, so only add skills that are actually helpful.
|
|
128
|
+
|
|
129
|
+
Provide the new skills within a SINGLE ``` block. Only include one ``` block, if you include multiple ``` blocks, the agent will not be able to parse the response."""
|
|
130
|
+
|
|
131
|
+
def __init__(self, run_dir: Path, reflection_lm: str):
|
|
132
|
+
"""Initialize the proposer.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
run_dir: Directory to save logs
|
|
136
|
+
reflection_lm: Model name for reflection LLM
|
|
137
|
+
"""
|
|
138
|
+
from gepa.lm import LM
|
|
139
|
+
|
|
140
|
+
self.run_dir = run_dir
|
|
141
|
+
self.reflection_lm = reflection_lm
|
|
142
|
+
self._lm = LM(reflection_lm)
|
|
143
|
+
self.proposer_dir = run_dir / "proposer_calls"
|
|
144
|
+
self.proposer_dir.mkdir(parents=True, exist_ok=True)
|
|
145
|
+
self.call_counter = 0
|
|
146
|
+
self.prompt_template = self.DEFAULT_PROMPT_TEMPLATE
|
|
147
|
+
|
|
148
|
+
def format_prompt(self, curr_skills: str, evaluation_data: str) -> str:
|
|
149
|
+
"""Format the prompt with current skills and evaluation data.
|
|
150
|
+
|
|
151
|
+
Override this method to customize prompt formatting.
|
|
152
|
+
"""
|
|
153
|
+
return self.prompt_template.format(
|
|
154
|
+
curr_skills=curr_skills if curr_skills else "(No skills learned yet)", evaluation_data=evaluation_data
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
def call_llm(self, prompt: str) -> str:
|
|
158
|
+
"""Call the LLM and return the response text.
|
|
159
|
+
|
|
160
|
+
Override this method to customize LLM calling.
|
|
161
|
+
"""
|
|
162
|
+
return self._lm(prompt)
|
|
163
|
+
|
|
164
|
+
def extract_skills(self, response_text: str) -> str:
|
|
165
|
+
"""Extract skills from LLM response.
|
|
166
|
+
|
|
167
|
+
Override this method to customize extraction logic.
|
|
168
|
+
Matches from the first ``` to the last ``` to handle nested backtick references.
|
|
169
|
+
"""
|
|
170
|
+
# Find the first code fence (with optional language tag)
|
|
171
|
+
first = re.search(r"```(?:\w*\n)?", response_text)
|
|
172
|
+
if not first:
|
|
173
|
+
return response_text.strip()
|
|
174
|
+
|
|
175
|
+
# Find the last occurrence of ``` to handle nested backtick references
|
|
176
|
+
last_pos = response_text.rfind("```")
|
|
177
|
+
if last_pos <= first.end():
|
|
178
|
+
return response_text.strip()
|
|
179
|
+
|
|
180
|
+
return response_text[first.end() : last_pos].strip()
|
|
181
|
+
|
|
182
|
+
def log_call(self, call_num: int, log_entry: dict) -> Path:
|
|
183
|
+
"""Log the call to a file and return the file path.
|
|
184
|
+
|
|
185
|
+
Override this method to customize logging.
|
|
186
|
+
"""
|
|
187
|
+
call_file = self.proposer_dir / f"call_{call_num:03d}.json"
|
|
188
|
+
with open(call_file, "w") as f:
|
|
189
|
+
json.dump(log_entry, f, indent=2, default=str)
|
|
190
|
+
return call_file
|
|
191
|
+
|
|
192
|
+
def __call__(self, candidate: dict, reflective_dataset: dict, components_to_update: list) -> dict:
|
|
193
|
+
"""Main proposer logic - processes all side info at once.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
candidate: Current candidate dict with component values
|
|
197
|
+
reflective_dataset: Dict mapping components to their side info lists
|
|
198
|
+
components_to_update: List of component names to update
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
Dict mapping components to their new values
|
|
202
|
+
"""
|
|
203
|
+
self.call_counter += 1
|
|
204
|
+
call_num = self.call_counter
|
|
205
|
+
|
|
206
|
+
results = {}
|
|
207
|
+
|
|
208
|
+
for component in components_to_update:
|
|
209
|
+
curr_value = candidate.get(component, "")
|
|
210
|
+
side_info = reflective_dataset.get(component, [])
|
|
211
|
+
|
|
212
|
+
# Format side info as string
|
|
213
|
+
side_info_str = json.dumps(side_info, indent=2, default=str)
|
|
214
|
+
|
|
215
|
+
# Format the prompt
|
|
216
|
+
prompt = self.format_prompt(curr_value, side_info_str)
|
|
217
|
+
|
|
218
|
+
# Prepare log entry
|
|
219
|
+
log_entry = {
|
|
220
|
+
"call_num": call_num,
|
|
221
|
+
"component": component,
|
|
222
|
+
"current_skills": curr_value,
|
|
223
|
+
"evaluation_data": side_info,
|
|
224
|
+
"full_prompt": prompt,
|
|
225
|
+
"type": "batch",
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
# Call the reflection LLM
|
|
229
|
+
try:
|
|
230
|
+
response_text = self.call_llm(prompt)
|
|
231
|
+
new_value = self.extract_skills(response_text)
|
|
232
|
+
|
|
233
|
+
log_entry["llm_response"] = response_text
|
|
234
|
+
log_entry["new_skills"] = new_value
|
|
235
|
+
log_entry["success"] = True
|
|
236
|
+
|
|
237
|
+
results[component] = new_value
|
|
238
|
+
|
|
239
|
+
except Exception as e:
|
|
240
|
+
log_entry["error"] = str(e)
|
|
241
|
+
log_entry["success"] = False
|
|
242
|
+
results[component] = curr_value # Keep current on error
|
|
243
|
+
|
|
244
|
+
# Write to separate file for this call
|
|
245
|
+
call_file = self.log_call(call_num, log_entry)
|
|
246
|
+
|
|
247
|
+
# Also print summary
|
|
248
|
+
print(f"\n[PROPOSER] Call {call_num} for '{component}':")
|
|
249
|
+
print(f" Current skills: {len(curr_value)} chars")
|
|
250
|
+
print(f" Evaluation items: {len(side_info)}")
|
|
251
|
+
print(f" New skills: {len(results.get(component, ''))} chars")
|
|
252
|
+
print(f" Saved to: {call_file}")
|
|
253
|
+
|
|
254
|
+
return results
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class LoopProposer(LoggingProposer):
|
|
258
|
+
"""Proposer that processes one side info item at a time, then merges all skills."""
|
|
259
|
+
|
|
260
|
+
MERGE_TEMPLATE = """You are helping an AI coding agent consolidate learned skills for fixing bugs.
|
|
261
|
+
|
|
262
|
+
## New Skills/Insights from Recent Evaluations
|
|
263
|
+
{intermediate_skills}
|
|
264
|
+
|
|
265
|
+
## Your Task
|
|
266
|
+
Merge all the above skills into a SINGLE, coherent skill set that:
|
|
267
|
+
1. Eliminates redundancy
|
|
268
|
+
2. Resolves conflicts (keep the most reliable/general one)
|
|
269
|
+
3. Prioritizes (most important first)
|
|
270
|
+
4. Stays concise
|
|
271
|
+
|
|
272
|
+
Provide the merged skills within a SINGLE ``` block."""
|
|
273
|
+
|
|
274
|
+
def _process_single_item(
|
|
275
|
+
self, component: str, curr_skills: str, item: dict, item_idx: int, total_items: int
|
|
276
|
+
) -> str | None:
|
|
277
|
+
"""Process a single evaluation item and return extracted skills, or None on failure."""
|
|
278
|
+
self.call_counter += 1
|
|
279
|
+
call_num = self.call_counter
|
|
280
|
+
|
|
281
|
+
item_str = json.dumps(item, indent=2, default=str)
|
|
282
|
+
prompt = self.format_prompt(curr_skills, item_str)
|
|
283
|
+
|
|
284
|
+
log_entry = {
|
|
285
|
+
"call_num": call_num,
|
|
286
|
+
"component": component,
|
|
287
|
+
"item_index": item_idx,
|
|
288
|
+
"total_items": total_items,
|
|
289
|
+
"current_skills": curr_skills,
|
|
290
|
+
"evaluation_item": item,
|
|
291
|
+
"full_prompt": prompt,
|
|
292
|
+
"type": "single_item",
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
try:
|
|
296
|
+
response_text = self.call_llm(prompt)
|
|
297
|
+
new_skills = self.extract_skills(response_text)
|
|
298
|
+
log_entry.update({"llm_response": response_text, "extracted_skills": new_skills, "success": True})
|
|
299
|
+
result = new_skills
|
|
300
|
+
except Exception as e:
|
|
301
|
+
log_entry.update({"error": str(e), "success": False})
|
|
302
|
+
result = None
|
|
303
|
+
|
|
304
|
+
self.log_call(call_num, log_entry)
|
|
305
|
+
print(
|
|
306
|
+
f"\n[LOOP PROPOSER] Call {call_num} - Item {item_idx + 1}/{total_items} for '{component}': {'OK' if result else 'FAIL'}"
|
|
307
|
+
)
|
|
308
|
+
return result
|
|
309
|
+
|
|
310
|
+
def _merge_skills(self, component: str, curr_skills: str, intermediate_skills: list) -> str:
|
|
311
|
+
"""Merge intermediate skills into final skill set."""
|
|
312
|
+
self.call_counter += 1
|
|
313
|
+
call_num = self.call_counter
|
|
314
|
+
|
|
315
|
+
formatted = "\n\n".join(f"### Evaluation {i}\n```\n{s}\n```" for i, s in enumerate(intermediate_skills, 1))
|
|
316
|
+
merge_prompt = self.MERGE_TEMPLATE.format(intermediate_skills=formatted)
|
|
317
|
+
|
|
318
|
+
log_entry = {
|
|
319
|
+
"call_num": call_num,
|
|
320
|
+
"component": component,
|
|
321
|
+
"type": "merge",
|
|
322
|
+
"num_intermediate_skills": len(intermediate_skills),
|
|
323
|
+
"intermediate_skills": intermediate_skills,
|
|
324
|
+
"full_prompt": merge_prompt,
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
try:
|
|
328
|
+
response_text = self.call_llm(merge_prompt)
|
|
329
|
+
final_skills = self.extract_skills(response_text)
|
|
330
|
+
log_entry.update({"llm_response": response_text, "final_skills": final_skills, "success": True})
|
|
331
|
+
except Exception as e:
|
|
332
|
+
log_entry.update({"error": str(e), "success": False})
|
|
333
|
+
final_skills = "\n\n---\n\n".join(intermediate_skills) # Fallback
|
|
334
|
+
|
|
335
|
+
self.log_call(call_num, log_entry)
|
|
336
|
+
print(
|
|
337
|
+
f"\n[LOOP PROPOSER] Merge call {call_num} for '{component}': {len(intermediate_skills)} items -> {len(final_skills)} chars"
|
|
338
|
+
)
|
|
339
|
+
return final_skills
|
|
340
|
+
|
|
341
|
+
def __call__(self, candidate: dict, reflective_dataset: dict, components_to_update: list) -> dict:
|
|
342
|
+
"""Process each side info item one at a time, then merge all skills."""
|
|
343
|
+
results = {}
|
|
344
|
+
|
|
345
|
+
for component in components_to_update:
|
|
346
|
+
curr_skills = candidate.get(component, "")
|
|
347
|
+
side_info_items = reflective_dataset.get(component, [])
|
|
348
|
+
|
|
349
|
+
if not side_info_items:
|
|
350
|
+
results[component] = curr_skills
|
|
351
|
+
continue
|
|
352
|
+
|
|
353
|
+
# Process each item
|
|
354
|
+
intermediate_skills = [
|
|
355
|
+
skills
|
|
356
|
+
for i, item in enumerate(side_info_items)
|
|
357
|
+
if (skills := self._process_single_item(component, curr_skills, item, i, len(side_info_items)))
|
|
358
|
+
]
|
|
359
|
+
|
|
360
|
+
# Merge results
|
|
361
|
+
results[component] = (
|
|
362
|
+
self._merge_skills(component, curr_skills, intermediate_skills) if intermediate_skills else curr_skills
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
return results
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def create_logging_proposer(run_dir: Path, reflection_lm: str):
|
|
369
|
+
"""Create a LoggingProposer instance (factory function for backward compatibility)."""
|
|
370
|
+
return LoggingProposer(run_dir, reflection_lm)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def create_loop_proposer(run_dir: Path, reflection_lm: str):
|
|
374
|
+
"""Create a LoopProposer instance that processes items one at a time then merges."""
|
|
375
|
+
return LoopProposer(run_dir, reflection_lm)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
import random
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def load_and_split_data(repo: str, train_size: int, val_size: int, test_size: int, seed: int = 42):
|
|
382
|
+
"""
|
|
383
|
+
Load data directly from HuggingFace and split into train/val/test.
|
|
384
|
+
|
|
385
|
+
Args:
|
|
386
|
+
repo: Repository name to filter (e.g., "pygments__pygments" or "swesmith/pygments__pygments")
|
|
387
|
+
train_size: Number of training examples
|
|
388
|
+
val_size: Number of validation examples
|
|
389
|
+
test_size: Number of test examples
|
|
390
|
+
seed: Random seed for shuffling
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
(train_data, val_data, test_data) tuple
|
|
394
|
+
"""
|
|
395
|
+
total_needed = train_size + val_size + test_size
|
|
396
|
+
print(f"Loading {repo} data from HuggingFace SWE-smith (need {total_needed})...")
|
|
397
|
+
ds = load_dataset("SWE-bench/SWE-smith", split="train")
|
|
398
|
+
|
|
399
|
+
# Normalize repo name for matching
|
|
400
|
+
# Handle both "pygments__pygments" and "swesmith/pygments__pygments"
|
|
401
|
+
repo_pattern = repo if "/" in repo else f"swesmith/{repo}"
|
|
402
|
+
|
|
403
|
+
all_data = []
|
|
404
|
+
for item in ds:
|
|
405
|
+
repo_name = item.get("repo", "")
|
|
406
|
+
if repo_pattern in repo_name:
|
|
407
|
+
all_data.append(dict(item))
|
|
408
|
+
if len(all_data) >= total_needed:
|
|
409
|
+
break
|
|
410
|
+
|
|
411
|
+
print(f"Loaded {len(all_data)} {repo} examples")
|
|
412
|
+
|
|
413
|
+
# Shuffle with seed
|
|
414
|
+
random.seed(seed)
|
|
415
|
+
random.shuffle(all_data)
|
|
416
|
+
|
|
417
|
+
# Calculate split sizes
|
|
418
|
+
total_needed = train_size + val_size + test_size
|
|
419
|
+
if len(all_data) < total_needed:
|
|
420
|
+
print(f"WARNING: Only {len(all_data)} examples available, need {total_needed}")
|
|
421
|
+
# Scale down proportionally
|
|
422
|
+
ratio = len(all_data) / total_needed
|
|
423
|
+
train_size = int(train_size * ratio)
|
|
424
|
+
val_size = int(val_size * ratio)
|
|
425
|
+
test_size = len(all_data) - train_size - val_size
|
|
426
|
+
|
|
427
|
+
# Split
|
|
428
|
+
train_data = all_data[:train_size]
|
|
429
|
+
val_data = all_data[train_size : train_size + val_size]
|
|
430
|
+
test_data = all_data[train_size + val_size : train_size + val_size + test_size]
|
|
431
|
+
|
|
432
|
+
print(f"Split: {len(train_data)} train, {len(val_data)} val, {len(test_data)} test")
|
|
433
|
+
|
|
434
|
+
return train_data, val_data, test_data
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def evaluate_on_test(fitness_fn, candidate: dict, test_data: list, name: str = "Test"):
|
|
438
|
+
"""Evaluate a candidate on test data and return results."""
|
|
439
|
+
print(f"\n{'=' * 70}")
|
|
440
|
+
print(f"Evaluating {name}...")
|
|
441
|
+
print(f"{'=' * 70}")
|
|
442
|
+
|
|
443
|
+
results = [fitness_fn(candidate, task) for task in test_data]
|
|
444
|
+
|
|
445
|
+
scores = [r[0] for r in results]
|
|
446
|
+
avg_score = sum(scores) / len(scores) if scores else 0.0
|
|
447
|
+
pass_count = sum(1 for s in scores if s == 1.0)
|
|
448
|
+
|
|
449
|
+
print(f"\n{name} Results:")
|
|
450
|
+
print(f" Pass rate: {pass_count}/{len(test_data)} ({avg_score:.1%})")
|
|
451
|
+
|
|
452
|
+
return {"avg_score": avg_score, "pass_count": pass_count, "total": len(test_data), "scores": scores}
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def main():
|
|
456
|
+
parser = argparse.ArgumentParser(description="GEPA optimization using optimize_anything API (recommended)")
|
|
457
|
+
parser.add_argument(
|
|
458
|
+
"--repo",
|
|
459
|
+
type=str,
|
|
460
|
+
default="pygments__pygments",
|
|
461
|
+
help="Repository to train on (e.g., 'pygments__pygments', 'django__django')",
|
|
462
|
+
)
|
|
463
|
+
parser.add_argument("--train-size", type=int, default=200, help="Number of training examples")
|
|
464
|
+
parser.add_argument("--val-size", type=int, default=50, help="Number of validation examples for Pareto selection")
|
|
465
|
+
parser.add_argument("--test-size", type=int, default=100, help="Number of test examples for final evaluation")
|
|
466
|
+
parser.add_argument(
|
|
467
|
+
"--model", type=str, default="gpt-5-mini", help="Agent model for running tasks (default: gpt-5-mini)"
|
|
468
|
+
)
|
|
469
|
+
parser.add_argument(
|
|
470
|
+
"--reflection-model",
|
|
471
|
+
type=str,
|
|
472
|
+
default="gpt-5.2-pro",
|
|
473
|
+
help="Model for GEPA reflection/prompt optimization (default: gpt-5.2-pro)",
|
|
474
|
+
)
|
|
475
|
+
parser.add_argument("--smoke-test", action="store_true", help="Run a quick smoke test")
|
|
476
|
+
parser.add_argument(
|
|
477
|
+
"--run-post-optimization-testset", action="store_true", help="Evaluate on test set after optimization"
|
|
478
|
+
)
|
|
479
|
+
parser.add_argument(
|
|
480
|
+
"--resume",
|
|
481
|
+
type=str,
|
|
482
|
+
default=None,
|
|
483
|
+
help="Resume from a previous run directory (e.g., gepa_results/logs/run_XXXXXXXX)",
|
|
484
|
+
)
|
|
485
|
+
parser.add_argument(
|
|
486
|
+
"--run-pre-optimization-testset", action="store_true", help="run the agent on the test set before optimization"
|
|
487
|
+
)
|
|
488
|
+
parser.add_argument(
|
|
489
|
+
"--run-testset", action="store_true", help="run the agent on the test set before and after optimization"
|
|
490
|
+
)
|
|
491
|
+
parser.add_argument("--verbose", action="store_true", help="Enable verbose logging")
|
|
492
|
+
parser.add_argument("--timeout", type=int, default=43200, help="Max seconds to run (default: 12 hours)")
|
|
493
|
+
parser.add_argument("--seed", type=int, default=42, help="Random seed for reproducibility")
|
|
494
|
+
parser.add_argument("--workers", type=int, default=6, help="Number of parallel workers (Docker containers)")
|
|
495
|
+
parser.add_argument("--max-metric-calls", type=int, default=600, help="Max rollouts for GEPA (controls budget)")
|
|
496
|
+
parser.add_argument("--wandb", action="store_true", help="Enable wandb tracking")
|
|
497
|
+
parser.add_argument("--wandb-project", type=str, default="gepa-swesmith", help="Wandb project name")
|
|
498
|
+
parser.add_argument(
|
|
499
|
+
"--proposer",
|
|
500
|
+
type=str,
|
|
501
|
+
default="batch",
|
|
502
|
+
choices=["batch", "loop"],
|
|
503
|
+
help="Proposer type: 'batch' (all at once) or 'loop' (one at a time, then merge)",
|
|
504
|
+
)
|
|
505
|
+
args = parser.parse_args()
|
|
506
|
+
|
|
507
|
+
if args.smoke_test:
|
|
508
|
+
args.train_size = 3
|
|
509
|
+
args.val_size = 2
|
|
510
|
+
args.test_size = 2
|
|
511
|
+
args.max_metric_calls = 20
|
|
512
|
+
print("SMOKE TEST MODE")
|
|
513
|
+
|
|
514
|
+
# Handle resume from previous run
|
|
515
|
+
resumed_from = None
|
|
516
|
+
if args.resume:
|
|
517
|
+
resume_dir = Path(args.resume)
|
|
518
|
+
if not resume_dir.exists():
|
|
519
|
+
print(f"ERROR: Resume directory not found: {resume_dir}")
|
|
520
|
+
sys.exit(1)
|
|
521
|
+
|
|
522
|
+
state_file = resume_dir / "gepa_state.bin"
|
|
523
|
+
if not state_file.exists():
|
|
524
|
+
print(f"ERROR: No gepa_state.bin found in {resume_dir}")
|
|
525
|
+
sys.exit(1)
|
|
526
|
+
|
|
527
|
+
# Load previous config to get consistent parameters
|
|
528
|
+
prev_config_file = resume_dir / "config.json"
|
|
529
|
+
if prev_config_file.exists():
|
|
530
|
+
with open(prev_config_file) as f:
|
|
531
|
+
prev_config = json.load(f)
|
|
532
|
+
# Use same repo and seed for data consistency
|
|
533
|
+
args.repo = prev_config.get("repo", args.repo)
|
|
534
|
+
args.seed = prev_config.get("seed", args.seed)
|
|
535
|
+
print(f"RESUME MODE: Loading state from {resume_dir}")
|
|
536
|
+
print(f" Using repo={args.repo}, seed={args.seed} from previous run")
|
|
537
|
+
|
|
538
|
+
resumed_from = str(resume_dir)
|
|
539
|
+
|
|
540
|
+
# Initialize experiment logger FIRST to get run_id
|
|
541
|
+
exp_logger = ExperimentLogger(log_dir="gepa_results/logs", repo=args.repo)
|
|
542
|
+
set_logger(exp_logger)
|
|
543
|
+
run_dir = exp_logger.log_dir
|
|
544
|
+
|
|
545
|
+
# If resuming, copy the state file to the new run directory
|
|
546
|
+
if resumed_from:
|
|
547
|
+
import shutil
|
|
548
|
+
|
|
549
|
+
src_state = Path(resumed_from) / "gepa_state.bin"
|
|
550
|
+
dst_state = run_dir / "gepa_state.bin"
|
|
551
|
+
shutil.copy2(src_state, dst_state)
|
|
552
|
+
print(f"Copied state file from {src_state} to {dst_state}")
|
|
553
|
+
|
|
554
|
+
# Setup output tee - capture all stdout/stderr to terminal.log
|
|
555
|
+
terminal_log = run_dir / "terminal.log"
|
|
556
|
+
tee = TeeOutput(terminal_log)
|
|
557
|
+
tee.start()
|
|
558
|
+
|
|
559
|
+
# Setup Python logging
|
|
560
|
+
log_file = run_dir / "training.log"
|
|
561
|
+
logging.basicConfig(
|
|
562
|
+
level=logging.INFO if args.verbose else logging.WARNING,
|
|
563
|
+
format="%(asctime)s - %(levelname)s - %(message)s",
|
|
564
|
+
handlers=[logging.FileHandler(log_file), logging.StreamHandler(sys.stdout)],
|
|
565
|
+
)
|
|
566
|
+
logger = logging.getLogger(__name__)
|
|
567
|
+
|
|
568
|
+
# Reset cost tracking
|
|
569
|
+
reset_tracker()
|
|
570
|
+
|
|
571
|
+
print("\n" + "=" * 70)
|
|
572
|
+
print("GEPA + SWE-smith Training (optimize_anything API)")
|
|
573
|
+
print("=" * 70)
|
|
574
|
+
print(f"Repository: {args.repo}")
|
|
575
|
+
print(f"Model: {args.model}")
|
|
576
|
+
print(f"Reflection Model: {args.reflection_model}")
|
|
577
|
+
print(f"Proposer: {args.proposer}")
|
|
578
|
+
print(f"Workers: {args.workers} (Docker containers)")
|
|
579
|
+
print(f"Run directory: {run_dir}")
|
|
580
|
+
if resumed_from:
|
|
581
|
+
print(f"Resumed from: {resumed_from}")
|
|
582
|
+
print("=" * 70 + "\n")
|
|
583
|
+
|
|
584
|
+
# 1. Load Data - directly from HuggingFace, split with shuffle
|
|
585
|
+
train_data, val_data, test_data = load_and_split_data(
|
|
586
|
+
repo=args.repo, train_size=args.train_size, val_size=args.val_size, test_size=args.test_size, seed=args.seed
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
print(f"Data splits: {len(train_data)} train, {len(val_data)} val, {len(test_data)} test")
|
|
590
|
+
logger.info(f"Data: train={len(train_data)}, val={len(val_data)}, test={len(test_data)}")
|
|
591
|
+
|
|
592
|
+
# Determine reflection model
|
|
593
|
+
reflection_model = args.reflection_model or args.model
|
|
594
|
+
|
|
595
|
+
# Save experiment config
|
|
596
|
+
exp_logger.save_config(
|
|
597
|
+
{
|
|
598
|
+
"api": "optimize_anything",
|
|
599
|
+
"repo": args.repo,
|
|
600
|
+
"model": args.model,
|
|
601
|
+
"reflection_model": reflection_model,
|
|
602
|
+
"train_size": len(train_data),
|
|
603
|
+
"val_size": len(val_data),
|
|
604
|
+
"test_size": len(test_data),
|
|
605
|
+
"max_metric_calls": args.max_metric_calls,
|
|
606
|
+
"workers": args.workers,
|
|
607
|
+
"seed": args.seed,
|
|
608
|
+
"timeout": args.timeout,
|
|
609
|
+
"resumed_from": resumed_from,
|
|
610
|
+
"run_pre_optimization_testset": args.run_pre_optimization_testset,
|
|
611
|
+
"run_post_optimization_testset": args.run_post_optimization_testset,
|
|
612
|
+
"execution_mode": "docker",
|
|
613
|
+
"wandb": args.wandb,
|
|
614
|
+
"wandb_project": args.wandb_project if args.wandb else None,
|
|
615
|
+
"proposer": args.proposer,
|
|
616
|
+
}
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
# 2. Create Fitness Function
|
|
620
|
+
print(f"\nCreating fitness function with {args.workers} workers...")
|
|
621
|
+
fitness_fn = create_swe_fitness_fn(model_name=args.model, n_workers=args.workers)
|
|
622
|
+
logger.info(f"Model: {args.model}")
|
|
623
|
+
logger.info("Execution: Docker containers via SWE-smith")
|
|
624
|
+
|
|
625
|
+
# 3. Initial Candidate (Baseline Prompt)
|
|
626
|
+
# Start with empty skills - GEPA will learn and evolve them
|
|
627
|
+
# The system_template in mini.yaml already has base instructions,
|
|
628
|
+
# this just populates the {{ skills }} placeholder
|
|
629
|
+
initial_skills = ""
|
|
630
|
+
|
|
631
|
+
seed_candidate = {"skills": initial_skills}
|
|
632
|
+
|
|
633
|
+
# 4. Setup stop conditions
|
|
634
|
+
stop_callbacks = [
|
|
635
|
+
TimeoutStopCondition(timeout_seconds=args.timeout),
|
|
636
|
+
]
|
|
637
|
+
|
|
638
|
+
# 5. Configure GEPA with structured config
|
|
639
|
+
wandb_kwargs = (
|
|
640
|
+
{
|
|
641
|
+
"project": args.wandb_project,
|
|
642
|
+
"name": run_dir.name,
|
|
643
|
+
"config": {
|
|
644
|
+
"repo": args.repo,
|
|
645
|
+
"model": args.model,
|
|
646
|
+
"reflection_model": reflection_model,
|
|
647
|
+
"train_size": len(train_data),
|
|
648
|
+
"val_size": len(val_data),
|
|
649
|
+
},
|
|
650
|
+
}
|
|
651
|
+
if args.wandb
|
|
652
|
+
else None
|
|
653
|
+
)
|
|
654
|
+
|
|
655
|
+
# Configure LiteLLM for reflection model (OpenAI regional endpoint)
|
|
656
|
+
if "openai" in reflection_model.lower() or reflection_model.startswith("gpt-"):
|
|
657
|
+
os.environ["OPENAI_API_BASE"] = "https://us.api.openai.com/v1"
|
|
658
|
+
|
|
659
|
+
# Create proposer based on command line choice
|
|
660
|
+
if args.proposer == "loop":
|
|
661
|
+
proposer = LoopProposer(run_dir, reflection_model)
|
|
662
|
+
elif args.proposer == "batch":
|
|
663
|
+
proposer = LoggingProposer(run_dir, reflection_model)
|
|
664
|
+
|
|
665
|
+
config = GEPAConfig(
|
|
666
|
+
engine=EngineConfig(
|
|
667
|
+
run_dir=str(run_dir),
|
|
668
|
+
seed=args.seed,
|
|
669
|
+
display_progress_bar=True,
|
|
670
|
+
max_metric_calls=args.max_metric_calls,
|
|
671
|
+
candidate_selection_strategy="pareto",
|
|
672
|
+
parallel=True,
|
|
673
|
+
max_workers=args.workers,
|
|
674
|
+
),
|
|
675
|
+
reflection=ReflectionConfig(
|
|
676
|
+
reflection_lm=reflection_model,
|
|
677
|
+
reflection_minibatch_size=3,
|
|
678
|
+
skip_perfect_score=True,
|
|
679
|
+
perfect_score=1.0,
|
|
680
|
+
custom_candidate_proposer=proposer,
|
|
681
|
+
),
|
|
682
|
+
tracking=TrackingConfig(
|
|
683
|
+
use_wandb=args.wandb,
|
|
684
|
+
wandb_init_kwargs=wandb_kwargs,
|
|
685
|
+
),
|
|
686
|
+
stop_callbacks=stop_callbacks,
|
|
687
|
+
)
|
|
688
|
+
|
|
689
|
+
# 6. Baseline evaluations (before optimization)
|
|
690
|
+
original_config_results = None
|
|
691
|
+
baseline_test_results = None
|
|
692
|
+
if args.run_pre_optimization_testset or args.run_testset:
|
|
693
|
+
# 6a. Evaluate with original mini-swe-agent config (no skills placeholder)
|
|
694
|
+
original_config_path = Path(__file__).parent / "mini_swe_agent_config" / "original_mini.yaml"
|
|
695
|
+
print(f"\nEvaluating original mini-swe-agent config: {original_config_path}")
|
|
696
|
+
original_fitness_fn = create_swe_fitness_fn(
|
|
697
|
+
model_name=args.model, n_workers=args.workers, config_path=str(original_config_path)
|
|
698
|
+
)
|
|
699
|
+
original_config_results = evaluate_on_test(
|
|
700
|
+
original_fitness_fn, {"skills": ""}, test_data, name="Original mini-swe-agent"
|
|
701
|
+
)
|
|
702
|
+
with open(run_dir / "original_config_test_results.json", "w") as f:
|
|
703
|
+
json.dump(original_config_results, f, indent=2)
|
|
704
|
+
|
|
705
|
+
# 6b. Evaluate with GEPA template + empty skills
|
|
706
|
+
print("\nEvaluating GEPA template with empty skills")
|
|
707
|
+
baseline_test_results = evaluate_on_test(
|
|
708
|
+
fitness_fn, seed_candidate, test_data, name="GEPA template (empty skills)"
|
|
709
|
+
)
|
|
710
|
+
with open(run_dir / "baseline_test_results.json", "w") as f:
|
|
711
|
+
json.dump(baseline_test_results, f, indent=2)
|
|
712
|
+
|
|
713
|
+
# 7. Run GEPA
|
|
714
|
+
print("\n" + "=" * 70)
|
|
715
|
+
print("Starting GEPA Optimization (optimize_anything API)...")
|
|
716
|
+
print("=" * 70 + "\n")
|
|
717
|
+
|
|
718
|
+
result = optimize_anything(
|
|
719
|
+
seed_candidate=seed_candidate,
|
|
720
|
+
evaluator=fitness_fn,
|
|
721
|
+
dataset=train_data,
|
|
722
|
+
valset=val_data,
|
|
723
|
+
config=config,
|
|
724
|
+
)
|
|
725
|
+
|
|
726
|
+
# 7. Results
|
|
727
|
+
print("\n" + "=" * 70)
|
|
728
|
+
print("Optimization Complete!")
|
|
729
|
+
print("=" * 70)
|
|
730
|
+
|
|
731
|
+
# best_candidate is a dict: {"skills": "..."}
|
|
732
|
+
best_candidate_dict = result.best_candidate
|
|
733
|
+
if isinstance(best_candidate_dict, dict):
|
|
734
|
+
# It's already a dict with the prompt
|
|
735
|
+
best_skills = best_candidate_dict.get("skills", str(best_candidate_dict))
|
|
736
|
+
else:
|
|
737
|
+
# It's an object with .candidate attribute
|
|
738
|
+
best_skills = best_candidate_dict.candidate["skills"]
|
|
739
|
+
|
|
740
|
+
# Get best score from result
|
|
741
|
+
best_idx = result.best_idx
|
|
742
|
+
best_score = result.val_aggregate_scores[best_idx] if result.val_aggregate_scores else 0.0
|
|
743
|
+
num_candidates = result.num_candidates
|
|
744
|
+
|
|
745
|
+
print(f"\nBest Prompt (Score: {best_score:.2%}):")
|
|
746
|
+
print("-" * 70)
|
|
747
|
+
print(best_skills)
|
|
748
|
+
print("-" * 70)
|
|
749
|
+
|
|
750
|
+
# Save best skills
|
|
751
|
+
skills_file = run_dir / "prompts" / "best_skills.txt"
|
|
752
|
+
skills_file.parent.mkdir(exist_ok=True)
|
|
753
|
+
with open(skills_file, "w") as f:
|
|
754
|
+
f.write(best_skills)
|
|
755
|
+
|
|
756
|
+
print(f"\nBest skills saved to: {skills_file}")
|
|
757
|
+
print(f"Full results in: {run_dir}")
|
|
758
|
+
|
|
759
|
+
# 9. Post-optimization test evaluation
|
|
760
|
+
optimized_test_results = None
|
|
761
|
+
if args.run_post_optimization_testset or args.run_testset:
|
|
762
|
+
optimized_candidate = {"skills": best_skills}
|
|
763
|
+
optimized_test_results = evaluate_on_test(
|
|
764
|
+
fitness_fn, optimized_candidate, test_data, name="Optimized (after optimization)"
|
|
765
|
+
)
|
|
766
|
+
# Save optimized results
|
|
767
|
+
with open(run_dir / "optimized_test_results.json", "w") as f:
|
|
768
|
+
json.dump(optimized_test_results, f, indent=2)
|
|
769
|
+
|
|
770
|
+
# Print comparison
|
|
771
|
+
print("\n" + "=" * 70)
|
|
772
|
+
print("TEST SET COMPARISON")
|
|
773
|
+
print("=" * 70)
|
|
774
|
+
if original_config_results:
|
|
775
|
+
print(
|
|
776
|
+
f" Original mini-swe-agent: {original_config_results['pass_count']}/{original_config_results['total']} ({original_config_results['avg_score']:.1%})"
|
|
777
|
+
)
|
|
778
|
+
if baseline_test_results:
|
|
779
|
+
print(
|
|
780
|
+
f" GEPA template (empty): {baseline_test_results['pass_count']}/{baseline_test_results['total']} ({baseline_test_results['avg_score']:.1%})"
|
|
781
|
+
)
|
|
782
|
+
print(
|
|
783
|
+
f" GEPA optimized: {optimized_test_results['pass_count']}/{optimized_test_results['total']} ({optimized_test_results['avg_score']:.1%})"
|
|
784
|
+
)
|
|
785
|
+
if original_config_results:
|
|
786
|
+
improvement_from_original = optimized_test_results["avg_score"] - original_config_results["avg_score"]
|
|
787
|
+
print(f" Improvement over original: {improvement_from_original:+.1%}")
|
|
788
|
+
if baseline_test_results:
|
|
789
|
+
improvement_from_baseline = optimized_test_results["avg_score"] - baseline_test_results["avg_score"]
|
|
790
|
+
print(f" Improvement over baseline: {improvement_from_baseline:+.1%}")
|
|
791
|
+
print("=" * 70)
|
|
792
|
+
|
|
793
|
+
# Summary
|
|
794
|
+
summary_data = {
|
|
795
|
+
"best_score": float(best_score),
|
|
796
|
+
"num_candidates": num_candidates,
|
|
797
|
+
"total_metric_calls": result.total_metric_calls,
|
|
798
|
+
"final_skills_length": len(best_skills),
|
|
799
|
+
}
|
|
800
|
+
if original_config_results:
|
|
801
|
+
summary_data["original_config_test_score"] = original_config_results["avg_score"]
|
|
802
|
+
if baseline_test_results:
|
|
803
|
+
summary_data["baseline_test_score"] = baseline_test_results["avg_score"]
|
|
804
|
+
if optimized_test_results:
|
|
805
|
+
summary_data["optimized_test_score"] = optimized_test_results["avg_score"]
|
|
806
|
+
|
|
807
|
+
exp_logger.save_summary(best_prompt=best_skills, extra_info=summary_data)
|
|
808
|
+
|
|
809
|
+
print("\nSummary:")
|
|
810
|
+
print(f" Best Val Score: {best_score:.2%}")
|
|
811
|
+
print(f" Candidates Generated: {num_candidates}")
|
|
812
|
+
print(f" Total Metric Calls: {result.total_metric_calls}")
|
|
813
|
+
print(f" Final Skills Length: {len(best_skills)} chars")
|
|
814
|
+
if original_config_results:
|
|
815
|
+
print(f" Original Config Test Score: {original_config_results['avg_score']:.1%}")
|
|
816
|
+
if baseline_test_results:
|
|
817
|
+
print(f" Baseline Test Score: {baseline_test_results['avg_score']:.1%}")
|
|
818
|
+
if optimized_test_results:
|
|
819
|
+
print(f" Optimized Test Score: {optimized_test_results['avg_score']:.1%}")
|
|
820
|
+
|
|
821
|
+
print("\n" + "=" * 70)
|
|
822
|
+
print("Done!")
|
|
823
|
+
print("=" * 70 + "\n")
|
|
824
|
+
|
|
825
|
+
# Stop tee logging
|
|
826
|
+
tee.stop()
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
if __name__ == "__main__":
|
|
830
|
+
main()
|