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,269 @@
|
|
|
1
|
+
"""Official GEPA execution wiring for the Orizu adapter and callback bridge."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable, Sequence
|
|
6
|
+
import dataclasses
|
|
7
|
+
import json
|
|
8
|
+
import random
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from gepa import optimize
|
|
12
|
+
from gepa.strategies.candidate_selector import EpsilonGreedyCandidateSelector
|
|
13
|
+
from orizu_gepa.optimizer import TextGepaConfig
|
|
14
|
+
|
|
15
|
+
from .callbacks import LifecycleHooks, OrizuCallback
|
|
16
|
+
from .preflight import validate_seed_and_scorer
|
|
17
|
+
from .stop_conditions import ProposalBudgetStopper
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _row_id(row: Any, index: int) -> str:
|
|
21
|
+
value = getattr(row, "id", row.get("id") if isinstance(row, dict) else None)
|
|
22
|
+
if value is None:
|
|
23
|
+
raise ValueError(f"GEPA dataset row at index {index} is missing its id")
|
|
24
|
+
return str(value)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _RowIdentityLoader:
|
|
28
|
+
"""Expose Orizu dataset ids to GEPA instead of its positional list ids."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, rows: Sequence[Any]):
|
|
31
|
+
self._rows_by_id = {_row_id(row, index): row for index, row in enumerate(rows)}
|
|
32
|
+
if len(self._rows_by_id) != len(rows):
|
|
33
|
+
raise ValueError("GEPA datasets require unique DatasetRow ids")
|
|
34
|
+
|
|
35
|
+
def all_ids(self) -> list[str]:
|
|
36
|
+
return list(self._rows_by_id)
|
|
37
|
+
|
|
38
|
+
def fetch(self, row_ids: Sequence[str]) -> list[Any]:
|
|
39
|
+
return [self._rows_by_id[str(row_id)] for row_id in row_ids]
|
|
40
|
+
|
|
41
|
+
def __len__(self) -> int:
|
|
42
|
+
return len(self._rows_by_id)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _with_row_identities(rows: Sequence[Any]) -> Any:
|
|
46
|
+
"""Keep caller-supplied loaders, otherwise prevent cross-split cache aliasing."""
|
|
47
|
+
if hasattr(rows, "all_ids") and hasattr(rows, "fetch"):
|
|
48
|
+
return rows
|
|
49
|
+
return _RowIdentityLoader(rows)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class SeedValidationRefused(RuntimeError):
|
|
53
|
+
"""Raised before a run is started when the scored seed has no gradient."""
|
|
54
|
+
|
|
55
|
+
def __init__(self, verdict: dict[str, Any], *, preflight_record_path: str | None = None):
|
|
56
|
+
self.verdict = verdict
|
|
57
|
+
self.preflight_record_path = preflight_record_path
|
|
58
|
+
message = (
|
|
59
|
+
f"{verdict['reason']}: preflight row evidence="
|
|
60
|
+
f"{json.dumps(verdict.get('row_evidence', []), ensure_ascii=False, default=str)}"
|
|
61
|
+
)
|
|
62
|
+
if preflight_record_path is not None:
|
|
63
|
+
message += f"; preflight record={preflight_record_path}"
|
|
64
|
+
super().__init__(message)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _preflight_row_evidence(rows: list[Any], scores: list[float], outputs: list[Any]) -> list[dict[str, Any]]:
|
|
68
|
+
"""Keep the raw scorer evidence that explains a preflight refusal."""
|
|
69
|
+
evidence: list[dict[str, Any]] = []
|
|
70
|
+
for index, score in enumerate(scores):
|
|
71
|
+
output = outputs[index] if index < len(outputs) and isinstance(outputs[index], dict) else {}
|
|
72
|
+
row = rows[index] if index < len(rows) else None
|
|
73
|
+
scorer_error = output.get("scorer_error")
|
|
74
|
+
if scorer_error is None and output.get("error_source") == "scorer":
|
|
75
|
+
scorer_error = output.get("error")
|
|
76
|
+
item = {
|
|
77
|
+
"row_id": output.get("row_id", getattr(row, "id", None)),
|
|
78
|
+
"score": score,
|
|
79
|
+
"scorer_output": output.get("scorer_output", output.get("scorer_response")),
|
|
80
|
+
"scorer_error": scorer_error,
|
|
81
|
+
}
|
|
82
|
+
if output.get("error") is not None:
|
|
83
|
+
item["execution_error"] = output["error"]
|
|
84
|
+
item["execution_error_source"] = output.get("error_source")
|
|
85
|
+
evidence.append(item)
|
|
86
|
+
return evidence
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _validate_seed_before_run(*, seed_candidate: dict[str, str], valset: list[Any], adapter: Any,
|
|
90
|
+
hooks: LifecycleHooks, allow_degenerate_seed: bool) -> tuple[dict[str, Any], Any, list[Any]]:
|
|
91
|
+
"""Cheap scorer preflight; GEPA owns the single full seed validation."""
|
|
92
|
+
# The approved cap bounds preflight spend. With a binary scorer and a seed
|
|
93
|
+
# that is correct 70% of the time, all three sampled rows can still score
|
|
94
|
+
# zero with probability 0.3**3 = 2.7%; do not silently change that policy.
|
|
95
|
+
preflight_rows = valset[:min(3, len(valset))]
|
|
96
|
+
seed_evaluation = adapter.evaluate(preflight_rows, seed_candidate, capture_traces=True)
|
|
97
|
+
scores = list(seed_evaluation.scores)
|
|
98
|
+
verdict = validate_seed_and_scorer(
|
|
99
|
+
scores=scores,
|
|
100
|
+
row_evidence=_preflight_row_evidence(preflight_rows, scores, list(seed_evaluation.outputs)),
|
|
101
|
+
allow_degenerate_seed=allow_degenerate_seed,
|
|
102
|
+
higher_is_better=getattr(getattr(adapter, "scorer_context", None), "higher_is_better", True),
|
|
103
|
+
)
|
|
104
|
+
verdict["preflight_metric_calls"] = getattr(adapter, "metric_calls_used", seed_evaluation.num_metric_calls)
|
|
105
|
+
hooks.emit("seed_validated", verdict)
|
|
106
|
+
if not verdict["allowed"]:
|
|
107
|
+
raise SeedValidationRefused(verdict)
|
|
108
|
+
return verdict, seed_evaluation, preflight_rows
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def validate_seed_before_run(*, seed_candidate: dict[str, str], valset: list[Any], adapter: Any,
|
|
112
|
+
hooks: LifecycleHooks, allow_degenerate_seed: bool) -> dict[str, Any]:
|
|
113
|
+
"""Validate the seed and return the durable public preflight verdict."""
|
|
114
|
+
verdict, _evaluation, _rows = _validate_seed_before_run(
|
|
115
|
+
seed_candidate=seed_candidate,
|
|
116
|
+
valset=valset,
|
|
117
|
+
adapter=adapter,
|
|
118
|
+
hooks=hooks,
|
|
119
|
+
allow_degenerate_seed=allow_degenerate_seed,
|
|
120
|
+
)
|
|
121
|
+
return verdict
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class _PreflightReusingAdapter:
|
|
125
|
+
"""Serve GEPA's immediate seed evaluation from the completed preflight."""
|
|
126
|
+
|
|
127
|
+
def __init__(self, adapter: Any, seed_candidate: dict[str, str], rows: list[Any], evaluation: Any):
|
|
128
|
+
self._adapter = adapter
|
|
129
|
+
self._seed_candidate = seed_candidate
|
|
130
|
+
self._rows = rows
|
|
131
|
+
self._evaluation = evaluation
|
|
132
|
+
self._served_seed = False
|
|
133
|
+
|
|
134
|
+
def evaluate(self, batch: list[Any], candidate: dict[str, str], capture_traces: bool = False):
|
|
135
|
+
if (not self._served_seed and not capture_traces and candidate == self._seed_candidate
|
|
136
|
+
and list(batch) == self._rows):
|
|
137
|
+
self._served_seed = True
|
|
138
|
+
return self._evaluation
|
|
139
|
+
return self._adapter.evaluate(batch, candidate, capture_traces=capture_traces)
|
|
140
|
+
|
|
141
|
+
def __getattr__(self, name: str) -> Any:
|
|
142
|
+
return getattr(self._adapter, name)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def run_official_gepa(
|
|
146
|
+
*,
|
|
147
|
+
seed_candidate: dict[str, str],
|
|
148
|
+
trainset: list[Any],
|
|
149
|
+
valset: list[Any],
|
|
150
|
+
adapter: Any,
|
|
151
|
+
callback: Any,
|
|
152
|
+
hooks: LifecycleHooks,
|
|
153
|
+
max_metric_calls: int | None = None,
|
|
154
|
+
stop_callbacks: Sequence[Callable[[Any], bool]] = (),
|
|
155
|
+
allow_degenerate_seed: bool = False,
|
|
156
|
+
reflection_lm: Callable[[str], str] | None = None,
|
|
157
|
+
custom_candidate_proposer: Callable[..., dict[str, str]] | None = None,
|
|
158
|
+
proposal_budget: Any | None = None,
|
|
159
|
+
seed_already_validated: bool = False,
|
|
160
|
+
config: TextGepaConfig | None = None,
|
|
161
|
+
module_selector: str = "round_robin",
|
|
162
|
+
) -> Any:
|
|
163
|
+
"""Run GEPA after the launch-time seed check and emit named lifecycle hooks.
|
|
164
|
+
|
|
165
|
+
The seed pass is deliberately outside ``optimize``: a bad scorer/seed is
|
|
166
|
+
refused before an optimization run exists or any configured GEPA budget is
|
|
167
|
+
consumed. The actual GEPA loop remains responsible for every later
|
|
168
|
+
stopping boundary.
|
|
169
|
+
"""
|
|
170
|
+
# Full-valset evaluations bypass GEPA's evaluation callbacks. Give the
|
|
171
|
+
# callback the real adapter so it can turn GEPA's positional score keys
|
|
172
|
+
# into the adapter's durable dataset row identities.
|
|
173
|
+
if isinstance(callback, OrizuCallback):
|
|
174
|
+
callback.evaluation_adapter = adapter
|
|
175
|
+
callback.validation_row_ids = [_row_id(row, index) for index, row in enumerate(valset)]
|
|
176
|
+
|
|
177
|
+
preflight_evaluation = None
|
|
178
|
+
preflight_rows: list[Any] = []
|
|
179
|
+
if not seed_already_validated:
|
|
180
|
+
_verdict, preflight_evaluation, preflight_rows = _validate_seed_before_run(
|
|
181
|
+
seed_candidate=seed_candidate,
|
|
182
|
+
valset=valset,
|
|
183
|
+
adapter=adapter,
|
|
184
|
+
hooks=hooks,
|
|
185
|
+
allow_degenerate_seed=allow_degenerate_seed,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# GEPA 0.1.4 reads this optional protocol attribute directly in its
|
|
189
|
+
# reflective proposer, even when a custom proposer owns the call. Our
|
|
190
|
+
# runner adapter supplies it; lightweight adapters used by the real GEPA
|
|
191
|
+
# boundary do not. Normalize the vendor's optional slot without replacing
|
|
192
|
+
# an adapter-owned proposer.
|
|
193
|
+
if custom_candidate_proposer is not None and not hasattr(adapter, "propose_new_texts"):
|
|
194
|
+
adapter.propose_new_texts = None
|
|
195
|
+
|
|
196
|
+
gepa_adapter = adapter
|
|
197
|
+
if custom_candidate_proposer is not None and preflight_evaluation is not None:
|
|
198
|
+
# A one-row low metric ceiling otherwise pays for this same seed row a
|
|
199
|
+
# second time inside GEPA before it reaches the custom proposal. The
|
|
200
|
+
# cached result is already a real evaluator result from this call's
|
|
201
|
+
# mandatory preflight; only the duplicate evaluator invocation is
|
|
202
|
+
# removed, never the separate proposal ledger.
|
|
203
|
+
gepa_adapter = _PreflightReusingAdapter(adapter, seed_candidate, preflight_rows, preflight_evaluation)
|
|
204
|
+
if custom_candidate_proposer is not None:
|
|
205
|
+
# GEPA refuses an adapter-owned proposer alongside its explicit custom
|
|
206
|
+
# proposer. The latter is the selected skilled-proposer path.
|
|
207
|
+
gepa_adapter.propose_new_texts = None
|
|
208
|
+
|
|
209
|
+
config = config or TextGepaConfig()
|
|
210
|
+
candidate_selection_strategy: Any = config.candidate_selection_strategy
|
|
211
|
+
# Official GEPA's string shortcut fixes epsilon at 0.1. Use its public
|
|
212
|
+
# selector class so the legacy --epsilon contract remains observable.
|
|
213
|
+
if candidate_selection_strategy == "epsilon_greedy":
|
|
214
|
+
candidate_selection_strategy = EpsilonGreedyCandidateSelector(
|
|
215
|
+
epsilon=max(0.0, min(1.0, config.epsilon)),
|
|
216
|
+
rng=random.Random(config.seed),
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
owned_stop_callbacks = list(stop_callbacks)
|
|
220
|
+
if proposal_budget is not None:
|
|
221
|
+
owned_stop_callbacks.append(ProposalBudgetStopper(proposal_budget))
|
|
222
|
+
|
|
223
|
+
reflection_minibatch_size = config.minibatch_size
|
|
224
|
+
if custom_candidate_proposer is not None and max_metric_calls is not None:
|
|
225
|
+
# GEPA's metric stopper is evaluated at iteration boundaries. Do not
|
|
226
|
+
# let its default three-row reflection batch overshoot a deliberately
|
|
227
|
+
# smaller evaluator-only ceiling before that boundary is observed.
|
|
228
|
+
reflection_minibatch_size = min(
|
|
229
|
+
reflection_minibatch_size,
|
|
230
|
+
max(1, max_metric_calls - len(valset)),
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
kwargs: dict[str, Any] = {
|
|
234
|
+
"seed_candidate": seed_candidate,
|
|
235
|
+
"trainset": trainset,
|
|
236
|
+
"valset": valset,
|
|
237
|
+
"adapter": gepa_adapter,
|
|
238
|
+
"callbacks": [callback],
|
|
239
|
+
"stop_callbacks": owned_stop_callbacks or None,
|
|
240
|
+
"max_metric_calls": max_metric_calls,
|
|
241
|
+
"candidate_selection_strategy": candidate_selection_strategy,
|
|
242
|
+
"skip_perfect_score": config.skip_perfect_parent_reflection,
|
|
243
|
+
"reflection_minibatch_size": reflection_minibatch_size,
|
|
244
|
+
"cache_evaluation": config.cache_evaluations,
|
|
245
|
+
"seed": config.seed,
|
|
246
|
+
"display_progress_bar": False,
|
|
247
|
+
"raise_on_exception": True,
|
|
248
|
+
"module_selector": module_selector,
|
|
249
|
+
}
|
|
250
|
+
if reflection_lm is not None:
|
|
251
|
+
kwargs["reflection_lm"] = reflection_lm
|
|
252
|
+
# The connector implements GEPA's component-aware strategy protocol;
|
|
253
|
+
# passing it as a bare callable would discard the selected component.
|
|
254
|
+
kwargs["reflection_strategy"] = reflection_lm
|
|
255
|
+
if custom_candidate_proposer is not None:
|
|
256
|
+
kwargs["custom_candidate_proposer"] = custom_candidate_proposer
|
|
257
|
+
kwargs["trainset"] = _with_row_identities(trainset)
|
|
258
|
+
kwargs["valset"] = _with_row_identities(valset)
|
|
259
|
+
result = optimize(**kwargs)
|
|
260
|
+
if custom_candidate_proposer is not None and preflight_evaluation is not None:
|
|
261
|
+
# GEPA's state correctly counts its seed evaluation, but this run
|
|
262
|
+
# served that evaluation from the already-accounted launch preflight.
|
|
263
|
+
# Its public metric result must consequently retain M1's convention:
|
|
264
|
+
# GEPA result counts exclude the one caller preflight, while the
|
|
265
|
+
# adapter's physical count is result + one.
|
|
266
|
+
total = getattr(result, "total_metric_calls", None)
|
|
267
|
+
if isinstance(total, int):
|
|
268
|
+
result = dataclasses.replace(result, total_metric_calls=max(0, total - len(preflight_rows)))
|
|
269
|
+
return result
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Offline reader for the ALI-1532 synced instruction-set layout."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class InstructionSetLoaderError(Exception):
|
|
8
|
+
def __init__(self, code: str):
|
|
9
|
+
self.code = code
|
|
10
|
+
super().__init__(code)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _inside(root: Path, candidate: Path) -> bool:
|
|
14
|
+
try:
|
|
15
|
+
candidate.relative_to(root)
|
|
16
|
+
return True
|
|
17
|
+
except ValueError:
|
|
18
|
+
return False
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def load_instruction_set(directory: str, name: str, model_config_identity: str) -> dict[str, str]:
|
|
22
|
+
root = (Path(directory) / name).resolve()
|
|
23
|
+
if not root.is_dir():
|
|
24
|
+
raise InstructionSetLoaderError("instruction_set_not_synced")
|
|
25
|
+
manifest_path = root / "manifest.json"
|
|
26
|
+
if not manifest_path.is_file():
|
|
27
|
+
raise InstructionSetLoaderError("instruction_set_manifest_missing")
|
|
28
|
+
try:
|
|
29
|
+
manifest = json.loads(manifest_path.read_text())
|
|
30
|
+
except (OSError, json.JSONDecodeError) as error:
|
|
31
|
+
raise InstructionSetLoaderError("instruction_set_manifest_missing") from error
|
|
32
|
+
if manifest.get("manifestVersion") != 1:
|
|
33
|
+
raise InstructionSetLoaderError("instruction_set_manifest_version_unsupported")
|
|
34
|
+
if manifest.get("filteredTo") and model_config_identity not in manifest["filteredTo"]:
|
|
35
|
+
raise InstructionSetLoaderError("instruction_set_profile_not_synced")
|
|
36
|
+
production = next((profile.get("production") for profile in manifest.get("profiles", []) if profile.get("modelConfigIdentity") == model_config_identity), None)
|
|
37
|
+
material = production or manifest.get("default", {})
|
|
38
|
+
values: dict[str, str] = {}
|
|
39
|
+
for key in manifest.get("shape", []):
|
|
40
|
+
if key in material.get("pinnedComponents", {}):
|
|
41
|
+
raise InstructionSetLoaderError("instruction_set_component_unavailable")
|
|
42
|
+
relative = material.get("files", {}).get(key)
|
|
43
|
+
if not relative:
|
|
44
|
+
raise InstructionSetLoaderError("instruction_set_profile_key_missing")
|
|
45
|
+
path = (root / relative).resolve()
|
|
46
|
+
if not _inside(root, path):
|
|
47
|
+
raise InstructionSetLoaderError("instruction_set_path_unsafe")
|
|
48
|
+
try:
|
|
49
|
+
values[key] = path.read_text()
|
|
50
|
+
except OSError as error:
|
|
51
|
+
raise InstructionSetLoaderError("instruction_set_component_unreadable") from error
|
|
52
|
+
return values
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Launch-time safety checks performed before an optimization run exists."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def validate_seed_and_scorer(
|
|
10
|
+
*,
|
|
11
|
+
scores: list[float],
|
|
12
|
+
row_evidence: list[dict[str, Any]] | None = None,
|
|
13
|
+
allow_degenerate_seed: bool,
|
|
14
|
+
higher_is_better: bool = True,
|
|
15
|
+
) -> dict[str, Any]:
|
|
16
|
+
"""Classify a sampled seed without treating a transient row failure as global.
|
|
17
|
+
|
|
18
|
+
A row that returns a score, including the worst score, proves the runner
|
|
19
|
+
and scorer pipeline executed. Only a sample containing *no* such row is
|
|
20
|
+
an execution refusal. Successful worst-score rows remain the separate,
|
|
21
|
+
deliberately bypassable ``degenerate_seed`` condition.
|
|
22
|
+
"""
|
|
23
|
+
evidence = list(row_evidence or [])
|
|
24
|
+
successful_scores: list[float] = []
|
|
25
|
+
failures: dict[str, list[str | None]] = {}
|
|
26
|
+
for index, score in enumerate(scores):
|
|
27
|
+
row = evidence[index] if index < len(evidence) else {}
|
|
28
|
+
if row.get("scorer_error"):
|
|
29
|
+
reason = "scorer_execution_failed"
|
|
30
|
+
elif row.get("execution_error"):
|
|
31
|
+
source = row.get("execution_error_source")
|
|
32
|
+
reason = f"{source}_execution_failed" if source in {"candidate", "scorer"} else "runner_execution_failed"
|
|
33
|
+
else:
|
|
34
|
+
successful_scores.append(score)
|
|
35
|
+
continue
|
|
36
|
+
failures.setdefault(reason, []).append(row.get("row_id"))
|
|
37
|
+
|
|
38
|
+
warnings = [
|
|
39
|
+
{"reason": reason, "row_ids": row_ids}
|
|
40
|
+
for reason, row_ids in failures.items()
|
|
41
|
+
]
|
|
42
|
+
if failures and not successful_scores and not allow_degenerate_seed:
|
|
43
|
+
# Every sampled row failed before yielding a usable score. Preserve a
|
|
44
|
+
# precise source when the failure mode is uniform, otherwise name the
|
|
45
|
+
# shared runner pipeline rather than pretending one source won.
|
|
46
|
+
reason = next(iter(failures)) if len(failures) == 1 else "runner_execution_failed"
|
|
47
|
+
return {"allowed": False, "reason": reason, "row_evidence": evidence}
|
|
48
|
+
|
|
49
|
+
worst_bound = all(math.isclose(score, 0.0, abs_tol=1e-9) for score in successful_scores)
|
|
50
|
+
# The adapter normalizes lower-is-better scores into GEPA's higher-is-
|
|
51
|
+
# better orientation. Legacy still refuses a uniform raw 0.0 lower-bound
|
|
52
|
+
# (normalized 1.0): it is a perfect seed or a silent contract mismatch,
|
|
53
|
+
# neither of which gives reflection a useful gradient.
|
|
54
|
+
lower_perfect_bound = not higher_is_better and all(
|
|
55
|
+
math.isclose(score, 1.0, abs_tol=1e-9) for score in successful_scores
|
|
56
|
+
)
|
|
57
|
+
degenerate = bool(successful_scores) and (worst_bound or lower_perfect_bound)
|
|
58
|
+
if degenerate and not allow_degenerate_seed:
|
|
59
|
+
verdict: dict[str, Any] = {"allowed": False, "reason": "degenerate_seed", "row_evidence": evidence}
|
|
60
|
+
else:
|
|
61
|
+
verdict = {"allowed": True, "reason": None, "row_evidence": evidence}
|
|
62
|
+
if warnings:
|
|
63
|
+
verdict["warnings"] = warnings
|
|
64
|
+
return verdict
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""GEPA reflection callable delegated to Orizu's existing provider layer."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from dataclasses import replace
|
|
7
|
+
import json
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from orizu_gepa.optimizer import DEFAULT_REFLECTION_PROMPT_TEMPLATE, build_reflection_prompt
|
|
11
|
+
from orizu_gepa.reflection import reflect_with_provider
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def provider_reflection_lm(parent_text: str, parent_results: list[Any], config: Any) -> str:
|
|
15
|
+
"""Run the frozen provider layer and return its raw response.
|
|
16
|
+
|
|
17
|
+
``reflect_with_provider`` owns retries, HTTP timeouts, token accounting and
|
|
18
|
+
candidate extraction. The connector intentionally does not recreate any
|
|
19
|
+
of that transport policy.
|
|
20
|
+
"""
|
|
21
|
+
result = reflect_with_provider(parent_text, parent_results, config)
|
|
22
|
+
return result.response
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class GepaReflectionLM:
|
|
26
|
+
"""Reflection bridge that preserves provider failures before GEPA isolates them.
|
|
27
|
+
|
|
28
|
+
GEPA intentionally catches reflection failures per proposal. That keeps an
|
|
29
|
+
optimization alive, but means the connector is the final durable boundary
|
|
30
|
+
for the actual exception. This wrapper records it *before* re-raising to
|
|
31
|
+
GEPA's safe helper and exposes provider-measured token usage in GEPA's
|
|
32
|
+
``TrackingLM``-shaped fields.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
*,
|
|
38
|
+
context_supplier: Callable[[], tuple[str | dict[str, str], list[Any]]],
|
|
39
|
+
config: Any,
|
|
40
|
+
failure_reporter: Callable[..., None] | None,
|
|
41
|
+
success_reporter: Callable[[str], None] | None,
|
|
42
|
+
) -> None:
|
|
43
|
+
self._context_supplier = context_supplier
|
|
44
|
+
self._config = config
|
|
45
|
+
self._failure_reporter = failure_reporter
|
|
46
|
+
self._success_reporter = success_reporter
|
|
47
|
+
self._total_tokens_in = 0
|
|
48
|
+
self._total_tokens_out = 0
|
|
49
|
+
self._total_tokens = 0
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def total_cost(self) -> float:
|
|
53
|
+
return 0.0
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def total_tokens_in(self) -> int:
|
|
57
|
+
return self._total_tokens_in
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def total_tokens_out(self) -> int:
|
|
61
|
+
return self._total_tokens_out
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def total_tokens(self) -> int:
|
|
65
|
+
return self._total_tokens
|
|
66
|
+
|
|
67
|
+
def _account_usage(self, usage: Any) -> None:
|
|
68
|
+
if not isinstance(usage, dict):
|
|
69
|
+
raise RuntimeError("ALI_1505_PROVIDER_USAGE_MISSING: reflection transport returned no provider usage")
|
|
70
|
+
try:
|
|
71
|
+
input_tokens = int(usage["input_tokens"])
|
|
72
|
+
output_tokens = int(usage["output_tokens"])
|
|
73
|
+
total_tokens = int(usage["total_tokens"])
|
|
74
|
+
except (KeyError, TypeError, ValueError) as error:
|
|
75
|
+
raise RuntimeError("ALI_1505_PROVIDER_USAGE_INVALID: reflection transport returned invalid provider usage") from error
|
|
76
|
+
if min(input_tokens, output_tokens, total_tokens) < 0:
|
|
77
|
+
raise RuntimeError("ALI_1505_PROVIDER_USAGE_INVALID: reflection transport returned negative provider usage")
|
|
78
|
+
self._total_tokens_in += input_tokens
|
|
79
|
+
self._total_tokens_out += output_tokens
|
|
80
|
+
self._total_tokens += total_tokens
|
|
81
|
+
|
|
82
|
+
def __call__(self, gepa_prompt: str) -> str:
|
|
83
|
+
parent_candidate, parent_results = self._context_supplier()
|
|
84
|
+
parent_text = (
|
|
85
|
+
json.dumps(parent_candidate, sort_keys=True, separators=(",", ":"))
|
|
86
|
+
if isinstance(parent_candidate, dict) and len(parent_candidate) > 1
|
|
87
|
+
else next(iter(parent_candidate.values()))
|
|
88
|
+
if isinstance(parent_candidate, dict)
|
|
89
|
+
else parent_candidate
|
|
90
|
+
)
|
|
91
|
+
try:
|
|
92
|
+
# Prompt validation is part of the provider attempt. Keep it
|
|
93
|
+
# inside this boundary so GEPA cannot silently swallow its error.
|
|
94
|
+
provider_prompt = build_reflection_prompt(parent_text, parent_results, self._config)
|
|
95
|
+
result = reflect_with_provider(parent_text, parent_results, self._config)
|
|
96
|
+
response = result.response
|
|
97
|
+
provider_prompt = getattr(result, "prompt", provider_prompt)
|
|
98
|
+
self._account_usage(getattr(result, "usage", None))
|
|
99
|
+
except Exception as error:
|
|
100
|
+
billable_usage = getattr(error, "usage", None)
|
|
101
|
+
if billable_usage is not None:
|
|
102
|
+
self._account_usage(billable_usage)
|
|
103
|
+
if self._failure_reporter is not None:
|
|
104
|
+
self._failure_reporter(
|
|
105
|
+
error=error,
|
|
106
|
+
gepa_prompt=gepa_prompt,
|
|
107
|
+
parent_text=parent_text,
|
|
108
|
+
parent_results=parent_results,
|
|
109
|
+
)
|
|
110
|
+
raise
|
|
111
|
+
if self._success_reporter is not None:
|
|
112
|
+
self._success_reporter(str(provider_prompt))
|
|
113
|
+
return response
|
|
114
|
+
|
|
115
|
+
def reflect(
|
|
116
|
+
self,
|
|
117
|
+
candidate: dict[str, str],
|
|
118
|
+
reflective_dataset: Any,
|
|
119
|
+
components_to_update: list[str],
|
|
120
|
+
) -> tuple[Any, "GepaReflectionLM"]:
|
|
121
|
+
"""Implement GEPA's component-aware ReflectionLM protocol.
|
|
122
|
+
|
|
123
|
+
The callable protocol has no selected-component information. GEPA's
|
|
124
|
+
newer protocol does, so tuples must use it rather than reverse-engineer
|
|
125
|
+
a key from a rendered vendor prompt.
|
|
126
|
+
"""
|
|
127
|
+
from gepa.proposer.reflective_mutation.reflection_lm import ReflectionProposal
|
|
128
|
+
|
|
129
|
+
_, parent_results = self._context_supplier()
|
|
130
|
+
full_candidate = candidate
|
|
131
|
+
proposal = ReflectionProposal(new_texts={}, prompts={}, raw_lm_outputs={})
|
|
132
|
+
for component in components_to_update:
|
|
133
|
+
if component not in candidate:
|
|
134
|
+
continue
|
|
135
|
+
parent_text = candidate[component]
|
|
136
|
+
others = {key: value for key, value in full_candidate.items() if key != component}
|
|
137
|
+
config = self._config
|
|
138
|
+
if others:
|
|
139
|
+
template = config.reflection_prompt_template or DEFAULT_REFLECTION_PROMPT_TEMPLATE
|
|
140
|
+
config = replace(
|
|
141
|
+
config,
|
|
142
|
+
reflection_prompt_template=(
|
|
143
|
+
f"{template}\n\nOther instruction-set components (read-only): "
|
|
144
|
+
f"{json.dumps(others, sort_keys=True, ensure_ascii=False)}"
|
|
145
|
+
),
|
|
146
|
+
)
|
|
147
|
+
provider_prompt = ""
|
|
148
|
+
try:
|
|
149
|
+
provider_prompt = build_reflection_prompt(parent_text, parent_results, config)
|
|
150
|
+
result = reflect_with_provider(parent_text, parent_results, config)
|
|
151
|
+
self._account_usage(getattr(result, "usage", None))
|
|
152
|
+
except Exception as error:
|
|
153
|
+
billable_usage = getattr(error, "usage", None)
|
|
154
|
+
if billable_usage is not None:
|
|
155
|
+
self._account_usage(billable_usage)
|
|
156
|
+
if self._failure_reporter is not None:
|
|
157
|
+
self._failure_reporter(error=error, gepa_prompt=provider_prompt, parent_text=parent_text, parent_results=parent_results)
|
|
158
|
+
raise
|
|
159
|
+
proposal.new_texts[component] = result.response
|
|
160
|
+
proposal.prompts[component] = getattr(result, "prompt", provider_prompt)
|
|
161
|
+
proposal.raw_lm_outputs[component] = result.response
|
|
162
|
+
if self._success_reporter is not None:
|
|
163
|
+
self._success_reporter(str(proposal.prompts[component]))
|
|
164
|
+
return proposal, self
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def make_gepa_reflection_lm(
|
|
168
|
+
*,
|
|
169
|
+
context_supplier: Callable[[], tuple[str | dict[str, str], list[Any]]],
|
|
170
|
+
config: Any,
|
|
171
|
+
failure_reporter: Callable[..., None] | None = None,
|
|
172
|
+
success_reporter: Callable[[str], None] | None = None,
|
|
173
|
+
) -> GepaReflectionLM:
|
|
174
|
+
"""Adapt GEPA's ``Callable[[rendered_prompt], str]`` contract.
|
|
175
|
+
|
|
176
|
+
GEPA owns its rendered prompt. The frozen provider layer owns the
|
|
177
|
+
production prompt and retry policy. ``context_supplier`` is read at each
|
|
178
|
+
invocation, after GEPA's selected-parent minibatch evaluation, so a later
|
|
179
|
+
proposal cannot accidentally reflect on the seed's rows.
|
|
180
|
+
"""
|
|
181
|
+
return GepaReflectionLM(
|
|
182
|
+
context_supplier=context_supplier,
|
|
183
|
+
config=config,
|
|
184
|
+
failure_reporter=failure_reporter,
|
|
185
|
+
success_reporter=success_reporter,
|
|
186
|
+
)
|