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,618 @@
|
|
|
1
|
+
# Copyright (c) 2025 Lakshya A Agrawal and the GEPA contributors
|
|
2
|
+
# https://github.com/gepa-ai/gepa
|
|
3
|
+
|
|
4
|
+
"""Confidence-aware adapter for structured-output classification tasks.
|
|
5
|
+
|
|
6
|
+
Uses token-level logprobs from ``llm-structured-confidence`` to detect
|
|
7
|
+
and penalise lucky guesses, feeding rich confidence diagnostics into
|
|
8
|
+
the reflection LLM. Requires structured output with enum constraints
|
|
9
|
+
and a model that supports ``logprobs=True``.
|
|
10
|
+
|
|
11
|
+
See the full guide: https://gepa-ai.github.io/gepa/guides/confidence-adapter/
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
import math
|
|
19
|
+
from collections.abc import Mapping, Sequence
|
|
20
|
+
from typing import Any, Protocol, TypedDict
|
|
21
|
+
|
|
22
|
+
from gepa.adapters.confidence_adapter.scoring import LinearBlendScoring, ScoringStrategy
|
|
23
|
+
from gepa.core.adapter import EvaluationBatch, GEPAAdapter, ProposalFn
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
TOP_ALTERNATIVES_IN_FEEDBACK = 3
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
# Data types
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ConfidenceDataInst(TypedDict):
|
|
36
|
+
"""Input data instance for confidence-aware evaluation.
|
|
37
|
+
|
|
38
|
+
Attributes
|
|
39
|
+
----------
|
|
40
|
+
input:
|
|
41
|
+
The user-facing text to classify (e.g. a transaction description).
|
|
42
|
+
additional_context:
|
|
43
|
+
Optional key-value pairs surfaced in reflective feedback.
|
|
44
|
+
answer:
|
|
45
|
+
The expected classification label (must match an enum value).
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
input: str
|
|
49
|
+
additional_context: dict[str, str]
|
|
50
|
+
answer: str
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ConfidenceTrajectory(TypedDict):
|
|
54
|
+
"""Per-example execution trace used to build reflective feedback.
|
|
55
|
+
|
|
56
|
+
Attributes
|
|
57
|
+
----------
|
|
58
|
+
data:
|
|
59
|
+
The original input data instance.
|
|
60
|
+
full_assistant_response:
|
|
61
|
+
Raw text returned by the LLM.
|
|
62
|
+
parsed_value:
|
|
63
|
+
Value extracted from the JSON response at ``answer_field``.
|
|
64
|
+
logprob_score:
|
|
65
|
+
Joint logprob (sum of per-token logprobs) for the target field.
|
|
66
|
+
Always ``<= 0``; closer to 0 = more confident. ``None`` when
|
|
67
|
+
logprobs are unavailable.
|
|
68
|
+
top_alternatives:
|
|
69
|
+
Top alternative tokens with their probabilities and resolved
|
|
70
|
+
enum values (when ``response_schema`` is provided).
|
|
71
|
+
is_correct:
|
|
72
|
+
Whether ``parsed_value`` matches the expected answer.
|
|
73
|
+
score:
|
|
74
|
+
Blended score produced by the scoring strategy.
|
|
75
|
+
feedback:
|
|
76
|
+
Human-readable feedback string including confidence details.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
data: ConfidenceDataInst
|
|
80
|
+
full_assistant_response: str
|
|
81
|
+
parsed_value: str | None
|
|
82
|
+
logprob_score: float | None
|
|
83
|
+
top_alternatives: list[dict[str, Any]]
|
|
84
|
+
is_correct: bool
|
|
85
|
+
score: float
|
|
86
|
+
feedback: str
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class ConfidenceRolloutOutput(TypedDict):
|
|
90
|
+
"""Per-example output exposed to GEPA (opaque to the engine).
|
|
91
|
+
|
|
92
|
+
Attributes
|
|
93
|
+
----------
|
|
94
|
+
full_assistant_response:
|
|
95
|
+
Raw text returned by the LLM.
|
|
96
|
+
parsed_value:
|
|
97
|
+
Value extracted from the JSON response at ``answer_field``.
|
|
98
|
+
logprob_score:
|
|
99
|
+
Joint logprob for the target field.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
full_assistant_response: str
|
|
103
|
+
parsed_value: str | None
|
|
104
|
+
logprob_score: float | None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
ConfidenceReflectiveRecord = TypedDict(
|
|
108
|
+
"ConfidenceReflectiveRecord",
|
|
109
|
+
{
|
|
110
|
+
"Inputs": str,
|
|
111
|
+
"Generated Outputs": str,
|
|
112
|
+
"Feedback": str,
|
|
113
|
+
},
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class ChatMessage(TypedDict):
|
|
118
|
+
role: str
|
|
119
|
+
content: str
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class ChatCompletionCallable(Protocol):
|
|
123
|
+
"""Protocol for callables that return the raw LLM response object.
|
|
124
|
+
|
|
125
|
+
The callable must return the **full** response object (e.g.
|
|
126
|
+
``litellm.ModelResponse``) so that logprobs can be extracted.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
def __call__(self, messages: Sequence[ChatMessage]) -> Any: ...
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# ---------------------------------------------------------------------------
|
|
133
|
+
# Helpers
|
|
134
|
+
# ---------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _extract_answer_from_json(text: str, field_path: str) -> str | None:
|
|
138
|
+
"""Walk *field_path* (dot-separated) into parsed JSON and return the leaf value."""
|
|
139
|
+
try:
|
|
140
|
+
obj = json.loads(text)
|
|
141
|
+
except (json.JSONDecodeError, TypeError):
|
|
142
|
+
return None
|
|
143
|
+
for key in field_path.split("."):
|
|
144
|
+
if isinstance(obj, dict):
|
|
145
|
+
obj = obj.get(key)
|
|
146
|
+
else:
|
|
147
|
+
return None
|
|
148
|
+
return str(obj) if obj is not None else None
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _build_feedback(
|
|
152
|
+
*,
|
|
153
|
+
is_correct: bool,
|
|
154
|
+
expected: str,
|
|
155
|
+
got: str | None,
|
|
156
|
+
logprob_score: float | None,
|
|
157
|
+
top_alternatives: list[dict[str, Any]],
|
|
158
|
+
additional_context: dict[str, str],
|
|
159
|
+
high_confidence_prob: float,
|
|
160
|
+
low_confidence_prob: float,
|
|
161
|
+
) -> str:
|
|
162
|
+
"""Build feedback for the reflection LLM using probability only.
|
|
163
|
+
|
|
164
|
+
Design principles:
|
|
165
|
+
- **Correct + confident**: just ``"Correct."`` -- no noise.
|
|
166
|
+
- **Correct + uncertain**: flag it as risky with alternatives.
|
|
167
|
+
- **Incorrect**: rich detail scaled by confidence -- the higher the
|
|
168
|
+
model's certainty on the wrong answer, the stronger the language.
|
|
169
|
+
|
|
170
|
+
Parameters
|
|
171
|
+
----------
|
|
172
|
+
high_confidence_prob:
|
|
173
|
+
Probability threshold above which a prediction is considered
|
|
174
|
+
"highly confident".
|
|
175
|
+
low_confidence_prob:
|
|
176
|
+
Probability threshold below which a *correct* prediction is
|
|
177
|
+
labelled "unreliable".
|
|
178
|
+
"""
|
|
179
|
+
probability = math.exp(logprob_score) if logprob_score is not None else None
|
|
180
|
+
got_str = got or "<parse error>"
|
|
181
|
+
|
|
182
|
+
if is_correct:
|
|
183
|
+
if probability is None or probability >= high_confidence_prob:
|
|
184
|
+
feedback = "Correct."
|
|
185
|
+
elif probability < low_confidence_prob:
|
|
186
|
+
alt_str = _format_alternatives(top_alternatives, exclude=expected)
|
|
187
|
+
feedback = (
|
|
188
|
+
f"Correct but uncertain ({probability:.0%} probability). "
|
|
189
|
+
f"Model answered '{expected}' but was nearly split with alternatives."
|
|
190
|
+
)
|
|
191
|
+
if alt_str:
|
|
192
|
+
feedback += f" Top alternatives: {alt_str}."
|
|
193
|
+
feedback += " The model cannot reliably distinguish between these categories with the current prompt."
|
|
194
|
+
else:
|
|
195
|
+
alt_str = _format_alternatives(top_alternatives, exclude=expected)
|
|
196
|
+
feedback = f"Correct ({probability:.0%} probability)."
|
|
197
|
+
if alt_str:
|
|
198
|
+
feedback += f" Close alternatives: {alt_str}."
|
|
199
|
+
else:
|
|
200
|
+
alt_str = _format_alternatives(top_alternatives, exclude=got_str)
|
|
201
|
+
correct_alt_prob = _find_alternative_prob(top_alternatives, expected)
|
|
202
|
+
|
|
203
|
+
if probability is not None and probability >= high_confidence_prob:
|
|
204
|
+
feedback = (
|
|
205
|
+
f"WRONG — model has {probability:.0%} certainty on '{got_str}' "
|
|
206
|
+
f"but the correct answer is '{expected}'. "
|
|
207
|
+
"The model has no doubt about its wrong answer; "
|
|
208
|
+
"the prompt is actively misleading it for this type of input."
|
|
209
|
+
)
|
|
210
|
+
if correct_alt_prob is not None:
|
|
211
|
+
feedback += f" The correct category '{expected}' only had {correct_alt_prob:.1%} probability."
|
|
212
|
+
if alt_str:
|
|
213
|
+
feedback += f" Alternatives: {alt_str}."
|
|
214
|
+
feedback += f" The prompt must add explicit rules to disambiguate '{got_str}' vs '{expected}'."
|
|
215
|
+
elif probability is not None and probability >= low_confidence_prob:
|
|
216
|
+
feedback = f"Wrong ({probability:.0%} probability). Expected '{expected}' but got '{got_str}'."
|
|
217
|
+
if alt_str:
|
|
218
|
+
feedback += f" Alternatives: {alt_str}."
|
|
219
|
+
feedback += " The prompt should better guide the model for this case."
|
|
220
|
+
else:
|
|
221
|
+
prob_str = f"{probability:.0%} probability" if probability is not None else "unknown confidence"
|
|
222
|
+
feedback = (
|
|
223
|
+
f"Wrong ({prob_str}). "
|
|
224
|
+
f"Expected '{expected}' but got '{got_str}'. "
|
|
225
|
+
"The model was uncertain — better prompt guidance could fix this."
|
|
226
|
+
)
|
|
227
|
+
if alt_str:
|
|
228
|
+
feedback += f" Alternatives: {alt_str}."
|
|
229
|
+
|
|
230
|
+
ctx = "\n".join(f"{k}: {v}" for k, v in additional_context.items())
|
|
231
|
+
if ctx:
|
|
232
|
+
feedback += f"\nAdditional context:\n{ctx}"
|
|
233
|
+
|
|
234
|
+
return feedback
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _find_alternative_prob(
|
|
238
|
+
alts: list[dict[str, Any]],
|
|
239
|
+
target: str,
|
|
240
|
+
) -> float | None:
|
|
241
|
+
"""Find the probability of *target* in the alternatives list."""
|
|
242
|
+
for alt in alts:
|
|
243
|
+
val = alt.get("resolved_value") or alt.get("token", "")
|
|
244
|
+
if val == target:
|
|
245
|
+
return alt.get("probability", 0.0)
|
|
246
|
+
return None
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _format_alternatives(alts: list[dict[str, Any]], exclude: str | None = None) -> str:
|
|
250
|
+
parts: list[str] = []
|
|
251
|
+
for alt in alts[:TOP_ALTERNATIVES_IN_FEEDBACK]:
|
|
252
|
+
val = alt.get("resolved_value") or alt.get("token", "")
|
|
253
|
+
prob = alt.get("probability", 0.0)
|
|
254
|
+
if val and val != exclude:
|
|
255
|
+
parts.append(f"'{val}' ({prob:.0%})")
|
|
256
|
+
return ", ".join(parts)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
# ---------------------------------------------------------------------------
|
|
260
|
+
# ConfidenceAdapter
|
|
261
|
+
# ---------------------------------------------------------------------------
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class ConfidenceAdapter(GEPAAdapter[ConfidenceDataInst, ConfidenceTrajectory, ConfidenceRolloutOutput]):
|
|
265
|
+
"""GEPA adapter for structured-output classification with logprob confidence.
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
This adapter is specifically designed for **classification tasks** where
|
|
269
|
+
the LLM returns a structured JSON output with an ``enum``-constrained
|
|
270
|
+
field. The ``enum`` constraint is critical: it forces the model to
|
|
271
|
+
choose from a closed set of categories, and the logprobs then represent
|
|
272
|
+
the model's true probability distribution over those categories.
|
|
273
|
+
|
|
274
|
+
The adapter owns the full LLM call lifecycle:
|
|
275
|
+
|
|
276
|
+
1. Sends requests with ``logprobs=True`` and ``response_format``
|
|
277
|
+
2. Parses the structured JSON output
|
|
278
|
+
3. Extracts the **joint logprob** (sum of per-token logprobs) for the
|
|
279
|
+
target field via ``llm-structured-confidence``
|
|
280
|
+
4. Computes a blended score via the pluggable :class:`ScoringStrategy`
|
|
281
|
+
5. Generates rich reflective feedback with confidence details
|
|
282
|
+
|
|
283
|
+
Why joint logprob?
|
|
284
|
+
~~~~~~~~~~~~~~~~~~
|
|
285
|
+
The ``joint_logprob`` is the sum of all per-token logprobs for the
|
|
286
|
+
value tokens of the target field. For example, if the model outputs
|
|
287
|
+
``"Bills/Electricity"`` and the tokens are ``["Bills", "/", "Elec",
|
|
288
|
+
"tricity"]`` with logprobs ``[-0.02, -0.01, -0.10, -0.01]``, the
|
|
289
|
+
joint logprob is ``-0.14``.
|
|
290
|
+
|
|
291
|
+
This is the most natural confidence measure because:
|
|
292
|
+
|
|
293
|
+
* It captures the **total uncertainty** across all tokens (not just
|
|
294
|
+
the average), so longer values with one uncertain token are correctly
|
|
295
|
+
penalised.
|
|
296
|
+
* ``exp(joint_logprob)`` gives the **joint probability** -- the
|
|
297
|
+
probability the model assigns to the entire value as a whole.
|
|
298
|
+
* It is numerically stable and works well across different tokenisations.
|
|
299
|
+
|
|
300
|
+
Parameters
|
|
301
|
+
----------
|
|
302
|
+
model:
|
|
303
|
+
Either a litellm model string (e.g. ``"openai/gpt-4.1-mini"``) or a
|
|
304
|
+
callable that takes ``messages`` and returns the full response object
|
|
305
|
+
(must include logprobs).
|
|
306
|
+
field_path:
|
|
307
|
+
Path to the target field in the JSON response, using the syntax of
|
|
308
|
+
``llm-structured-confidence``: ``"category_name"`` for a top-level
|
|
309
|
+
field, ``"classification.name"`` for a nested field, or
|
|
310
|
+
``"results[].category"`` for an array of objects.
|
|
311
|
+
response_format:
|
|
312
|
+
JSON schema dict passed to litellm as ``response_format``. Should
|
|
313
|
+
define ``enum`` constraints on the target field for meaningful
|
|
314
|
+
confidence extraction. Required when *model* is a string.
|
|
315
|
+
response_schema:
|
|
316
|
+
Optional Pydantic model or dict schema passed to
|
|
317
|
+
``extract_logprobs(response_schema=…)`` for enum resolution.
|
|
318
|
+
When provided, ``TopAlternative.resolved_value`` maps token
|
|
319
|
+
prefixes back to full enum values (e.g. ``"Pos"`` -> ``"Positive"``).
|
|
320
|
+
scoring_strategy:
|
|
321
|
+
How to blend correctness and logprob confidence into a single score.
|
|
322
|
+
Defaults to :class:`LinearBlendScoring`.
|
|
323
|
+
answer_field:
|
|
324
|
+
JSON field path used to extract the answer from the response text.
|
|
325
|
+
Defaults to *field_path* (they are usually the same).
|
|
326
|
+
high_confidence_threshold:
|
|
327
|
+
Probability threshold (in ``(0, 1]``) above which a prediction is
|
|
328
|
+
labelled "high confidence" in reflective feedback. Models using
|
|
329
|
+
structured output with enum constraints typically produce
|
|
330
|
+
probabilities above 95%, so this should be set high (e.g. ``0.99``)
|
|
331
|
+
to produce useful feedback gradients. Default ``0.99``.
|
|
332
|
+
low_confidence_threshold:
|
|
333
|
+
Probability threshold (in ``(0, 1)``) below which a *correct*
|
|
334
|
+
prediction is labelled "unreliable" in reflective feedback.
|
|
335
|
+
Default ``0.90``.
|
|
336
|
+
top_logprobs:
|
|
337
|
+
Number of top logprobs to request from the LLM (1-20).
|
|
338
|
+
failure_score:
|
|
339
|
+
Score assigned when an example fails (parse error, API error, etc.).
|
|
340
|
+
max_litellm_workers:
|
|
341
|
+
Concurrency for litellm calls (only used when *model* is a string).
|
|
342
|
+
litellm_batch_completion_kwargs:
|
|
343
|
+
Extra keyword arguments forwarded to every ``litellm.batch_completion``
|
|
344
|
+
call (e.g. ``temperature``, ``max_tokens``).
|
|
345
|
+
"""
|
|
346
|
+
|
|
347
|
+
propose_new_texts: ProposalFn | None = None
|
|
348
|
+
|
|
349
|
+
def __init__(
|
|
350
|
+
self,
|
|
351
|
+
model: str | ChatCompletionCallable,
|
|
352
|
+
field_path: str,
|
|
353
|
+
response_format: dict[str, Any] | None = None,
|
|
354
|
+
response_schema: type | dict[str, Any] | None = None,
|
|
355
|
+
scoring_strategy: ScoringStrategy | None = None,
|
|
356
|
+
answer_field: str | None = None,
|
|
357
|
+
high_confidence_threshold: float = 0.99,
|
|
358
|
+
low_confidence_threshold: float = 0.90,
|
|
359
|
+
top_logprobs: int = 5,
|
|
360
|
+
failure_score: float = 0.0,
|
|
361
|
+
max_litellm_workers: int = 10,
|
|
362
|
+
litellm_batch_completion_kwargs: dict[str, Any] | None = None,
|
|
363
|
+
) -> None:
|
|
364
|
+
if isinstance(model, str):
|
|
365
|
+
import litellm
|
|
366
|
+
|
|
367
|
+
self.litellm = litellm
|
|
368
|
+
if response_format is None:
|
|
369
|
+
raise ValueError(
|
|
370
|
+
"response_format is required when model is a string (LiteLLM path). "
|
|
371
|
+
"Provide a JSON schema with enum constraints for structured classification output."
|
|
372
|
+
)
|
|
373
|
+
self.model = model
|
|
374
|
+
self.field_path = field_path
|
|
375
|
+
self.response_format = response_format
|
|
376
|
+
self.response_schema = response_schema
|
|
377
|
+
self.scoring_strategy: ScoringStrategy = scoring_strategy or LinearBlendScoring(
|
|
378
|
+
low_confidence_threshold=high_confidence_threshold,
|
|
379
|
+
)
|
|
380
|
+
self.answer_field = answer_field or field_path
|
|
381
|
+
self.high_confidence_threshold = high_confidence_threshold
|
|
382
|
+
self.low_confidence_threshold = low_confidence_threshold
|
|
383
|
+
self.top_logprobs = top_logprobs
|
|
384
|
+
self.failure_score = failure_score
|
|
385
|
+
self.max_litellm_workers = max_litellm_workers
|
|
386
|
+
self.litellm_batch_completion_kwargs = litellm_batch_completion_kwargs or {}
|
|
387
|
+
|
|
388
|
+
# ------------------------------------------------------------------
|
|
389
|
+
# evaluate
|
|
390
|
+
# ------------------------------------------------------------------
|
|
391
|
+
|
|
392
|
+
def _process_response(
|
|
393
|
+
self,
|
|
394
|
+
response: Any,
|
|
395
|
+
data: ConfidenceDataInst,
|
|
396
|
+
capture_traces: bool,
|
|
397
|
+
) -> tuple[ConfidenceRolloutOutput, float, dict[str, float], ConfidenceTrajectory | None]:
|
|
398
|
+
"""Extract logprobs, compute score, and build feedback from a single response."""
|
|
399
|
+
from llm_structured_confidence import extract_logprobs
|
|
400
|
+
|
|
401
|
+
try:
|
|
402
|
+
if isinstance(response, Exception):
|
|
403
|
+
raise response
|
|
404
|
+
|
|
405
|
+
response_text = self._extract_text(response)
|
|
406
|
+
parsed_value = _extract_answer_from_json(response_text, self.answer_field)
|
|
407
|
+
|
|
408
|
+
logprob_score: float | None = None
|
|
409
|
+
top_alternatives: list[dict[str, Any]] = []
|
|
410
|
+
|
|
411
|
+
try:
|
|
412
|
+
entries = extract_logprobs(
|
|
413
|
+
response,
|
|
414
|
+
field_path=self.field_path,
|
|
415
|
+
response_schema=self.response_schema,
|
|
416
|
+
)
|
|
417
|
+
if entries:
|
|
418
|
+
fl = entries[0].field_logprob
|
|
419
|
+
logprob_score = fl.joint_logprob
|
|
420
|
+
top_alternatives = [
|
|
421
|
+
{
|
|
422
|
+
"token": alt.token,
|
|
423
|
+
"probability": alt.probability,
|
|
424
|
+
"resolved_value": alt.resolved_value,
|
|
425
|
+
}
|
|
426
|
+
for alt in fl.top_logprobs
|
|
427
|
+
]
|
|
428
|
+
except Exception:
|
|
429
|
+
logger.debug("Logprob extraction failed for an example", exc_info=True)
|
|
430
|
+
|
|
431
|
+
is_correct = self._check_correctness(parsed_value, data["answer"])
|
|
432
|
+
score = self.scoring_strategy.score(is_correct, logprob_score)
|
|
433
|
+
|
|
434
|
+
except Exception:
|
|
435
|
+
logger.debug("LLM call or parsing failed for an example", exc_info=True)
|
|
436
|
+
response_text = ""
|
|
437
|
+
parsed_value = None
|
|
438
|
+
logprob_score = None
|
|
439
|
+
top_alternatives = []
|
|
440
|
+
is_correct = False
|
|
441
|
+
score = self.failure_score
|
|
442
|
+
|
|
443
|
+
feedback = _build_feedback(
|
|
444
|
+
is_correct=is_correct,
|
|
445
|
+
expected=data["answer"],
|
|
446
|
+
got=parsed_value,
|
|
447
|
+
logprob_score=logprob_score,
|
|
448
|
+
top_alternatives=top_alternatives,
|
|
449
|
+
additional_context=data.get("additional_context", {}),
|
|
450
|
+
high_confidence_prob=self.high_confidence_threshold,
|
|
451
|
+
low_confidence_prob=self.low_confidence_threshold,
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
output: ConfidenceRolloutOutput = {
|
|
455
|
+
"full_assistant_response": response_text,
|
|
456
|
+
"parsed_value": parsed_value,
|
|
457
|
+
"logprob_score": logprob_score,
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
probability = math.exp(logprob_score) if logprob_score is not None else 0.0
|
|
461
|
+
obj_scores = {
|
|
462
|
+
"accuracy": 1.0 if is_correct else 0.0,
|
|
463
|
+
"probability": probability,
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
trajectory = None
|
|
467
|
+
if capture_traces:
|
|
468
|
+
trajectory = {
|
|
469
|
+
"data": data,
|
|
470
|
+
"full_assistant_response": response_text,
|
|
471
|
+
"parsed_value": parsed_value,
|
|
472
|
+
"logprob_score": logprob_score,
|
|
473
|
+
"top_alternatives": top_alternatives,
|
|
474
|
+
"is_correct": is_correct,
|
|
475
|
+
"score": score,
|
|
476
|
+
"feedback": feedback,
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return output, score, obj_scores, trajectory
|
|
480
|
+
|
|
481
|
+
def evaluate(
|
|
482
|
+
self,
|
|
483
|
+
batch: list[ConfidenceDataInst],
|
|
484
|
+
candidate: dict[str, str],
|
|
485
|
+
capture_traces: bool = False,
|
|
486
|
+
) -> EvaluationBatch[ConfidenceTrajectory, ConfidenceRolloutOutput]:
|
|
487
|
+
"""Run *candidate* on *batch*, extracting logprob confidence.
|
|
488
|
+
|
|
489
|
+
Uses ``litellm.batch_completion`` for parallel LLM calls, then
|
|
490
|
+
post-processes each response to extract logprobs and build feedback.
|
|
491
|
+
"""
|
|
492
|
+
system_content = next(iter(candidate.values()))
|
|
493
|
+
|
|
494
|
+
all_messages: list[list[ChatMessage]] = [
|
|
495
|
+
[
|
|
496
|
+
{"role": "system", "content": system_content},
|
|
497
|
+
{"role": "user", "content": data["input"]},
|
|
498
|
+
]
|
|
499
|
+
for data in batch
|
|
500
|
+
]
|
|
501
|
+
|
|
502
|
+
if isinstance(self.model, str):
|
|
503
|
+
batch_kwargs: dict[str, Any] = {
|
|
504
|
+
"model": self.model,
|
|
505
|
+
"messages": all_messages,
|
|
506
|
+
"max_workers": self.max_litellm_workers,
|
|
507
|
+
"logprobs": True,
|
|
508
|
+
"top_logprobs": self.top_logprobs,
|
|
509
|
+
**self.litellm_batch_completion_kwargs,
|
|
510
|
+
}
|
|
511
|
+
if self.response_format is not None:
|
|
512
|
+
batch_kwargs["response_format"] = self.response_format
|
|
513
|
+
responses = list(self.litellm.batch_completion(**batch_kwargs))
|
|
514
|
+
else:
|
|
515
|
+
responses: list[Any] = []
|
|
516
|
+
for msgs in all_messages:
|
|
517
|
+
try:
|
|
518
|
+
responses.append(self.model(msgs))
|
|
519
|
+
except Exception as exc:
|
|
520
|
+
responses.append(exc)
|
|
521
|
+
|
|
522
|
+
outputs: list[ConfidenceRolloutOutput] = []
|
|
523
|
+
scores: list[float] = []
|
|
524
|
+
objective_scores_list: list[dict[str, float]] = []
|
|
525
|
+
trajectories: list[ConfidenceTrajectory] | None = [] if capture_traces else None
|
|
526
|
+
|
|
527
|
+
for data, response in zip(batch, responses, strict=True):
|
|
528
|
+
output, score, obj_scores, trajectory = self._process_response(
|
|
529
|
+
response,
|
|
530
|
+
data,
|
|
531
|
+
capture_traces,
|
|
532
|
+
)
|
|
533
|
+
outputs.append(output)
|
|
534
|
+
scores.append(score)
|
|
535
|
+
objective_scores_list.append(obj_scores)
|
|
536
|
+
if trajectories is not None and trajectory is not None:
|
|
537
|
+
trajectories.append(trajectory)
|
|
538
|
+
|
|
539
|
+
return EvaluationBatch(
|
|
540
|
+
outputs=outputs,
|
|
541
|
+
scores=scores,
|
|
542
|
+
trajectories=trajectories,
|
|
543
|
+
objective_scores=objective_scores_list,
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
# ------------------------------------------------------------------
|
|
547
|
+
# make_reflective_dataset
|
|
548
|
+
# ------------------------------------------------------------------
|
|
549
|
+
|
|
550
|
+
def make_reflective_dataset(
|
|
551
|
+
self,
|
|
552
|
+
candidate: dict[str, str],
|
|
553
|
+
eval_batch: EvaluationBatch[ConfidenceTrajectory, ConfidenceRolloutOutput],
|
|
554
|
+
components_to_update: list[str],
|
|
555
|
+
) -> Mapping[str, Sequence[Mapping[str, Any]]]:
|
|
556
|
+
"""Build reflective dataset with confidence-enriched feedback.
|
|
557
|
+
|
|
558
|
+
The feedback tells the reflection LLM *why* the task model was
|
|
559
|
+
uncertain, not just whether it was correct. This enables GEPA to
|
|
560
|
+
evolve prompts that resolve specific ambiguities between categories.
|
|
561
|
+
|
|
562
|
+
Each record in the dataset contains:
|
|
563
|
+
|
|
564
|
+
* **Inputs**: the original user input text.
|
|
565
|
+
* **Generated Outputs**: the model's answer annotated with
|
|
566
|
+
probability.
|
|
567
|
+
* **Feedback**: a diagnosis including the probability, the top
|
|
568
|
+
competing alternatives, and guidance for what the prompt should
|
|
569
|
+
improve.
|
|
570
|
+
"""
|
|
571
|
+
assert len(components_to_update) == 1
|
|
572
|
+
comp = components_to_update[0]
|
|
573
|
+
|
|
574
|
+
trajectories = eval_batch.trajectories
|
|
575
|
+
assert trajectories is not None, "Trajectories are required to build a reflective dataset."
|
|
576
|
+
|
|
577
|
+
items: list[ConfidenceReflectiveRecord] = []
|
|
578
|
+
for traj in trajectories:
|
|
579
|
+
generated = traj["parsed_value"] or traj["full_assistant_response"]
|
|
580
|
+
if traj["logprob_score"] is not None:
|
|
581
|
+
probability = math.exp(traj["logprob_score"])
|
|
582
|
+
generated += f" ({probability:.0%} probability)"
|
|
583
|
+
|
|
584
|
+
items.append(
|
|
585
|
+
{
|
|
586
|
+
"Inputs": traj["data"]["input"],
|
|
587
|
+
"Generated Outputs": generated,
|
|
588
|
+
"Feedback": traj["feedback"],
|
|
589
|
+
}
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
if not items:
|
|
593
|
+
raise Exception("No valid predictions found for any module.")
|
|
594
|
+
|
|
595
|
+
return {comp: items}
|
|
596
|
+
|
|
597
|
+
# ------------------------------------------------------------------
|
|
598
|
+
# Private helpers
|
|
599
|
+
# ------------------------------------------------------------------
|
|
600
|
+
|
|
601
|
+
def _extract_text(self, response: Any) -> str:
|
|
602
|
+
"""Extract the text content from a response object."""
|
|
603
|
+
if hasattr(response, "choices"):
|
|
604
|
+
return response.choices[0].message.content.strip()
|
|
605
|
+
if isinstance(response, str):
|
|
606
|
+
return response.strip()
|
|
607
|
+
if isinstance(response, dict):
|
|
608
|
+
choices = response.get("choices", [])
|
|
609
|
+
if choices:
|
|
610
|
+
return choices[0].get("message", {}).get("content", "").strip()
|
|
611
|
+
raise TypeError(f"Cannot extract text from response of type {type(response).__name__}")
|
|
612
|
+
|
|
613
|
+
@staticmethod
|
|
614
|
+
def _check_correctness(parsed_value: str | None, expected: str) -> bool:
|
|
615
|
+
"""Check if the parsed answer matches the expected answer."""
|
|
616
|
+
if parsed_value is None:
|
|
617
|
+
return False
|
|
618
|
+
return parsed_value.strip().lower() == expected.strip().lower()
|