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,641 @@
|
|
|
1
|
+
# Copyright (c) 2025 Lakshya A Agrawal and the GEPA contributors
|
|
2
|
+
# https://github.com/gepa-ai/gepa
|
|
3
|
+
|
|
4
|
+
import traceback
|
|
5
|
+
from collections.abc import Mapping, Sequence
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from gepa.core.adapter import (
|
|
9
|
+
DataInst,
|
|
10
|
+
EvaluationBatch,
|
|
11
|
+
GEPAAdapter,
|
|
12
|
+
ProposalFn,
|
|
13
|
+
RolloutOutput,
|
|
14
|
+
Trajectory,
|
|
15
|
+
default_batch_evaluate,
|
|
16
|
+
)
|
|
17
|
+
from gepa.core.callbacks import (
|
|
18
|
+
CandidateSelectedEvent,
|
|
19
|
+
EvaluationEndEvent,
|
|
20
|
+
EvaluationSkippedEvent,
|
|
21
|
+
EvaluationStartEvent,
|
|
22
|
+
GEPACallback,
|
|
23
|
+
MinibatchSampledEvent,
|
|
24
|
+
ProposalEndEvent,
|
|
25
|
+
ProposalStartEvent,
|
|
26
|
+
ReflectiveDatasetBuiltEvent,
|
|
27
|
+
notify_callbacks,
|
|
28
|
+
)
|
|
29
|
+
from gepa.core.data_loader import DataId, DataLoader, ensure_loader
|
|
30
|
+
from gepa.core.state import GEPAState, _candidate_hash
|
|
31
|
+
from gepa.proposer.base import CandidateProposal, SubsampleEvaluation
|
|
32
|
+
from gepa.proposer.reflective_mutation.base import (
|
|
33
|
+
CandidateSelector,
|
|
34
|
+
LanguageModel,
|
|
35
|
+
ReflectionComponentSelector,
|
|
36
|
+
)
|
|
37
|
+
from gepa.proposer.reflective_mutation.reflection_lm import ReflectionLM, StatelessReflectionLM
|
|
38
|
+
from gepa.strategies.batch_sampler import BatchSampler
|
|
39
|
+
from gepa.strategies.instruction_proposal import InstructionProposalSignature
|
|
40
|
+
from gepa.strategies.proposal_sampling import ProposalTask, SamplingStrategy, SingleMutationSampling
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ReflectiveMutationProposer:
|
|
44
|
+
"""Implements the reflective mutation flow.
|
|
45
|
+
|
|
46
|
+
Each iteration, the proposer:
|
|
47
|
+
|
|
48
|
+
1. Samples one or more (parent, minibatch) tasks via ``sampling_strategy``
|
|
49
|
+
2. Batch-evaluates all parents (deduplicated)
|
|
50
|
+
3. For each task: builds a reflective dataset and proposes new texts
|
|
51
|
+
4. Batch-evaluates all children
|
|
52
|
+
5. Returns ALL evaluated proposals as :class:`CandidateProposal` objects —
|
|
53
|
+
acceptance and selection are applied by the engine, which is the single
|
|
54
|
+
accept+select authority
|
|
55
|
+
|
|
56
|
+
With the default ``SingleMutationSampling``, this produces exactly one
|
|
57
|
+
task per iteration — matching GEPA's original sequential behavior.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __init__(
|
|
61
|
+
self,
|
|
62
|
+
logger: Any,
|
|
63
|
+
trainset: list[DataInst] | DataLoader[DataId, DataInst],
|
|
64
|
+
adapter: GEPAAdapter[DataInst, Trajectory, RolloutOutput],
|
|
65
|
+
candidate_selector: CandidateSelector,
|
|
66
|
+
module_selector: ReflectionComponentSelector,
|
|
67
|
+
batch_sampler: BatchSampler[DataId, DataInst],
|
|
68
|
+
perfect_score: float | None,
|
|
69
|
+
skip_perfect_score: bool,
|
|
70
|
+
experiment_tracker: Any,
|
|
71
|
+
reflection_lm: LanguageModel | None = None,
|
|
72
|
+
reflection_prompt_template: str | dict[str, str] | None = None,
|
|
73
|
+
custom_candidate_proposer: ProposalFn | None = None,
|
|
74
|
+
callbacks: list[GEPACallback] | None = None,
|
|
75
|
+
sampling_strategy: SamplingStrategy | None = None,
|
|
76
|
+
reflection_strategy: ReflectionLM | None = None,
|
|
77
|
+
):
|
|
78
|
+
self.logger = logger
|
|
79
|
+
self.trainset = ensure_loader(trainset)
|
|
80
|
+
self.adapter = adapter
|
|
81
|
+
self.candidate_selector = candidate_selector
|
|
82
|
+
self.module_selector = module_selector
|
|
83
|
+
self.batch_sampler = batch_sampler
|
|
84
|
+
self.perfect_score = perfect_score
|
|
85
|
+
self.skip_perfect_score = skip_perfect_score
|
|
86
|
+
self.experiment_tracker = experiment_tracker
|
|
87
|
+
self.reflection_lm = reflection_lm
|
|
88
|
+
self.custom_candidate_proposer = custom_candidate_proposer
|
|
89
|
+
self.callbacks = callbacks
|
|
90
|
+
self.sampling_strategy: SamplingStrategy = sampling_strategy or SingleMutationSampling()
|
|
91
|
+
|
|
92
|
+
self.reflection_prompt_template = reflection_prompt_template
|
|
93
|
+
|
|
94
|
+
if isinstance(reflection_prompt_template, dict):
|
|
95
|
+
for _param_name, template in reflection_prompt_template.items():
|
|
96
|
+
InstructionProposalSignature.validate_prompt_template(template)
|
|
97
|
+
else:
|
|
98
|
+
InstructionProposalSignature.validate_prompt_template(reflection_prompt_template)
|
|
99
|
+
|
|
100
|
+
if reflection_strategy is not None and (
|
|
101
|
+
adapter.propose_new_texts is not None or custom_candidate_proposer is not None
|
|
102
|
+
):
|
|
103
|
+
owner = (
|
|
104
|
+
"adapter.propose_new_texts"
|
|
105
|
+
if adapter.propose_new_texts is not None
|
|
106
|
+
else "custom_candidate_proposer"
|
|
107
|
+
)
|
|
108
|
+
raise ValueError(
|
|
109
|
+
f"reflection_strategy was provided, but {owner} owns proposal generation "
|
|
110
|
+
"and the reflection strategy would be silently ignored. Remove one of the two."
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Reflection LM (#329 Phase 1); None when an adapter/custom proposer owns
|
|
114
|
+
# reflection. An injected reflection_strategy — any ReflectionLM
|
|
115
|
+
# implementation, e.g. session-based or ComBEE-style aggregating
|
|
116
|
+
# reflectors (#329 Phase 2/3) — takes precedence over the stateless
|
|
117
|
+
# default built from the raw reflection_lm callable.
|
|
118
|
+
self._reflection_lm: ReflectionLM | None = reflection_strategy or (
|
|
119
|
+
StatelessReflectionLM(reflection_lm, reflection_prompt_template, logger)
|
|
120
|
+
if reflection_lm is not None
|
|
121
|
+
else None
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
if self.skip_perfect_score and self.perfect_score is None:
|
|
125
|
+
raise ValueError(
|
|
126
|
+
"perfect_score must be provided when skip_perfect_score is True. "
|
|
127
|
+
"If you do not have a perfect target score, set skip_perfect_score=False."
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
def propose_new_texts(
|
|
131
|
+
self,
|
|
132
|
+
candidate: dict[str, str],
|
|
133
|
+
reflective_dataset: Mapping[str, Sequence[Mapping[str, Any]]],
|
|
134
|
+
components_to_update: list[str],
|
|
135
|
+
) -> tuple[dict[str, str], dict[str, str | list[dict[str, Any]]], dict[str, str], dict[str, Any]]:
|
|
136
|
+
"""Propose new instruction texts for the given components.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
A tuple of (new_texts, prompts, raw_lm_outputs, reflection_metadata)
|
|
140
|
+
where the first three are dicts keyed by component name and
|
|
141
|
+
``reflection_metadata`` is the ReflectionLM's free-form diagnostics
|
|
142
|
+
(empty for single-call reflectors; multi-call strategies such as
|
|
143
|
+
ComBEE record per-call intermediates here).
|
|
144
|
+
"""
|
|
145
|
+
empty: dict[str, str | list[dict[str, Any]]] = {}
|
|
146
|
+
if self.adapter.propose_new_texts is not None:
|
|
147
|
+
return self.adapter.propose_new_texts(candidate, reflective_dataset, components_to_update), empty, {}, {}
|
|
148
|
+
|
|
149
|
+
if self.custom_candidate_proposer is not None:
|
|
150
|
+
return self.custom_candidate_proposer(candidate, reflective_dataset, components_to_update), empty, {}, {}
|
|
151
|
+
|
|
152
|
+
if self._reflection_lm is None:
|
|
153
|
+
raise ValueError("reflection_lm must be provided when adapter.propose_new_texts is None.")
|
|
154
|
+
|
|
155
|
+
# Delegate to the ReflectionLM (#329 Phase 1). Stateful implementations
|
|
156
|
+
# return a successor carrying accumulated context; chain it so session
|
|
157
|
+
# state actually persists (stateless implementations return self,
|
|
158
|
+
# making this a no-op).
|
|
159
|
+
proposal, next_lm = self._reflection_lm.reflect(candidate, reflective_dataset, components_to_update)
|
|
160
|
+
self._reflection_lm = next_lm
|
|
161
|
+
return proposal.new_texts, proposal.prompts, proposal.raw_lm_outputs, proposal.metadata
|
|
162
|
+
|
|
163
|
+
def _propose_texts_batch(
|
|
164
|
+
self, jobs: list[tuple[dict[str, str], Mapping[str, Sequence[Mapping[str, Any]]], list[str]]]
|
|
165
|
+
) -> list[tuple[dict[str, str], dict[str, str | list[dict[str, Any]]], dict[str, str], dict[str, Any]]]:
|
|
166
|
+
"""Propose new texts for many tasks, batching the reflection LM calls.
|
|
167
|
+
|
|
168
|
+
ReflectionLM implementations that provide ``reflect_many`` (e.g. the
|
|
169
|
+
stateless default, which issues one ``litellm.batch_completion``
|
|
170
|
+
covering every task/component) are batched; implementations that only
|
|
171
|
+
provide ``reflect()`` are called once per task. When an adapter
|
|
172
|
+
proposer or custom proposer owns the call, fall back to one invocation
|
|
173
|
+
per task — their batching, if any, is their concern.
|
|
174
|
+
"""
|
|
175
|
+
if (
|
|
176
|
+
self.adapter.propose_new_texts is not None
|
|
177
|
+
or self.custom_candidate_proposer is not None
|
|
178
|
+
or self._reflection_lm is None
|
|
179
|
+
):
|
|
180
|
+
return [self.propose_new_texts(cand, refds, comps) for cand, refds, comps in jobs]
|
|
181
|
+
|
|
182
|
+
reflect_many = getattr(self._reflection_lm, "reflect_many", None)
|
|
183
|
+
if reflect_many is not None:
|
|
184
|
+
results = list(reflect_many(jobs))
|
|
185
|
+
if len(results) != len(jobs):
|
|
186
|
+
raise ValueError(
|
|
187
|
+
f"ReflectionLM.reflect_many returned {len(results)} results for {len(jobs)} jobs"
|
|
188
|
+
)
|
|
189
|
+
else:
|
|
190
|
+
results = []
|
|
191
|
+
for cand, refds, comps in jobs:
|
|
192
|
+
proposal, next_lm = self._reflection_lm.reflect(cand, refds, comps)
|
|
193
|
+
self._reflection_lm = next_lm # chain stateful reflectors
|
|
194
|
+
results.append((proposal, next_lm))
|
|
195
|
+
if results:
|
|
196
|
+
# For batched reflection, chain to the final returned successor.
|
|
197
|
+
self._reflection_lm = results[-1][1]
|
|
198
|
+
return [
|
|
199
|
+
(proposal.new_texts, proposal.prompts, proposal.raw_lm_outputs, proposal.metadata)
|
|
200
|
+
for proposal, _next_lm in results
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
def _propose_texts_batch_safe(
|
|
204
|
+
self, jobs: list[tuple[dict[str, str], Mapping[str, Sequence[Mapping[str, Any]]], list[str]]]
|
|
205
|
+
) -> list[tuple[dict[str, str], dict[str, str | list[dict[str, Any]]], dict[str, str], dict[str, Any]] | None]:
|
|
206
|
+
"""Like :meth:`_propose_texts_batch`, but isolates per-task failures.
|
|
207
|
+
|
|
208
|
+
Returns ``None`` in the slot of any task whose reflection raised, so one
|
|
209
|
+
bad task (or a failed batch) does not sink the whole iteration.
|
|
210
|
+
"""
|
|
211
|
+
if not jobs:
|
|
212
|
+
return []
|
|
213
|
+
try:
|
|
214
|
+
return list(self._propose_texts_batch(jobs))
|
|
215
|
+
except Exception as e:
|
|
216
|
+
self.logger.log(f"Batched reflection failed ({e}); retrying per task.")
|
|
217
|
+
self.logger.log(traceback.format_exc())
|
|
218
|
+
out: list[tuple[dict[str, str], dict[str, str | list[dict[str, Any]]], dict[str, str], dict[str, Any]] | None] = []
|
|
219
|
+
for cand, refds, comps in jobs:
|
|
220
|
+
try:
|
|
221
|
+
out.append(self.propose_new_texts(cand, refds, comps))
|
|
222
|
+
except Exception as e2:
|
|
223
|
+
self.logger.log(f"Per-task reflection failed: {e2}")
|
|
224
|
+
out.append(None)
|
|
225
|
+
return out
|
|
226
|
+
|
|
227
|
+
# ------------------------------------------------------------------
|
|
228
|
+
# Batch evaluate helper
|
|
229
|
+
# ------------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
def _batch_evaluate(self, items: list[tuple[dict[str, str], list]]) -> list[EvaluationBatch]:
|
|
232
|
+
"""Evaluate (candidate, batch) pairs via the adapter's batch_evaluate or fallback."""
|
|
233
|
+
batch_fn = getattr(self.adapter, "batch_evaluate", None)
|
|
234
|
+
if batch_fn is not None:
|
|
235
|
+
return batch_fn(items)
|
|
236
|
+
return default_batch_evaluate(self.adapter, items)
|
|
237
|
+
|
|
238
|
+
# ------------------------------------------------------------------
|
|
239
|
+
# Main proposal method
|
|
240
|
+
# ------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
def propose(self, state: GEPAState) -> list[CandidateProposal]:
|
|
243
|
+
"""Run the reflective mutation pipeline and return all evaluated proposals.
|
|
244
|
+
|
|
245
|
+
The proposer generates and minibatch-evaluates candidates; acceptance and
|
|
246
|
+
selection (which to keep) are the engine's job. With the default
|
|
247
|
+
``SingleMutationSampling`` this returns at most one proposal — identical to
|
|
248
|
+
the original sequential behavior.
|
|
249
|
+
"""
|
|
250
|
+
i = state.i + 1
|
|
251
|
+
|
|
252
|
+
# Stage 1: Sample (parent, minibatch) tasks
|
|
253
|
+
tasks = self.sampling_strategy.sample_tasks(state, self.candidate_selector, self.batch_sampler, self.trainset)
|
|
254
|
+
if not tasks:
|
|
255
|
+
return []
|
|
256
|
+
|
|
257
|
+
# Fire callbacks for each sampled task
|
|
258
|
+
for task in tasks:
|
|
259
|
+
notify_callbacks(
|
|
260
|
+
self.callbacks,
|
|
261
|
+
"on_candidate_selected",
|
|
262
|
+
CandidateSelectedEvent(
|
|
263
|
+
iteration=i,
|
|
264
|
+
candidate_idx=task.parent_idx,
|
|
265
|
+
candidate=task.parent_candidate,
|
|
266
|
+
score=state.program_full_scores_val_set[task.parent_idx],
|
|
267
|
+
),
|
|
268
|
+
)
|
|
269
|
+
notify_callbacks(
|
|
270
|
+
self.callbacks,
|
|
271
|
+
"on_minibatch_sampled",
|
|
272
|
+
MinibatchSampledEvent(
|
|
273
|
+
iteration=i,
|
|
274
|
+
minibatch_ids=task.minibatch_ids,
|
|
275
|
+
trainset_size=len(self.trainset),
|
|
276
|
+
),
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# Stage 2: Batch evaluate parents (deduplicated)
|
|
280
|
+
unique_keys: dict[tuple[str, tuple], tuple[dict[str, str], list[Any]]] = {}
|
|
281
|
+
task_to_key: list[tuple[str, tuple]] = []
|
|
282
|
+
for task in tasks:
|
|
283
|
+
key = (_candidate_hash(task.parent_candidate), tuple(task.minibatch_ids))
|
|
284
|
+
unique_keys.setdefault(key, (task.parent_candidate, task.minibatch))
|
|
285
|
+
task_to_key.append(key)
|
|
286
|
+
|
|
287
|
+
key_list = list(unique_keys.keys())
|
|
288
|
+
items = [unique_keys[k] for k in key_list]
|
|
289
|
+
|
|
290
|
+
# Fire evaluation start callbacks for each task
|
|
291
|
+
for task in tasks:
|
|
292
|
+
notify_callbacks(
|
|
293
|
+
self.callbacks,
|
|
294
|
+
"on_evaluation_start",
|
|
295
|
+
EvaluationStartEvent(
|
|
296
|
+
iteration=i,
|
|
297
|
+
candidate_idx=task.parent_idx,
|
|
298
|
+
batch_size=len(task.minibatch),
|
|
299
|
+
capture_traces=True,
|
|
300
|
+
parent_ids=[p for p in state.parent_program_for_candidate[task.parent_idx] if p is not None],
|
|
301
|
+
inputs=task.minibatch,
|
|
302
|
+
is_seed_candidate=task.parent_idx == 0,
|
|
303
|
+
),
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
parent_evals = self._batch_evaluate(items)
|
|
307
|
+
key_to_eval: dict[tuple[str, tuple], EvaluationBatch] = dict(zip(key_list, parent_evals, strict=True))
|
|
308
|
+
|
|
309
|
+
# Fire evaluation end callbacks for each task
|
|
310
|
+
for task, key in zip(tasks, task_to_key, strict=True):
|
|
311
|
+
eval_curr = key_to_eval[key]
|
|
312
|
+
notify_callbacks(
|
|
313
|
+
self.callbacks,
|
|
314
|
+
"on_evaluation_end",
|
|
315
|
+
EvaluationEndEvent(
|
|
316
|
+
iteration=i,
|
|
317
|
+
candidate_idx=task.parent_idx,
|
|
318
|
+
scores=eval_curr.scores,
|
|
319
|
+
has_trajectories=bool(eval_curr.trajectories),
|
|
320
|
+
parent_ids=[p for p in state.parent_program_for_candidate[task.parent_idx] if p is not None],
|
|
321
|
+
outputs=eval_curr.outputs,
|
|
322
|
+
trajectories=eval_curr.trajectories,
|
|
323
|
+
objective_scores=eval_curr.objective_scores,
|
|
324
|
+
is_seed_candidate=task.parent_idx == 0,
|
|
325
|
+
),
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
total_parent_evals = sum(
|
|
329
|
+
e.num_metric_calls if e.num_metric_calls is not None else len(items[idx][1])
|
|
330
|
+
for idx, e in enumerate(parent_evals)
|
|
331
|
+
)
|
|
332
|
+
state.increment_evals(total_parent_evals)
|
|
333
|
+
|
|
334
|
+
# Update evaluation cache for parents
|
|
335
|
+
if state.evaluation_cache is not None:
|
|
336
|
+
for task, key in zip(tasks, task_to_key, strict=True):
|
|
337
|
+
eval_curr = key_to_eval[key]
|
|
338
|
+
objective_scores_list = list(eval_curr.objective_scores) if eval_curr.objective_scores else None
|
|
339
|
+
state.evaluation_cache.put_batch(
|
|
340
|
+
task.parent_candidate,
|
|
341
|
+
task.minibatch_ids,
|
|
342
|
+
eval_curr.outputs,
|
|
343
|
+
eval_curr.scores,
|
|
344
|
+
objective_scores_list,
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
# Trace: legacy first-task keys (pre-#329 tooling compatibility) plus
|
|
348
|
+
# full per-task records — multi-task iterations record every task, not
|
|
349
|
+
# just the first. Tasks that get skipped later simply never receive
|
|
350
|
+
# score keys.
|
|
351
|
+
first_task = tasks[0]
|
|
352
|
+
state.full_program_trace[-1]["selected_program_candidate"] = first_task.parent_idx
|
|
353
|
+
state.full_program_trace[-1]["subsample_ids"] = first_task.minibatch_ids
|
|
354
|
+
state.full_program_trace[-1]["n_tasks"] = len(tasks)
|
|
355
|
+
state.full_program_trace[-1]["tasks"] = [
|
|
356
|
+
{"parent_idx": task.parent_idx, "subsample_ids": list(task.minibatch_ids)} for task in tasks
|
|
357
|
+
]
|
|
358
|
+
self.logger.log(
|
|
359
|
+
f"Iteration {i}: Selected program {first_task.parent_idx} "
|
|
360
|
+
f"score: {state.program_full_scores_val_set[first_task.parent_idx]}"
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
self.experiment_tracker.log_metrics(
|
|
364
|
+
{
|
|
365
|
+
"iteration": i,
|
|
366
|
+
"selected_program_candidate": first_task.parent_idx,
|
|
367
|
+
"total_metric_calls": state.total_num_evals,
|
|
368
|
+
},
|
|
369
|
+
step=i,
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
# Stage 3a: Build reflective datasets + fire pre-reflection callbacks (per task).
|
|
373
|
+
# ``prepared`` holds one slot per task (None = skipped); ``jobs`` is the
|
|
374
|
+
# subset that will reflect, in order, so the reflection LM can batch them.
|
|
375
|
+
prepared: list[tuple[ProposalTask, EvaluationBatch, list[str], Any] | None] = []
|
|
376
|
+
for task, key in zip(tasks, task_to_key, strict=True):
|
|
377
|
+
eval_curr = key_to_eval[key]
|
|
378
|
+
|
|
379
|
+
if not eval_curr.trajectories:
|
|
380
|
+
self.logger.log(f"Iteration {i}: No trajectories for parent {task.parent_idx}. Skipping.")
|
|
381
|
+
notify_callbacks(
|
|
382
|
+
self.callbacks,
|
|
383
|
+
"on_evaluation_skipped",
|
|
384
|
+
EvaluationSkippedEvent(
|
|
385
|
+
iteration=i,
|
|
386
|
+
candidate_idx=task.parent_idx,
|
|
387
|
+
reason="no_trajectories",
|
|
388
|
+
scores=eval_curr.scores,
|
|
389
|
+
is_seed_candidate=task.parent_idx == 0,
|
|
390
|
+
),
|
|
391
|
+
)
|
|
392
|
+
prepared.append(None)
|
|
393
|
+
continue
|
|
394
|
+
|
|
395
|
+
if (
|
|
396
|
+
self.skip_perfect_score
|
|
397
|
+
and self.perfect_score is not None
|
|
398
|
+
and all(s is not None and s >= self.perfect_score for s in eval_curr.scores)
|
|
399
|
+
):
|
|
400
|
+
self.logger.log(f"Iteration {i}: All subsample scores perfect for parent {task.parent_idx}. Skipping.")
|
|
401
|
+
notify_callbacks(
|
|
402
|
+
self.callbacks,
|
|
403
|
+
"on_evaluation_skipped",
|
|
404
|
+
EvaluationSkippedEvent(
|
|
405
|
+
iteration=i,
|
|
406
|
+
candidate_idx=task.parent_idx,
|
|
407
|
+
reason="all_scores_perfect",
|
|
408
|
+
scores=eval_curr.scores,
|
|
409
|
+
is_seed_candidate=task.parent_idx == 0,
|
|
410
|
+
),
|
|
411
|
+
)
|
|
412
|
+
prepared.append(None)
|
|
413
|
+
continue
|
|
414
|
+
|
|
415
|
+
predictor_names = self.module_selector(
|
|
416
|
+
state, eval_curr.trajectories, eval_curr.scores, task.parent_idx, task.parent_candidate
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
try:
|
|
420
|
+
reflective_dataset = self.adapter.make_reflective_dataset(
|
|
421
|
+
task.parent_candidate, eval_curr, predictor_names
|
|
422
|
+
)
|
|
423
|
+
reflective_dataset_concrete: dict[str, list[dict[str, Any]]] = {
|
|
424
|
+
k: [dict(item) for item in v] for k, v in reflective_dataset.items()
|
|
425
|
+
}
|
|
426
|
+
notify_callbacks(
|
|
427
|
+
self.callbacks,
|
|
428
|
+
"on_reflective_dataset_built",
|
|
429
|
+
ReflectiveDatasetBuiltEvent(
|
|
430
|
+
iteration=i,
|
|
431
|
+
candidate_idx=task.parent_idx,
|
|
432
|
+
components=predictor_names,
|
|
433
|
+
dataset=reflective_dataset_concrete,
|
|
434
|
+
),
|
|
435
|
+
)
|
|
436
|
+
notify_callbacks(
|
|
437
|
+
self.callbacks,
|
|
438
|
+
"on_proposal_start",
|
|
439
|
+
ProposalStartEvent(
|
|
440
|
+
iteration=i,
|
|
441
|
+
parent_candidate=task.parent_candidate,
|
|
442
|
+
components=predictor_names,
|
|
443
|
+
reflective_dataset=reflective_dataset_concrete,
|
|
444
|
+
),
|
|
445
|
+
)
|
|
446
|
+
except Exception as e:
|
|
447
|
+
self.logger.log(f"Iteration {i}: Exception building reflective dataset: {e}")
|
|
448
|
+
self.logger.log(traceback.format_exc())
|
|
449
|
+
prepared.append(None)
|
|
450
|
+
continue
|
|
451
|
+
|
|
452
|
+
prepared.append((task, eval_curr, predictor_names, reflective_dataset))
|
|
453
|
+
|
|
454
|
+
# Stage 3b: Reflect across all prepared tasks — one batched LM call when the
|
|
455
|
+
# reflection LM supports it (litellm.batch_completion), else per task.
|
|
456
|
+
jobs = [(p[0].parent_candidate, p[3], p[2]) for p in prepared if p is not None]
|
|
457
|
+
batch_texts = iter(self._propose_texts_batch_safe(jobs))
|
|
458
|
+
|
|
459
|
+
# Stage 3c: Build each child candidate from its proposed texts.
|
|
460
|
+
children: list[tuple[ProposalTask, dict[str, str], EvaluationBatch, dict[str, Any]] | None] = []
|
|
461
|
+
for p in prepared:
|
|
462
|
+
if p is None:
|
|
463
|
+
children.append(None)
|
|
464
|
+
continue
|
|
465
|
+
task, eval_curr, _predictor_names, _reflective_dataset = p
|
|
466
|
+
texts = next(batch_texts)
|
|
467
|
+
if texts is None:
|
|
468
|
+
children.append(None)
|
|
469
|
+
continue
|
|
470
|
+
new_texts, prompts, raw_outputs, reflection_metadata = texts
|
|
471
|
+
|
|
472
|
+
if not new_texts:
|
|
473
|
+
# Reflection produced no text updates (e.g. every requested
|
|
474
|
+
# component was missing from the reflective dataset). A child
|
|
475
|
+
# would be byte-identical to its parent: don't burn minibatch
|
|
476
|
+
# metric calls evaluating it or emit proposal/rejection events
|
|
477
|
+
# for a proposal that never happened.
|
|
478
|
+
self.logger.log(
|
|
479
|
+
f"Iteration {i}: Reflection returned no text updates; skipping proposal for this task."
|
|
480
|
+
)
|
|
481
|
+
children.append(None)
|
|
482
|
+
continue
|
|
483
|
+
|
|
484
|
+
notify_callbacks(
|
|
485
|
+
self.callbacks,
|
|
486
|
+
"on_proposal_end",
|
|
487
|
+
ProposalEndEvent(
|
|
488
|
+
iteration=i,
|
|
489
|
+
new_instructions=new_texts,
|
|
490
|
+
prompts=prompts,
|
|
491
|
+
raw_lm_outputs=raw_outputs,
|
|
492
|
+
),
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
_lm_metadata: dict[str, Any] = {}
|
|
496
|
+
# Stable per-proposal identifier (iteration-taskindex): downstream
|
|
497
|
+
# consumers (run manifests, #346's per-proposal state anchors) can
|
|
498
|
+
# key on this instead of positional inference.
|
|
499
|
+
_lm_metadata["proposal_id"] = f"{i}-{len(children)}"
|
|
500
|
+
for comp in new_texts:
|
|
501
|
+
_lm_metadata[f"prompt:{comp}"] = prompts.get(comp, "")
|
|
502
|
+
_lm_metadata[f"raw_lm_output:{comp}"] = raw_outputs.get(comp, "")
|
|
503
|
+
# Multi-call reflection diagnostics (e.g. ComBEE per-call
|
|
504
|
+
# intermediates) flow into the proposal metadata for callbacks,
|
|
505
|
+
# trackers, and the run manifest. Keys that would collide with the
|
|
506
|
+
# reserved prompt:/raw_lm_output: namespaces are remapped so a
|
|
507
|
+
# reflector cannot inject phantom components into proposal tables.
|
|
508
|
+
for meta_key, meta_val in (reflection_metadata or {}).items():
|
|
509
|
+
if meta_key.startswith(("prompt:", "raw_lm_output:")):
|
|
510
|
+
_lm_metadata[f"reflection_meta:{meta_key}"] = meta_val
|
|
511
|
+
else:
|
|
512
|
+
_lm_metadata[meta_key] = meta_val
|
|
513
|
+
|
|
514
|
+
for pname, text in new_texts.items():
|
|
515
|
+
self.logger.log(f"Iteration {i}: Proposed new text for {pname}: {text}")
|
|
516
|
+
|
|
517
|
+
new_candidate = task.parent_candidate.copy()
|
|
518
|
+
for name, text in new_texts.items():
|
|
519
|
+
assert name in new_candidate, f"{name} missing in candidate"
|
|
520
|
+
new_candidate[name] = text
|
|
521
|
+
|
|
522
|
+
children.append((task, new_candidate, eval_curr, _lm_metadata))
|
|
523
|
+
|
|
524
|
+
# Stage 4: Batch evaluate children
|
|
525
|
+
valid_children = [(idx, c) for idx, c in enumerate(children) if c is not None]
|
|
526
|
+
if not valid_children:
|
|
527
|
+
return []
|
|
528
|
+
|
|
529
|
+
child_items = [(c[1], c[0].minibatch) for _, c in valid_children]
|
|
530
|
+
|
|
531
|
+
# Fire evaluation start callbacks for each child candidate (parity with
|
|
532
|
+
# the pre-batch sequential path, which emitted these around the new
|
|
533
|
+
# candidate's minibatch evaluation; candidate_idx is None because the
|
|
534
|
+
# child is not in the candidate pool yet)
|
|
535
|
+
for _, (task, _new_candidate, _eval_curr, _meta) in valid_children:
|
|
536
|
+
notify_callbacks(
|
|
537
|
+
self.callbacks,
|
|
538
|
+
"on_evaluation_start",
|
|
539
|
+
EvaluationStartEvent(
|
|
540
|
+
iteration=i,
|
|
541
|
+
candidate_idx=None,
|
|
542
|
+
batch_size=len(task.minibatch),
|
|
543
|
+
capture_traces=True,
|
|
544
|
+
parent_ids=[task.parent_idx],
|
|
545
|
+
inputs=task.minibatch,
|
|
546
|
+
is_seed_candidate=False,
|
|
547
|
+
),
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
child_evals = self._batch_evaluate(child_items)
|
|
551
|
+
|
|
552
|
+
# Fire evaluation end callbacks for each child candidate
|
|
553
|
+
for (_, (task, _new_candidate, _eval_curr, _meta)), child_eval in zip(valid_children, child_evals, strict=True):
|
|
554
|
+
notify_callbacks(
|
|
555
|
+
self.callbacks,
|
|
556
|
+
"on_evaluation_end",
|
|
557
|
+
EvaluationEndEvent(
|
|
558
|
+
iteration=i,
|
|
559
|
+
candidate_idx=None,
|
|
560
|
+
scores=child_eval.scores,
|
|
561
|
+
has_trajectories=bool(child_eval.trajectories),
|
|
562
|
+
parent_ids=[task.parent_idx],
|
|
563
|
+
outputs=child_eval.outputs,
|
|
564
|
+
trajectories=child_eval.trajectories,
|
|
565
|
+
objective_scores=child_eval.objective_scores,
|
|
566
|
+
is_seed_candidate=False,
|
|
567
|
+
),
|
|
568
|
+
)
|
|
569
|
+
|
|
570
|
+
total_child_evals = sum(
|
|
571
|
+
e.num_metric_calls if e.num_metric_calls is not None else len(child_items[idx][1])
|
|
572
|
+
for idx, e in enumerate(child_evals)
|
|
573
|
+
)
|
|
574
|
+
state.increment_evals(total_child_evals)
|
|
575
|
+
|
|
576
|
+
# Update evaluation cache for children
|
|
577
|
+
if state.evaluation_cache is not None:
|
|
578
|
+
for (_, (task, new_candidate, _, _)), child_eval in zip(valid_children, child_evals, strict=True):
|
|
579
|
+
new_obj_scores = list(child_eval.objective_scores) if child_eval.objective_scores else None
|
|
580
|
+
state.evaluation_cache.put_batch(
|
|
581
|
+
new_candidate, task.minibatch_ids, child_eval.outputs, child_eval.scores, new_obj_scores
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
# Trace: per-task before/after scores (children is index-aligned with tasks)
|
|
585
|
+
trace_tasks = state.full_program_trace[-1].get("tasks")
|
|
586
|
+
if trace_tasks is not None:
|
|
587
|
+
for (child_idx, (_task, _nc, eval_curr, _md)), child_eval in zip(valid_children, child_evals, strict=True):
|
|
588
|
+
trace_tasks[child_idx]["subsample_scores"] = list(eval_curr.scores)
|
|
589
|
+
trace_tasks[child_idx]["new_subsample_scores"] = list(child_eval.scores)
|
|
590
|
+
|
|
591
|
+
# Log subsample scores for first task (trace compatibility)
|
|
592
|
+
if valid_children:
|
|
593
|
+
first_child_idx = valid_children[0][0]
|
|
594
|
+
first_child = children[first_child_idx]
|
|
595
|
+
if first_child is not None:
|
|
596
|
+
state.full_program_trace[-1]["subsample_scores"] = key_to_eval[task_to_key[first_child_idx]].scores
|
|
597
|
+
state.full_program_trace[-1]["new_subsample_scores"] = child_evals[0].scores
|
|
598
|
+
|
|
599
|
+
subsample_before = sum(key_to_eval[task_to_key[first_child_idx]].scores)
|
|
600
|
+
subsample_after = sum(child_evals[0].scores)
|
|
601
|
+
self.experiment_tracker.log_metrics(
|
|
602
|
+
{
|
|
603
|
+
# pre-#329 key names, kept for existing dashboards
|
|
604
|
+
"subsample_score": subsample_before,
|
|
605
|
+
"new_subsample_score": subsample_after,
|
|
606
|
+
"subsample/before": subsample_before,
|
|
607
|
+
"subsample/after": subsample_after,
|
|
608
|
+
"total_metric_calls": state.total_num_evals,
|
|
609
|
+
},
|
|
610
|
+
step=i,
|
|
611
|
+
)
|
|
612
|
+
|
|
613
|
+
# Stage 5: Build proposals and filter
|
|
614
|
+
proposals: list[CandidateProposal] = []
|
|
615
|
+
for (_, (task, new_candidate, eval_curr, _lm_metadata)), child_eval in zip(
|
|
616
|
+
valid_children, child_evals, strict=True
|
|
617
|
+
):
|
|
618
|
+
proposal = CandidateProposal(
|
|
619
|
+
candidate=new_candidate,
|
|
620
|
+
parent_program_ids=[task.parent_idx],
|
|
621
|
+
subsample_indices=task.minibatch_ids,
|
|
622
|
+
subsample_scores_before=eval_curr.scores,
|
|
623
|
+
subsample_scores_after=child_eval.scores,
|
|
624
|
+
eval_before=SubsampleEvaluation(
|
|
625
|
+
scores=eval_curr.scores,
|
|
626
|
+
outputs=eval_curr.outputs,
|
|
627
|
+
objective_scores=list(eval_curr.objective_scores) if eval_curr.objective_scores else None,
|
|
628
|
+
trajectories=eval_curr.trajectories,
|
|
629
|
+
),
|
|
630
|
+
eval_after=SubsampleEvaluation(
|
|
631
|
+
scores=child_eval.scores,
|
|
632
|
+
outputs=child_eval.outputs,
|
|
633
|
+
objective_scores=list(child_eval.objective_scores) if child_eval.objective_scores else None,
|
|
634
|
+
trajectories=child_eval.trajectories,
|
|
635
|
+
),
|
|
636
|
+
tag="reflective_mutation",
|
|
637
|
+
metadata=_lm_metadata,
|
|
638
|
+
)
|
|
639
|
+
proposals.append(proposal)
|
|
640
|
+
|
|
641
|
+
return proposals
|
|
File without changes
|
|
File without changes
|