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,283 @@
|
|
|
1
|
+
"""Pinned native SmartSearch curriculum preparation, separate from inference.
|
|
2
|
+
|
|
3
|
+
These APIs do not train a model or manufacture process rewards. They consume
|
|
4
|
+
recorded training-only rollouts and call the original redundancy/SFT/DPO/prefix
|
|
5
|
+
converters. The complete SFT/DPO/GRPO training recipe remains a separate gate.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import contextlib
|
|
10
|
+
import hashlib
|
|
11
|
+
import importlib.util
|
|
12
|
+
import io
|
|
13
|
+
import json
|
|
14
|
+
import math
|
|
15
|
+
import os
|
|
16
|
+
import subprocess
|
|
17
|
+
from collections.abc import Mapping, Sequence
|
|
18
|
+
from dataclasses import dataclass, field
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from agentinputlab.contracts import ExternalDependencyError, ValidationError
|
|
23
|
+
from agentinputlab.contracts.serialization import content_hash, freeze_mapping, to_jsonable
|
|
24
|
+
|
|
25
|
+
from .smartsearch import SMARTSEARCH_UPSTREAM_COMMIT
|
|
26
|
+
|
|
27
|
+
_FILES = {
|
|
28
|
+
"redundancy": "scripts/data_construction/detect_redundancy.py",
|
|
29
|
+
"sft": "scripts/data_construction/transfer_sft.py",
|
|
30
|
+
"dpo": "scripts/data_construction/transfer_dpo.py",
|
|
31
|
+
"prefix": "scripts/data_construction/transfer_regenerate.py",
|
|
32
|
+
"reward": "scripts/data_construction/process_reward.py",
|
|
33
|
+
"refinement": "scripts/data_construction/query_refinement.py",
|
|
34
|
+
}
|
|
35
|
+
_PREPARATION_KEYS = ("redundancy", "sft", "dpo", "prefix")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass(frozen=True, slots=True)
|
|
39
|
+
class SmartSearchTrainingCase:
|
|
40
|
+
case_id: str
|
|
41
|
+
question: str
|
|
42
|
+
split: str
|
|
43
|
+
source_reference: Mapping[str, Any] = field(default_factory=dict)
|
|
44
|
+
|
|
45
|
+
def __post_init__(self) -> None:
|
|
46
|
+
if not isinstance(self.case_id, str) or not self.case_id.strip():
|
|
47
|
+
raise ValidationError("SmartSearch training case requires a non-empty ID")
|
|
48
|
+
if not isinstance(self.question, str) or not self.question.strip():
|
|
49
|
+
raise ValidationError("SmartSearch training case requires a non-empty question")
|
|
50
|
+
if self.split not in {"train", "validation", "test"}:
|
|
51
|
+
raise ValidationError("SmartSearch training case split is invalid")
|
|
52
|
+
try:
|
|
53
|
+
object.__setattr__(self, "source_reference", freeze_mapping(self.source_reference))
|
|
54
|
+
except (TypeError, ValueError) as exc:
|
|
55
|
+
raise ValidationError("SmartSearch case provenance is not canonical JSON") from exc
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _question_hash(question: str) -> str:
|
|
59
|
+
# This additional overlap check is not a model-input transformation.
|
|
60
|
+
return content_hash(" ".join(question.split()).casefold())
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def validate_smartsearch_training_splits(
|
|
64
|
+
train: Sequence[SmartSearchTrainingCase],
|
|
65
|
+
validation: Sequence[SmartSearchTrainingCase],
|
|
66
|
+
test: Sequence[SmartSearchTrainingCase] = (),
|
|
67
|
+
) -> Mapping[str, Any]:
|
|
68
|
+
if not train or not validation:
|
|
69
|
+
raise ValidationError("SmartSearch curriculum needs non-empty training and validation collections")
|
|
70
|
+
audit = {}
|
|
71
|
+
seen_ids: set[str] = set()
|
|
72
|
+
seen_questions: set[str] = set()
|
|
73
|
+
for name, cases in (("train", train), ("validation", validation), ("test", test)):
|
|
74
|
+
if any(not isinstance(case, SmartSearchTrainingCase) or case.split != name for case in cases):
|
|
75
|
+
raise ValidationError("SmartSearch curriculum case split label mismatch")
|
|
76
|
+
ids = tuple(case.case_id for case in cases)
|
|
77
|
+
hashes = tuple(_question_hash(case.question) for case in cases)
|
|
78
|
+
if len(ids) != len(set(ids)) or len(hashes) != len(set(hashes)):
|
|
79
|
+
raise ValidationError("SmartSearch curriculum split contains duplicate IDs/questions")
|
|
80
|
+
if set(ids) & seen_ids or set(hashes) & seen_questions:
|
|
81
|
+
raise ValidationError("SmartSearch fitting, validation and test collections overlap")
|
|
82
|
+
seen_ids.update(ids)
|
|
83
|
+
seen_questions.update(hashes)
|
|
84
|
+
audit[name] = {"case_ids": ids, "question_hashes": hashes,
|
|
85
|
+
"case_hashes": tuple(content_hash(case) for case in cases)}
|
|
86
|
+
return freeze_mapping(audit)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def verify_smartsearch_preparation_source(
|
|
90
|
+
checkout: str | Path, *, include_teacher: bool = False,
|
|
91
|
+
) -> Mapping[str, Any]:
|
|
92
|
+
"""Bind the exact upstream Git objects and their on-disk converter bytes."""
|
|
93
|
+
root = Path(checkout)
|
|
94
|
+
if root.is_symlink() or not root.is_dir():
|
|
95
|
+
raise ExternalDependencyError("SmartSearch preparation requires a regular pinned Git checkout")
|
|
96
|
+
root = root.resolve()
|
|
97
|
+
|
|
98
|
+
def git(*args: str) -> bytes:
|
|
99
|
+
try:
|
|
100
|
+
result = subprocess.run(
|
|
101
|
+
["git", "-c", "core.fsmonitor=false", "-c", f"core.hooksPath={os.devnull}",
|
|
102
|
+
"-C", str(root), *args], capture_output=True, check=True, timeout=30,
|
|
103
|
+
env={"PATH": os.defpath, "LANG": "C", "LC_ALL": "C",
|
|
104
|
+
"GIT_CONFIG_NOSYSTEM": "1", "GIT_CONFIG_GLOBAL": os.devnull,
|
|
105
|
+
"GIT_OPTIONAL_LOCKS": "0", "GIT_TERMINAL_PROMPT": "0"},
|
|
106
|
+
)
|
|
107
|
+
except (OSError, subprocess.SubprocessError) as exc:
|
|
108
|
+
raise ExternalDependencyError("SmartSearch preparation source Git verification failed") from exc
|
|
109
|
+
return result.stdout
|
|
110
|
+
|
|
111
|
+
if git("rev-parse", "HEAD").decode().strip() != SMARTSEARCH_UPSTREAM_COMMIT:
|
|
112
|
+
raise ExternalDependencyError("SmartSearch preparation source revision changed")
|
|
113
|
+
if Path(git("rev-parse", "--show-toplevel").decode().strip()).resolve() != root:
|
|
114
|
+
raise ExternalDependencyError("SmartSearch preparation checkout is not the repository root")
|
|
115
|
+
if git("status", "--porcelain", "--untracked-files=all").strip():
|
|
116
|
+
raise ExternalDependencyError("SmartSearch preparation requires an unchanged source checkout")
|
|
117
|
+
files = {}
|
|
118
|
+
keys = tuple(_FILES) if include_teacher else _PREPARATION_KEYS
|
|
119
|
+
for relative in (_FILES[key] for key in keys):
|
|
120
|
+
path = root
|
|
121
|
+
for component in Path(relative).parts:
|
|
122
|
+
path = path / component
|
|
123
|
+
if path.is_symlink():
|
|
124
|
+
raise ExternalDependencyError("SmartSearch preparation source contains a symlink")
|
|
125
|
+
if not path.is_file():
|
|
126
|
+
raise ExternalDependencyError(f"SmartSearch native preparation file is missing: {relative}")
|
|
127
|
+
actual = path.read_bytes()
|
|
128
|
+
expected = git("show", f"{SMARTSEARCH_UPSTREAM_COMMIT}:{relative}")
|
|
129
|
+
if actual != expected:
|
|
130
|
+
raise ExternalDependencyError(f"SmartSearch native preparation file changed: {relative}")
|
|
131
|
+
files[relative] = hashlib.sha256(actual).hexdigest()
|
|
132
|
+
return freeze_mapping({"source_commit": SMARTSEARCH_UPSTREAM_COMMIT, "files": files,
|
|
133
|
+
"root": str(root), "preparation_math_modified": False})
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _native_converter(root: Path, key: str, source: Mapping[str, Any]) -> Any:
|
|
137
|
+
path = root / _FILES[key]
|
|
138
|
+
source_bytes = path.read_bytes()
|
|
139
|
+
if hashlib.sha256(source_bytes).hexdigest() != source["files"][_FILES[key]]:
|
|
140
|
+
raise ExternalDependencyError("SmartSearch preparation source changed before import")
|
|
141
|
+
name = f"_agentinputlab_smartsearch_{key}_{source['files'][_FILES[key]][:12]}"
|
|
142
|
+
spec = importlib.util.spec_from_file_location(name, path)
|
|
143
|
+
if spec is None or spec.loader is None:
|
|
144
|
+
raise ExternalDependencyError("SmartSearch native converter could not be imported")
|
|
145
|
+
module = importlib.util.module_from_spec(spec)
|
|
146
|
+
try:
|
|
147
|
+
# Compile the verified bytes, never an unbound pre-existing .pyc cache.
|
|
148
|
+
exec(compile(source_bytes, str(path), "exec"), module.__dict__)
|
|
149
|
+
except ImportError as exc:
|
|
150
|
+
raise ExternalDependencyError("Install agentinputlab[smartsearch-prepare] in the preparation worker") from exc
|
|
151
|
+
class_name = {"redundancy": "Redundancy", "reward": "SearchEvaluation",
|
|
152
|
+
"refinement": "Rewrite"}.get(key, "Transfer")
|
|
153
|
+
constructor = getattr(module, class_name, None)
|
|
154
|
+
if not callable(constructor):
|
|
155
|
+
raise ExternalDependencyError("SmartSearch native converter class signature changed")
|
|
156
|
+
return constructor("controlled-provider-no-network") if key in {"reward", "refinement"} else constructor()
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _scored_rows(
|
|
160
|
+
value: Sequence[Mapping[str, Any]], allowed_questions: set[str], max_rows: int,
|
|
161
|
+
) -> list[dict[str, Any]]:
|
|
162
|
+
if not isinstance(value, (tuple, list)) or len(value) > max_rows:
|
|
163
|
+
raise ValidationError("SmartSearch recorded rollout collection exceeds its explicit bound")
|
|
164
|
+
rows = []
|
|
165
|
+
for row in value:
|
|
166
|
+
if not isinstance(row, Mapping) or row.get("question") not in allowed_questions:
|
|
167
|
+
raise ValidationError("SmartSearch curriculum rollout is outside the allowed training questions")
|
|
168
|
+
if not isinstance(row.get("response"), str) or not isinstance(row.get("process_scores"), (list, tuple)):
|
|
169
|
+
raise ValidationError("SmartSearch curriculum requires recorded response and process scores")
|
|
170
|
+
metric = row.get("outcome_score")
|
|
171
|
+
score = metric.get("f1") if isinstance(metric, Mapping) else None
|
|
172
|
+
if isinstance(score, bool) or not isinstance(score, (float, int)) or not math.isfinite(score) or not 0 <= score <= 1:
|
|
173
|
+
raise ValidationError("SmartSearch curriculum requires a measured finite outcome F1")
|
|
174
|
+
for process in row["process_scores"]:
|
|
175
|
+
if not isinstance(process, Mapping) or not isinstance(process.get("score"), str) or process["score"] not in {"", "0", "1"}:
|
|
176
|
+
raise ValidationError("SmartSearch native process-score representation is invalid")
|
|
177
|
+
try:
|
|
178
|
+
rows.append(json.loads(json.dumps(to_jsonable(row), allow_nan=False)))
|
|
179
|
+
except (TypeError, ValueError) as exc:
|
|
180
|
+
raise ValidationError("SmartSearch scored rollout is not canonical JSON") from exc
|
|
181
|
+
return rows
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@dataclass(frozen=True, slots=True)
|
|
185
|
+
class SmartSearchCurriculumArtifact:
|
|
186
|
+
root: str
|
|
187
|
+
artifact_id: str
|
|
188
|
+
sft_count: int
|
|
189
|
+
dpo_count: int
|
|
190
|
+
prefix_count: int
|
|
191
|
+
source_fingerprint_sha256: str
|
|
192
|
+
split_audit_sha256: str
|
|
193
|
+
output_hashes: Mapping[str, str]
|
|
194
|
+
|
|
195
|
+
def __post_init__(self) -> None:
|
|
196
|
+
object.__setattr__(self, "output_hashes", freeze_mapping(self.output_hashes))
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@dataclass(frozen=True, slots=True)
|
|
200
|
+
class SmartSearchCurriculumPreparation:
|
|
201
|
+
max_rollout_rows: int = 1000
|
|
202
|
+
max_input_bytes: int = 16 * 1024 * 1024
|
|
203
|
+
|
|
204
|
+
def __post_init__(self) -> None:
|
|
205
|
+
if type(self.max_rollout_rows) is not int or self.max_rollout_rows < 1 or (
|
|
206
|
+
type(self.max_input_bytes) is not int or self.max_input_bytes < 1
|
|
207
|
+
):
|
|
208
|
+
raise ValidationError("SmartSearch curriculum limits must be positive integers")
|
|
209
|
+
|
|
210
|
+
def prepare(
|
|
211
|
+
self, *, checkout: str | Path, output_root: str | Path,
|
|
212
|
+
train: Sequence[SmartSearchTrainingCase], validation: Sequence[SmartSearchTrainingCase],
|
|
213
|
+
initial_scored_rollouts: Sequence[Mapping[str, Any]],
|
|
214
|
+
regenerated_scored_rollouts: Sequence[Mapping[str, Any]],
|
|
215
|
+
test: Sequence[SmartSearchTrainingCase] = (),
|
|
216
|
+
rollout_provenance: Mapping[str, Any],
|
|
217
|
+
) -> SmartSearchCurriculumArtifact:
|
|
218
|
+
audit = validate_smartsearch_training_splits(train, validation, test)
|
|
219
|
+
if not isinstance(rollout_provenance, Mapping) or not rollout_provenance:
|
|
220
|
+
raise ValidationError("SmartSearch recorded rollouts require explicit producer provenance")
|
|
221
|
+
allowed = {case.question for case in train}
|
|
222
|
+
initial = _scored_rows(initial_scored_rollouts, allowed, self.max_rollout_rows)
|
|
223
|
+
regenerated = _scored_rows(regenerated_scored_rollouts, allowed, self.max_rollout_rows)
|
|
224
|
+
if not initial:
|
|
225
|
+
raise ValidationError("SmartSearch curriculum needs initial recorded training rollouts")
|
|
226
|
+
raw_inputs = {"initial": initial, "regenerated": regenerated,
|
|
227
|
+
"producer_provenance": to_jsonable(rollout_provenance)}
|
|
228
|
+
encoded = json.dumps(raw_inputs, ensure_ascii=False, allow_nan=False).encode()
|
|
229
|
+
if len(encoded) > self.max_input_bytes:
|
|
230
|
+
raise ValidationError("SmartSearch curriculum input exceeds its explicit byte bound")
|
|
231
|
+
source = verify_smartsearch_preparation_source(checkout)
|
|
232
|
+
source_root = Path(source["root"])
|
|
233
|
+
root = Path(output_root)
|
|
234
|
+
if root.is_symlink() or root.exists():
|
|
235
|
+
raise ValidationError("SmartSearch curriculum output must be a new directory")
|
|
236
|
+
root = root.resolve(strict=False)
|
|
237
|
+
if root.is_relative_to(source_root) or source_root.is_relative_to(root):
|
|
238
|
+
raise ValidationError("SmartSearch curriculum outputs must not overlap source checkout")
|
|
239
|
+
root.mkdir(parents=True, exist_ok=False)
|
|
240
|
+
|
|
241
|
+
def save(name: str, value: Any) -> None:
|
|
242
|
+
with (root / name).open("x", encoding="utf-8") as stream:
|
|
243
|
+
json.dump(to_jsonable(value), stream, ensure_ascii=False, sort_keys=True, allow_nan=False)
|
|
244
|
+
|
|
245
|
+
save("claim.json", {"source": source, "split_audit": audit, "input_hash": content_hash(raw_inputs),
|
|
246
|
+
"rollout_provenance": rollout_provenance, "model_calls_performed": 0})
|
|
247
|
+
try:
|
|
248
|
+
with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):
|
|
249
|
+
redundancy = _native_converter(source_root, "redundancy", source)
|
|
250
|
+
initial_checked = redundancy.detect_redundancy(initial)
|
|
251
|
+
regenerated_checked = redundancy.detect_redundancy(regenerated)
|
|
252
|
+
sft = _native_converter(source_root, "sft", source).transfer(initial_checked)
|
|
253
|
+
dpo = _native_converter(source_root, "dpo", source).transfer(initial_checked, regenerated_checked)
|
|
254
|
+
prefix = _native_converter(source_root, "prefix", source).transfer(initial_checked)
|
|
255
|
+
for values in (sft, dpo, prefix):
|
|
256
|
+
if not isinstance(values, list):
|
|
257
|
+
raise ExternalDependencyError("SmartSearch native converter returned a non-list")
|
|
258
|
+
for relative, digest in source["files"].items():
|
|
259
|
+
if hashlib.sha256((source_root / relative).read_bytes()).hexdigest() != digest:
|
|
260
|
+
raise ExternalDependencyError("SmartSearch preparation source changed during execution")
|
|
261
|
+
outputs = {"native-initial-scored.json": initial_checked,
|
|
262
|
+
"native-regenerated-scored.json": regenerated_checked,
|
|
263
|
+
"sft.json": sft, "dpo.json": dpo, "prefix.json": prefix}
|
|
264
|
+
for name, value in outputs.items():
|
|
265
|
+
save(name, value)
|
|
266
|
+
hashes = {name: hashlib.sha256((root / name).read_bytes()).hexdigest() for name in outputs}
|
|
267
|
+
manifest = {"schema": "agentinputlab.smartsearch.native-curriculum-data.v1",
|
|
268
|
+
"source": source, "split_audit": audit, "outputs": hashes,
|
|
269
|
+
"sft_count": len(sft), "dpo_count": len(dpo), "prefix_count": len(prefix),
|
|
270
|
+
"initial_rollout_count": len(initial), "regenerated_rollout_count": len(regenerated),
|
|
271
|
+
"input_hash": content_hash(raw_inputs), "rollout_provenance": rollout_provenance,
|
|
272
|
+
"model_calls_performed": 0, "neural_training_performed": False,
|
|
273
|
+
"native_selection_thresholds_changed": False, "empty_selection_is_not_training_success": True}
|
|
274
|
+
artifact_id = content_hash(manifest)
|
|
275
|
+
save("manifest.json", {**manifest, "artifact_id": artifact_id})
|
|
276
|
+
return SmartSearchCurriculumArtifact(
|
|
277
|
+
str(root), artifact_id, len(sft), len(dpo), len(prefix), content_hash(source),
|
|
278
|
+
content_hash(audit), hashes,
|
|
279
|
+
)
|
|
280
|
+
except Exception as exc:
|
|
281
|
+
save("failed.json", {"error_type": type(exc).__name__, "error": str(exc),
|
|
282
|
+
"model_calls_performed": 0, "neural_training_performed": False})
|
|
283
|
+
raise
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Execution contracts for the pinned native GRPO driver, not reward math.
|
|
2
|
+
|
|
3
|
+
The native manager omits ``reward_extra_info`` while its PPO driver indexes
|
|
4
|
+
that key and catches failures by invoking the manager again. Complete the
|
|
5
|
+
dictionary without another scoring pass, and latch failures across the whole
|
|
6
|
+
batch so a fallback cannot repeat already consumed helper calls.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from collections.abc import Mapping
|
|
11
|
+
|
|
12
|
+
from agentinputlab.contracts import ExternalDependencyError, ValidationError
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class NativeGRPORewardManagerContract:
|
|
16
|
+
"""Keep native rewards unchanged and prohibit automatic batch retries.
|
|
17
|
+
|
|
18
|
+
This adapter does not itself load a model or certify a GRPO fit. The
|
|
19
|
+
execution worker must construct its manager from the verified native
|
|
20
|
+
source, bind the metered scorer, and retain original per-item costs.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, native_manager):
|
|
24
|
+
if not callable(native_manager):
|
|
25
|
+
raise ValidationError("SmartSearch GRPO requires a callable native reward manager")
|
|
26
|
+
self.native_manager = native_manager
|
|
27
|
+
self.native_calls = 0
|
|
28
|
+
self._failed = False
|
|
29
|
+
|
|
30
|
+
def __call__(self, data, return_dict=False, curr_save_path=None):
|
|
31
|
+
if self._failed:
|
|
32
|
+
raise ExternalDependencyError("SmartSearch native reward batch failed; no automatic scoring retry")
|
|
33
|
+
if type(return_dict) is not bool:
|
|
34
|
+
raise ValidationError("SmartSearch reward dictionary flag must be a boolean")
|
|
35
|
+
try:
|
|
36
|
+
self.native_calls += 1
|
|
37
|
+
result = self.native_manager(data, return_dict=return_dict, curr_save_path=curr_save_path)
|
|
38
|
+
if not return_dict:
|
|
39
|
+
return result
|
|
40
|
+
if not isinstance(result, Mapping):
|
|
41
|
+
# The native manager's explicit cached-rm branch returns the
|
|
42
|
+
# exact cached tensor, even when return_dict=True.
|
|
43
|
+
batch = getattr(data, "batch", None)
|
|
44
|
+
cached = batch.get("rm_scores") if hasattr(batch, "get") else None
|
|
45
|
+
if cached is None or result is not cached:
|
|
46
|
+
raise ExternalDependencyError("SmartSearch native reward dictionary contract differs")
|
|
47
|
+
result = {"reward_tensor": result}
|
|
48
|
+
if "reward_tensor" not in result or result["reward_tensor"] is None:
|
|
49
|
+
raise ExternalDependencyError("SmartSearch native reward tensor is missing")
|
|
50
|
+
extras = result.get("reward_extra_info", {})
|
|
51
|
+
if not isinstance(extras, Mapping):
|
|
52
|
+
raise ExternalDependencyError("SmartSearch native reward extra-info mapping differs")
|
|
53
|
+
# Preserve the original tensor object and existing extra fields.
|
|
54
|
+
# No tensor arithmetic, rescaling, default positive or re-score.
|
|
55
|
+
return {**result, "reward_extra_info": extras}
|
|
56
|
+
except BaseException:
|
|
57
|
+
self._failed = True
|
|
58
|
+
raise
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"""Pinned native SmartSearch GRPO data/configuration, with explicit split roles."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import math
|
|
6
|
+
from collections.abc import Mapping, Sequence
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from urllib.parse import urlsplit
|
|
10
|
+
|
|
11
|
+
from agentinputlab.contracts import ExternalDependencyError, ValidationError
|
|
12
|
+
from agentinputlab.contracts.serialization import content_hash, to_jsonable
|
|
13
|
+
|
|
14
|
+
from .qrag import _file, _sha
|
|
15
|
+
from .smartsearch import SMARTSEARCH_TOOL_SCHEMA
|
|
16
|
+
from .smartsearch_curriculum import (
|
|
17
|
+
SmartSearchTrainingCase,
|
|
18
|
+
_question_hash,
|
|
19
|
+
validate_smartsearch_training_splits,
|
|
20
|
+
)
|
|
21
|
+
from .smartsearch_grpo_tools import SMARTSEARCH_GRPO_ENVIRONMENT
|
|
22
|
+
from .smartsearch_sampling import verify_smartsearch_sampling_source
|
|
23
|
+
|
|
24
|
+
GRPO_DATA_PROTOCOL = "agentinputlab.smartsearch.native_grpo_data.v1"
|
|
25
|
+
_SOURCE = {
|
|
26
|
+
"data/prepare_dataset.py": "abf1dc41c410e8716c02b8651c9ef3fb3bbba6d52b50ae86db8325ecf5154554",
|
|
27
|
+
"scripts/train/train.sh": "07903f49e46bf18a0d764b6e92c1430d0a651523751fee653dec112379c66d72",
|
|
28
|
+
"src/verl/trainer/main_ppo.py": "6eace6c898923fe2e25081f473801c9439a709eb02d1968944f1f2cd2602f258",
|
|
29
|
+
"src/verl/trainer/config/ppo_trainer.yaml": "8a239cda92c40d520df0344857b5f51d6550254c449d28841e1de3f5b3feb1d7",
|
|
30
|
+
"src/verl/utils/dataset/rl_dataset.py": "06a599f81f7288fdd183111b15207c37e0c32e2d9399c8e9289edba637bf5f26",
|
|
31
|
+
"src/verl/workers/rollout/vllm_rollout/generate_new_prompts.py": "bc1f7d2a16d599e7f180406c9cd356034f1bb5ce0e97b5fb09d6264a11511615",
|
|
32
|
+
"src/verl/workers/rollout/vllm_rollout/vllm_rollout_spmd.py": "064aa3d6682149620c5b55239379199130941dc05d6fc5ed13026987b2867453",
|
|
33
|
+
"src/verl/workers/reward_manager/re_call.py": "0b239aaa9ee0c21b693359569e3f091bc650d537d7cf2a63e478c8fb4d976a7b",
|
|
34
|
+
"src/verl/trainer/ppo/ray_trainer.py": "465e1b53dfa9f0bfcdb597957cef64ea18941e5e75a2af17a48c0ecfd00ab3e2",
|
|
35
|
+
"src/verl/workers/actor/dp_actor.py": "09923f0891e2ca913e1eb860bfa7e62537b10b1f4527b9647784f7063ba86a8d",
|
|
36
|
+
"src/verl/workers/fsdp_workers.py": "65aa287db53a3308d5b579f47cf557ab8333231e26625ed62bbb65ca90153833",
|
|
37
|
+
"src/verl/utils/checkpoint/fsdp_checkpoint_manager.py": "640556d9c0801602818fcfd52aa6d2d066b49bf30f30eb0a81c08efde2495f4a",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def verify_smartsearch_grpo_source(checkout):
|
|
42
|
+
root, binding = verify_smartsearch_sampling_source(checkout)
|
|
43
|
+
for name, expected in _SOURCE.items():
|
|
44
|
+
path = _file(root / name, "SmartSearch native GRPO source")
|
|
45
|
+
if not path.is_relative_to(root) or _sha(path) != expected:
|
|
46
|
+
raise ExternalDependencyError("SmartSearch native GRPO source/configuration changed")
|
|
47
|
+
return root, {**binding, "grpo_source": dict(_SOURCE)}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _save(root, name, value):
|
|
51
|
+
encoded = json.dumps(to_jsonable(value), ensure_ascii=False, sort_keys=True, allow_nan=False)
|
|
52
|
+
with (root / name).open("x", encoding="utf-8") as stream:
|
|
53
|
+
stream.write(encoded)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass(frozen=True, slots=True)
|
|
57
|
+
class SmartSearchGRPOExample:
|
|
58
|
+
case: SmartSearchTrainingCase
|
|
59
|
+
golden_answers: tuple[str, ...]
|
|
60
|
+
|
|
61
|
+
def __post_init__(self):
|
|
62
|
+
if not isinstance(self.case, SmartSearchTrainingCase) or self.case.split not in {"train", "validation"}:
|
|
63
|
+
raise ValidationError("SmartSearch GRPO examples must declare training/development case roles")
|
|
64
|
+
answers = self.golden_answers
|
|
65
|
+
if not isinstance(answers, (tuple, list)) or not answers or any(
|
|
66
|
+
not isinstance(value, str) or not value.strip() for value in answers
|
|
67
|
+
):
|
|
68
|
+
raise ValidationError("SmartSearch GRPO examples require nonempty native reference answers")
|
|
69
|
+
object.__setattr__(self, "golden_answers", tuple(answers))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass(frozen=True, slots=True)
|
|
73
|
+
class SmartSearchGRPODataArtifact:
|
|
74
|
+
root: Path
|
|
75
|
+
artifact_id: str
|
|
76
|
+
train_rows: int
|
|
77
|
+
validation_rows: int
|
|
78
|
+
|
|
79
|
+
@classmethod
|
|
80
|
+
def load(cls, root, *, max_rows=10000, max_file_bytes=64 * 1024 * 1024):
|
|
81
|
+
if any(type(n) is not int or n < 1 for n in (max_rows, max_file_bytes)):
|
|
82
|
+
raise ValidationError("SmartSearch GRPO artifact read limits must be positive integers")
|
|
83
|
+
folder = Path(root)
|
|
84
|
+
if folder.is_symlink() or not folder.is_dir():
|
|
85
|
+
raise ValidationError("SmartSearch GRPO data artifact must be a regular directory")
|
|
86
|
+
folder = folder.resolve()
|
|
87
|
+
record = json.loads(_file(folder / "manifest.json", "GRPO data manifest").read_text())
|
|
88
|
+
identity = record.pop("artifact_id", None)
|
|
89
|
+
if record.get("schema") != GRPO_DATA_PROTOCOL or identity != content_hash(record):
|
|
90
|
+
raise ValidationError("SmartSearch GRPO data artifact identity differs")
|
|
91
|
+
if set(record.get("outputs", {})) != {"train.parquet", "validation.parquet"}:
|
|
92
|
+
raise ValidationError("SmartSearch GRPO data artifact has an incomplete closure")
|
|
93
|
+
for name, digest in record["outputs"].items():
|
|
94
|
+
path = _file(folder / name, "GRPO native data")
|
|
95
|
+
if path.stat().st_size > max_file_bytes or _sha(path) != digest:
|
|
96
|
+
raise ValidationError("SmartSearch GRPO native data bytes changed")
|
|
97
|
+
for key in ("train_rows", "validation_rows"):
|
|
98
|
+
if type(record.get(key)) is not int or record[key] < 1:
|
|
99
|
+
raise ValidationError("SmartSearch GRPO data has an empty declared split")
|
|
100
|
+
try:
|
|
101
|
+
import pyarrow.parquet as pq
|
|
102
|
+
except ImportError as exc:
|
|
103
|
+
raise ExternalDependencyError("Install agentinputlab[benchmarks] to verify native GRPO data") from exc
|
|
104
|
+
for split in ("train", "validation"):
|
|
105
|
+
path = folder / f"{split}.parquet"
|
|
106
|
+
declared = record[split + "_rows"]
|
|
107
|
+
if pq.read_metadata(path).num_rows != declared or declared > max_rows:
|
|
108
|
+
raise ValidationError("SmartSearch GRPO parquet row count differs or exceeds its read limit")
|
|
109
|
+
rows = pq.read_table(path).to_pylist()
|
|
110
|
+
hashes = []
|
|
111
|
+
for row in rows:
|
|
112
|
+
if set(row) != {"data_source", "question", "ability", "reward_model", "extra_info"} or (
|
|
113
|
+
row["data_source"] != "re_call" or row["ability"] != "re_call"
|
|
114
|
+
) or not isinstance(row["question"], str) or not row["question"].strip():
|
|
115
|
+
raise ValidationError("SmartSearch GRPO native logical fields differ")
|
|
116
|
+
reward, extra = row["reward_model"], row["extra_info"]
|
|
117
|
+
if not isinstance(reward, dict) or set(reward) != {"style", "ground_truth"} or (
|
|
118
|
+
reward["style"] != "rule" or not isinstance(reward["ground_truth"], list)
|
|
119
|
+
or not reward["ground_truth"] or any(not isinstance(v, str) or not v.strip() for v in reward["ground_truth"])
|
|
120
|
+
) or not isinstance(extra, dict) or set(extra) != {"env", "func_schemas"} or (
|
|
121
|
+
extra["env"] != SMARTSEARCH_GRPO_ENVIRONMENT
|
|
122
|
+
or json.loads(extra["func_schemas"]) != to_jsonable(SMARTSEARCH_TOOL_SCHEMA)
|
|
123
|
+
):
|
|
124
|
+
raise ValidationError("SmartSearch GRPO reference/tool field contract differs")
|
|
125
|
+
hashes.append(_question_hash(row["question"]))
|
|
126
|
+
audit = record.get("split_audit", {}).get(split, {})
|
|
127
|
+
if hashes != audit.get("question_hashes") or len(set(hashes)) != declared:
|
|
128
|
+
raise ValidationError("SmartSearch GRPO native questions differ from their declared split")
|
|
129
|
+
if set(record["split_audit"]["train"]["question_hashes"]) & set(
|
|
130
|
+
record["split_audit"]["validation"]["question_hashes"]
|
|
131
|
+
):
|
|
132
|
+
raise ValidationError("SmartSearch GRPO data artifact splits overlap")
|
|
133
|
+
return cls(folder, identity, record["train_rows"], record["validation_rows"])
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def prepare_smartsearch_grpo_data(
|
|
137
|
+
*, checkout, output_root, train: Sequence[SmartSearchGRPOExample],
|
|
138
|
+
validation: Sequence[SmartSearchGRPOExample], data_provenance: Mapping,
|
|
139
|
+
test: Sequence[SmartSearchTrainingCase] = (), max_rows: int = 10000,
|
|
140
|
+
max_input_bytes: int = 64 * 1024 * 1024,
|
|
141
|
+
):
|
|
142
|
+
"""Write exact native logical rows without upstream's test-to-dev sampling.
|
|
143
|
+
|
|
144
|
+
Corpus/retrieval is a separate frozen input. References remain in reward_model
|
|
145
|
+
and never enter the question field. The environment is replaced with the
|
|
146
|
+
fixed non-executable retrieval identifier. No model is loaded or fit here.
|
|
147
|
+
"""
|
|
148
|
+
if any(type(n) is not int or n < 1 for n in (max_rows, max_input_bytes)) or (
|
|
149
|
+
not isinstance(data_provenance, Mapping) or not data_provenance
|
|
150
|
+
):
|
|
151
|
+
raise ValidationError("SmartSearch GRPO preparation needs explicit limits and provenance")
|
|
152
|
+
for rows in (train, validation):
|
|
153
|
+
if not isinstance(rows, (tuple, list)) or not rows or len(rows) > max_rows or any(
|
|
154
|
+
not isinstance(row, SmartSearchGRPOExample) for row in rows
|
|
155
|
+
):
|
|
156
|
+
raise ValidationError("SmartSearch GRPO preparation split exceeds its explicit row bound")
|
|
157
|
+
train, validation = tuple(train), tuple(validation)
|
|
158
|
+
data_provenance = to_jsonable(data_provenance)
|
|
159
|
+
audit = validate_smartsearch_training_splits([r.case for r in train], [r.case for r in validation], test)
|
|
160
|
+
encoded = json.dumps(to_jsonable({"train": train, "validation": validation,
|
|
161
|
+
"provenance": data_provenance}), allow_nan=False).encode()
|
|
162
|
+
if len(encoded) > max_input_bytes:
|
|
163
|
+
raise ValidationError("SmartSearch GRPO data inputs exceed the explicit byte bound")
|
|
164
|
+
source, binding = verify_smartsearch_grpo_source(checkout)
|
|
165
|
+
root = Path(output_root)
|
|
166
|
+
if root.is_symlink() or root.exists():
|
|
167
|
+
raise ValidationError("SmartSearch GRPO preparation must be create-only")
|
|
168
|
+
root = root.resolve(strict=False)
|
|
169
|
+
if root.is_relative_to(source) or source.is_relative_to(root):
|
|
170
|
+
raise ValidationError("SmartSearch GRPO preparation output must not overlap native source")
|
|
171
|
+
try:
|
|
172
|
+
import pyarrow as pa
|
|
173
|
+
import pyarrow.parquet as pq
|
|
174
|
+
except ImportError as exc:
|
|
175
|
+
raise ExternalDependencyError("Install agentinputlab[benchmarks] for native GRPO parquet data") from exc
|
|
176
|
+
root.mkdir(parents=True, exist_ok=False)
|
|
177
|
+
_save(root, "claim.json", {"source": binding, "split_audit": audit,
|
|
178
|
+
"inputs_sha256": content_hash({"train": train, "validation": validation}),
|
|
179
|
+
"data_provenance": data_provenance, "model_calls": 0, "optimizer_steps": 0})
|
|
180
|
+
try:
|
|
181
|
+
schema_text = json.dumps(to_jsonable(SMARTSEARCH_TOOL_SCHEMA), indent=4)
|
|
182
|
+
for name, rows in (("train", train), ("validation", validation)):
|
|
183
|
+
native_rows = [{"data_source": "re_call", "question": row.case.question,
|
|
184
|
+
"ability": "re_call", "reward_model": {"style": "rule", "ground_truth": list(row.golden_answers)},
|
|
185
|
+
"extra_info": {"env": SMARTSEARCH_GRPO_ENVIRONMENT, "func_schemas": schema_text}}
|
|
186
|
+
for row in rows]
|
|
187
|
+
pq.write_table(pa.Table.from_pylist(native_rows), root / f"{name}.parquet", compression="snappy")
|
|
188
|
+
if pq.read_table(root / f"{name}.parquet").to_pylist() != native_rows:
|
|
189
|
+
raise ExternalDependencyError("SmartSearch GRPO parquet roundtrip changed native rows")
|
|
190
|
+
manifest = {"schema": GRPO_DATA_PROTOCOL, "source": binding, "split_audit": audit,
|
|
191
|
+
"train_rows": len(train), "validation_rows": len(validation),
|
|
192
|
+
"outputs": {name: _sha(root / name) for name in ("train.parquet", "validation.parquet")},
|
|
193
|
+
"data_provenance": data_provenance, "model_calls": 0, "optimizer_steps": 0,
|
|
194
|
+
"native_logical_fields_unchanged": True, "fixed_environment_identifier_adapter": True,
|
|
195
|
+
"no_native_test_to_dev_downsampling": True}
|
|
196
|
+
_save(root, "manifest.json", {**manifest, "artifact_id": content_hash(manifest)})
|
|
197
|
+
return SmartSearchGRPODataArtifact.load(root, max_rows=max_rows, max_file_bytes=max_input_bytes * 2 + 1024**2)
|
|
198
|
+
except Exception as exc:
|
|
199
|
+
_save(root, "failed.json", {"error_type": type(exc).__name__, "error": str(exc),
|
|
200
|
+
"model_calls": 0, "optimizer_steps": 0})
|
|
201
|
+
raise
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@dataclass(frozen=True, slots=True)
|
|
205
|
+
class SmartSearchGRPOControls:
|
|
206
|
+
train_batch_size: int = 256
|
|
207
|
+
ppo_mini_batch_size: int = 64
|
|
208
|
+
rollout_samples: int = 8
|
|
209
|
+
total_epochs: int = 2
|
|
210
|
+
gpu_processes: int = 4
|
|
211
|
+
gpu_memory_utilization: float = .8
|
|
212
|
+
max_optimizer_steps: int = 10000
|
|
213
|
+
seed: int = 17
|
|
214
|
+
bounded_training_variant: bool = False
|
|
215
|
+
|
|
216
|
+
def __post_init__(self):
|
|
217
|
+
names = ("train_batch_size", "ppo_mini_batch_size", "rollout_samples", "total_epochs",
|
|
218
|
+
"gpu_processes", "max_optimizer_steps")
|
|
219
|
+
if any(type(getattr(self, n)) is not int or getattr(self, n) < 1 for n in names) or (
|
|
220
|
+
type(self.seed) is not int or self.seed < 0 or type(self.bounded_training_variant) is not bool
|
|
221
|
+
):
|
|
222
|
+
raise ValidationError("SmartSearch GRPO controls require explicit positive integer bounds")
|
|
223
|
+
if not 1 <= self.gpu_processes <= 4 or self.rollout_samples < 2 or (
|
|
224
|
+
self.ppo_mini_batch_size > self.train_batch_size or self.train_batch_size % self.ppo_mini_batch_size
|
|
225
|
+
) or (self.train_batch_size * self.rollout_samples) % self.gpu_processes or (
|
|
226
|
+
(self.ppo_mini_batch_size * self.rollout_samples) % self.gpu_processes
|
|
227
|
+
):
|
|
228
|
+
raise ValidationError("SmartSearch GRPO native batch/sample/GPU divisibility differs")
|
|
229
|
+
utilization = self.gpu_memory_utilization
|
|
230
|
+
if isinstance(utilization, bool) or not isinstance(utilization, (float, int)) or (
|
|
231
|
+
not math.isfinite(utilization) or not 0 < utilization <= .95
|
|
232
|
+
):
|
|
233
|
+
raise ValidationError("SmartSearch GRPO GPU cache allowance is invalid")
|
|
234
|
+
if (self.train_batch_size, self.ppo_mini_batch_size, self.rollout_samples, self.total_epochs) != (
|
|
235
|
+
256, 64, 8, 2
|
|
236
|
+
) and not self.bounded_training_variant:
|
|
237
|
+
raise ValidationError("Changing native GRPO batch/n/epochs requires an explicit labeled training variant")
|
|
238
|
+
|
|
239
|
+
def planned_steps(self, train_rows):
|
|
240
|
+
"""Native dataloader/global steps, not the number of actor updates."""
|
|
241
|
+
if type(train_rows) is not int or train_rows < self.train_batch_size:
|
|
242
|
+
raise ValidationError("SmartSearch native drop_last would produce an empty GRPO training loader")
|
|
243
|
+
steps = train_rows // self.train_batch_size * self.total_epochs
|
|
244
|
+
if steps > self.max_optimizer_steps:
|
|
245
|
+
raise ValidationError("SmartSearch native optimizer plan exceeds the declared cap; it is not truncated")
|
|
246
|
+
return steps
|
|
247
|
+
|
|
248
|
+
def planned_actor_optimizer_steps(self, train_rows, *, ppo_epochs):
|
|
249
|
+
"""Synchronized actor updates per rank, before any neural work.
|
|
250
|
+
|
|
251
|
+
Native FSDP normalizes the PPO minibatch by rollout_n/world_size;
|
|
252
|
+
those factors cancel when dividing each rank's local training batch.
|
|
253
|
+
Do not sum synchronized rank counters into extra distributed updates.
|
|
254
|
+
The executor must still meter actual optimizer calls on every rank.
|
|
255
|
+
"""
|
|
256
|
+
if type(ppo_epochs) is not int or ppo_epochs < 1:
|
|
257
|
+
raise ValidationError("SmartSearch native PPO epochs must be a positive integer")
|
|
258
|
+
global_steps = self.planned_steps(train_rows)
|
|
259
|
+
steps = global_steps * (self.train_batch_size // self.ppo_mini_batch_size) * ppo_epochs
|
|
260
|
+
if steps > self.max_optimizer_steps:
|
|
261
|
+
raise ValidationError("SmartSearch native actor optimizer plan exceeds the declared cap; it is not truncated")
|
|
262
|
+
return steps
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _native_grpo_config(source, *, model, data, output_root, controls, sandbox_url, reward_module):
|
|
266
|
+
try:
|
|
267
|
+
import yaml
|
|
268
|
+
except ImportError as exc:
|
|
269
|
+
raise ExternalDependencyError("Install agentinputlab[yaml] to build native GRPO config") from exc
|
|
270
|
+
if not isinstance(sandbox_url, str):
|
|
271
|
+
raise ValidationError("SmartSearch GRPO fixed tool URL must be operator-owned loopback HTTP")
|
|
272
|
+
try:
|
|
273
|
+
url = urlsplit(sandbox_url)
|
|
274
|
+
port = url.port
|
|
275
|
+
except ValueError as exc:
|
|
276
|
+
raise ValidationError("SmartSearch GRPO fixed tool URL is malformed") from exc
|
|
277
|
+
if url.scheme != "http" or url.hostname != "127.0.0.1" or not port or (
|
|
278
|
+
url.username or url.password or url.query or url.fragment
|
|
279
|
+
):
|
|
280
|
+
raise ValidationError("SmartSearch GRPO fixed tool URL must be operator-owned loopback HTTP")
|
|
281
|
+
controls.planned_steps(data.train_rows)
|
|
282
|
+
config = yaml.safe_load((Path(source) / "src/verl/trainer/config/ppo_trainer.yaml").read_text())
|
|
283
|
+
config["data"].update(train_files=str(data.root / "train.parquet"), val_files=str(data.root / "validation.parquet"),
|
|
284
|
+
prompt_key="question", train_batch_size=controls.train_batch_size, max_prompt_length=8192,
|
|
285
|
+
max_response_length=8192, use_re_call=True, prompt_template_name="re_call_template_sys",
|
|
286
|
+
search_url=sandbox_url, filter_overlong_prompts=True, trust_remote_code=False, seed=controls.seed,
|
|
287
|
+
cache_dir=str(Path(output_root) / "data-cache"))
|
|
288
|
+
policy = config["actor_rollout_ref"]
|
|
289
|
+
policy["model"].update(path=str(model), enable_gradient_checkpointing=True, use_remove_padding=True)
|
|
290
|
+
actor = policy["actor"]
|
|
291
|
+
controls.planned_actor_optimizer_steps(data.train_rows, ppo_epochs=actor["ppo_epochs"])
|
|
292
|
+
actor["optim"]["lr"] = 1e-6
|
|
293
|
+
actor.update(ppo_mini_batch_size=controls.ppo_mini_batch_size, use_dynamic_bsz=True,
|
|
294
|
+
ppo_max_token_len_per_gpu=32768, use_kl_loss=True, kl_loss_coef=.001, kl_loss_type="low_var_kl")
|
|
295
|
+
actor["fsdp_config"].update(param_offload=False, optimizer_offload=False)
|
|
296
|
+
# Preserve native shards plus its HF config/tokenizer metadata. The native
|
|
297
|
+
# checkpoint manager does NOT export HF weights; the live actor observer
|
|
298
|
+
# separately gathers the actual trained state into safe HF tensors.
|
|
299
|
+
actor["checkpoint"]["contents"] = [*actor["checkpoint"]["contents"], "hf_model"]
|
|
300
|
+
policy["rollout"].update(log_prob_max_token_len_per_gpu=65536, tensor_model_parallel_size=1,
|
|
301
|
+
name="vllm_with_tool", gpu_memory_utilization=controls.gpu_memory_utilization,
|
|
302
|
+
n=controls.rollout_samples, max_turns=5, sandbox_url=sandbox_url, enforce_eager=False, free_cache_engine=False)
|
|
303
|
+
policy["ref"]["log_prob_max_token_len_per_gpu"] = 65536
|
|
304
|
+
policy["ref"]["fsdp_config"]["param_offload"] = True
|
|
305
|
+
config["algorithm"].update(adv_estimator="grpo")
|
|
306
|
+
config["algorithm"]["kl_ctrl"]["kl_coef"] = .001
|
|
307
|
+
config["reward_model"]["reward_manager"] = "re_call"
|
|
308
|
+
config["custom_reward_function"].update(path=str(reward_module), name="compute_score")
|
|
309
|
+
config["trainer"].update(critic_warmup=0, logger=["console"], project_name="agentinputlab-smartsearch",
|
|
310
|
+
experiment_name="native-grpo", n_gpus_per_node=controls.gpu_processes, nnodes=1,
|
|
311
|
+
save_freq=10, test_freq=10, total_epochs=controls.total_epochs, resume_mode="disable",
|
|
312
|
+
resume_from_path=None, default_hdfs_dir=None, default_local_dir=str(output_root),
|
|
313
|
+
rollout_save_path=str(Path(output_root) / "rollouts"))
|
|
314
|
+
return config
|