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,235 @@
|
|
|
1
|
+
"""Fail-closed artifact acquisition with an injected hardened transport.
|
|
2
|
+
|
|
3
|
+
The core package deliberately does not ship a generic ``urlopen`` transport.
|
|
4
|
+
An injected transport receives already-resolved targets, must connect to one of
|
|
5
|
+
those addresses while validating TLS for the original hostname, and must not
|
|
6
|
+
follow redirects itself. AgentInputLab validates every redirect hop and the
|
|
7
|
+
reported peer before accepting bytes.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import ipaddress
|
|
13
|
+
import socket
|
|
14
|
+
import urllib.parse
|
|
15
|
+
from collections.abc import Iterable, Mapping
|
|
16
|
+
from contextlib import AbstractContextManager
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
from typing import Protocol, runtime_checkable
|
|
19
|
+
|
|
20
|
+
from agentinputlab.artifacts import ArtifactManifest, ArtifactStore
|
|
21
|
+
from agentinputlab.contracts.errors import ArtifactError
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True, slots=True)
|
|
25
|
+
class DownloadPolicy:
|
|
26
|
+
allow_network: bool = False
|
|
27
|
+
allowed_hosts: tuple[str, ...] = ()
|
|
28
|
+
allow_private_addresses: bool = False
|
|
29
|
+
max_bytes: int = 2 * 1024 * 1024 * 1024
|
|
30
|
+
timeout_seconds: float = 120.0
|
|
31
|
+
max_redirects: int = 3
|
|
32
|
+
|
|
33
|
+
def __post_init__(self) -> None:
|
|
34
|
+
normalized = tuple(sorted({host.strip().lower() for host in self.allowed_hosts if host}))
|
|
35
|
+
object.__setattr__(self, "allowed_hosts", normalized)
|
|
36
|
+
if self.max_bytes < 1:
|
|
37
|
+
raise ArtifactError("download max_bytes must be positive")
|
|
38
|
+
if self.timeout_seconds <= 0:
|
|
39
|
+
raise ArtifactError("download timeout_seconds must be positive")
|
|
40
|
+
if self.max_redirects < 0:
|
|
41
|
+
raise ArtifactError("download max_redirects must be non-negative")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True, slots=True)
|
|
45
|
+
class ValidatedDownloadTarget:
|
|
46
|
+
url: str
|
|
47
|
+
hostname: str
|
|
48
|
+
port: int
|
|
49
|
+
resolved_addresses: tuple[str, ...]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass(frozen=True, slots=True)
|
|
53
|
+
class DownloadResponse:
|
|
54
|
+
status_code: int
|
|
55
|
+
headers: Mapping[str, str]
|
|
56
|
+
body: bytes
|
|
57
|
+
peer_address: str
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass(frozen=True, slots=True)
|
|
61
|
+
class StreamingDownloadResponse:
|
|
62
|
+
status_code: int
|
|
63
|
+
headers: Mapping[str, str]
|
|
64
|
+
chunks: Iterable[bytes]
|
|
65
|
+
peer_address: str
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class StreamingDownloadTransport(Protocol):
|
|
69
|
+
def stream(
|
|
70
|
+
self, target: ValidatedDownloadTarget, *, timeout_seconds: float, max_bytes: int
|
|
71
|
+
) -> AbstractContextManager[StreamingDownloadResponse]:
|
|
72
|
+
"""Open one DNS-pinned hop; close it even when the consumer stops early."""
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@runtime_checkable
|
|
76
|
+
class DownloadTransport(Protocol):
|
|
77
|
+
def request(
|
|
78
|
+
self,
|
|
79
|
+
target: ValidatedDownloadTarget,
|
|
80
|
+
*,
|
|
81
|
+
timeout_seconds: float,
|
|
82
|
+
max_bytes: int,
|
|
83
|
+
) -> DownloadResponse:
|
|
84
|
+
"""Fetch one hop without redirects or decompression expansion."""
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def validate_download_url(url: str, policy: DownloadPolicy) -> ValidatedDownloadTarget:
|
|
88
|
+
if not policy.allow_network:
|
|
89
|
+
raise ArtifactError("network acquisition is disabled")
|
|
90
|
+
if not policy.allowed_hosts:
|
|
91
|
+
raise ArtifactError("network acquisition requires a non-empty host allowlist")
|
|
92
|
+
parsed = urllib.parse.urlsplit(url)
|
|
93
|
+
if parsed.scheme != "https" or not parsed.hostname:
|
|
94
|
+
raise ArtifactError("artifact URLs must use absolute HTTPS")
|
|
95
|
+
if parsed.username is not None or parsed.password is not None:
|
|
96
|
+
raise ArtifactError("artifact URLs must not contain user information")
|
|
97
|
+
hostname = parsed.hostname.lower()
|
|
98
|
+
if hostname not in policy.allowed_hosts:
|
|
99
|
+
raise ArtifactError(f"host is not allowlisted: {hostname}")
|
|
100
|
+
try:
|
|
101
|
+
port = parsed.port or 443
|
|
102
|
+
except ValueError as exc:
|
|
103
|
+
raise ArtifactError("artifact URL contains an invalid port") from exc
|
|
104
|
+
try:
|
|
105
|
+
addresses = {
|
|
106
|
+
info[4][0].split("%", 1)[0]
|
|
107
|
+
for info in socket.getaddrinfo(hostname, port, type=socket.SOCK_STREAM)
|
|
108
|
+
}
|
|
109
|
+
except socket.gaierror as exc:
|
|
110
|
+
raise ArtifactError(f"cannot resolve artifact host: {hostname}") from exc
|
|
111
|
+
if not addresses:
|
|
112
|
+
raise ArtifactError(f"artifact host resolved to no addresses: {hostname}")
|
|
113
|
+
if not policy.allow_private_addresses:
|
|
114
|
+
for address in addresses:
|
|
115
|
+
ip = ipaddress.ip_address(address)
|
|
116
|
+
if not ip.is_global:
|
|
117
|
+
raise ArtifactError(f"artifact host resolves to disallowed address: {address}")
|
|
118
|
+
return ValidatedDownloadTarget(
|
|
119
|
+
url=urllib.parse.urlunsplit(parsed),
|
|
120
|
+
hostname=hostname,
|
|
121
|
+
port=port,
|
|
122
|
+
resolved_addresses=tuple(sorted(addresses)),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def download_artifact(
|
|
127
|
+
manifest: ArtifactManifest,
|
|
128
|
+
store: ArtifactStore,
|
|
129
|
+
*,
|
|
130
|
+
policy: DownloadPolicy,
|
|
131
|
+
transport: DownloadTransport | None = None,
|
|
132
|
+
) -> str:
|
|
133
|
+
if not manifest.sha256:
|
|
134
|
+
raise ArtifactError("downloaded artifacts require a pinned SHA-256")
|
|
135
|
+
if transport is None:
|
|
136
|
+
raise ArtifactError("network acquisition requires an explicit hardened transport")
|
|
137
|
+
target = validate_download_url(manifest.source_uri, policy)
|
|
138
|
+
response: DownloadResponse | None = None
|
|
139
|
+
for redirect_count in range(policy.max_redirects + 1):
|
|
140
|
+
response = transport.request(
|
|
141
|
+
target,
|
|
142
|
+
timeout_seconds=policy.timeout_seconds,
|
|
143
|
+
max_bytes=policy.max_bytes,
|
|
144
|
+
)
|
|
145
|
+
_validate_peer(response.peer_address, target)
|
|
146
|
+
if 300 <= response.status_code < 400:
|
|
147
|
+
if redirect_count >= policy.max_redirects:
|
|
148
|
+
raise ArtifactError("artifact download exceeded redirect limit")
|
|
149
|
+
location = _header(response.headers, "location")
|
|
150
|
+
if not location:
|
|
151
|
+
raise ArtifactError("artifact redirect is missing Location")
|
|
152
|
+
target = validate_download_url(
|
|
153
|
+
urllib.parse.urljoin(target.url, location),
|
|
154
|
+
policy,
|
|
155
|
+
)
|
|
156
|
+
continue
|
|
157
|
+
if not 200 <= response.status_code < 300:
|
|
158
|
+
raise ArtifactError(f"artifact download returned HTTP {response.status_code}")
|
|
159
|
+
break
|
|
160
|
+
if response is None: # pragma: no cover - loop invariant
|
|
161
|
+
raise ArtifactError("artifact transport returned no response")
|
|
162
|
+
content_length = _header(response.headers, "content-length")
|
|
163
|
+
if content_length is not None:
|
|
164
|
+
try:
|
|
165
|
+
declared_size = int(content_length)
|
|
166
|
+
except ValueError as exc:
|
|
167
|
+
raise ArtifactError("artifact Content-Length is invalid") from exc
|
|
168
|
+
if declared_size < 0 or declared_size > policy.max_bytes:
|
|
169
|
+
raise ArtifactError("artifact exceeds configured size limit")
|
|
170
|
+
if len(response.body) > policy.max_bytes:
|
|
171
|
+
raise ArtifactError("artifact exceeds configured size limit")
|
|
172
|
+
return str(store.put_bytes(manifest, response.body))
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _validate_peer(peer_address: str, target: ValidatedDownloadTarget) -> None:
|
|
176
|
+
try:
|
|
177
|
+
normalized = str(ipaddress.ip_address(peer_address.split("%", 1)[0]))
|
|
178
|
+
except ValueError as exc:
|
|
179
|
+
raise ArtifactError("download transport reported an invalid peer address") from exc
|
|
180
|
+
allowed = {str(ipaddress.ip_address(address)) for address in target.resolved_addresses}
|
|
181
|
+
if normalized not in allowed:
|
|
182
|
+
raise ArtifactError("download peer does not match the validated DNS result")
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def download_artifact_streamed(
|
|
186
|
+
manifest: ArtifactManifest,
|
|
187
|
+
store: ArtifactStore,
|
|
188
|
+
*,
|
|
189
|
+
policy: DownloadPolicy,
|
|
190
|
+
transport: StreamingDownloadTransport,
|
|
191
|
+
) -> str:
|
|
192
|
+
"""Acquire a pinned file with bounded RAM and validation at every hop."""
|
|
193
|
+
if not manifest.sha256:
|
|
194
|
+
raise ArtifactError("downloaded artifacts require a pinned SHA-256")
|
|
195
|
+
if manifest.size_bytes is not None and manifest.size_bytes > policy.max_bytes:
|
|
196
|
+
raise ArtifactError("artifact exceeds configured size limit before download")
|
|
197
|
+
target = validate_download_url(manifest.source_uri, policy)
|
|
198
|
+
for count in range(policy.max_redirects + 1):
|
|
199
|
+
with transport.stream(
|
|
200
|
+
target, timeout_seconds=policy.timeout_seconds, max_bytes=policy.max_bytes
|
|
201
|
+
) as response:
|
|
202
|
+
_validate_peer(response.peer_address, target)
|
|
203
|
+
if 300 <= response.status_code < 400:
|
|
204
|
+
if count >= policy.max_redirects:
|
|
205
|
+
raise ArtifactError("artifact download exceeded redirect limit")
|
|
206
|
+
location = _header(response.headers, "location")
|
|
207
|
+
if not location:
|
|
208
|
+
raise ArtifactError("artifact redirect is missing Location")
|
|
209
|
+
target = validate_download_url(urllib.parse.urljoin(target.url, location), policy)
|
|
210
|
+
continue
|
|
211
|
+
if not 200 <= response.status_code < 300:
|
|
212
|
+
raise ArtifactError(f"artifact download returned HTTP {response.status_code}")
|
|
213
|
+
encoding = _header(response.headers, "content-encoding")
|
|
214
|
+
if encoding and encoding.lower() != "identity":
|
|
215
|
+
raise ArtifactError("artifact stream refuses encoded response bodies")
|
|
216
|
+
declared = _header(response.headers, "content-length")
|
|
217
|
+
if declared is not None:
|
|
218
|
+
try:
|
|
219
|
+
size = int(declared)
|
|
220
|
+
except ValueError as exc:
|
|
221
|
+
raise ArtifactError("artifact Content-Length is invalid") from exc
|
|
222
|
+
if size < 0 or size > policy.max_bytes:
|
|
223
|
+
raise ArtifactError("artifact exceeds configured size limit")
|
|
224
|
+
if manifest.size_bytes is not None and size != manifest.size_bytes:
|
|
225
|
+
raise ArtifactError("artifact declared size differs from pinned size")
|
|
226
|
+
return str(store.put_stream(manifest, response.chunks, max_bytes=policy.max_bytes))
|
|
227
|
+
raise ArtifactError("artifact download exceeded redirect limit") # pragma: no cover
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _header(headers: Mapping[str, str], name: str) -> str | None:
|
|
231
|
+
expected = name.lower()
|
|
232
|
+
for key, value in headers.items():
|
|
233
|
+
if key.lower() == expected:
|
|
234
|
+
return str(value)
|
|
235
|
+
return None
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""Pinned-address HTTPS transport for explicit benchmark acquisition.
|
|
2
|
+
|
|
3
|
+
This transport is opt-in. It connects to one of the addresses validated by
|
|
4
|
+
``validate_download_url`` while retaining the original hostname for TLS SNI and
|
|
5
|
+
certificate verification. It does not use environment proxies, follow
|
|
6
|
+
redirects, or decompress response bodies.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import http.client
|
|
12
|
+
import socket
|
|
13
|
+
import ssl
|
|
14
|
+
import urllib.parse
|
|
15
|
+
from contextlib import contextmanager
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
|
|
18
|
+
from agentinputlab.contracts.errors import ArtifactError
|
|
19
|
+
|
|
20
|
+
from .downloader import DownloadResponse, StreamingDownloadResponse, ValidatedDownloadTarget
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class _PinnedHTTPSConnection(http.client.HTTPSConnection):
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
target: ValidatedDownloadTarget,
|
|
27
|
+
address: str,
|
|
28
|
+
*,
|
|
29
|
+
timeout: float,
|
|
30
|
+
context: ssl.SSLContext,
|
|
31
|
+
) -> None:
|
|
32
|
+
super().__init__(
|
|
33
|
+
target.hostname,
|
|
34
|
+
target.port,
|
|
35
|
+
timeout=timeout,
|
|
36
|
+
context=context,
|
|
37
|
+
)
|
|
38
|
+
self._validated_address = address
|
|
39
|
+
|
|
40
|
+
def connect(self) -> None:
|
|
41
|
+
raw_socket = socket.create_connection(
|
|
42
|
+
(self._validated_address, self.port),
|
|
43
|
+
self.timeout,
|
|
44
|
+
self.source_address,
|
|
45
|
+
)
|
|
46
|
+
try:
|
|
47
|
+
self.sock = self._context.wrap_socket(
|
|
48
|
+
raw_socket,
|
|
49
|
+
server_hostname=self.host,
|
|
50
|
+
)
|
|
51
|
+
except BaseException:
|
|
52
|
+
raw_socket.close()
|
|
53
|
+
raise
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass(slots=True)
|
|
57
|
+
class PinnedHTTPSDownloadTransport:
|
|
58
|
+
"""One-hop stdlib HTTPS client honoring the downloader's DNS pin."""
|
|
59
|
+
|
|
60
|
+
user_agent: str = "AgentInputLab/0.1 benchmark-acquisition"
|
|
61
|
+
ssl_context: ssl.SSLContext = field(default_factory=ssl.create_default_context)
|
|
62
|
+
|
|
63
|
+
def request(
|
|
64
|
+
self,
|
|
65
|
+
target: ValidatedDownloadTarget,
|
|
66
|
+
*,
|
|
67
|
+
timeout_seconds: float,
|
|
68
|
+
max_bytes: int,
|
|
69
|
+
) -> DownloadResponse:
|
|
70
|
+
with self.stream(target, timeout_seconds=timeout_seconds, max_bytes=max_bytes) as response:
|
|
71
|
+
return DownloadResponse(
|
|
72
|
+
status_code=response.status_code,
|
|
73
|
+
headers=response.headers,
|
|
74
|
+
body=b"".join(response.chunks),
|
|
75
|
+
peer_address=response.peer_address,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
@contextmanager
|
|
79
|
+
def stream(
|
|
80
|
+
self,
|
|
81
|
+
target: ValidatedDownloadTarget,
|
|
82
|
+
*,
|
|
83
|
+
timeout_seconds: float,
|
|
84
|
+
max_bytes: int,
|
|
85
|
+
):
|
|
86
|
+
"""Stream one validated address, without redirect or body-read retries."""
|
|
87
|
+
if max_bytes < 1:
|
|
88
|
+
raise ArtifactError("download transport size limit must be positive")
|
|
89
|
+
parsed = urllib.parse.urlsplit(target.url)
|
|
90
|
+
request_target = urllib.parse.urlunsplit(("", "", parsed.path or "/", parsed.query, ""))
|
|
91
|
+
host_header = target.hostname if target.port == 443 else f"{target.hostname}:{target.port}"
|
|
92
|
+
failures: list[str] = []
|
|
93
|
+
for address in target.resolved_addresses:
|
|
94
|
+
connection = _PinnedHTTPSConnection(
|
|
95
|
+
target,
|
|
96
|
+
address,
|
|
97
|
+
timeout=timeout_seconds,
|
|
98
|
+
context=self.ssl_context,
|
|
99
|
+
)
|
|
100
|
+
try:
|
|
101
|
+
connection.request(
|
|
102
|
+
"GET",
|
|
103
|
+
request_target,
|
|
104
|
+
headers={
|
|
105
|
+
"Accept": "*/*",
|
|
106
|
+
"Accept-Encoding": "identity",
|
|
107
|
+
"Connection": "close",
|
|
108
|
+
"Host": host_header,
|
|
109
|
+
"User-Agent": self.user_agent,
|
|
110
|
+
},
|
|
111
|
+
)
|
|
112
|
+
if connection.sock is None: # pragma: no cover - http.client invariant
|
|
113
|
+
raise ArtifactError("HTTPS transport did not establish a socket")
|
|
114
|
+
peer_address = str(connection.sock.getpeername()[0])
|
|
115
|
+
response = connection.getresponse()
|
|
116
|
+
headers = {key: value for key, value in response.getheaders()}
|
|
117
|
+
encoding = _header(headers, "content-encoding")
|
|
118
|
+
if encoding and encoding.lower() != "identity":
|
|
119
|
+
raise ArtifactError("download transport refuses encoded response bodies")
|
|
120
|
+
declared = _header(headers, "content-length")
|
|
121
|
+
if declared is not None:
|
|
122
|
+
try:
|
|
123
|
+
declared_size = int(declared)
|
|
124
|
+
except ValueError as exc:
|
|
125
|
+
raise ArtifactError(
|
|
126
|
+
"download response has an invalid Content-Length"
|
|
127
|
+
) from exc
|
|
128
|
+
if declared_size < 0 or declared_size > max_bytes:
|
|
129
|
+
raise ArtifactError("download response exceeds the transport size limit")
|
|
130
|
+
except ArtifactError:
|
|
131
|
+
connection.close()
|
|
132
|
+
raise
|
|
133
|
+
except (OSError, ssl.SSLError, http.client.HTTPException) as exc:
|
|
134
|
+
connection.close()
|
|
135
|
+
failures.append(f"{address}: {type(exc).__name__}")
|
|
136
|
+
continue
|
|
137
|
+
break
|
|
138
|
+
else:
|
|
139
|
+
detail = ", ".join(failures) if failures else "no validated addresses"
|
|
140
|
+
raise ArtifactError(f"HTTPS transport could not connect ({detail})")
|
|
141
|
+
try:
|
|
142
|
+
yield StreamingDownloadResponse(
|
|
143
|
+
status_code=response.status,
|
|
144
|
+
headers=headers,
|
|
145
|
+
chunks=_bounded_chunks(response, max_bytes=max_bytes),
|
|
146
|
+
peer_address=peer_address,
|
|
147
|
+
)
|
|
148
|
+
except (OSError, ssl.SSLError, http.client.HTTPException) as exc:
|
|
149
|
+
raise ArtifactError(f"artifact stream interrupted ({type(exc).__name__})") from exc
|
|
150
|
+
finally:
|
|
151
|
+
connection.close()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _bounded_chunks(response: http.client.HTTPResponse, *, max_bytes: int):
|
|
155
|
+
size = 0
|
|
156
|
+
while True:
|
|
157
|
+
chunk = response.read(min(1024 * 1024, max_bytes + 1 - size))
|
|
158
|
+
if not chunk:
|
|
159
|
+
return
|
|
160
|
+
size += len(chunk)
|
|
161
|
+
if size > max_bytes:
|
|
162
|
+
raise ArtifactError("download response exceeds the transport size limit")
|
|
163
|
+
yield chunk
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _header(headers: dict[str, str], name: str) -> str | None:
|
|
167
|
+
expected = name.lower()
|
|
168
|
+
for key, value in headers.items():
|
|
169
|
+
if key.lower() == expected:
|
|
170
|
+
return value
|
|
171
|
+
return None
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Versioned index identity used by retrieval balance checks."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
from agentinputlab.contracts.serialization import content_hash
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True, slots=True)
|
|
11
|
+
class IndexManifest:
|
|
12
|
+
corpus_revision: str
|
|
13
|
+
document_filter_hash: str
|
|
14
|
+
chunker_hash: str
|
|
15
|
+
embedder_revision: str
|
|
16
|
+
index_revision: str
|
|
17
|
+
metric: str
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def lineage_hash(self) -> str:
|
|
21
|
+
return content_hash(self)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Dataset split-overlap records used by contamination-aware evaluation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True, slots=True)
|
|
10
|
+
class OverlapRecord:
|
|
11
|
+
left_split: str
|
|
12
|
+
right_split: str
|
|
13
|
+
shared_ids: tuple[str, ...]
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def count(self) -> int:
|
|
17
|
+
return len(self.shared_ids)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def detect_id_overlap(
|
|
21
|
+
left_ids: Iterable[str],
|
|
22
|
+
right_ids: Iterable[str],
|
|
23
|
+
*,
|
|
24
|
+
left_split: str,
|
|
25
|
+
right_split: str,
|
|
26
|
+
) -> OverlapRecord:
|
|
27
|
+
shared = tuple(sorted(set(left_ids) & set(right_ids)))
|
|
28
|
+
return OverlapRecord(left_split, right_split, shared)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Deterministic JSONL preprocessing primitives."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from collections.abc import Callable, Iterable
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from agentinputlab.contracts.serialization import canonical_json
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def normalize_records(
|
|
13
|
+
records: Iterable[dict[str, Any]],
|
|
14
|
+
transform: Callable[[dict[str, Any]], dict[str, Any]],
|
|
15
|
+
*,
|
|
16
|
+
id_field: str = "id",
|
|
17
|
+
) -> tuple[dict[str, Any], ...]:
|
|
18
|
+
normalized = [transform(dict(record)) for record in records]
|
|
19
|
+
if any(id_field not in record for record in normalized):
|
|
20
|
+
raise ValueError(f"all normalized records require {id_field!r}")
|
|
21
|
+
normalized.sort(key=lambda record: str(record[id_field]))
|
|
22
|
+
if len({str(record[id_field]) for record in normalized}) != len(normalized):
|
|
23
|
+
raise ValueError("normalized record IDs must be unique")
|
|
24
|
+
return tuple(normalized)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def to_jsonl(records: Iterable[dict[str, Any]]) -> str:
|
|
28
|
+
return "\n".join(canonical_json(record) for record in records) + "\n"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def from_jsonl(content: str) -> tuple[dict[str, Any], ...]:
|
|
32
|
+
return tuple(json.loads(line) for line in content.splitlines() if line.strip())
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Read-only destination-space checks for bounded data preparation.
|
|
2
|
+
|
|
3
|
+
These checks are snapshots, not filesystem reservations. Independent writers can
|
|
4
|
+
consume space later; callers must still bound each write and clean partial data.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import shutil
|
|
10
|
+
from collections.abc import Iterable
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from agentinputlab.contracts import ArtifactError, ValidationError
|
|
14
|
+
|
|
15
|
+
DEFAULT_PREPARED_LIMIT = 512 * 1024 * 1024
|
|
16
|
+
DEFAULT_DISK_RESERVE = 1024**3
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def positive_byte_limit(value: int, *, name: str) -> int:
|
|
20
|
+
if isinstance(value, bool) or not isinstance(value, int) or value < 1:
|
|
21
|
+
raise ValidationError(f"{name} must be a positive integer")
|
|
22
|
+
return value
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def require_storage_capacity(
|
|
26
|
+
allocations: Iterable[tuple[str | Path, int]],
|
|
27
|
+
*,
|
|
28
|
+
reserve_bytes: int = DEFAULT_DISK_RESERVE,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Check all planned bytes, summing paths on the same destination device.
|
|
31
|
+
|
|
32
|
+
No directory or temporary file is created. A missing destination is checked
|
|
33
|
+
using its nearest existing ancestor, not the current working directory.
|
|
34
|
+
``required`` is an upper bound on *additional* source/prepared bytes; cached
|
|
35
|
+
sources do not need a second allowance. Unknown or negative sizes are errors.
|
|
36
|
+
"""
|
|
37
|
+
positive_byte_limit(reserve_bytes, name="reserve_bytes")
|
|
38
|
+
devices: dict[int, tuple[Path, int]] = {}
|
|
39
|
+
for destination, required in allocations:
|
|
40
|
+
if isinstance(required, bool) or not isinstance(required, int) or required < 0:
|
|
41
|
+
raise ValidationError("planned storage bytes must be a non-negative integer")
|
|
42
|
+
ancestor = Path(destination).expanduser().resolve()
|
|
43
|
+
while not ancestor.exists():
|
|
44
|
+
ancestor = ancestor.parent
|
|
45
|
+
if not ancestor.is_dir():
|
|
46
|
+
raise ArtifactError(f"storage destination ancestor is not a directory: {ancestor}")
|
|
47
|
+
device = ancestor.stat().st_dev
|
|
48
|
+
previous = devices.get(device, (ancestor, 0))
|
|
49
|
+
devices[device] = (previous[0], previous[1] + required)
|
|
50
|
+
for ancestor, required in devices.values():
|
|
51
|
+
free = shutil.disk_usage(ancestor).free
|
|
52
|
+
if free < required + reserve_bytes:
|
|
53
|
+
raise ArtifactError(
|
|
54
|
+
f"insufficient storage at {ancestor}: need {required:,} additional bytes "
|
|
55
|
+
f"plus {reserve_bytes:,} reserve, found {free:,} free; "
|
|
56
|
+
"defer this source or use a source-side bounded sample"
|
|
57
|
+
)
|