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,509 @@
|
|
|
1
|
+
"""Fail-closed batch execution for unified benchmark adapters.
|
|
2
|
+
|
|
3
|
+
Prediction runners receive only the evaluator-blind :class:`FrozenAgentState`.
|
|
4
|
+
The original :class:`BenchmarkExample`, including evaluator gold, crosses the
|
|
5
|
+
boundary only when the adapter scores a completed prediction.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import math
|
|
11
|
+
from collections.abc import Callable, Iterable, Mapping
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from numbers import Real
|
|
14
|
+
from typing import Any, TypeAlias
|
|
15
|
+
|
|
16
|
+
from agentinputlab.contracts.errors import ValidationError
|
|
17
|
+
from agentinputlab.contracts.serialization import (
|
|
18
|
+
canonical_json,
|
|
19
|
+
deep_freeze_jsonable,
|
|
20
|
+
freeze_mapping,
|
|
21
|
+
)
|
|
22
|
+
from agentinputlab.contracts.state import ExecutionBudget, FrozenAgentState
|
|
23
|
+
|
|
24
|
+
from .base import BenchmarkAdapter, BenchmarkExample
|
|
25
|
+
|
|
26
|
+
PredictionRunner: TypeAlias = Callable[[FrozenAgentState], Any]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True, slots=True)
|
|
30
|
+
class BenchmarkExampleRecord:
|
|
31
|
+
"""One prediction, its evaluator-produced metrics, and scorer provenance."""
|
|
32
|
+
|
|
33
|
+
example_id: str
|
|
34
|
+
state_hash: str
|
|
35
|
+
prediction: Any = field(repr=False)
|
|
36
|
+
metrics: Mapping[str, float]
|
|
37
|
+
evaluation_provenance: Mapping[str, Any] = field(default_factory=dict)
|
|
38
|
+
|
|
39
|
+
def __post_init__(self) -> None:
|
|
40
|
+
_require_nonempty_text(self.example_id, field_name="example_id")
|
|
41
|
+
_require_state_hash(self.state_hash)
|
|
42
|
+
try:
|
|
43
|
+
frozen_prediction = deep_freeze_jsonable(self.prediction)
|
|
44
|
+
canonical_json(frozen_prediction)
|
|
45
|
+
except (TypeError, ValueError) as exc:
|
|
46
|
+
raise ValidationError(
|
|
47
|
+
f"prediction for example {self.example_id!r} must be canonically serializable: "
|
|
48
|
+
f"{exc}"
|
|
49
|
+
) from exc
|
|
50
|
+
object.__setattr__(self, "prediction", frozen_prediction)
|
|
51
|
+
object.__setattr__(
|
|
52
|
+
self,
|
|
53
|
+
"metrics",
|
|
54
|
+
_validated_metrics(self.metrics, example_id=self.example_id),
|
|
55
|
+
)
|
|
56
|
+
object.__setattr__(
|
|
57
|
+
self,
|
|
58
|
+
"evaluation_provenance",
|
|
59
|
+
_validated_evaluation_provenance(
|
|
60
|
+
self.evaluation_provenance,
|
|
61
|
+
example_id=self.example_id,
|
|
62
|
+
),
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass(frozen=True, slots=True)
|
|
67
|
+
class BenchmarkBatchRecord:
|
|
68
|
+
"""Complete batch result for one benchmark split and prediction runner."""
|
|
69
|
+
|
|
70
|
+
benchmark_id: str
|
|
71
|
+
split: str
|
|
72
|
+
examples: tuple[BenchmarkExampleRecord, ...]
|
|
73
|
+
aggregate_metrics: Mapping[str, float]
|
|
74
|
+
|
|
75
|
+
def __post_init__(self) -> None:
|
|
76
|
+
_require_nonempty_text(self.benchmark_id, field_name="benchmark_id")
|
|
77
|
+
_require_nonempty_text(self.split, field_name="split")
|
|
78
|
+
examples = tuple(self.examples)
|
|
79
|
+
if not examples:
|
|
80
|
+
raise ValidationError("benchmark batch must contain at least one example")
|
|
81
|
+
if not all(isinstance(record, BenchmarkExampleRecord) for record in examples):
|
|
82
|
+
raise ValidationError("batch examples must be BenchmarkExampleRecord instances")
|
|
83
|
+
_require_unique_example_ids(record.example_id for record in examples)
|
|
84
|
+
expected = _metric_keys(examples[0].metrics)
|
|
85
|
+
for record in examples[1:]:
|
|
86
|
+
_require_same_metric_keys(expected, record.metrics, example_id=record.example_id)
|
|
87
|
+
validated_aggregate = _validated_metrics(
|
|
88
|
+
self.aggregate_metrics,
|
|
89
|
+
example_id="<aggregate>",
|
|
90
|
+
)
|
|
91
|
+
_require_same_metric_keys(expected, validated_aggregate, example_id="<aggregate>")
|
|
92
|
+
computed_aggregate = _aggregate_metrics(tuple(record.metrics for record in examples))
|
|
93
|
+
_require_same_metric_values(
|
|
94
|
+
computed_aggregate,
|
|
95
|
+
validated_aggregate,
|
|
96
|
+
record_name="batch aggregate",
|
|
97
|
+
)
|
|
98
|
+
object.__setattr__(self, "examples", examples)
|
|
99
|
+
object.__setattr__(self, "aggregate_metrics", validated_aggregate)
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def example_count(self) -> int:
|
|
103
|
+
return len(self.examples)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@dataclass(frozen=True, slots=True)
|
|
107
|
+
class PairedBenchmarkExampleRecord:
|
|
108
|
+
"""Baseline and treatment outcomes sharing one pre-action state identity."""
|
|
109
|
+
|
|
110
|
+
example_id: str
|
|
111
|
+
state_hash: str
|
|
112
|
+
baseline: BenchmarkExampleRecord
|
|
113
|
+
treatment: BenchmarkExampleRecord
|
|
114
|
+
metric_deltas: Mapping[str, float]
|
|
115
|
+
|
|
116
|
+
def __post_init__(self) -> None:
|
|
117
|
+
_require_nonempty_text(self.example_id, field_name="example_id")
|
|
118
|
+
_require_state_hash(self.state_hash)
|
|
119
|
+
if not isinstance(self.baseline, BenchmarkExampleRecord) or not isinstance(
|
|
120
|
+
self.treatment, BenchmarkExampleRecord
|
|
121
|
+
):
|
|
122
|
+
raise ValidationError("paired outcomes must be BenchmarkExampleRecord instances")
|
|
123
|
+
for arm_name, record in (
|
|
124
|
+
("baseline", self.baseline),
|
|
125
|
+
("treatment", self.treatment),
|
|
126
|
+
):
|
|
127
|
+
if record.example_id != self.example_id:
|
|
128
|
+
raise ValidationError(f"{arm_name} example ID differs from paired example ID")
|
|
129
|
+
if record.state_hash != self.state_hash:
|
|
130
|
+
raise ValidationError(f"{arm_name} state hash differs from paired state hash")
|
|
131
|
+
expected = _metric_keys(self.baseline.metrics)
|
|
132
|
+
_require_same_metric_keys(expected, self.treatment.metrics, example_id=self.example_id)
|
|
133
|
+
deltas = _validated_metrics(self.metric_deltas, example_id=self.example_id)
|
|
134
|
+
_require_same_metric_keys(expected, deltas, example_id=self.example_id)
|
|
135
|
+
for key in expected:
|
|
136
|
+
expected_delta = self.treatment.metrics[key] - self.baseline.metrics[key]
|
|
137
|
+
if deltas[key] != expected_delta:
|
|
138
|
+
raise ValidationError(
|
|
139
|
+
f"metric delta {key!r} for example {self.example_id!r} is inconsistent"
|
|
140
|
+
)
|
|
141
|
+
object.__setattr__(self, "metric_deltas", deltas)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@dataclass(frozen=True, slots=True)
|
|
145
|
+
class PairedBenchmarkRecord:
|
|
146
|
+
"""Aggregated baseline/treatment comparison over a benchmark split."""
|
|
147
|
+
|
|
148
|
+
benchmark_id: str
|
|
149
|
+
split: str
|
|
150
|
+
examples: tuple[PairedBenchmarkExampleRecord, ...]
|
|
151
|
+
baseline_metrics: Mapping[str, float]
|
|
152
|
+
treatment_metrics: Mapping[str, float]
|
|
153
|
+
metric_deltas: Mapping[str, float]
|
|
154
|
+
|
|
155
|
+
def __post_init__(self) -> None:
|
|
156
|
+
_require_nonempty_text(self.benchmark_id, field_name="benchmark_id")
|
|
157
|
+
_require_nonempty_text(self.split, field_name="split")
|
|
158
|
+
examples = tuple(self.examples)
|
|
159
|
+
if not examples:
|
|
160
|
+
raise ValidationError("paired benchmark must contain at least one example")
|
|
161
|
+
if not all(isinstance(record, PairedBenchmarkExampleRecord) for record in examples):
|
|
162
|
+
raise ValidationError("paired examples must be PairedBenchmarkExampleRecord instances")
|
|
163
|
+
_require_unique_example_ids(record.example_id for record in examples)
|
|
164
|
+
expected = _metric_keys(examples[0].metric_deltas)
|
|
165
|
+
for record in examples[1:]:
|
|
166
|
+
_require_same_metric_keys(expected, record.metric_deltas, example_id=record.example_id)
|
|
167
|
+
baseline = _validated_metrics(self.baseline_metrics, example_id="<baseline aggregate>")
|
|
168
|
+
treatment = _validated_metrics(
|
|
169
|
+
self.treatment_metrics,
|
|
170
|
+
example_id="<treatment aggregate>",
|
|
171
|
+
)
|
|
172
|
+
deltas = _validated_metrics(self.metric_deltas, example_id="<paired aggregate>")
|
|
173
|
+
for name, metrics in (
|
|
174
|
+
("baseline aggregate", baseline),
|
|
175
|
+
("treatment aggregate", treatment),
|
|
176
|
+
("paired aggregate", deltas),
|
|
177
|
+
):
|
|
178
|
+
_require_same_metric_keys(expected, metrics, example_id=f"<{name}>")
|
|
179
|
+
computed_baseline = _aggregate_metrics(
|
|
180
|
+
tuple(record.baseline.metrics for record in examples)
|
|
181
|
+
)
|
|
182
|
+
computed_treatment = _aggregate_metrics(
|
|
183
|
+
tuple(record.treatment.metrics for record in examples)
|
|
184
|
+
)
|
|
185
|
+
_require_same_metric_values(
|
|
186
|
+
computed_baseline,
|
|
187
|
+
baseline,
|
|
188
|
+
record_name="baseline aggregate",
|
|
189
|
+
)
|
|
190
|
+
_require_same_metric_values(
|
|
191
|
+
computed_treatment,
|
|
192
|
+
treatment,
|
|
193
|
+
record_name="treatment aggregate",
|
|
194
|
+
)
|
|
195
|
+
for key in expected:
|
|
196
|
+
expected_delta = treatment[key] - baseline[key]
|
|
197
|
+
if deltas[key] != expected_delta:
|
|
198
|
+
raise ValidationError(f"aggregate metric delta {key!r} is inconsistent")
|
|
199
|
+
object.__setattr__(self, "examples", examples)
|
|
200
|
+
object.__setattr__(self, "baseline_metrics", baseline)
|
|
201
|
+
object.__setattr__(self, "treatment_metrics", treatment)
|
|
202
|
+
object.__setattr__(self, "metric_deltas", deltas)
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def example_count(self) -> int:
|
|
206
|
+
return len(self.examples)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class BenchmarkBatchRunner:
|
|
210
|
+
"""Execute an evaluator-blind prediction callback over one benchmark split."""
|
|
211
|
+
|
|
212
|
+
def run(
|
|
213
|
+
self,
|
|
214
|
+
adapter: BenchmarkAdapter,
|
|
215
|
+
split: str,
|
|
216
|
+
predict: PredictionRunner,
|
|
217
|
+
*,
|
|
218
|
+
budget: ExecutionBudget | None = None,
|
|
219
|
+
) -> BenchmarkBatchRecord:
|
|
220
|
+
benchmark_id, examples = _prepare_run(adapter, split, predict, budget)
|
|
221
|
+
records = tuple(
|
|
222
|
+
_run_example(adapter, example, predict, budget=budget) for example in examples
|
|
223
|
+
)
|
|
224
|
+
return BenchmarkBatchRecord(
|
|
225
|
+
benchmark_id=benchmark_id,
|
|
226
|
+
split=split,
|
|
227
|
+
examples=records,
|
|
228
|
+
aggregate_metrics=_aggregate_metrics(tuple(record.metrics for record in records)),
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class PairedBenchmarkRunner:
|
|
233
|
+
"""Run baseline and treatment callbacks on identical stateless examples.
|
|
234
|
+
|
|
235
|
+
Stateful external arenas must expose an atomic restore/evaluate-pair seam
|
|
236
|
+
and use a dedicated replay runner. Scoring the two arms sequentially proves
|
|
237
|
+
only that their optimizer-visible state hashes match; it cannot prove that
|
|
238
|
+
hidden environment or user-simulator state was restored.
|
|
239
|
+
"""
|
|
240
|
+
|
|
241
|
+
def run(
|
|
242
|
+
self,
|
|
243
|
+
adapter: BenchmarkAdapter,
|
|
244
|
+
split: str,
|
|
245
|
+
baseline: PredictionRunner,
|
|
246
|
+
treatment: PredictionRunner,
|
|
247
|
+
*,
|
|
248
|
+
budget: ExecutionBudget | None = None,
|
|
249
|
+
) -> PairedBenchmarkRecord:
|
|
250
|
+
if not callable(treatment):
|
|
251
|
+
raise TypeError("treatment prediction runner must be callable")
|
|
252
|
+
pairing_mode = getattr(adapter, "pairing_mode", None)
|
|
253
|
+
if pairing_mode != "stateless_score_twice":
|
|
254
|
+
raise ValidationError(
|
|
255
|
+
"PairedBenchmarkRunner requires an explicit pairing_mode="
|
|
256
|
+
"'stateless_score_twice'; "
|
|
257
|
+
"stateful external arenas require an atomic restore/evaluate-pair bridge "
|
|
258
|
+
"with replay receipts"
|
|
259
|
+
)
|
|
260
|
+
benchmark_id, examples = _prepare_run(adapter, split, baseline, budget)
|
|
261
|
+
|
|
262
|
+
records: list[PairedBenchmarkExampleRecord] = []
|
|
263
|
+
for example in examples:
|
|
264
|
+
state = example.visible_state(budget=budget)
|
|
265
|
+
baseline_record = _score_prediction(adapter, example, state, baseline(state))
|
|
266
|
+
treatment_record = _score_prediction(adapter, example, state, treatment(state))
|
|
267
|
+
if baseline_record.state_hash != treatment_record.state_hash:
|
|
268
|
+
raise RuntimeError("paired callbacks did not share one input state identity")
|
|
269
|
+
_require_same_metric_keys(
|
|
270
|
+
_metric_keys(baseline_record.metrics),
|
|
271
|
+
treatment_record.metrics,
|
|
272
|
+
example_id=example.example_id,
|
|
273
|
+
)
|
|
274
|
+
records.append(
|
|
275
|
+
PairedBenchmarkExampleRecord(
|
|
276
|
+
example_id=example.example_id,
|
|
277
|
+
state_hash=state.state_hash,
|
|
278
|
+
baseline=baseline_record,
|
|
279
|
+
treatment=treatment_record,
|
|
280
|
+
metric_deltas={
|
|
281
|
+
key: treatment_record.metrics[key] - baseline_record.metrics[key]
|
|
282
|
+
for key in baseline_record.metrics
|
|
283
|
+
},
|
|
284
|
+
)
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
paired = tuple(records)
|
|
288
|
+
baseline_metrics = _aggregate_metrics(tuple(record.baseline.metrics for record in paired))
|
|
289
|
+
treatment_metrics = _aggregate_metrics(tuple(record.treatment.metrics for record in paired))
|
|
290
|
+
return PairedBenchmarkRecord(
|
|
291
|
+
benchmark_id=benchmark_id,
|
|
292
|
+
split=split,
|
|
293
|
+
examples=paired,
|
|
294
|
+
baseline_metrics=baseline_metrics,
|
|
295
|
+
treatment_metrics=treatment_metrics,
|
|
296
|
+
metric_deltas={
|
|
297
|
+
key: treatment_metrics[key] - baseline_metrics[key] for key in baseline_metrics
|
|
298
|
+
},
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _prepare_run(
|
|
303
|
+
adapter: BenchmarkAdapter,
|
|
304
|
+
split: str,
|
|
305
|
+
predict: PredictionRunner,
|
|
306
|
+
budget: ExecutionBudget | None,
|
|
307
|
+
) -> tuple[str, tuple[BenchmarkExample, ...]]:
|
|
308
|
+
benchmark_id = getattr(adapter, "benchmark_id", None)
|
|
309
|
+
_require_nonempty_text(benchmark_id, field_name="adapter.benchmark_id")
|
|
310
|
+
_require_nonempty_text(split, field_name="split")
|
|
311
|
+
if not callable(predict):
|
|
312
|
+
raise TypeError("prediction runner must be callable")
|
|
313
|
+
if budget is not None and not isinstance(budget, ExecutionBudget):
|
|
314
|
+
raise TypeError("budget must be an ExecutionBudget or None")
|
|
315
|
+
|
|
316
|
+
examples = tuple(adapter.examples(split))
|
|
317
|
+
if not examples:
|
|
318
|
+
raise ValidationError("benchmark split must contain at least one example")
|
|
319
|
+
if not all(isinstance(example, BenchmarkExample) for example in examples):
|
|
320
|
+
raise ValidationError("adapter.examples() must return BenchmarkExample instances")
|
|
321
|
+
for example in examples:
|
|
322
|
+
_require_nonempty_text(example.example_id, field_name="example.example_id")
|
|
323
|
+
_require_unique_example_ids(example.example_id for example in examples)
|
|
324
|
+
return benchmark_id, examples
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def _run_example(
|
|
328
|
+
adapter: BenchmarkAdapter,
|
|
329
|
+
example: BenchmarkExample,
|
|
330
|
+
predict: PredictionRunner,
|
|
331
|
+
*,
|
|
332
|
+
budget: ExecutionBudget | None,
|
|
333
|
+
) -> BenchmarkExampleRecord:
|
|
334
|
+
state = example.visible_state(budget=budget)
|
|
335
|
+
return _score_prediction(adapter, example, state, predict(state))
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def _score_prediction(
|
|
339
|
+
adapter: BenchmarkAdapter,
|
|
340
|
+
example: BenchmarkExample,
|
|
341
|
+
state: FrozenAgentState,
|
|
342
|
+
prediction: Any,
|
|
343
|
+
) -> BenchmarkExampleRecord:
|
|
344
|
+
return build_benchmark_example_record(
|
|
345
|
+
adapter,
|
|
346
|
+
example,
|
|
347
|
+
state_hash=state.state_hash,
|
|
348
|
+
prediction=prediction,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def build_benchmark_example_record(
|
|
353
|
+
adapter: BenchmarkAdapter,
|
|
354
|
+
example: BenchmarkExample,
|
|
355
|
+
*,
|
|
356
|
+
state_hash: str,
|
|
357
|
+
prediction: Any,
|
|
358
|
+
) -> BenchmarkExampleRecord:
|
|
359
|
+
"""Score one prediction and bind the adapter's exact evaluator provenance."""
|
|
360
|
+
|
|
361
|
+
provenance = getattr(adapter, "evaluation_provenance", {})
|
|
362
|
+
if not isinstance(provenance, Mapping):
|
|
363
|
+
raise ValidationError("adapter.evaluation_provenance must be a mapping when it is exposed")
|
|
364
|
+
frozen_provenance = _validated_evaluation_provenance(
|
|
365
|
+
provenance,
|
|
366
|
+
example_id=example.example_id,
|
|
367
|
+
)
|
|
368
|
+
metrics = adapter.score(example, prediction)
|
|
369
|
+
return BenchmarkExampleRecord(
|
|
370
|
+
example_id=example.example_id,
|
|
371
|
+
state_hash=state_hash,
|
|
372
|
+
prediction=prediction,
|
|
373
|
+
metrics=metrics,
|
|
374
|
+
evaluation_provenance=frozen_provenance,
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def _validated_evaluation_provenance(
|
|
379
|
+
value: Mapping[str, Any],
|
|
380
|
+
*,
|
|
381
|
+
example_id: str,
|
|
382
|
+
) -> Mapping[str, Any]:
|
|
383
|
+
if not isinstance(value, Mapping):
|
|
384
|
+
raise ValidationError(f"evaluation provenance for {example_id!r} must be a mapping")
|
|
385
|
+
try:
|
|
386
|
+
frozen = freeze_mapping(value)
|
|
387
|
+
canonical_json(frozen)
|
|
388
|
+
except (TypeError, ValueError) as exc:
|
|
389
|
+
raise ValidationError(
|
|
390
|
+
f"evaluation provenance for {example_id!r} must be canonically serializable: {exc}"
|
|
391
|
+
) from exc
|
|
392
|
+
return frozen
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def _validated_metrics(
|
|
396
|
+
metrics: Mapping[str, float],
|
|
397
|
+
*,
|
|
398
|
+
example_id: str,
|
|
399
|
+
) -> Mapping[str, float]:
|
|
400
|
+
if not isinstance(metrics, Mapping):
|
|
401
|
+
raise ValidationError(f"metrics for {example_id!r} must be a mapping")
|
|
402
|
+
if not metrics:
|
|
403
|
+
raise ValidationError(f"metrics for {example_id!r} must not be empty")
|
|
404
|
+
validated: dict[str, float] = {}
|
|
405
|
+
for key, value in metrics.items():
|
|
406
|
+
if (
|
|
407
|
+
not isinstance(key, str)
|
|
408
|
+
or not key
|
|
409
|
+
or key != key.strip()
|
|
410
|
+
or any(not character.isprintable() for character in key)
|
|
411
|
+
):
|
|
412
|
+
raise ValidationError(
|
|
413
|
+
f"metric key for {example_id!r} must be a non-empty, trimmed string "
|
|
414
|
+
"without control characters"
|
|
415
|
+
)
|
|
416
|
+
if isinstance(value, bool) or not isinstance(value, Real):
|
|
417
|
+
raise ValidationError(f"metric {key!r} for {example_id!r} must be numeric")
|
|
418
|
+
try:
|
|
419
|
+
numeric = float(value)
|
|
420
|
+
except (OverflowError, TypeError, ValueError) as exc:
|
|
421
|
+
raise ValidationError(f"metric {key!r} for {example_id!r} must be finite") from exc
|
|
422
|
+
if not math.isfinite(numeric):
|
|
423
|
+
raise ValidationError(f"metric {key!r} for {example_id!r} must be finite")
|
|
424
|
+
validated[key] = numeric
|
|
425
|
+
return freeze_mapping(validated)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def _aggregate_metrics(metrics: tuple[Mapping[str, float], ...]) -> Mapping[str, float]:
|
|
429
|
+
if not metrics:
|
|
430
|
+
raise ValidationError("cannot aggregate an empty metric collection")
|
|
431
|
+
expected = _metric_keys(metrics[0])
|
|
432
|
+
for index, item in enumerate(metrics[1:], start=1):
|
|
433
|
+
_require_same_metric_keys(expected, item, example_id=f"<index {index}>")
|
|
434
|
+
count = len(metrics)
|
|
435
|
+
aggregated: dict[str, float] = {}
|
|
436
|
+
for key in expected:
|
|
437
|
+
try:
|
|
438
|
+
value = math.fsum(item[key] / count for item in metrics)
|
|
439
|
+
except (OverflowError, ValueError) as exc:
|
|
440
|
+
raise ValidationError(f"aggregate metric {key!r} is not finite") from exc
|
|
441
|
+
if not math.isfinite(value):
|
|
442
|
+
raise ValidationError(f"aggregate metric {key!r} is not finite")
|
|
443
|
+
aggregated[key] = value
|
|
444
|
+
return freeze_mapping(aggregated)
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def _metric_keys(metrics: Mapping[str, float]) -> tuple[str, ...]:
|
|
448
|
+
return tuple(sorted(metrics))
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def _require_same_metric_keys(
|
|
452
|
+
expected: tuple[str, ...],
|
|
453
|
+
metrics: Mapping[str, float],
|
|
454
|
+
*,
|
|
455
|
+
example_id: str,
|
|
456
|
+
) -> None:
|
|
457
|
+
actual = _metric_keys(metrics)
|
|
458
|
+
if actual != expected:
|
|
459
|
+
raise ValidationError(
|
|
460
|
+
f"metric keys for {example_id!r} differ from the batch schema: "
|
|
461
|
+
f"expected {expected!r}, got {actual!r}"
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def _require_same_metric_values(
|
|
466
|
+
expected: Mapping[str, float],
|
|
467
|
+
actual: Mapping[str, float],
|
|
468
|
+
*,
|
|
469
|
+
record_name: str,
|
|
470
|
+
) -> None:
|
|
471
|
+
for key in expected:
|
|
472
|
+
if actual[key] != expected[key]:
|
|
473
|
+
raise ValidationError(f"{record_name} metric {key!r} is inconsistent")
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
def _require_nonempty_text(value: object, *, field_name: str) -> None:
|
|
477
|
+
if not isinstance(value, str) or not value.strip():
|
|
478
|
+
raise ValidationError(f"{field_name} must be a non-empty string")
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def _require_state_hash(value: object) -> None:
|
|
482
|
+
if (
|
|
483
|
+
not isinstance(value, str)
|
|
484
|
+
or len(value) != 64
|
|
485
|
+
or any(character not in "0123456789abcdef" for character in value)
|
|
486
|
+
):
|
|
487
|
+
raise ValidationError("state_hash must be a lowercase SHA-256 digest")
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def _require_unique_example_ids(example_ids: Iterable[str]) -> None:
|
|
491
|
+
seen: set[str] = set()
|
|
492
|
+
duplicates: set[str] = set()
|
|
493
|
+
for example_id in example_ids:
|
|
494
|
+
if example_id in seen:
|
|
495
|
+
duplicates.add(example_id)
|
|
496
|
+
seen.add(example_id)
|
|
497
|
+
if duplicates:
|
|
498
|
+
raise ValidationError(f"benchmark example IDs must be unique: {sorted(duplicates)!r}")
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
__all__ = [
|
|
502
|
+
"BenchmarkBatchRecord",
|
|
503
|
+
"BenchmarkBatchRunner",
|
|
504
|
+
"BenchmarkExampleRecord",
|
|
505
|
+
"PairedBenchmarkExampleRecord",
|
|
506
|
+
"PairedBenchmarkRecord",
|
|
507
|
+
"PairedBenchmarkRunner",
|
|
508
|
+
"PredictionRunner",
|
|
509
|
+
]
|