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,203 @@
|
|
|
1
|
+
"""Capability-locked 27-method by seven-static-dataset execution matrix.
|
|
2
|
+
|
|
3
|
+
The matrix distinguishes structural eligibility from execution evidence. A
|
|
4
|
+
static benchmark is eligible only when it declares the method's semantic
|
|
5
|
+
family. Ineligible pairs remain explicit rows; they are never converted into
|
|
6
|
+
zero scores or silently omitted from denominators.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
from collections.abc import Mapping
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from importlib import resources
|
|
15
|
+
from types import MappingProxyType
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
from agentinputlab.benchmarks import BenchmarkRegistry, production_benchmark_specs
|
|
19
|
+
from agentinputlab.contracts.enums import ProfileKind
|
|
20
|
+
from agentinputlab.contracts.errors import ArtifactError, ValidationError
|
|
21
|
+
from agentinputlab.contracts.serialization import content_hash, freeze_mapping
|
|
22
|
+
from agentinputlab.registry import AlgorithmRegistry
|
|
23
|
+
|
|
24
|
+
AUXILIARY_MATRIX_PROTOCOL = "agentinputlab.auxiliary-method-cell-matrix.v1"
|
|
25
|
+
AUXILIARY_PROFILE_PROTOCOL = "agentinputlab.auxiliary-method-profiles.v1"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True, slots=True)
|
|
29
|
+
class AuxiliaryMethodProfile:
|
|
30
|
+
method_id: str
|
|
31
|
+
release_id: str
|
|
32
|
+
profile_kind: ProfileKind
|
|
33
|
+
|
|
34
|
+
def __post_init__(self) -> None:
|
|
35
|
+
for label, value in (
|
|
36
|
+
("method_id", self.method_id),
|
|
37
|
+
("release_id", self.release_id),
|
|
38
|
+
):
|
|
39
|
+
if not isinstance(value, str) or not value.strip():
|
|
40
|
+
raise ValidationError(f"auxiliary profile {label} must be non-empty")
|
|
41
|
+
if not isinstance(self.profile_kind, ProfileKind):
|
|
42
|
+
raise TypeError("auxiliary profile_kind must be ProfileKind")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def auxiliary_static_cells() -> Mapping[str, str]:
|
|
46
|
+
"""Return the exact seven production static cells and frozen splits."""
|
|
47
|
+
|
|
48
|
+
cells = {
|
|
49
|
+
spec.cell_id: spec.split
|
|
50
|
+
for spec in production_benchmark_specs()
|
|
51
|
+
if spec.adapter_kind in {"retrieval", "qa"}
|
|
52
|
+
}
|
|
53
|
+
if len(cells) != 7:
|
|
54
|
+
raise ValidationError(f"auxiliary matrix requires seven static cells, got {len(cells)}")
|
|
55
|
+
return MappingProxyType(dict(sorted(cells.items())))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def load_auxiliary_method_profiles() -> Mapping[str, AuxiliaryMethodProfile]:
|
|
59
|
+
"""Load and validate the packaged method-to-executable-profile selection."""
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
source = resources.files("agentinputlab.registry").joinpath(
|
|
63
|
+
"data/auxiliary_method_profiles.json"
|
|
64
|
+
)
|
|
65
|
+
raw_bytes = source.read_bytes()
|
|
66
|
+
raw = json.loads(raw_bytes.decode("utf-8"))
|
|
67
|
+
except (OSError, UnicodeError, json.JSONDecodeError) as exc:
|
|
68
|
+
raise ArtifactError("auxiliary method profile catalog is unavailable") from exc
|
|
69
|
+
if (
|
|
70
|
+
not isinstance(raw, dict)
|
|
71
|
+
or set(raw) != {"schema_version", "protocol", "method_count", "methods"}
|
|
72
|
+
or raw.get("schema_version") != 1
|
|
73
|
+
or raw.get("protocol") != AUXILIARY_PROFILE_PROTOCOL
|
|
74
|
+
or not isinstance(raw.get("methods"), list)
|
|
75
|
+
or raw.get("method_count") != len(raw["methods"])
|
|
76
|
+
):
|
|
77
|
+
raise ValidationError("auxiliary method profile catalog schema is invalid")
|
|
78
|
+
|
|
79
|
+
registry = AlgorithmRegistry.default()
|
|
80
|
+
profiles: dict[str, AuxiliaryMethodProfile] = {}
|
|
81
|
+
for index, item in enumerate(raw["methods"]):
|
|
82
|
+
if not isinstance(item, dict) or set(item) != {
|
|
83
|
+
"method_id",
|
|
84
|
+
"release_id",
|
|
85
|
+
"profile_kind",
|
|
86
|
+
}:
|
|
87
|
+
raise ValidationError(f"auxiliary method profile row {index} is invalid")
|
|
88
|
+
try:
|
|
89
|
+
profile = AuxiliaryMethodProfile(
|
|
90
|
+
method_id=item["method_id"],
|
|
91
|
+
release_id=item["release_id"],
|
|
92
|
+
profile_kind=ProfileKind(item["profile_kind"]),
|
|
93
|
+
)
|
|
94
|
+
method, release = registry.get_release(profile.release_id)
|
|
95
|
+
except (KeyError, TypeError, ValueError) as exc:
|
|
96
|
+
raise ValidationError(
|
|
97
|
+
f"auxiliary method profile row {index} cannot be resolved"
|
|
98
|
+
) from exc
|
|
99
|
+
if profile.method_id in profiles:
|
|
100
|
+
raise ValidationError("auxiliary method profile catalog contains duplicates")
|
|
101
|
+
if method.method_id != profile.method_id:
|
|
102
|
+
raise ValidationError("auxiliary profile release belongs to another method")
|
|
103
|
+
if profile.profile_kind not in release.profile_modes:
|
|
104
|
+
raise ValidationError("auxiliary profile kind is unsupported by its release")
|
|
105
|
+
if release.entrypoint is None:
|
|
106
|
+
raise ValidationError("auxiliary profile release has no executable entrypoint")
|
|
107
|
+
profiles[profile.method_id] = profile
|
|
108
|
+
|
|
109
|
+
registered = {method.method_id for method in registry.list_methods()}
|
|
110
|
+
if set(profiles) != registered or len(profiles) != 27:
|
|
111
|
+
raise ValidationError("auxiliary profiles must cover the exact 27-method registry")
|
|
112
|
+
return MappingProxyType(dict(sorted(profiles.items())))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def build_auxiliary_method_cell_matrix() -> Mapping[str, Any]:
|
|
116
|
+
"""Build the deterministic 27x7 eligibility and launch matrix."""
|
|
117
|
+
|
|
118
|
+
registry = AlgorithmRegistry.default()
|
|
119
|
+
benchmark_registry = BenchmarkRegistry.default()
|
|
120
|
+
profiles = load_auxiliary_method_profiles()
|
|
121
|
+
cells = auxiliary_static_cells()
|
|
122
|
+
rows: list[dict[str, Any]] = []
|
|
123
|
+
family_method_counts: dict[str, int] = {}
|
|
124
|
+
for method in sorted(registry.list_methods(), key=lambda value: value.method_id):
|
|
125
|
+
family = method.semantic_family.value
|
|
126
|
+
family_method_counts[family] = family_method_counts.get(family, 0) + 1
|
|
127
|
+
profile = profiles[method.method_id]
|
|
128
|
+
for cell_id, split in cells.items():
|
|
129
|
+
cell = benchmark_registry.get(cell_id)
|
|
130
|
+
eligible = method.semantic_family in cell.families
|
|
131
|
+
reason = (
|
|
132
|
+
None
|
|
133
|
+
if eligible
|
|
134
|
+
else (
|
|
135
|
+
f"{cell_id} does not declare {method.semantic_family.value} support; "
|
|
136
|
+
"the pair is structurally ineligible"
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
rows.append(
|
|
140
|
+
{
|
|
141
|
+
"method_id": method.method_id,
|
|
142
|
+
"display_name": method.display_name,
|
|
143
|
+
"release_id": profile.release_id,
|
|
144
|
+
"profile_kind": profile.profile_kind.value,
|
|
145
|
+
"family": family,
|
|
146
|
+
"benchmark_cell_id": cell_id,
|
|
147
|
+
"split": split,
|
|
148
|
+
"benchmark_family_support": tuple(
|
|
149
|
+
item.value for item in sorted(cell.families, key=lambda value: value.value)
|
|
150
|
+
),
|
|
151
|
+
"eligible": eligible,
|
|
152
|
+
"state": "launchable" if eligible else "structurally_ineligible",
|
|
153
|
+
"reason": reason,
|
|
154
|
+
"one_click_command": (
|
|
155
|
+
"python scripts/experiments/run_auxiliary_method_cell.py "
|
|
156
|
+
"<frozen-campaign.json> "
|
|
157
|
+
f"--method {method.method_id} --cell {cell_id}"
|
|
158
|
+
if eligible
|
|
159
|
+
else None
|
|
160
|
+
),
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
eligible_count = sum(bool(row["eligible"]) for row in rows)
|
|
164
|
+
if len(rows) != 189 or eligible_count != 117:
|
|
165
|
+
raise ValidationError(
|
|
166
|
+
f"auxiliary matrix invariant failed: rows={len(rows)}, eligible={eligible_count}"
|
|
167
|
+
)
|
|
168
|
+
payload: dict[str, Any] = {
|
|
169
|
+
"schema_version": 1,
|
|
170
|
+
"protocol": AUXILIARY_MATRIX_PROTOCOL,
|
|
171
|
+
"record_type": "EXECUTION_DESIGN",
|
|
172
|
+
"observed_results": False,
|
|
173
|
+
"method_count": 27,
|
|
174
|
+
"dataset_count": 7,
|
|
175
|
+
"row_count": len(rows),
|
|
176
|
+
"eligible_pair_count": eligible_count,
|
|
177
|
+
"structurally_ineligible_pair_count": len(rows) - eligible_count,
|
|
178
|
+
"family_method_counts": dict(sorted(family_method_counts.items())),
|
|
179
|
+
"cells": dict(cells),
|
|
180
|
+
"rows": rows,
|
|
181
|
+
}
|
|
182
|
+
payload["matrix_hash"] = content_hash(payload)
|
|
183
|
+
return freeze_mapping(payload)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def auxiliary_pair(method_id: str, cell_id: str) -> Mapping[str, Any]:
|
|
187
|
+
"""Resolve one row and reject unknown identities without guessing."""
|
|
188
|
+
|
|
189
|
+
for row in build_auxiliary_method_cell_matrix()["rows"]:
|
|
190
|
+
if row["method_id"] == method_id and row["benchmark_cell_id"] == cell_id:
|
|
191
|
+
return row
|
|
192
|
+
raise KeyError(f"unknown auxiliary method-cell pair: {method_id} x {cell_id}")
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
__all__ = [
|
|
196
|
+
"AUXILIARY_MATRIX_PROTOCOL",
|
|
197
|
+
"AUXILIARY_PROFILE_PROTOCOL",
|
|
198
|
+
"AuxiliaryMethodProfile",
|
|
199
|
+
"auxiliary_pair",
|
|
200
|
+
"auxiliary_static_cells",
|
|
201
|
+
"build_auxiliary_method_cell_matrix",
|
|
202
|
+
"load_auxiliary_method_profiles",
|
|
203
|
+
]
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
"""Content-bound receipts for assets admitted by experiment preflight.
|
|
2
|
+
|
|
3
|
+
The manifest deliberately stores environment-variable *names*, not machine-local
|
|
4
|
+
paths or secret values. This module resolves those names at preflight time and
|
|
5
|
+
turns every admitted prerequisite into a canonical, secret-safe identity. The
|
|
6
|
+
resulting receipt is embedded in the effective experiment-driver fingerprint.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import hashlib
|
|
12
|
+
import os
|
|
13
|
+
import shutil
|
|
14
|
+
import stat
|
|
15
|
+
import subprocess
|
|
16
|
+
from collections.abc import Mapping
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
from agentinputlab.contracts.errors import ArtifactError, ValidationError
|
|
22
|
+
from agentinputlab.contracts.serialization import (
|
|
23
|
+
content_hash,
|
|
24
|
+
freeze_mapping,
|
|
25
|
+
to_jsonable,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
from .schema import ExperimentManifest, PrerequisiteKind, require_sha256
|
|
29
|
+
|
|
30
|
+
_GIT_OBJECT_ID_LENGTHS = frozenset({40, 64})
|
|
31
|
+
_CHECKOUT_SUFFIX = "_CHECKOUT"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True, slots=True)
|
|
35
|
+
class FrozenBindingEntry:
|
|
36
|
+
"""One prerequisite identity without its raw environment value."""
|
|
37
|
+
|
|
38
|
+
name: str
|
|
39
|
+
kind: str
|
|
40
|
+
identity: Mapping[str, Any]
|
|
41
|
+
schema_version: int = 1
|
|
42
|
+
|
|
43
|
+
def __post_init__(self) -> None:
|
|
44
|
+
if self.schema_version != 1:
|
|
45
|
+
raise ValidationError("unsupported frozen binding entry schema")
|
|
46
|
+
if not isinstance(self.name, str) or not self.name.strip():
|
|
47
|
+
raise ValidationError("frozen binding entry requires a name")
|
|
48
|
+
if not isinstance(self.kind, str) or not self.kind.strip():
|
|
49
|
+
raise ValidationError("frozen binding entry requires a kind")
|
|
50
|
+
try:
|
|
51
|
+
identity = freeze_mapping(self.identity)
|
|
52
|
+
except (TypeError, ValueError) as exc:
|
|
53
|
+
raise ValidationError("frozen binding identity must be canonical JSON") from exc
|
|
54
|
+
if not identity:
|
|
55
|
+
raise ValidationError("frozen binding identity must not be empty")
|
|
56
|
+
object.__setattr__(self, "identity", identity)
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def binding_hash(self) -> str:
|
|
60
|
+
return content_hash(
|
|
61
|
+
{
|
|
62
|
+
"schema_version": self.schema_version,
|
|
63
|
+
"name": self.name,
|
|
64
|
+
"kind": self.kind,
|
|
65
|
+
"identity": self.identity,
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def to_dict(self) -> dict[str, Any]:
|
|
70
|
+
return {
|
|
71
|
+
"schema_version": self.schema_version,
|
|
72
|
+
"name": self.name,
|
|
73
|
+
"kind": self.kind,
|
|
74
|
+
"identity": to_jsonable(self.identity),
|
|
75
|
+
"binding_hash": self.binding_hash,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass(frozen=True, slots=True)
|
|
80
|
+
class FrozenBindingReceipt:
|
|
81
|
+
"""Canonical receipt for all manifest prerequisites accepted by preflight."""
|
|
82
|
+
|
|
83
|
+
manifest_hash: str
|
|
84
|
+
bindings: tuple[FrozenBindingEntry, ...]
|
|
85
|
+
schema_version: int = 1
|
|
86
|
+
|
|
87
|
+
def __post_init__(self) -> None:
|
|
88
|
+
if self.schema_version != 1:
|
|
89
|
+
raise ValidationError("unsupported frozen binding receipt schema")
|
|
90
|
+
require_sha256(self.manifest_hash, label="binding receipt manifest_hash")
|
|
91
|
+
bindings = tuple(self.bindings)
|
|
92
|
+
if any(not isinstance(item, FrozenBindingEntry) for item in bindings):
|
|
93
|
+
raise ValidationError("frozen binding receipt entries must be typed")
|
|
94
|
+
identities = [(item.kind, item.name) for item in bindings]
|
|
95
|
+
if len(identities) != len(set(identities)):
|
|
96
|
+
raise ValidationError("frozen binding receipt entries must be unique")
|
|
97
|
+
canonical = tuple(sorted(bindings, key=lambda item: (item.kind, item.name)))
|
|
98
|
+
object.__setattr__(self, "bindings", canonical)
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def receipt_hash(self) -> str:
|
|
102
|
+
return content_hash(
|
|
103
|
+
{
|
|
104
|
+
"schema_version": self.schema_version,
|
|
105
|
+
"manifest_hash": self.manifest_hash,
|
|
106
|
+
"bindings": [
|
|
107
|
+
{
|
|
108
|
+
"schema_version": item.schema_version,
|
|
109
|
+
"name": item.name,
|
|
110
|
+
"kind": item.kind,
|
|
111
|
+
"identity": item.identity,
|
|
112
|
+
}
|
|
113
|
+
for item in self.bindings
|
|
114
|
+
],
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def binding(self, name: str, *, kind: str | None = None) -> FrozenBindingEntry:
|
|
119
|
+
matches = tuple(
|
|
120
|
+
item
|
|
121
|
+
for item in self.bindings
|
|
122
|
+
if item.name == name and (kind is None or item.kind == kind)
|
|
123
|
+
)
|
|
124
|
+
if len(matches) != 1:
|
|
125
|
+
raise ArtifactError(f"frozen binding receipt has no unique entry for {name!r}")
|
|
126
|
+
return matches[0]
|
|
127
|
+
|
|
128
|
+
def to_dict(self) -> dict[str, Any]:
|
|
129
|
+
return {
|
|
130
|
+
"schema_version": self.schema_version,
|
|
131
|
+
"manifest_hash": self.manifest_hash,
|
|
132
|
+
"bindings": [item.to_dict() for item in self.bindings],
|
|
133
|
+
"receipt_hash": self.receipt_hash,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def resolve_frozen_binding_receipt(
|
|
138
|
+
manifest: ExperimentManifest,
|
|
139
|
+
*,
|
|
140
|
+
environment: Mapping[str, str] | None = None,
|
|
141
|
+
) -> FrozenBindingReceipt:
|
|
142
|
+
"""Resolve and independently attest every declared prerequisite.
|
|
143
|
+
|
|
144
|
+
Checkout directories are required to be clean Git roots. Other directories
|
|
145
|
+
receive a deterministic content-tree hash. Raw paths and environment values
|
|
146
|
+
never enter the receipt; only their SHA-256 identities do.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
if not isinstance(manifest, ExperimentManifest):
|
|
150
|
+
raise TypeError("binding resolution requires ExperimentManifest")
|
|
151
|
+
env = dict(os.environ if environment is None else environment)
|
|
152
|
+
expectations = _checkout_expectations(manifest, environment=env)
|
|
153
|
+
declared_directories = {
|
|
154
|
+
item.name for item in manifest.prerequisites if item.kind is PrerequisiteKind.DIRECTORY_ENV
|
|
155
|
+
}
|
|
156
|
+
unknown_expectations = sorted(set(expectations) - declared_directories)
|
|
157
|
+
if unknown_expectations:
|
|
158
|
+
raise ValidationError(
|
|
159
|
+
"checkout_expected_revisions references undeclared directories: "
|
|
160
|
+
+ ", ".join(unknown_expectations)
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
bindings: list[FrozenBindingEntry] = []
|
|
164
|
+
for prerequisite in manifest.prerequisites:
|
|
165
|
+
if prerequisite.kind is PrerequisiteKind.ENV:
|
|
166
|
+
raw = env.get(prerequisite.name)
|
|
167
|
+
if not raw:
|
|
168
|
+
raise ArtifactError(f"missing environment prerequisite {prerequisite.name}")
|
|
169
|
+
encoded = raw.encode("utf-8")
|
|
170
|
+
identity = {
|
|
171
|
+
"identity_mode": "value_sha256",
|
|
172
|
+
"value_sha256": hashlib.sha256(encoded).hexdigest(),
|
|
173
|
+
"value_bytes": len(encoded),
|
|
174
|
+
}
|
|
175
|
+
elif prerequisite.kind is PrerequisiteKind.EXECUTABLE:
|
|
176
|
+
executable = shutil.which(prerequisite.name, path=env.get("PATH"))
|
|
177
|
+
if executable is None:
|
|
178
|
+
raise ArtifactError(f"missing executable prerequisite {prerequisite.name}")
|
|
179
|
+
candidate = Path(executable).expanduser().resolve()
|
|
180
|
+
if not candidate.is_file():
|
|
181
|
+
raise ArtifactError(f"executable prerequisite {prerequisite.name} is not a file")
|
|
182
|
+
identity = {
|
|
183
|
+
"identity_mode": "executable_sha256",
|
|
184
|
+
"resolved_path_sha256": _sha256_text(str(candidate)),
|
|
185
|
+
"content_sha256": _sha256_file(candidate),
|
|
186
|
+
"size_bytes": candidate.stat().st_size,
|
|
187
|
+
}
|
|
188
|
+
else:
|
|
189
|
+
raw = env.get(prerequisite.name)
|
|
190
|
+
if not raw:
|
|
191
|
+
raise ArtifactError(f"missing environment prerequisite {prerequisite.name}")
|
|
192
|
+
candidate = Path(raw).expanduser().resolve()
|
|
193
|
+
if prerequisite.kind is PrerequisiteKind.FILE_ENV:
|
|
194
|
+
if not candidate.is_file():
|
|
195
|
+
raise ArtifactError(f"{prerequisite.name} does not identify an existing file")
|
|
196
|
+
actual = _sha256_file(candidate)
|
|
197
|
+
if prerequisite.sha256_env is not None:
|
|
198
|
+
expected = env.get(prerequisite.sha256_env)
|
|
199
|
+
if not expected:
|
|
200
|
+
raise ArtifactError(
|
|
201
|
+
f"missing checksum prerequisite {prerequisite.sha256_env}"
|
|
202
|
+
)
|
|
203
|
+
require_sha256(
|
|
204
|
+
expected,
|
|
205
|
+
label=f"environment {prerequisite.sha256_env}",
|
|
206
|
+
)
|
|
207
|
+
if actual != expected:
|
|
208
|
+
raise ArtifactError(
|
|
209
|
+
f"{prerequisite.name} checksum differs from {prerequisite.sha256_env}"
|
|
210
|
+
)
|
|
211
|
+
identity = {
|
|
212
|
+
"identity_mode": "file_sha256",
|
|
213
|
+
"resolved_path_sha256": _sha256_text(str(candidate)),
|
|
214
|
+
"content_sha256": actual,
|
|
215
|
+
"size_bytes": candidate.stat().st_size,
|
|
216
|
+
"checksum_environment": prerequisite.sha256_env,
|
|
217
|
+
}
|
|
218
|
+
else:
|
|
219
|
+
if not candidate.is_dir():
|
|
220
|
+
raise ArtifactError(
|
|
221
|
+
f"{prerequisite.name} does not identify an existing directory"
|
|
222
|
+
)
|
|
223
|
+
expected_revision = expectations.get(prerequisite.name)
|
|
224
|
+
if expected_revision is not None or prerequisite.name.endswith(_CHECKOUT_SUFFIX):
|
|
225
|
+
identity = _git_checkout_identity(
|
|
226
|
+
candidate,
|
|
227
|
+
expected_revision=expected_revision,
|
|
228
|
+
)
|
|
229
|
+
else:
|
|
230
|
+
identity = {
|
|
231
|
+
"identity_mode": "directory_tree_sha256",
|
|
232
|
+
"resolved_path_sha256": _sha256_text(str(candidate)),
|
|
233
|
+
"tree_sha256": _sha256_directory_tree(candidate),
|
|
234
|
+
}
|
|
235
|
+
bindings.append(
|
|
236
|
+
FrozenBindingEntry(
|
|
237
|
+
name=prerequisite.name,
|
|
238
|
+
kind=prerequisite.kind.value,
|
|
239
|
+
identity=identity,
|
|
240
|
+
)
|
|
241
|
+
)
|
|
242
|
+
return FrozenBindingReceipt(
|
|
243
|
+
manifest_hash=manifest.manifest_hash,
|
|
244
|
+
bindings=tuple(bindings),
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def build_guarded_driver_fingerprint(
|
|
249
|
+
operator_fingerprint: Mapping[str, Any],
|
|
250
|
+
binding_receipt: FrozenBindingReceipt,
|
|
251
|
+
*,
|
|
252
|
+
parity_contract: Mapping[str, Any] | None = None,
|
|
253
|
+
) -> Mapping[str, Any]:
|
|
254
|
+
"""Build the exact fingerprint persisted by the guarded runtime driver."""
|
|
255
|
+
|
|
256
|
+
if not isinstance(binding_receipt, FrozenBindingReceipt):
|
|
257
|
+
raise TypeError("guarded fingerprint requires FrozenBindingReceipt")
|
|
258
|
+
try:
|
|
259
|
+
operator = freeze_mapping(operator_fingerprint)
|
|
260
|
+
contract = freeze_mapping(parity_contract or {})
|
|
261
|
+
except (TypeError, ValueError) as exc:
|
|
262
|
+
raise ValidationError("guarded driver identity must be canonical JSON") from exc
|
|
263
|
+
if not operator:
|
|
264
|
+
raise ValidationError("operator driver fingerprint must not be empty")
|
|
265
|
+
return freeze_mapping(
|
|
266
|
+
{
|
|
267
|
+
"schema_version": 1,
|
|
268
|
+
"guard": "agentinputlab.frozen_binding_driver_guard",
|
|
269
|
+
"operator_driver_fingerprint": operator,
|
|
270
|
+
"frozen_binding_receipt": binding_receipt.to_dict(),
|
|
271
|
+
"frozen_binding_receipt_hash": binding_receipt.receipt_hash,
|
|
272
|
+
"parity_contract": contract,
|
|
273
|
+
}
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _checkout_expectations(
|
|
278
|
+
manifest: ExperimentManifest,
|
|
279
|
+
*,
|
|
280
|
+
environment: Mapping[str, str],
|
|
281
|
+
) -> dict[str, str]:
|
|
282
|
+
raw = manifest.metadata.get("checkout_expected_revisions", {})
|
|
283
|
+
if not isinstance(raw, Mapping):
|
|
284
|
+
raise ValidationError("checkout_expected_revisions metadata must be an object")
|
|
285
|
+
result: dict[str, str] = {}
|
|
286
|
+
for name, revision in raw.items():
|
|
287
|
+
if not isinstance(name, str) or not name:
|
|
288
|
+
raise ValidationError("checkout expectation names must be non-empty strings")
|
|
289
|
+
if (
|
|
290
|
+
not isinstance(revision, str)
|
|
291
|
+
or len(revision) not in _GIT_OBJECT_ID_LENGTHS
|
|
292
|
+
or any(character not in "0123456789abcdef" for character in revision)
|
|
293
|
+
):
|
|
294
|
+
raise ValidationError(
|
|
295
|
+
f"checkout expectation {name} must be a full lowercase Git object ID"
|
|
296
|
+
)
|
|
297
|
+
result[name] = revision
|
|
298
|
+
|
|
299
|
+
dynamic = manifest.metadata.get("checkout_expected_revision_from_env", {})
|
|
300
|
+
if not isinstance(dynamic, Mapping):
|
|
301
|
+
raise ValidationError("checkout_expected_revision_from_env metadata must be an object")
|
|
302
|
+
declared_value_environments = {
|
|
303
|
+
item.name for item in manifest.prerequisites if item.kind is PrerequisiteKind.ENV
|
|
304
|
+
}
|
|
305
|
+
for checkout_environment, revision_environment in dynamic.items():
|
|
306
|
+
if not isinstance(checkout_environment, str) or not checkout_environment:
|
|
307
|
+
raise ValidationError("dynamic checkout expectation names must be non-empty strings")
|
|
308
|
+
if not isinstance(revision_environment, str) or not revision_environment:
|
|
309
|
+
raise ValidationError(
|
|
310
|
+
"dynamic checkout revision environments must be non-empty strings"
|
|
311
|
+
)
|
|
312
|
+
if revision_environment not in declared_value_environments:
|
|
313
|
+
raise ValidationError(
|
|
314
|
+
"checkout_expected_revision_from_env references an undeclared "
|
|
315
|
+
f"value prerequisite: {revision_environment}"
|
|
316
|
+
)
|
|
317
|
+
revision = environment.get(revision_environment)
|
|
318
|
+
if not revision:
|
|
319
|
+
raise ArtifactError(f"missing checkout revision prerequisite {revision_environment}")
|
|
320
|
+
if (
|
|
321
|
+
not isinstance(revision, str)
|
|
322
|
+
or len(revision) not in _GIT_OBJECT_ID_LENGTHS
|
|
323
|
+
or any(character not in "0123456789abcdef" for character in revision)
|
|
324
|
+
):
|
|
325
|
+
raise ValidationError(
|
|
326
|
+
f"environment {revision_environment} must be a full lowercase Git object ID"
|
|
327
|
+
)
|
|
328
|
+
existing = result.get(checkout_environment)
|
|
329
|
+
if existing is not None and existing != revision:
|
|
330
|
+
raise ValidationError(
|
|
331
|
+
f"dynamic checkout expectation for {checkout_environment} "
|
|
332
|
+
"conflicts with the manifest-pinned revision"
|
|
333
|
+
)
|
|
334
|
+
result[checkout_environment] = revision
|
|
335
|
+
return result
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def _git_checkout_identity(
|
|
339
|
+
path: Path,
|
|
340
|
+
*,
|
|
341
|
+
expected_revision: str | None,
|
|
342
|
+
) -> Mapping[str, Any]:
|
|
343
|
+
if shutil.which("git") is None:
|
|
344
|
+
raise ArtifactError("git is required to attest checkout prerequisites")
|
|
345
|
+
top_level = Path(_git(path, "rev-parse", "--show-toplevel")).resolve()
|
|
346
|
+
if top_level != path:
|
|
347
|
+
raise ArtifactError("checkout prerequisite must identify the Git repository root")
|
|
348
|
+
head = _git(path, "rev-parse", "HEAD")
|
|
349
|
+
tree = _git(path, "rev-parse", "HEAD^{tree}")
|
|
350
|
+
for label, value in (("HEAD", head), ("tree", tree)):
|
|
351
|
+
if len(value) not in _GIT_OBJECT_ID_LENGTHS or any(
|
|
352
|
+
character not in "0123456789abcdef" for character in value
|
|
353
|
+
):
|
|
354
|
+
raise ArtifactError(f"checkout {label} is not a full Git object ID")
|
|
355
|
+
if expected_revision is not None and head != expected_revision:
|
|
356
|
+
raise ArtifactError("checkout HEAD differs from the manifest-pinned revision")
|
|
357
|
+
status = _git(path, "status", "--porcelain=v1", "--untracked-files=all")
|
|
358
|
+
if status:
|
|
359
|
+
raise ArtifactError("checkout prerequisite must have a clean working tree")
|
|
360
|
+
return freeze_mapping(
|
|
361
|
+
{
|
|
362
|
+
"identity_mode": "clean_git_checkout",
|
|
363
|
+
"resolved_path_sha256": _sha256_text(str(path)),
|
|
364
|
+
"git_head": head,
|
|
365
|
+
"git_tree": tree,
|
|
366
|
+
"git_clean": True,
|
|
367
|
+
"expected_revision": expected_revision,
|
|
368
|
+
}
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def _git(path: Path, *arguments: str) -> str:
|
|
373
|
+
try:
|
|
374
|
+
completed = subprocess.run(
|
|
375
|
+
("git", "-C", str(path), *arguments),
|
|
376
|
+
check=True,
|
|
377
|
+
capture_output=True,
|
|
378
|
+
text=True,
|
|
379
|
+
timeout=30,
|
|
380
|
+
)
|
|
381
|
+
except (OSError, subprocess.SubprocessError) as exc:
|
|
382
|
+
raise ArtifactError(f"cannot attest Git checkout with {' '.join(arguments)}") from exc
|
|
383
|
+
return completed.stdout.strip()
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def _sha256_directory_tree(root: Path) -> str:
|
|
387
|
+
digest = hashlib.sha256()
|
|
388
|
+
for candidate in sorted(root.rglob("*"), key=lambda item: item.relative_to(root).as_posix()):
|
|
389
|
+
relative = candidate.relative_to(root).as_posix()
|
|
390
|
+
mode = candidate.lstat().st_mode
|
|
391
|
+
if stat.S_ISDIR(mode):
|
|
392
|
+
digest.update(f"D\0{relative}\0".encode())
|
|
393
|
+
elif stat.S_ISREG(mode):
|
|
394
|
+
digest.update(f"F\0{relative}\0".encode())
|
|
395
|
+
digest.update(_sha256_file(candidate).encode())
|
|
396
|
+
digest.update(b"\0")
|
|
397
|
+
elif stat.S_ISLNK(mode):
|
|
398
|
+
target = candidate.resolve(strict=True)
|
|
399
|
+
if not target.is_file():
|
|
400
|
+
raise ArtifactError(f"directory binding symlink must resolve to a file: {relative}")
|
|
401
|
+
digest.update(f"L\0{relative}\0".encode())
|
|
402
|
+
digest.update(_sha256_text(os.readlink(candidate)).encode())
|
|
403
|
+
digest.update(b"\0")
|
|
404
|
+
digest.update(_sha256_file(target).encode())
|
|
405
|
+
digest.update(b"\0")
|
|
406
|
+
else:
|
|
407
|
+
raise ArtifactError(
|
|
408
|
+
f"directory binding contains unsupported filesystem entry: {relative}"
|
|
409
|
+
)
|
|
410
|
+
return digest.hexdigest()
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def _sha256_file(path: Path) -> str:
|
|
414
|
+
digest = hashlib.sha256()
|
|
415
|
+
with path.open("rb") as handle:
|
|
416
|
+
for block in iter(lambda: handle.read(1024 * 1024), b""):
|
|
417
|
+
digest.update(block)
|
|
418
|
+
return digest.hexdigest()
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def _sha256_text(value: str) -> str:
|
|
422
|
+
return hashlib.sha256(value.encode("utf-8")).hexdigest()
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
__all__ = [
|
|
426
|
+
"FrozenBindingEntry",
|
|
427
|
+
"FrozenBindingReceipt",
|
|
428
|
+
"build_guarded_driver_fingerprint",
|
|
429
|
+
"resolve_frozen_binding_receipt",
|
|
430
|
+
]
|