agentinputlab 0.1.0a1__py3-none-any.whl
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.
- agentinputlab/__init__.py +28 -0
- agentinputlab/algorithms/__init__.py +6 -0
- agentinputlab/algorithms/acquire/__init__.py +145 -0
- agentinputlab/algorithms/acquire/adaptive_rag/__init__.py +43 -0
- agentinputlab/algorithms/acquire/adaptive_rag/replay.py +367 -0
- agentinputlab/algorithms/acquire/adaptive_rag/runtime.py +1202 -0
- agentinputlab/algorithms/acquire/adaptive_rag_common_support.py +542 -0
- agentinputlab/algorithms/acquire/hyde.py +296 -0
- agentinputlab/algorithms/acquire/hyde_controlled.py +200 -0
- agentinputlab/algorithms/acquire/hyde_external.py +148 -0
- agentinputlab/algorithms/acquire/ircot.py +28 -0
- agentinputlab/algorithms/acquire/ircot_common_support.py +478 -0
- agentinputlab/algorithms/acquire/ircot_native.py +355 -0
- agentinputlab/algorithms/acquire/ircot_replay.py +327 -0
- agentinputlab/algorithms/acquire/qrag/__init__.py +79 -0
- agentinputlab/algorithms/acquire/qrag/bridge.py +828 -0
- agentinputlab/algorithms/acquire/qrag/common_support.py +891 -0
- agentinputlab/algorithms/acquire/qrag/native_axis.py +71 -0
- agentinputlab/algorithms/acquire/qrag/reader_adapter.py +139 -0
- agentinputlab/algorithms/acquire/r2ag/__init__.py +57 -0
- agentinputlab/algorithms/acquire/r2ag/bridge.py +1312 -0
- agentinputlab/algorithms/acquire/r2ag/common_support.py +1029 -0
- agentinputlab/algorithms/acquire/r2ag/socket_runtime.py +255 -0
- agentinputlab/algorithms/clarify/__init__.py +61 -0
- agentinputlab/algorithms/clarify/_structured.py +64 -0
- agentinputlab/algorithms/clarify/active_task_disambiguation.py +371 -0
- agentinputlab/algorithms/clarify/ask_or_assume/__init__.py +17 -0
- agentinputlab/algorithms/clarify/ask_or_assume/monitor.py +410 -0
- agentinputlab/algorithms/clarify/future_turns.py +379 -0
- agentinputlab/algorithms/clarify/udcs.py +255 -0
- agentinputlab/algorithms/clarify/udcs_deterministic.py +196 -0
- agentinputlab/algorithms/curate/__init__.py +65 -0
- agentinputlab/algorithms/curate/acon/__init__.py +27 -0
- agentinputlab/algorithms/curate/acon/common.py +284 -0
- agentinputlab/algorithms/curate/acon/common_support.py +136 -0
- agentinputlab/algorithms/curate/acon/history_bridge.py +309 -0
- agentinputlab/algorithms/curate/acon/observation_bridge.py +290 -0
- agentinputlab/algorithms/curate/llmlingua/__init__.py +30 -0
- agentinputlab/algorithms/curate/llmlingua/adapters.py +537 -0
- agentinputlab/algorithms/curate/llmlingua/budget.py +48 -0
- agentinputlab/algorithms/curate/llmlingua/controlled.py +175 -0
- agentinputlab/algorithms/curate/llmlingua/multilingual.py +105 -0
- agentinputlab/algorithms/curate/llmlingua/span_map.py +167 -0
- agentinputlab/algorithms/curate/recomp/__init__.py +47 -0
- agentinputlab/algorithms/curate/recomp/external.py +1129 -0
- agentinputlab/algorithms/curate/recomp/selective.py +304 -0
- agentinputlab/algorithms/decompose/__init__.py +107 -0
- agentinputlab/algorithms/decompose/decomp/__init__.py +53 -0
- agentinputlab/algorithms/decompose/decomp/common_support.py +478 -0
- agentinputlab/algorithms/decompose/decomp/planner_component.py +199 -0
- agentinputlab/algorithms/decompose/decomp/worker_bridge.py +416 -0
- agentinputlab/algorithms/decompose/llm_compiler/__init__.py +35 -0
- agentinputlab/algorithms/decompose/llm_compiler/bridge.py +520 -0
- agentinputlab/algorithms/decompose/llm_compiler/common_support.py +504 -0
- agentinputlab/algorithms/decompose/plan_and_budget/__init__.py +43 -0
- agentinputlab/algorithms/decompose/plan_and_budget/cached_soft_budget.py +362 -0
- agentinputlab/algorithms/decompose/plan_and_budget/decomposer_component.py +107 -0
- agentinputlab/algorithms/decompose/plan_and_budget/full.py +205 -0
- agentinputlab/algorithms/decompose/plan_and_budget/hard_cap.py +246 -0
- agentinputlab/algorithms/decompose/plan_and_budget/regenerated_soft_budget.py +448 -0
- agentinputlab/algorithms/decompose/plan_and_solve/__init__.py +33 -0
- agentinputlab/algorithms/decompose/plan_and_solve/plan_component.py +192 -0
- agentinputlab/algorithms/decompose/plan_and_solve/ps_prompt.py +127 -0
- agentinputlab/algorithms/decompose/self_ask/__init__.py +27 -0
- agentinputlab/algorithms/decompose/self_ask/loop.py +362 -0
- agentinputlab/algorithms/decompose/self_ask/planner_component.py +117 -0
- agentinputlab/algorithms/reformulate/__init__.py +85 -0
- agentinputlab/algorithms/reformulate/infocqr/__init__.py +40 -0
- agentinputlab/algorithms/reformulate/infocqr/cache_replay.py +362 -0
- agentinputlab/algorithms/reformulate/infocqr/external.py +675 -0
- agentinputlab/algorithms/reformulate/infocqr/student.py +189 -0
- agentinputlab/algorithms/reformulate/query2doc/__init__.py +42 -0
- agentinputlab/algorithms/reformulate/query2doc/controlled_live.py +190 -0
- agentinputlab/algorithms/reformulate/query2doc/models.py +95 -0
- agentinputlab/algorithms/reformulate/query2doc/official_cached.py +335 -0
- agentinputlab/algorithms/reformulate/query2doc/querygym_bridge.py +223 -0
- agentinputlab/algorithms/reformulate/query2doc/querygym_runtime.py +326 -0
- agentinputlab/algorithms/reformulate/reformer/__init__.py +23 -0
- agentinputlab/algorithms/reformulate/reformer/external.py +417 -0
- agentinputlab/algorithms/reformulate/rrr.py +696 -0
- agentinputlab/annotation/__init__.py +5 -0
- agentinputlab/annotation/independent.py +428 -0
- agentinputlab/annotation/server.py +233 -0
- agentinputlab/annotation/static/app.js +121 -0
- agentinputlab/annotation/static/index.html +60 -0
- agentinputlab/annotation/static/review.css +2 -0
- agentinputlab/annotation/static/review.html +10 -0
- agentinputlab/annotation/static/review.js +11 -0
- agentinputlab/annotation/static/styles.css +55 -0
- agentinputlab/annotation/store.py +444 -0
- agentinputlab/api.py +368 -0
- agentinputlab/artifacts/__init__.py +15 -0
- agentinputlab/artifacts/json_file.py +104 -0
- agentinputlab/artifacts/manifest.py +98 -0
- agentinputlab/artifacts/store.py +157 -0
- agentinputlab/backends/__init__.py +98 -0
- agentinputlab/backends/embedding/__init__.py +25 -0
- agentinputlab/backends/embedding/base.py +145 -0
- agentinputlab/backends/embedding/callable.py +75 -0
- agentinputlab/backends/embedding/replay.py +129 -0
- agentinputlab/backends/llm/__init__.py +31 -0
- agentinputlab/backends/llm/base.py +149 -0
- agentinputlab/backends/llm/callable.py +108 -0
- agentinputlab/backends/llm/decomp_completion.py +88 -0
- agentinputlab/backends/llm/final_content_stop.py +72 -0
- agentinputlab/backends/llm/gpt_oss_final_channel.py +84 -0
- agentinputlab/backends/llm/openai_compatible.py +332 -0
- agentinputlab/backends/llm/transformers.py +171 -0
- agentinputlab/backends/retrieval/__init__.py +35 -0
- agentinputlab/backends/retrieval/base.py +50 -0
- agentinputlab/backends/retrieval/dense.py +777 -0
- agentinputlab/backends/retrieval/memory.py +119 -0
- agentinputlab/backends/retrieval/sqlite_fts.py +155 -0
- agentinputlab/backends/user/__init__.py +15 -0
- agentinputlab/backends/user/base.py +66 -0
- agentinputlab/backends/user/callable.py +54 -0
- agentinputlab/backends/user/replay.py +89 -0
- agentinputlab/backends/vector.py +38 -0
- agentinputlab/benchmarks/__init__.py +246 -0
- agentinputlab/benchmarks/acquisition.py +106 -0
- agentinputlab/benchmarks/ale.py +540 -0
- agentinputlab/benchmarks/appworld_ul.py +669 -0
- agentinputlab/benchmarks/assets.py +226 -0
- agentinputlab/benchmarks/base.py +68 -0
- agentinputlab/benchmarks/beir_archive.py +235 -0
- agentinputlab/benchmarks/beir_sample.py +269 -0
- agentinputlab/benchmarks/bfcl_native.py +245 -0
- agentinputlab/benchmarks/bfcl_v3.py +607 -0
- agentinputlab/benchmarks/cache.py +218 -0
- agentinputlab/benchmarks/clariq.py +203 -0
- agentinputlab/benchmarks/data/registry.json +321 -0
- agentinputlab/benchmarks/data/smoke_assets.json +511 -0
- agentinputlab/benchmarks/data/statebench_v0_8_1_task_ids.json +475 -0
- agentinputlab/benchmarks/data/toolsandbox_165848b_scenario_names.json +1 -0
- agentinputlab/benchmarks/execution.py +1111 -0
- agentinputlab/benchmarks/interactive.py +257 -0
- agentinputlab/benchmarks/ir_query.py +204 -0
- agentinputlab/benchmarks/longbench.py +203 -0
- agentinputlab/benchmarks/paired_replay.py +479 -0
- agentinputlab/benchmarks/preprocess.py +2313 -0
- agentinputlab/benchmarks/production.py +236 -0
- agentinputlab/benchmarks/qa.py +963 -0
- agentinputlab/benchmarks/registry.py +110 -0
- agentinputlab/benchmarks/retrieval.py +459 -0
- agentinputlab/benchmarks/runtime.py +509 -0
- agentinputlab/benchmarks/statebench.py +938 -0
- agentinputlab/benchmarks/tau3.py +725 -0
- agentinputlab/benchmarks/toolsandbox.py +626 -0
- agentinputlab/benchmarks/trec_dl_sample.py +263 -0
- agentinputlab/campaign.py +654 -0
- agentinputlab/campaign_runner.py +953 -0
- agentinputlab/cli/__init__.py +6 -0
- agentinputlab/cli/main.py +933 -0
- agentinputlab/connectors/__init__.py +46 -0
- agentinputlab/connectors/knowledge/__init__.py +4 -0
- agentinputlab/connectors/tools/__init__.py +30 -0
- agentinputlab/connectors/tools/base.py +57 -0
- agentinputlab/connectors/tools/mcp.py +222 -0
- agentinputlab/connectors/tools/memory.py +41 -0
- agentinputlab/connectors/tools/openapi.py +695 -0
- agentinputlab/connectors/tools/schema.py +102 -0
- agentinputlab/contracts/__init__.py +91 -0
- agentinputlab/contracts/availability.py +24 -0
- agentinputlab/contracts/dependency.py +58 -0
- agentinputlab/contracts/enums.py +82 -0
- agentinputlab/contracts/errors.py +63 -0
- agentinputlab/contracts/evidence.py +43 -0
- agentinputlab/contracts/intent.py +110 -0
- agentinputlab/contracts/lifecycle.py +164 -0
- agentinputlab/contracts/patch.py +167 -0
- agentinputlab/contracts/serialization.py +93 -0
- agentinputlab/contracts/state.py +127 -0
- agentinputlab/contracts/trace.py +59 -0
- agentinputlab/contracts/worker.py +42 -0
- agentinputlab/core/__init__.py +7 -0
- agentinputlab/data/__init__.py +32 -0
- agentinputlab/data/checksums.py +9 -0
- agentinputlab/data/downloader.py +235 -0
- agentinputlab/data/http.py +171 -0
- agentinputlab/data/index.py +21 -0
- agentinputlab/data/overlap.py +28 -0
- agentinputlab/data/preprocess.py +32 -0
- agentinputlab/data/storage.py +57 -0
- agentinputlab/data/trec_sample.py +427 -0
- agentinputlab/evaluation/__init__.py +5 -0
- agentinputlab/evaluation/outcomes.py +32 -0
- agentinputlab/experiments/__init__.py +278 -0
- agentinputlab/experiments/analysis.py +981 -0
- agentinputlab/experiments/artifacts.py +687 -0
- agentinputlab/experiments/automatic_measurement.py +678 -0
- agentinputlab/experiments/auxiliary_matrix.py +203 -0
- agentinputlab/experiments/bindings.py +430 -0
- agentinputlab/experiments/blueprints.py +147 -0
- agentinputlab/experiments/builders/__init__.py +45 -0
- agentinputlab/experiments/builders/executable_external_payload.py +423 -0
- agentinputlab/experiments/builders/external_process_arena.py +1018 -0
- agentinputlab/experiments/builders/registry_intervention.py +463 -0
- agentinputlab/experiments/cli.py +158 -0
- agentinputlab/experiments/controls.py +340 -0
- agentinputlab/experiments/driver_guard.py +205 -0
- agentinputlab/experiments/drivers/__init__.py +89 -0
- agentinputlab/experiments/drivers/external_arena.py +2908 -0
- agentinputlab/experiments/drivers/method_process.py +662 -0
- agentinputlab/experiments/drivers/parity_process.py +1484 -0
- agentinputlab/experiments/drivers/static_production.py +1574 -0
- agentinputlab/experiments/executor.py +448 -0
- agentinputlab/experiments/loader.py +605 -0
- agentinputlab/experiments/measurement.py +675 -0
- agentinputlab/experiments/paper_analysis.py +1818 -0
- agentinputlab/experiments/parity_identity.py +605 -0
- agentinputlab/experiments/plan.py +277 -0
- agentinputlab/experiments/production_builders.py +3739 -0
- agentinputlab/experiments/readiness.py +432 -0
- agentinputlab/experiments/schema.py +514 -0
- agentinputlab/experiments/secrets.py +177 -0
- agentinputlab/experiments/stateful_analysis.py +1738 -0
- agentinputlab/experiments/transfer_analysis.py +1316 -0
- agentinputlab/experiments/unseen_analysis.py +1025 -0
- agentinputlab/integrations/__init__.py +1 -0
- agentinputlab/integrations/action_space/__init__.py +1 -0
- agentinputlab/integrations/external_workers/__init__.py +76 -0
- agentinputlab/integrations/external_workers/ace.py +431 -0
- agentinputlab/integrations/external_workers/base.py +181 -0
- agentinputlab/integrations/external_workers/decomp_live.py +249 -0
- agentinputlab/integrations/external_workers/decomp_planner.py +30 -0
- agentinputlab/integrations/external_workers/infocqr_student.py +280 -0
- agentinputlab/integrations/external_workers/ircot.py +576 -0
- agentinputlab/integrations/external_workers/llmcompiler_live.py +360 -0
- agentinputlab/integrations/external_workers/longllmlingua.py +162 -0
- agentinputlab/integrations/external_workers/method.py +314 -0
- agentinputlab/integrations/external_workers/process.py +678 -0
- agentinputlab/integrations/external_workers/supervisor.py +1071 -0
- agentinputlab/integrations/full_architecture/__init__.py +1 -0
- agentinputlab/integrations/full_architecture/hyde.py +212 -0
- agentinputlab/integrations/full_architecture/plan_and_budget.py +188 -0
- agentinputlab/integrations/live_history.py +222 -0
- agentinputlab/integrations/prompt_optimization/__init__.py +1 -0
- agentinputlab/integrations/training/__init__.py +1 -0
- agentinputlab/metrics/__init__.py +50 -0
- agentinputlab/metrics/catalog.py +313 -0
- agentinputlab/metrics/harm.py +95 -0
- agentinputlab/metrics/paired.py +40 -0
- agentinputlab/metrics/qa.py +76 -0
- agentinputlab/metrics/text.py +33 -0
- agentinputlab/metrics/third_party.py +161 -0
- agentinputlab/models/__init__.py +4 -0
- agentinputlab/observability/__init__.py +56 -0
- agentinputlab/observability/budget.py +316 -0
- agentinputlab/observability/instrumentation.py +754 -0
- agentinputlab/observability/models.py +403 -0
- agentinputlab/observability/monitor.py +380 -0
- agentinputlab/optimizers/__init__.py +1 -0
- agentinputlab/optimizers/clarify/__init__.py +12 -0
- agentinputlab/optimizers/context/__init__.py +22 -0
- agentinputlab/optimizers/decompose/__init__.py +64 -0
- agentinputlab/optimizers/evidence/__init__.py +22 -0
- agentinputlab/optimizers/rewrite/__init__.py +30 -0
- agentinputlab/parity/__init__.py +5 -0
- agentinputlab/parity/base.py +206 -0
- agentinputlab/production_campaign.py +763 -0
- agentinputlab/py.typed +1 -0
- agentinputlab/recipes/__init__.py +333 -0
- agentinputlab/recipes/ace.py +418 -0
- agentinputlab/recipes/ace_bfcl.py +273 -0
- agentinputlab/recipes/ace_common_support.py +169 -0
- agentinputlab/recipes/ace_native_plan.py +322 -0
- agentinputlab/recipes/ace_online.py +711 -0
- agentinputlab/recipes/ace_retrieval.py +330 -0
- agentinputlab/recipes/ace_statebench.py +382 -0
- agentinputlab/recipes/ace_tau.py +463 -0
- agentinputlab/recipes/ace_toolsandbox.py +432 -0
- agentinputlab/recipes/acon_guideline.py +22 -0
- agentinputlab/recipes/adaptive_rag.py +822 -0
- agentinputlab/recipes/llmlingua2_inference.py +146 -0
- agentinputlab/recipes/llmlingua2_training.py +796 -0
- agentinputlab/recipes/mce.py +1486 -0
- agentinputlab/recipes/mce_final.py +335 -0
- agentinputlab/recipes/mce_text_fit.py +499 -0
- agentinputlab/recipes/mce_text_only.py +298 -0
- agentinputlab/recipes/qrag.py +729 -0
- agentinputlab/recipes/qrag_inference.py +364 -0
- agentinputlab/recipes/r2ag_features.py +236 -0
- agentinputlab/recipes/r2ag_inference.py +503 -0
- agentinputlab/recipes/r2ag_training.py +948 -0
- agentinputlab/recipes/recomp_abstractive.py +592 -0
- agentinputlab/recipes/recomp_extractive.py +525 -0
- agentinputlab/recipes/reformer.py +17 -0
- agentinputlab/recipes/rqrag.py +1516 -0
- agentinputlab/recipes/rqrag_common_support.py +193 -0
- agentinputlab/recipes/rqrag_completion.py +147 -0
- agentinputlab/recipes/skillopt.py +462 -0
- agentinputlab/recipes/skillopt_common_support.py +154 -0
- agentinputlab/recipes/skillopt_environment.py +165 -0
- agentinputlab/recipes/skillopt_environment_cli.py +5 -0
- agentinputlab/recipes/skillopt_retrieval.py +188 -0
- agentinputlab/recipes/smartsearch.py +897 -0
- agentinputlab/recipes/smartsearch_curriculum.py +283 -0
- agentinputlab/recipes/smartsearch_grpo_contracts.py +58 -0
- agentinputlab/recipes/smartsearch_grpo_data.py +314 -0
- agentinputlab/recipes/smartsearch_grpo_meter.py +324 -0
- agentinputlab/recipes/smartsearch_grpo_prefix.py +144 -0
- agentinputlab/recipes/smartsearch_grpo_rollout.py +119 -0
- agentinputlab/recipes/smartsearch_grpo_tools.py +364 -0
- agentinputlab/recipes/smartsearch_grpo_training.py +305 -0
- agentinputlab/recipes/smartsearch_grpo_transport.py +248 -0
- agentinputlab/recipes/smartsearch_grpo_worker.py +364 -0
- agentinputlab/recipes/smartsearch_inference.py +524 -0
- agentinputlab/recipes/smartsearch_native_data.py +172 -0
- agentinputlab/recipes/smartsearch_policy.py +616 -0
- agentinputlab/recipes/smartsearch_policy_worker.py +9 -0
- agentinputlab/recipes/smartsearch_sampling.py +232 -0
- agentinputlab/recipes/smartsearch_teacher.py +203 -0
- agentinputlab/recipes/smartsearch_training.py +265 -0
- agentinputlab/registry/__init__.py +46 -0
- agentinputlab/registry/beta.py +727 -0
- agentinputlab/registry/data/algorithms.json +1959 -0
- agentinputlab/registry/data/auxiliary_method_profiles.json +34 -0
- agentinputlab/registry/loader.py +100 -0
- agentinputlab/registry/result_manifest.py +184 -0
- agentinputlab/registry/runtime.py +195 -0
- agentinputlab/registry/schema.py +449 -0
- agentinputlab/runner/__init__.py +30 -0
- agentinputlab/runner/balance.py +248 -0
- agentinputlab/runner/cache.py +135 -0
- agentinputlab/runner/composite.py +130 -0
- agentinputlab/runner/engine.py +285 -0
- agentinputlab/runner/runtime_guard.py +268 -0
- agentinputlab/runner/worker.py +80 -0
- agentinputlab/runtime_bootstrap.py +288 -0
- agentinputlab/selectors/__init__.py +196 -0
- agentinputlab/selectors/advanced.py +1514 -0
- agentinputlab/selectors/artifacts.py +1087 -0
- agentinputlab/selectors/base.py +112 -0
- agentinputlab/selectors/campaigns.py +1893 -0
- agentinputlab/selectors/catalog.py +86 -0
- agentinputlab/selectors/discovery.py +1860 -0
- agentinputlab/selectors/evaluation.py +1348 -0
- agentinputlab/selectors/features.py +383 -0
- agentinputlab/selectors/learned.py +502 -0
- agentinputlab/selectors/no_op.py +28 -0
- agentinputlab/selectors/outcome_table.py +475 -0
- agentinputlab/selectors/producer.py +853 -0
- agentinputlab/selectors/rules.py +109 -0
- agentinputlab/selectors/runtime.py +420 -0
- agentinputlab/studies/__init__.py +16 -0
- agentinputlab/studies/design.py +165 -0
- agentinputlab/studies/paired.py +322 -0
- agentinputlab/studio/__init__.py +6 -0
- agentinputlab/studio/campaigns.py +819 -0
- agentinputlab/studio/engine.py +1408 -0
- agentinputlab/studio/model_backends.py +425 -0
- agentinputlab/studio/prepared.py +410 -0
- agentinputlab/studio/server.py +613 -0
- agentinputlab/studio/static/app.js +397 -0
- agentinputlab/studio/static/campaigns.html +175 -0
- agentinputlab/studio/static/campaigns.js +426 -0
- agentinputlab/studio/static/index.html +192 -0
- agentinputlab/studio/static/result.html +103 -0
- agentinputlab/studio/static/result.js +273 -0
- agentinputlab/studio/static/styles.css +467 -0
- agentinputlab-0.1.0a1.data/data/share/agentinputlab/CITATION.cff +22 -0
- agentinputlab-0.1.0a1.dist-info/METADATA +392 -0
- agentinputlab-0.1.0a1.dist-info/RECORD +469 -0
- agentinputlab-0.1.0a1.dist-info/WHEEL +5 -0
- agentinputlab-0.1.0a1.dist-info/entry_points.txt +6 -0
- agentinputlab-0.1.0a1.dist-info/licenses/LICENSE +21 -0
- agentinputlab-0.1.0a1.dist-info/licenses/NOTICE +31 -0
- agentinputlab-0.1.0a1.dist-info/licenses/THIRD_PARTY_NOTICES.md +94 -0
- agentinputlab-0.1.0a1.dist-info/top_level.txt +2 -0
- workers/README.md +94 -0
- workers/ace/README.md +261 -0
- workers/ace/__init__.py +1 -0
- workers/ace/compatibility_manifest.json +39 -0
- workers/ace/driver.py +1682 -0
- workers/acon/README.md +215 -0
- workers/acon/__init__.py +5 -0
- workers/acon/compatibility_manifest.json +93 -0
- workers/acon/driver.py +1859 -0
- workers/acon/fitted.py +395 -0
- workers/acon/guideline.py +470 -0
- workers/acon/guideline_source_manifest.json +20 -0
- workers/adaptive_rag/README.md +96 -0
- workers/adaptive_rag/__init__.py +15 -0
- workers/adaptive_rag/compatibility_manifest.json +61 -0
- workers/adaptive_rag/driver.py +1470 -0
- workers/adaptive_rag/fixture_runtime.py +163 -0
- workers/adaptive_rag/runtime.py +252 -0
- workers/ask_or_assume/README.md +124 -0
- workers/ask_or_assume/__init__.py +1 -0
- workers/ask_or_assume/compatibility_manifest.json +36 -0
- workers/ask_or_assume/driver.py +1227 -0
- workers/decomp/README.md +133 -0
- workers/decomp/UPSTREAM_LICENSE.Apache-2.0.txt +201 -0
- workers/decomp/__init__.py +5 -0
- workers/decomp/compatibility_manifest.json +205 -0
- workers/decomp/driver.py +1015 -0
- workers/decomp/live.py +137 -0
- workers/decomp/runtime.py +231 -0
- workers/infocqr/README.md +106 -0
- workers/infocqr/__init__.py +1 -0
- workers/infocqr/compatibility_manifest.json +84 -0
- workers/infocqr/driver.py +1766 -0
- workers/ircot/README.md +167 -0
- workers/ircot/__init__.py +7 -0
- workers/ircot/compatibility_manifest.json +121 -0
- workers/ircot/controlled.py +457 -0
- workers/ircot/driver.py +1373 -0
- workers/ircot/fixture_bindings.json +39 -0
- workers/ircot/fixture_config.json +48 -0
- workers/ircot/fixture_prompt.txt +2 -0
- workers/ircot/native_qa.py +398 -0
- workers/ircot/qa_compatibility_manifest.json +57 -0
- workers/ircot/runtime.py +97 -0
- workers/llmcompiler/README.md +160 -0
- workers/llmcompiler/__init__.py +1 -0
- workers/llmcompiler/compatibility_manifest.json +45 -0
- workers/llmcompiler/driver.py +1514 -0
- workers/llmcompiler/export_prompts.py +74 -0
- workers/llmcompiler/live.py +174 -0
- workers/llmcompiler/patch_manifest.json +147 -0
- workers/mce/README.md +198 -0
- workers/mce/__init__.py +29 -0
- workers/mce/compatibility_manifest.json +115 -0
- workers/mce/driver.py +2585 -0
- workers/mce/final_eval.py +173 -0
- workers/official_arenas/README.md +25 -0
- workers/official_arenas/__init__.py +1 -0
- workers/official_arenas/capture_records.py +110 -0
- workers/official_arenas/driver.py +619 -0
- workers/official_arenas/protocol.py +334 -0
- workers/official_arenas/providers/__init__.py +1 -0
- workers/official_arenas/providers/_live_history.py +228 -0
- workers/official_arenas/providers/_message_compat.py +77 -0
- workers/official_arenas/providers/appworld_ul.py +196 -0
- workers/official_arenas/providers/fixture.py +112 -0
- workers/official_arenas/providers/statebench.py +960 -0
- workers/official_arenas/providers/tau3.py +1672 -0
- workers/official_arenas/providers/tau_retail.py +586 -0
- workers/official_arenas/providers/toolsandbox.py +1321 -0
- workers/official_arenas/providers/tooltalk.py +699 -0
- workers/official_arenas/retail_capture.py +188 -0
- workers/official_arenas/retail_driver.py +275 -0
- workers/qrag/README.md +172 -0
- workers/qrag/__init__.py +1 -0
- workers/qrag/compatibility_manifest.json +64 -0
- workers/qrag/driver.py +673 -0
- workers/r2ag/README.md +154 -0
- workers/r2ag/__init__.py +5 -0
- workers/r2ag/compatibility_manifest.json +55 -0
- workers/r2ag/driver.py +1287 -0
- workers/r2ag/feature_schema.json +8 -0
- workers/r2ag/runtime.py +589 -0
- workers/recomp/README.md +120 -0
- workers/recomp/__init__.py +1 -0
- workers/recomp/compatibility_manifest.json +43 -0
- workers/recomp/driver.py +1653 -0
- workers/reformer/README.md +125 -0
- workers/reformer/__init__.py +1 -0
- workers/reformer/compatibility_manifest.json +68 -0
- workers/reformer/driver.py +1459 -0
- workers/reformer/induction.py +457 -0
- workers/rrr/README.md +126 -0
- workers/rrr/__init__.py +1 -0
- workers/rrr/compatibility_manifest.json +57 -0
- workers/rrr/driver.py +1133 -0
- workers/smartsearch/README.md +331 -0
- workers/smartsearch/__init__.py +1 -0
- workers/smartsearch/compatibility_manifest.json +41 -0
- workers/smartsearch/driver.py +1643 -0
|
@@ -0,0 +1,853 @@
|
|
|
1
|
+
"""Explicit selector fit, calibration, and freeze producers.
|
|
2
|
+
|
|
3
|
+
The functions here consume a previously frozen :class:`SelectorDiscoveryFreeze`.
|
|
4
|
+
They never execute benchmark cells or fetch external assets. Every transition
|
|
5
|
+
returns an immutable selector bundle whose store enforces the lifecycle.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import math
|
|
12
|
+
import re
|
|
13
|
+
from collections.abc import Mapping, Sequence
|
|
14
|
+
from dataclasses import dataclass, replace
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from statistics import fmean
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
from agentinputlab.contracts.enums import SemanticFamily
|
|
20
|
+
from agentinputlab.contracts.errors import ArtifactError, ValidationError
|
|
21
|
+
from agentinputlab.contracts.serialization import content_hash, freeze_mapping
|
|
22
|
+
|
|
23
|
+
from .advanced import (
|
|
24
|
+
CostRiskAwareSelector,
|
|
25
|
+
GBDTTLearnerSelector,
|
|
26
|
+
KNNUtilitySelector,
|
|
27
|
+
LogisticTLearnerSelector,
|
|
28
|
+
RidgeTLearnerSelector,
|
|
29
|
+
SelectorCalibrationResult,
|
|
30
|
+
calibrate_cost_risk_guardrails,
|
|
31
|
+
calibrate_selector_abstention,
|
|
32
|
+
fit_cost_risk_selector,
|
|
33
|
+
fit_gbdt_t_learner,
|
|
34
|
+
fit_knn_selector,
|
|
35
|
+
fit_logistic_t_learner,
|
|
36
|
+
fit_ridge_t_learner,
|
|
37
|
+
)
|
|
38
|
+
from .artifacts import SelectorArtifactBundle, SelectorArtifactStage
|
|
39
|
+
from .base import Selector, UtilityGainProvider
|
|
40
|
+
from .discovery import SelectorDiscoveryFreeze
|
|
41
|
+
from .learned import (
|
|
42
|
+
PolicyEvaluation,
|
|
43
|
+
RidgeUtilitySelector,
|
|
44
|
+
SelectorExample,
|
|
45
|
+
evaluate_selector,
|
|
46
|
+
fit_ridge_selector,
|
|
47
|
+
)
|
|
48
|
+
from .rules import RuleSelector
|
|
49
|
+
|
|
50
|
+
_SELECTOR_KINDS = frozenset(
|
|
51
|
+
{
|
|
52
|
+
"rule",
|
|
53
|
+
"ridge_utility",
|
|
54
|
+
"ridge_t_learner",
|
|
55
|
+
"logistic_t_learner",
|
|
56
|
+
"gbdt_t_learner",
|
|
57
|
+
"knn_utility",
|
|
58
|
+
"cost_risk_guardrail",
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
_PRIVACY_SAFE_GROUP_ID = re.compile(r"^group_[0-9a-f]{64}$")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass(frozen=True, slots=True)
|
|
65
|
+
class SelectorCalibrationSummary:
|
|
66
|
+
selector: Selector
|
|
67
|
+
evaluation: PolicyEvaluation
|
|
68
|
+
candidates_considered: int
|
|
69
|
+
receipt: Mapping[str, Any]
|
|
70
|
+
|
|
71
|
+
def __post_init__(self) -> None:
|
|
72
|
+
if not isinstance(self.selector, Selector):
|
|
73
|
+
raise ValidationError("calibration summary requires a Selector")
|
|
74
|
+
if not isinstance(self.evaluation, PolicyEvaluation):
|
|
75
|
+
raise ValidationError("calibration summary requires PolicyEvaluation")
|
|
76
|
+
if (
|
|
77
|
+
isinstance(self.candidates_considered, bool)
|
|
78
|
+
or not isinstance(self.candidates_considered, int)
|
|
79
|
+
or self.candidates_considered < 1
|
|
80
|
+
):
|
|
81
|
+
raise ValidationError("calibration candidates_considered must be positive")
|
|
82
|
+
object.__setattr__(self, "receipt", freeze_mapping(self.receipt))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def fit_selector(
|
|
86
|
+
discovery: SelectorDiscoveryFreeze,
|
|
87
|
+
*,
|
|
88
|
+
selector_kind: str,
|
|
89
|
+
fit_config: Mapping[str, Any],
|
|
90
|
+
base_selector_bundle: SelectorArtifactBundle | None = None,
|
|
91
|
+
) -> Selector:
|
|
92
|
+
"""Fit one of the seven catalogued selectors from ``split='train'`` rows."""
|
|
93
|
+
|
|
94
|
+
if not isinstance(discovery, SelectorDiscoveryFreeze):
|
|
95
|
+
raise TypeError("selector fitting requires SelectorDiscoveryFreeze")
|
|
96
|
+
if selector_kind not in _SELECTOR_KINDS:
|
|
97
|
+
raise ValidationError(f"unsupported selector_kind: {selector_kind!r}")
|
|
98
|
+
if selector_kind != "cost_risk_guardrail" and base_selector_bundle is not None:
|
|
99
|
+
raise ValidationError("base_selector_bundle is valid only for cost_risk_guardrail")
|
|
100
|
+
config = _mapping(fit_config, label="fit config")
|
|
101
|
+
train = _examples_for_split(discovery, "train")
|
|
102
|
+
releases = discovery.representative_by_family
|
|
103
|
+
|
|
104
|
+
if selector_kind == "rule":
|
|
105
|
+
_require_exact_keys(config, {"threshold", "margin"}, label="rule fit config")
|
|
106
|
+
return RuleSelector(
|
|
107
|
+
threshold=_number(config["threshold"], label="threshold"),
|
|
108
|
+
margin=_number(config["margin"], label="margin"),
|
|
109
|
+
)
|
|
110
|
+
if selector_kind == "ridge_utility":
|
|
111
|
+
_require_exact_keys(config, {"ridge"}, label="ridge utility fit config")
|
|
112
|
+
return fit_ridge_selector(
|
|
113
|
+
train,
|
|
114
|
+
release_by_family=releases,
|
|
115
|
+
ridge=_nonnegative(config["ridge"], label="ridge"),
|
|
116
|
+
)
|
|
117
|
+
if selector_kind == "ridge_t_learner":
|
|
118
|
+
_require_exact_keys(config, {"ridge"}, label="ridge T-learner fit config")
|
|
119
|
+
return fit_ridge_t_learner(
|
|
120
|
+
train,
|
|
121
|
+
release_by_family=releases,
|
|
122
|
+
ridge=_nonnegative(config["ridge"], label="ridge"),
|
|
123
|
+
)
|
|
124
|
+
if selector_kind == "logistic_t_learner":
|
|
125
|
+
_require_exact_keys(
|
|
126
|
+
config,
|
|
127
|
+
{"l2", "learning_rate", "iterations"},
|
|
128
|
+
label="logistic T-learner fit config",
|
|
129
|
+
)
|
|
130
|
+
return fit_logistic_t_learner(
|
|
131
|
+
train,
|
|
132
|
+
release_by_family=releases,
|
|
133
|
+
l2=_nonnegative(config["l2"], label="l2"),
|
|
134
|
+
learning_rate=_positive(
|
|
135
|
+
config["learning_rate"],
|
|
136
|
+
label="learning_rate",
|
|
137
|
+
),
|
|
138
|
+
iterations=_positive_integer(
|
|
139
|
+
config["iterations"],
|
|
140
|
+
label="iterations",
|
|
141
|
+
),
|
|
142
|
+
)
|
|
143
|
+
if selector_kind == "gbdt_t_learner":
|
|
144
|
+
_require_exact_keys(
|
|
145
|
+
config,
|
|
146
|
+
{
|
|
147
|
+
"n_estimators",
|
|
148
|
+
"learning_rate",
|
|
149
|
+
"max_depth",
|
|
150
|
+
"min_samples_leaf",
|
|
151
|
+
"random_state",
|
|
152
|
+
},
|
|
153
|
+
label="GBDT T-learner fit config",
|
|
154
|
+
)
|
|
155
|
+
return fit_gbdt_t_learner(
|
|
156
|
+
train,
|
|
157
|
+
release_by_family=releases,
|
|
158
|
+
n_estimators=_positive_integer(
|
|
159
|
+
config["n_estimators"],
|
|
160
|
+
label="n_estimators",
|
|
161
|
+
),
|
|
162
|
+
learning_rate=_positive(
|
|
163
|
+
config["learning_rate"],
|
|
164
|
+
label="learning_rate",
|
|
165
|
+
),
|
|
166
|
+
max_depth=_positive_integer(config["max_depth"], label="max_depth"),
|
|
167
|
+
min_samples_leaf=_positive_integer(
|
|
168
|
+
config["min_samples_leaf"],
|
|
169
|
+
label="min_samples_leaf",
|
|
170
|
+
),
|
|
171
|
+
random_state=_integer(config["random_state"], label="random_state"),
|
|
172
|
+
)
|
|
173
|
+
if selector_kind == "knn_utility":
|
|
174
|
+
_require_exact_keys(
|
|
175
|
+
config,
|
|
176
|
+
{"k", "distance_power"},
|
|
177
|
+
label="KNN utility fit config",
|
|
178
|
+
)
|
|
179
|
+
return fit_knn_selector(
|
|
180
|
+
train,
|
|
181
|
+
release_by_family=releases,
|
|
182
|
+
k=_positive_integer(config["k"], label="k"),
|
|
183
|
+
distance_power=_positive(
|
|
184
|
+
config["distance_power"],
|
|
185
|
+
label="distance_power",
|
|
186
|
+
),
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
_require_exact_keys(
|
|
190
|
+
config,
|
|
191
|
+
{"max_cost", "max_risk", "cost_weight", "risk_weight"},
|
|
192
|
+
label="cost/risk guardrail fit config",
|
|
193
|
+
)
|
|
194
|
+
base_selector = _guardrail_base_selector(
|
|
195
|
+
discovery,
|
|
196
|
+
base_selector_bundle,
|
|
197
|
+
)
|
|
198
|
+
declared_releases = getattr(base_selector, "release_by_family", None)
|
|
199
|
+
if not isinstance(declared_releases, Mapping) or dict(declared_releases) != dict(releases):
|
|
200
|
+
raise ValidationError(
|
|
201
|
+
"cost/risk base selector release mapping differs from discovery freeze"
|
|
202
|
+
)
|
|
203
|
+
return fit_cost_risk_selector(
|
|
204
|
+
base_selector,
|
|
205
|
+
train,
|
|
206
|
+
release_by_family=releases,
|
|
207
|
+
max_cost=_nonnegative(config["max_cost"], label="max_cost"),
|
|
208
|
+
max_risk=_bounded(config["max_risk"], label="max_risk"),
|
|
209
|
+
cost_weight=_nonnegative(config["cost_weight"], label="cost_weight"),
|
|
210
|
+
risk_weight=_nonnegative(config["risk_weight"], label="risk_weight"),
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def create_fitted_selector_bundle(
|
|
215
|
+
discovery: SelectorDiscoveryFreeze,
|
|
216
|
+
*,
|
|
217
|
+
selector_kind: str,
|
|
218
|
+
revision: str,
|
|
219
|
+
fit_config: Mapping[str, Any],
|
|
220
|
+
base_selector_bundle: SelectorArtifactBundle | None = None,
|
|
221
|
+
) -> SelectorArtifactBundle:
|
|
222
|
+
"""Fit and bind a selector to one exact discovery freeze."""
|
|
223
|
+
|
|
224
|
+
selector = fit_selector(
|
|
225
|
+
discovery,
|
|
226
|
+
selector_kind=selector_kind,
|
|
227
|
+
fit_config=fit_config,
|
|
228
|
+
base_selector_bundle=base_selector_bundle,
|
|
229
|
+
)
|
|
230
|
+
fit_lineage: Mapping[str, Any] = _selector_fit_lineage(
|
|
231
|
+
discovery,
|
|
232
|
+
fit_config=fit_config,
|
|
233
|
+
)
|
|
234
|
+
if selector_kind == "cost_risk_guardrail":
|
|
235
|
+
if not isinstance(base_selector_bundle, SelectorArtifactBundle):
|
|
236
|
+
raise ValidationError("cost_risk_guardrail requires a SelectorArtifactBundle base")
|
|
237
|
+
fit_lineage = _guardrail_fit_lineage(
|
|
238
|
+
discovery,
|
|
239
|
+
base_selector_bundle,
|
|
240
|
+
fit_config=fit_config,
|
|
241
|
+
)
|
|
242
|
+
return SelectorArtifactBundle.create(
|
|
243
|
+
selector,
|
|
244
|
+
stage=SelectorArtifactStage.FITTED,
|
|
245
|
+
revision=revision,
|
|
246
|
+
extractor_id=discovery.extractor_id,
|
|
247
|
+
extractor_revision=discovery.extractor_revision,
|
|
248
|
+
extractor_hash=discovery.extractor_hash,
|
|
249
|
+
feature_schema_id=discovery.feature_schema_id,
|
|
250
|
+
feature_schema_hash=discovery.feature_schema_hash,
|
|
251
|
+
representative_by_family=discovery.representative_by_family,
|
|
252
|
+
training_table_sha256=discovery.training_table.table_hash,
|
|
253
|
+
split_provenance_hash=discovery.split_provenance_hash,
|
|
254
|
+
comparison_profile_hash=discovery.comparison_profile_hash,
|
|
255
|
+
fit_lineage=fit_lineage,
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def calibrate_selector_bundle(
|
|
260
|
+
fitted: SelectorArtifactBundle,
|
|
261
|
+
discovery: SelectorDiscoveryFreeze,
|
|
262
|
+
*,
|
|
263
|
+
revision: str,
|
|
264
|
+
calibration_config: Mapping[str, Any],
|
|
265
|
+
) -> tuple[SelectorArtifactBundle, SelectorCalibrationSummary]:
|
|
266
|
+
"""Calibrate only predeclared policy gates on discovery calibration rows."""
|
|
267
|
+
|
|
268
|
+
if not isinstance(fitted, SelectorArtifactBundle):
|
|
269
|
+
raise TypeError("selector calibration requires SelectorArtifactBundle")
|
|
270
|
+
if fitted.stage is not SelectorArtifactStage.FITTED:
|
|
271
|
+
raise ValidationError("selector calibration requires a fitted bundle")
|
|
272
|
+
_validate_discovery_binding(fitted, discovery)
|
|
273
|
+
config = _mapping(calibration_config, label="calibration config")
|
|
274
|
+
calibration = _examples_for_split(discovery, "calibration")
|
|
275
|
+
selector = fitted.selector()
|
|
276
|
+
|
|
277
|
+
if isinstance(selector, RuleSelector):
|
|
278
|
+
_require_exact_keys(
|
|
279
|
+
config,
|
|
280
|
+
{"threshold_grid", "margin_grid", "max_harm_rate"},
|
|
281
|
+
label="rule calibration config",
|
|
282
|
+
)
|
|
283
|
+
result = _calibrate_rule(
|
|
284
|
+
selector,
|
|
285
|
+
calibration,
|
|
286
|
+
threshold_grid=_number_array(
|
|
287
|
+
config["threshold_grid"],
|
|
288
|
+
label="threshold_grid",
|
|
289
|
+
lower=0.0,
|
|
290
|
+
upper=1.0,
|
|
291
|
+
),
|
|
292
|
+
margin_grid=_number_array(
|
|
293
|
+
config["margin_grid"],
|
|
294
|
+
label="margin_grid",
|
|
295
|
+
lower=0.0,
|
|
296
|
+
),
|
|
297
|
+
max_harm_rate=_bounded(
|
|
298
|
+
config["max_harm_rate"],
|
|
299
|
+
label="max_harm_rate",
|
|
300
|
+
),
|
|
301
|
+
)
|
|
302
|
+
elif isinstance(selector, CostRiskAwareSelector):
|
|
303
|
+
_require_exact_keys(
|
|
304
|
+
config,
|
|
305
|
+
{
|
|
306
|
+
"max_cost_grid",
|
|
307
|
+
"max_risk_grid",
|
|
308
|
+
"gain_grid",
|
|
309
|
+
"margin_grid",
|
|
310
|
+
"max_harm_rate",
|
|
311
|
+
},
|
|
312
|
+
label="cost/risk calibration config",
|
|
313
|
+
)
|
|
314
|
+
advanced = calibrate_cost_risk_guardrails(
|
|
315
|
+
selector,
|
|
316
|
+
calibration,
|
|
317
|
+
max_cost_grid=_number_array(
|
|
318
|
+
config["max_cost_grid"],
|
|
319
|
+
label="max_cost_grid",
|
|
320
|
+
lower=0.0,
|
|
321
|
+
),
|
|
322
|
+
max_risk_grid=_number_array(
|
|
323
|
+
config["max_risk_grid"],
|
|
324
|
+
label="max_risk_grid",
|
|
325
|
+
lower=0.0,
|
|
326
|
+
upper=1.0,
|
|
327
|
+
),
|
|
328
|
+
gain_grid=_number_array(config["gain_grid"], label="gain_grid"),
|
|
329
|
+
margin_grid=_number_array(
|
|
330
|
+
config["margin_grid"],
|
|
331
|
+
label="margin_grid",
|
|
332
|
+
lower=0.0,
|
|
333
|
+
),
|
|
334
|
+
max_harm_rate=_bounded(
|
|
335
|
+
config["max_harm_rate"],
|
|
336
|
+
label="max_harm_rate",
|
|
337
|
+
),
|
|
338
|
+
)
|
|
339
|
+
result = _from_advanced_calibration(advanced)
|
|
340
|
+
elif isinstance(
|
|
341
|
+
selector,
|
|
342
|
+
(
|
|
343
|
+
RidgeUtilitySelector,
|
|
344
|
+
RidgeTLearnerSelector,
|
|
345
|
+
LogisticTLearnerSelector,
|
|
346
|
+
GBDTTLearnerSelector,
|
|
347
|
+
KNNUtilitySelector,
|
|
348
|
+
),
|
|
349
|
+
):
|
|
350
|
+
_require_exact_keys(
|
|
351
|
+
config,
|
|
352
|
+
{"gain_grid", "margin_grid", "max_harm_rate"},
|
|
353
|
+
label="selector calibration config",
|
|
354
|
+
)
|
|
355
|
+
advanced = calibrate_selector_abstention(
|
|
356
|
+
selector,
|
|
357
|
+
calibration,
|
|
358
|
+
gain_grid=_number_array(config["gain_grid"], label="gain_grid"),
|
|
359
|
+
margin_grid=_number_array(
|
|
360
|
+
config["margin_grid"],
|
|
361
|
+
label="margin_grid",
|
|
362
|
+
lower=0.0,
|
|
363
|
+
),
|
|
364
|
+
max_harm_rate=_bounded(
|
|
365
|
+
config["max_harm_rate"],
|
|
366
|
+
label="max_harm_rate",
|
|
367
|
+
),
|
|
368
|
+
)
|
|
369
|
+
result = _from_advanced_calibration(advanced)
|
|
370
|
+
else: # pragma: no cover - bundle codec admits exactly the seven selectors
|
|
371
|
+
raise ValidationError(f"unsupported selector calibration type: {type(selector).__name__}")
|
|
372
|
+
|
|
373
|
+
receipt = {
|
|
374
|
+
"schema_version": 1,
|
|
375
|
+
"predecessor_bundle_hash": fitted.bundle_hash,
|
|
376
|
+
"discovery_hash": discovery.discovery_hash,
|
|
377
|
+
"calibration_config_hash": content_hash(config),
|
|
378
|
+
"calibration_split_digest": discovery.training_table.group_split_digests["calibration"],
|
|
379
|
+
"candidates_considered": result.candidates_considered,
|
|
380
|
+
"evaluation": _evaluation_to_artifact(result.evaluation),
|
|
381
|
+
}
|
|
382
|
+
summary = SelectorCalibrationSummary(
|
|
383
|
+
selector=result.selector,
|
|
384
|
+
evaluation=result.evaluation,
|
|
385
|
+
candidates_considered=result.candidates_considered,
|
|
386
|
+
receipt=receipt,
|
|
387
|
+
)
|
|
388
|
+
calibrated = SelectorArtifactBundle.create(
|
|
389
|
+
result.selector,
|
|
390
|
+
stage=SelectorArtifactStage.CALIBRATED,
|
|
391
|
+
revision=revision,
|
|
392
|
+
extractor_id=fitted.extractor_id,
|
|
393
|
+
extractor_revision=fitted.extractor_revision,
|
|
394
|
+
extractor_hash=fitted.extractor_hash,
|
|
395
|
+
feature_schema_id=fitted.feature_schema_id,
|
|
396
|
+
feature_schema_hash=fitted.feature_schema_hash,
|
|
397
|
+
representative_by_family=fitted.representative_by_family,
|
|
398
|
+
training_table_sha256=fitted.training_table_sha256,
|
|
399
|
+
split_provenance_hash=fitted.split_provenance_hash,
|
|
400
|
+
comparison_profile_hash=fitted.comparison_profile_hash,
|
|
401
|
+
calibration_receipt=receipt,
|
|
402
|
+
fit_lineage=fitted.fit_lineage,
|
|
403
|
+
)
|
|
404
|
+
return calibrated, summary
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def freeze_selector_bundle(
|
|
408
|
+
calibrated: SelectorArtifactBundle,
|
|
409
|
+
*,
|
|
410
|
+
revision: str,
|
|
411
|
+
) -> SelectorArtifactBundle:
|
|
412
|
+
"""Create a byte-equivalent policy at the terminal frozen stage."""
|
|
413
|
+
|
|
414
|
+
if not isinstance(calibrated, SelectorArtifactBundle):
|
|
415
|
+
raise TypeError("selector freeze requires SelectorArtifactBundle")
|
|
416
|
+
if calibrated.stage is not SelectorArtifactStage.CALIBRATED:
|
|
417
|
+
raise ValidationError("selector freeze requires a calibrated bundle")
|
|
418
|
+
return replace(
|
|
419
|
+
calibrated,
|
|
420
|
+
stage=SelectorArtifactStage.FROZEN,
|
|
421
|
+
revision=revision,
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def build_selector_policy_manifest(
|
|
426
|
+
frozen: SelectorArtifactBundle,
|
|
427
|
+
discovery: SelectorDiscoveryFreeze,
|
|
428
|
+
) -> Mapping[str, Any]:
|
|
429
|
+
"""Derive the locked global comparator from the frozen calibration split.
|
|
430
|
+
|
|
431
|
+
The returned object is the exact schema consumed by the external-arena
|
|
432
|
+
driver. It is intentionally derived from a content-addressed discovery
|
|
433
|
+
freeze and a selector bundle already at the terminal ``frozen`` stage;
|
|
434
|
+
callers never type a family or release ID into the policy manifest by
|
|
435
|
+
hand.
|
|
436
|
+
"""
|
|
437
|
+
|
|
438
|
+
if not isinstance(frozen, SelectorArtifactBundle):
|
|
439
|
+
raise TypeError("policy manifest production requires SelectorArtifactBundle")
|
|
440
|
+
if frozen.stage is not SelectorArtifactStage.FROZEN:
|
|
441
|
+
raise ValidationError("policy manifest requires a frozen selector bundle")
|
|
442
|
+
_validate_discovery_binding(frozen, discovery)
|
|
443
|
+
lineage = frozen.fit_lineage
|
|
444
|
+
lineage_discovery = lineage.get("discovery") if isinstance(lineage, Mapping) else None
|
|
445
|
+
if (
|
|
446
|
+
not isinstance(lineage_discovery, Mapping)
|
|
447
|
+
or lineage_discovery.get("revision") != discovery.revision
|
|
448
|
+
or lineage_discovery.get("sha256") != discovery.discovery_hash
|
|
449
|
+
):
|
|
450
|
+
raise ValidationError(
|
|
451
|
+
"frozen selector fit lineage differs from the supplied discovery freeze"
|
|
452
|
+
)
|
|
453
|
+
calibration_receipt = frozen.calibration_receipt
|
|
454
|
+
if calibration_receipt.get(
|
|
455
|
+
"discovery_hash"
|
|
456
|
+
) != discovery.discovery_hash or calibration_receipt.get(
|
|
457
|
+
"calibration_split_digest"
|
|
458
|
+
) != discovery.training_table.group_split_digests.get("calibration"):
|
|
459
|
+
raise ValidationError(
|
|
460
|
+
"frozen selector calibration receipt differs from the supplied discovery freeze"
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
calibration = _examples_for_split(discovery, "calibration")
|
|
464
|
+
families = tuple(sorted(discovery.representative_by_family, key=lambda item: item.value))
|
|
465
|
+
if len(families) != 5 or any(
|
|
466
|
+
set(row.utilities) != {SemanticFamily.NO_OP, *families} for row in calibration
|
|
467
|
+
):
|
|
468
|
+
raise ValidationError(
|
|
469
|
+
"locked best-eligible-global selection requires a full-five-family "
|
|
470
|
+
"calibration block for every state"
|
|
471
|
+
)
|
|
472
|
+
mean_utility = {
|
|
473
|
+
family: fmean(row.utilities[family] for row in calibration) for family in families
|
|
474
|
+
}
|
|
475
|
+
selected_family = min(
|
|
476
|
+
families,
|
|
477
|
+
key=lambda family: (-mean_utility[family], family.value),
|
|
478
|
+
)
|
|
479
|
+
selected_release = discovery.representative_by_family[selected_family]
|
|
480
|
+
calibration_digest = discovery.training_table.group_split_digests["calibration"]
|
|
481
|
+
members_by_split = {
|
|
482
|
+
split: tuple(
|
|
483
|
+
sorted({outcome.group_id for outcome in discovery.outcomes if outcome.split == split})
|
|
484
|
+
)
|
|
485
|
+
for split in ("train", "calibration")
|
|
486
|
+
}
|
|
487
|
+
if any(
|
|
488
|
+
not members or any(_PRIVACY_SAFE_GROUP_ID.fullmatch(item) is None for item in members)
|
|
489
|
+
for members in members_by_split.values()
|
|
490
|
+
):
|
|
491
|
+
raise ValidationError(
|
|
492
|
+
"policy manifest requires privacy-safe benchmark-scoped group hashes "
|
|
493
|
+
"for train and calibration"
|
|
494
|
+
)
|
|
495
|
+
if set(members_by_split["train"]).intersection(members_by_split["calibration"]):
|
|
496
|
+
raise ValidationError("policy manifest group membership crosses splits")
|
|
497
|
+
partition_splits = {
|
|
498
|
+
split: {
|
|
499
|
+
"member_hashes": members,
|
|
500
|
+
"commitment_sha256": content_hash({"split": split, "group_ids": list(members)}),
|
|
501
|
+
}
|
|
502
|
+
for split, members in members_by_split.items()
|
|
503
|
+
}
|
|
504
|
+
if {split: row["commitment_sha256"] for split, row in partition_splits.items()} != {
|
|
505
|
+
split: discovery.training_table.group_split_digests[split]
|
|
506
|
+
for split in ("train", "calibration")
|
|
507
|
+
}:
|
|
508
|
+
raise ValidationError("policy group membership differs from the frozen split provenance")
|
|
509
|
+
return freeze_mapping(
|
|
510
|
+
{
|
|
511
|
+
"schema_version": 1,
|
|
512
|
+
"artifact": "agentinputlab.selector_policy_manifest",
|
|
513
|
+
"stage": "frozen",
|
|
514
|
+
"discovery": {
|
|
515
|
+
"revision": discovery.revision,
|
|
516
|
+
"sha256": discovery.discovery_hash,
|
|
517
|
+
},
|
|
518
|
+
"training_table_sha256": discovery.training_table.table_hash,
|
|
519
|
+
"split_provenance_hash": discovery.split_provenance_hash,
|
|
520
|
+
"comparison_profile_hash": discovery.comparison_profile_hash,
|
|
521
|
+
"representative_by_family": {
|
|
522
|
+
family.value: release_id
|
|
523
|
+
for family, release_id in sorted(
|
|
524
|
+
discovery.representative_by_family.items(),
|
|
525
|
+
key=lambda item: item[0].value,
|
|
526
|
+
)
|
|
527
|
+
},
|
|
528
|
+
"group_partition": {
|
|
529
|
+
"schema_version": 1,
|
|
530
|
+
"hash_scheme": "benchmark_group.content_hash.v1",
|
|
531
|
+
"splits": partition_splits,
|
|
532
|
+
},
|
|
533
|
+
"locked_best_eligible_global": {
|
|
534
|
+
"selected_family": selected_family.value,
|
|
535
|
+
"selected_release_id": selected_release,
|
|
536
|
+
"selection_receipt": {
|
|
537
|
+
"schema_version": 1,
|
|
538
|
+
"rule_id": "best_eligible_global.v1",
|
|
539
|
+
"selection_split": "calibration",
|
|
540
|
+
"training_table_sha256": discovery.training_table.table_hash,
|
|
541
|
+
"calibration_split_digest": calibration_digest,
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
}
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def load_selector_fit_config(path: str | Path) -> tuple[str, Mapping[str, Any]]:
|
|
549
|
+
raw = _read_json(path, label="selector fit config")
|
|
550
|
+
_require_exact_keys(
|
|
551
|
+
raw,
|
|
552
|
+
{"schema_version", "selector_kind", "fit"},
|
|
553
|
+
label="selector fit config",
|
|
554
|
+
)
|
|
555
|
+
if _integer(raw["schema_version"], label="schema_version") != 1:
|
|
556
|
+
raise ValidationError("unsupported selector fit config schema")
|
|
557
|
+
kind = _text(raw["selector_kind"], label="selector_kind")
|
|
558
|
+
if kind not in _SELECTOR_KINDS:
|
|
559
|
+
raise ValidationError(f"unsupported selector_kind: {kind!r}")
|
|
560
|
+
return kind, freeze_mapping(_mapping(raw["fit"], label="fit"))
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
def load_selector_calibration_config(path: str | Path) -> Mapping[str, Any]:
|
|
564
|
+
raw = _read_json(path, label="selector calibration config")
|
|
565
|
+
_require_exact_keys(
|
|
566
|
+
raw,
|
|
567
|
+
{"schema_version", "calibration"},
|
|
568
|
+
label="selector calibration config",
|
|
569
|
+
)
|
|
570
|
+
if _integer(raw["schema_version"], label="schema_version") != 1:
|
|
571
|
+
raise ValidationError("unsupported selector calibration config schema")
|
|
572
|
+
return freeze_mapping(_mapping(raw["calibration"], label="calibration"))
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
def _guardrail_base_selector(
|
|
576
|
+
discovery: SelectorDiscoveryFreeze,
|
|
577
|
+
base_bundle: SelectorArtifactBundle | None,
|
|
578
|
+
) -> UtilityGainProvider:
|
|
579
|
+
if not isinstance(base_bundle, SelectorArtifactBundle):
|
|
580
|
+
raise ValidationError(
|
|
581
|
+
"cost_risk_guardrail requires a SelectorArtifactBundle base, not a naked selector"
|
|
582
|
+
)
|
|
583
|
+
_validate_discovery_binding(base_bundle, discovery)
|
|
584
|
+
_validate_base_discovery_lineage(base_bundle, discovery)
|
|
585
|
+
base_selector = base_bundle.selector()
|
|
586
|
+
if not isinstance(base_selector, UtilityGainProvider):
|
|
587
|
+
raise ValidationError("cost_risk_guardrail base bundle must contain a UtilityGainProvider")
|
|
588
|
+
return base_selector
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def _guardrail_fit_lineage(
|
|
592
|
+
discovery: SelectorDiscoveryFreeze,
|
|
593
|
+
base_bundle: SelectorArtifactBundle,
|
|
594
|
+
*,
|
|
595
|
+
fit_config: Mapping[str, Any],
|
|
596
|
+
) -> Mapping[str, Any]:
|
|
597
|
+
_validate_discovery_binding(base_bundle, discovery)
|
|
598
|
+
return freeze_mapping(
|
|
599
|
+
{
|
|
600
|
+
"schema_version": 1,
|
|
601
|
+
"kind": "cost_risk_guardrail_base_bundle",
|
|
602
|
+
"discovery": {
|
|
603
|
+
"revision": discovery.revision,
|
|
604
|
+
"sha256": discovery.discovery_hash,
|
|
605
|
+
},
|
|
606
|
+
"fit_config_sha256": content_hash(_mapping(fit_config, label="fit config")),
|
|
607
|
+
"base_selector_bundle": {
|
|
608
|
+
"selector_id": base_bundle.selector_card_id,
|
|
609
|
+
"revision": base_bundle.revision,
|
|
610
|
+
"sha256": base_bundle.bundle_hash,
|
|
611
|
+
"stage": base_bundle.stage.value,
|
|
612
|
+
"model_hash": base_bundle.model_hash,
|
|
613
|
+
},
|
|
614
|
+
}
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
def _selector_fit_lineage(
|
|
619
|
+
discovery: SelectorDiscoveryFreeze,
|
|
620
|
+
*,
|
|
621
|
+
fit_config: Mapping[str, Any],
|
|
622
|
+
) -> Mapping[str, Any]:
|
|
623
|
+
return freeze_mapping(
|
|
624
|
+
{
|
|
625
|
+
"schema_version": 1,
|
|
626
|
+
"kind": "selector_fit",
|
|
627
|
+
"discovery": {
|
|
628
|
+
"revision": discovery.revision,
|
|
629
|
+
"sha256": discovery.discovery_hash,
|
|
630
|
+
},
|
|
631
|
+
"fit_config_sha256": content_hash(_mapping(fit_config, label="fit config")),
|
|
632
|
+
}
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
def _validate_base_discovery_lineage(
|
|
637
|
+
base_bundle: SelectorArtifactBundle,
|
|
638
|
+
discovery: SelectorDiscoveryFreeze,
|
|
639
|
+
) -> None:
|
|
640
|
+
lineage = base_bundle.fit_lineage
|
|
641
|
+
if not lineage:
|
|
642
|
+
raise ValidationError("cost_risk_guardrail base bundle lacks exact discovery fit lineage")
|
|
643
|
+
source = lineage.get("discovery")
|
|
644
|
+
if not isinstance(source, Mapping):
|
|
645
|
+
raise ValidationError("cost_risk_guardrail base bundle has invalid discovery fit lineage")
|
|
646
|
+
if (
|
|
647
|
+
source.get("revision") != discovery.revision
|
|
648
|
+
or source.get("sha256") != discovery.discovery_hash
|
|
649
|
+
):
|
|
650
|
+
raise ValidationError(
|
|
651
|
+
"cost/risk base selector bundle was fitted from an unrelated SelectorDiscoveryFreeze"
|
|
652
|
+
)
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
def _validate_discovery_binding(
|
|
656
|
+
bundle: SelectorArtifactBundle,
|
|
657
|
+
discovery: SelectorDiscoveryFreeze,
|
|
658
|
+
) -> None:
|
|
659
|
+
if not isinstance(discovery, SelectorDiscoveryFreeze):
|
|
660
|
+
raise TypeError("selector calibration requires SelectorDiscoveryFreeze")
|
|
661
|
+
expected = {
|
|
662
|
+
"extractor_id": discovery.extractor_id,
|
|
663
|
+
"extractor_revision": discovery.extractor_revision,
|
|
664
|
+
"extractor_hash": discovery.extractor_hash,
|
|
665
|
+
"feature_schema_id": discovery.feature_schema_id,
|
|
666
|
+
"feature_schema_hash": discovery.feature_schema_hash,
|
|
667
|
+
"representative_by_family": discovery.representative_by_family,
|
|
668
|
+
"training_table_sha256": discovery.training_table.table_hash,
|
|
669
|
+
"split_provenance_hash": discovery.split_provenance_hash,
|
|
670
|
+
"comparison_profile_hash": discovery.comparison_profile_hash,
|
|
671
|
+
}
|
|
672
|
+
if any(getattr(bundle, name) != value for name, value in expected.items()):
|
|
673
|
+
raise ValidationError("fitted selector bundle differs from the supplied discovery freeze")
|
|
674
|
+
if "calibration" not in discovery.training_table.group_split_digests:
|
|
675
|
+
raise ValidationError("discovery freeze contains no calibration split")
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
def _examples_for_split(
|
|
679
|
+
discovery: SelectorDiscoveryFreeze,
|
|
680
|
+
split: str,
|
|
681
|
+
) -> tuple[SelectorExample, ...]:
|
|
682
|
+
rows = tuple(item for item in discovery.training_table.examples if item.split == split)
|
|
683
|
+
if not rows:
|
|
684
|
+
raise ValidationError(f"selector discovery freeze has no {split!r} examples")
|
|
685
|
+
return rows
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
def _calibrate_rule(
|
|
689
|
+
selector: RuleSelector,
|
|
690
|
+
examples: Sequence[SelectorExample],
|
|
691
|
+
*,
|
|
692
|
+
threshold_grid: Sequence[float],
|
|
693
|
+
margin_grid: Sequence[float],
|
|
694
|
+
max_harm_rate: float,
|
|
695
|
+
) -> SelectorCalibrationResult:
|
|
696
|
+
candidates: list[tuple[PolicyEvaluation, RuleSelector]] = []
|
|
697
|
+
considered = 0
|
|
698
|
+
for threshold in threshold_grid:
|
|
699
|
+
for margin in margin_grid:
|
|
700
|
+
considered += 1
|
|
701
|
+
candidate = replace(
|
|
702
|
+
selector,
|
|
703
|
+
threshold=float(threshold),
|
|
704
|
+
margin=float(margin),
|
|
705
|
+
)
|
|
706
|
+
evaluation = evaluate_selector(
|
|
707
|
+
candidate,
|
|
708
|
+
examples,
|
|
709
|
+
required_split="calibration",
|
|
710
|
+
)
|
|
711
|
+
if evaluation.harm_rate <= max_harm_rate:
|
|
712
|
+
candidates.append((evaluation, candidate))
|
|
713
|
+
if not candidates:
|
|
714
|
+
raise ValidationError("no rule calibration candidate satisfies the harm constraint")
|
|
715
|
+
evaluation, selected = max(
|
|
716
|
+
candidates,
|
|
717
|
+
key=lambda item: (
|
|
718
|
+
item[0].mean_policy_value,
|
|
719
|
+
item[0].coverage,
|
|
720
|
+
-item[0].harm_rate,
|
|
721
|
+
-item[1].threshold,
|
|
722
|
+
-item[1].margin,
|
|
723
|
+
),
|
|
724
|
+
)
|
|
725
|
+
return SelectorCalibrationResult(selected, evaluation, considered)
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
def _from_advanced_calibration(
|
|
729
|
+
result: SelectorCalibrationResult,
|
|
730
|
+
) -> SelectorCalibrationResult:
|
|
731
|
+
if not isinstance(result, SelectorCalibrationResult): # pragma: no cover
|
|
732
|
+
raise TypeError("calibration API returned an invalid result")
|
|
733
|
+
return result
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
def _evaluation_to_artifact(value: PolicyEvaluation) -> dict[str, Any]:
|
|
737
|
+
return {
|
|
738
|
+
"count": value.count,
|
|
739
|
+
"coverage": value.coverage,
|
|
740
|
+
"mean_policy_value": value.mean_policy_value,
|
|
741
|
+
"mean_no_op_value": value.mean_no_op_value,
|
|
742
|
+
"mean_gain": value.mean_gain,
|
|
743
|
+
"harm_rate": value.harm_rate,
|
|
744
|
+
"oracle_regret": value.oracle_regret,
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
def _read_json(path: str | Path, *, label: str) -> dict[str, Any]:
|
|
749
|
+
source = Path(path).expanduser().resolve()
|
|
750
|
+
try:
|
|
751
|
+
raw = json.loads(source.read_text(encoding="utf-8"))
|
|
752
|
+
except (OSError, UnicodeError, json.JSONDecodeError) as exc:
|
|
753
|
+
raise ArtifactError(f"{label} is not valid UTF-8 JSON: {source}") from exc
|
|
754
|
+
return _mapping(raw, label=label)
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
def _require_exact_keys(
|
|
758
|
+
value: Mapping[str, Any],
|
|
759
|
+
expected: set[str],
|
|
760
|
+
*,
|
|
761
|
+
label: str,
|
|
762
|
+
) -> None:
|
|
763
|
+
if set(value) != expected:
|
|
764
|
+
raise ValidationError(
|
|
765
|
+
f"{label} fields differ: expected {sorted(expected)!r}, got {sorted(value)!r}"
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
def _mapping(value: object, *, label: str) -> dict[str, Any]:
|
|
770
|
+
if not isinstance(value, Mapping) or any(not isinstance(key, str) for key in value):
|
|
771
|
+
raise ValidationError(f"{label} must be an object with string keys")
|
|
772
|
+
return dict(value)
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
def _array(value: object, *, label: str) -> list[Any]:
|
|
776
|
+
if not isinstance(value, (list, tuple)):
|
|
777
|
+
raise ValidationError(f"{label} must be an array")
|
|
778
|
+
return list(value)
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
def _text(value: object, *, label: str) -> str:
|
|
782
|
+
if not isinstance(value, str) or not value.strip() or value != value.strip():
|
|
783
|
+
raise ValidationError(f"{label} must be a trimmed non-empty string")
|
|
784
|
+
return value
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
def _integer(value: object, *, label: str) -> int:
|
|
788
|
+
if isinstance(value, bool) or not isinstance(value, int):
|
|
789
|
+
raise ValidationError(f"{label} must be an integer")
|
|
790
|
+
return value
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
def _positive_integer(value: object, *, label: str) -> int:
|
|
794
|
+
result = _integer(value, label=label)
|
|
795
|
+
if result < 1:
|
|
796
|
+
raise ValidationError(f"{label} must be positive")
|
|
797
|
+
return result
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
def _number(value: object, *, label: str) -> float:
|
|
801
|
+
if isinstance(value, bool) or not isinstance(value, (int, float)) or not math.isfinite(value):
|
|
802
|
+
raise ValidationError(f"{label} must be a finite number")
|
|
803
|
+
return float(value)
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
def _positive(value: object, *, label: str) -> float:
|
|
807
|
+
result = _number(value, label=label)
|
|
808
|
+
if result <= 0:
|
|
809
|
+
raise ValidationError(f"{label} must be positive")
|
|
810
|
+
return result
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
def _nonnegative(value: object, *, label: str) -> float:
|
|
814
|
+
result = _number(value, label=label)
|
|
815
|
+
if result < 0:
|
|
816
|
+
raise ValidationError(f"{label} must be non-negative")
|
|
817
|
+
return result
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
def _bounded(value: object, *, label: str) -> float:
|
|
821
|
+
result = _number(value, label=label)
|
|
822
|
+
if not 0 <= result <= 1:
|
|
823
|
+
raise ValidationError(f"{label} must be in [0, 1]")
|
|
824
|
+
return result
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
def _number_array(
|
|
828
|
+
value: object,
|
|
829
|
+
*,
|
|
830
|
+
label: str,
|
|
831
|
+
lower: float | None = None,
|
|
832
|
+
upper: float | None = None,
|
|
833
|
+
) -> tuple[float, ...]:
|
|
834
|
+
raw = _array(value, label=label)
|
|
835
|
+
if not raw:
|
|
836
|
+
raise ValidationError(f"{label} must not be empty")
|
|
837
|
+
numbers = tuple(_number(item, label=f"{label} item") for item in raw)
|
|
838
|
+
if lower is not None and any(item < lower for item in numbers):
|
|
839
|
+
raise ValidationError(f"{label} values must be at least {lower:g}")
|
|
840
|
+
if upper is not None and any(item > upper for item in numbers):
|
|
841
|
+
raise ValidationError(f"{label} values must be at most {upper:g}")
|
|
842
|
+
return tuple(sorted(set(numbers)))
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
__all__ = [
|
|
846
|
+
"SelectorCalibrationSummary",
|
|
847
|
+
"calibrate_selector_bundle",
|
|
848
|
+
"create_fitted_selector_bundle",
|
|
849
|
+
"fit_selector",
|
|
850
|
+
"freeze_selector_bundle",
|
|
851
|
+
"load_selector_calibration_config",
|
|
852
|
+
"load_selector_fit_config",
|
|
853
|
+
]
|