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,285 @@
|
|
|
1
|
+
"""Minimal intervention runner preserving paired state and typed failures."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
|
|
9
|
+
from agentinputlab.contracts.enums import PatchOp, StrEnum
|
|
10
|
+
from agentinputlab.contracts.errors import (
|
|
11
|
+
AlgorithmOutputError,
|
|
12
|
+
BudgetExceededError,
|
|
13
|
+
IntentViolationError,
|
|
14
|
+
ValidationError,
|
|
15
|
+
)
|
|
16
|
+
from agentinputlab.contracts.intent import IntentCheck, check_intent_contract
|
|
17
|
+
from agentinputlab.contracts.lifecycle import CompositeResult, Intervention, InterventionContext
|
|
18
|
+
from agentinputlab.contracts.patch import InputPatch
|
|
19
|
+
from agentinputlab.contracts.state import FrozenAgentState
|
|
20
|
+
from agentinputlab.observability import (
|
|
21
|
+
BudgetLedger,
|
|
22
|
+
EventKind,
|
|
23
|
+
ObservedRunStatus,
|
|
24
|
+
PricingCatalog,
|
|
25
|
+
ResourceUsage,
|
|
26
|
+
RunMonitor,
|
|
27
|
+
instrument_context,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
from .runtime_guard import runtime_dependency_nodes
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class RunStatus(StrEnum):
|
|
34
|
+
SUCCESS = "success"
|
|
35
|
+
NO_OP = "no_op"
|
|
36
|
+
FALLBACK = "fallback"
|
|
37
|
+
BUDGET_EXHAUSTED = "budget_exhausted"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True, slots=True)
|
|
41
|
+
class RunRecord:
|
|
42
|
+
release_id: str
|
|
43
|
+
input_state_hash: str
|
|
44
|
+
output_state_hash: str
|
|
45
|
+
patch: InputPatch
|
|
46
|
+
status: RunStatus
|
|
47
|
+
monitor_run_id: str = ""
|
|
48
|
+
duration_ms: float | None = None
|
|
49
|
+
usage: ResourceUsage = field(default_factory=ResourceUsage)
|
|
50
|
+
intent_check: IntentCheck | None = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class InterventionRunner:
|
|
54
|
+
"""Run a profile without swallowing unavailable/error conditions."""
|
|
55
|
+
|
|
56
|
+
def __init__(self, *, monitor: RunMonitor | None = None) -> None:
|
|
57
|
+
self.monitor = monitor or RunMonitor()
|
|
58
|
+
|
|
59
|
+
def run(
|
|
60
|
+
self,
|
|
61
|
+
intervention: Intervention,
|
|
62
|
+
state: FrozenAgentState,
|
|
63
|
+
context: InterventionContext,
|
|
64
|
+
) -> RunRecord:
|
|
65
|
+
_reject_hidden_runtime_dependencies(intervention)
|
|
66
|
+
monitor = context.monitor or self.monitor
|
|
67
|
+
if not isinstance(monitor, RunMonitor):
|
|
68
|
+
raise TypeError("context.monitor must be a RunMonitor")
|
|
69
|
+
intent_check: IntentCheck | None = None
|
|
70
|
+
with monitor.run_scope(
|
|
71
|
+
release_id=intervention.release_id,
|
|
72
|
+
state_hash=state.state_hash,
|
|
73
|
+
tags={"method_id": intervention.method_id, "family": intervention.family.value},
|
|
74
|
+
) as run_id:
|
|
75
|
+
pricing = context.pricing_catalog
|
|
76
|
+
if pricing is not None and not isinstance(pricing, PricingCatalog):
|
|
77
|
+
raise TypeError("context.pricing_catalog must be a PricingCatalog")
|
|
78
|
+
runtime_context = instrument_context(
|
|
79
|
+
context,
|
|
80
|
+
state,
|
|
81
|
+
monitor,
|
|
82
|
+
run_id=run_id,
|
|
83
|
+
pricing=pricing,
|
|
84
|
+
)
|
|
85
|
+
ledger = runtime_context.budget_ledger
|
|
86
|
+
if not isinstance(ledger, BudgetLedger): # pragma: no cover - helper invariant
|
|
87
|
+
raise TypeError("instrumented context did not produce a BudgetLedger")
|
|
88
|
+
monitor.emit(EventKind.STAGE_STARTED, component="intervention")
|
|
89
|
+
try:
|
|
90
|
+
patch = intervention.propose(state, runtime_context)
|
|
91
|
+
if not isinstance(patch, InputPatch):
|
|
92
|
+
raise AlgorithmOutputError(
|
|
93
|
+
f"intervention must return an InputPatch; got {type(patch).__name__}"
|
|
94
|
+
)
|
|
95
|
+
if patch.method_id != intervention.method_id:
|
|
96
|
+
raise AlgorithmOutputError("intervention returned a patch for another method")
|
|
97
|
+
if patch.release_id != intervention.release_id:
|
|
98
|
+
raise AlgorithmOutputError("intervention returned a patch for another release")
|
|
99
|
+
self._reconcile_trace_usage(patch, ledger, monitor)
|
|
100
|
+
output = patch.apply(state)
|
|
101
|
+
if runtime_context.intent_contract is not None:
|
|
102
|
+
intent_check = check_intent_contract(
|
|
103
|
+
runtime_context.intent_contract,
|
|
104
|
+
state,
|
|
105
|
+
patch,
|
|
106
|
+
output,
|
|
107
|
+
)
|
|
108
|
+
monitor.emit(
|
|
109
|
+
EventKind.INTENT_CHECKED,
|
|
110
|
+
component="intent_gate",
|
|
111
|
+
payload={
|
|
112
|
+
"preserved": intent_check.preserved,
|
|
113
|
+
"missing_entities": intent_check.missing_entities,
|
|
114
|
+
"missing_constraints": intent_check.missing_constraints,
|
|
115
|
+
"introduced_assumptions": intent_check.introduced_assumptions,
|
|
116
|
+
},
|
|
117
|
+
)
|
|
118
|
+
if runtime_context.strict_intent and not intent_check.preserved:
|
|
119
|
+
raise IntentViolationError("observable intent contract was not preserved")
|
|
120
|
+
ledger.require_within_budget()
|
|
121
|
+
except BudgetExceededError as exc:
|
|
122
|
+
monitor.record_failure(
|
|
123
|
+
exc,
|
|
124
|
+
category="budget_exhausted",
|
|
125
|
+
stage="intervention",
|
|
126
|
+
)
|
|
127
|
+
monitor.finish_run(ObservedRunStatus.BUDGET_EXHAUSTED, run_id=run_id)
|
|
128
|
+
raise
|
|
129
|
+
except IntentViolationError as exc:
|
|
130
|
+
monitor.record_failure(
|
|
131
|
+
exc,
|
|
132
|
+
category="intent_drift",
|
|
133
|
+
stage="intent_gate",
|
|
134
|
+
)
|
|
135
|
+
monitor.finish_run(ObservedRunStatus.INTENT_REJECTED, run_id=run_id)
|
|
136
|
+
raise
|
|
137
|
+
|
|
138
|
+
is_noop = all(operation.op is PatchOp.NO_OP for operation in patch.operations)
|
|
139
|
+
if patch.metadata.get("fallback"):
|
|
140
|
+
status = RunStatus.FALLBACK
|
|
141
|
+
elif patch.metadata.get("budget_exhausted"):
|
|
142
|
+
status = RunStatus.BUDGET_EXHAUSTED
|
|
143
|
+
elif is_noop:
|
|
144
|
+
status = RunStatus.NO_OP
|
|
145
|
+
else:
|
|
146
|
+
status = RunStatus.SUCCESS
|
|
147
|
+
monitor.emit(
|
|
148
|
+
EventKind.STAGE_FINISHED,
|
|
149
|
+
component="intervention",
|
|
150
|
+
payload={"status": status.value, "patch_hash": patch.patch_hash},
|
|
151
|
+
)
|
|
152
|
+
observed_status = ObservedRunStatus.SUCCEEDED
|
|
153
|
+
if status is RunStatus.BUDGET_EXHAUSTED:
|
|
154
|
+
error = BudgetExceededError("intervention reported budget exhaustion")
|
|
155
|
+
monitor.record_failure(
|
|
156
|
+
error,
|
|
157
|
+
category="budget_exhausted",
|
|
158
|
+
stage="intervention",
|
|
159
|
+
)
|
|
160
|
+
observed_status = ObservedRunStatus.BUDGET_EXHAUSTED
|
|
161
|
+
snapshot = monitor.finish_run(
|
|
162
|
+
observed_status,
|
|
163
|
+
run_id=run_id,
|
|
164
|
+
payload={"outcome": status.value},
|
|
165
|
+
)
|
|
166
|
+
return RunRecord(
|
|
167
|
+
release_id=intervention.release_id,
|
|
168
|
+
input_state_hash=state.state_hash,
|
|
169
|
+
output_state_hash=output.state_hash,
|
|
170
|
+
patch=patch,
|
|
171
|
+
status=status,
|
|
172
|
+
monitor_run_id=run_id,
|
|
173
|
+
duration_ms=snapshot.duration_ms,
|
|
174
|
+
usage=snapshot.usage,
|
|
175
|
+
intent_check=intent_check,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
@staticmethod
|
|
179
|
+
def _reconcile_trace_usage(
|
|
180
|
+
patch: InputPatch | CompositeResult,
|
|
181
|
+
ledger: BudgetLedger,
|
|
182
|
+
monitor: RunMonitor,
|
|
183
|
+
) -> None:
|
|
184
|
+
"""Charge counters emitted by uninstrumented upstream workers once."""
|
|
185
|
+
|
|
186
|
+
counters = patch.trace.counters
|
|
187
|
+
current = ledger.usage
|
|
188
|
+
declared = ResourceUsage(
|
|
189
|
+
model_calls=_trace_integer_counter(counters, "model_calls"),
|
|
190
|
+
retrieval_calls=_trace_integer_counter(counters, "retrieval_calls"),
|
|
191
|
+
tool_calls=_trace_integer_counter(counters, "tool_calls"),
|
|
192
|
+
embedding_calls=_trace_integer_counter(counters, "embedding_calls"),
|
|
193
|
+
unpriced_model_calls=_trace_integer_counter(counters, "unpriced_model_calls"),
|
|
194
|
+
input_tokens=_trace_integer_counter(counters, "input_tokens"),
|
|
195
|
+
output_tokens=_trace_integer_counter(counters, "output_tokens"),
|
|
196
|
+
cpu_seconds=_trace_float_counter(counters, "cpu_seconds"),
|
|
197
|
+
accelerator_seconds=_trace_float_counter(counters, "accelerator_seconds"),
|
|
198
|
+
cost_usd=_trace_float_counter(counters, "cost_usd"),
|
|
199
|
+
compute_cost_usd=_trace_float_counter(counters, "compute_cost_usd"),
|
|
200
|
+
)
|
|
201
|
+
delta = ResourceUsage(
|
|
202
|
+
model_calls=max(0, declared.model_calls - current.model_calls),
|
|
203
|
+
retrieval_calls=max(0, declared.retrieval_calls - current.retrieval_calls),
|
|
204
|
+
tool_calls=max(0, declared.tool_calls - current.tool_calls),
|
|
205
|
+
embedding_calls=max(0, declared.embedding_calls - current.embedding_calls),
|
|
206
|
+
unpriced_model_calls=max(
|
|
207
|
+
0,
|
|
208
|
+
declared.unpriced_model_calls - current.unpriced_model_calls,
|
|
209
|
+
),
|
|
210
|
+
input_tokens=max(0, declared.input_tokens - current.input_tokens),
|
|
211
|
+
output_tokens=max(0, declared.output_tokens - current.output_tokens),
|
|
212
|
+
cpu_seconds=max(0.0, declared.cpu_seconds - current.cpu_seconds),
|
|
213
|
+
accelerator_seconds=max(
|
|
214
|
+
0.0,
|
|
215
|
+
declared.accelerator_seconds - current.accelerator_seconds,
|
|
216
|
+
),
|
|
217
|
+
cost_usd=max(0.0, declared.cost_usd - current.cost_usd),
|
|
218
|
+
compute_cost_usd=max(
|
|
219
|
+
0.0,
|
|
220
|
+
declared.compute_cost_usd - current.compute_cost_usd,
|
|
221
|
+
),
|
|
222
|
+
)
|
|
223
|
+
if delta != ResourceUsage():
|
|
224
|
+
try:
|
|
225
|
+
ledger.charge_actual(delta)
|
|
226
|
+
except BudgetExceededError:
|
|
227
|
+
monitor.record_usage(delta, component="upstream_trace")
|
|
228
|
+
monitor.emit(EventKind.BUDGET_EXCEEDED, component="upstream_trace")
|
|
229
|
+
raise
|
|
230
|
+
monitor.record_usage(delta, component="upstream_trace")
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _trace_integer_counter(counters: Mapping[str, object], name: str) -> int:
|
|
234
|
+
value = counters.get(name, 0)
|
|
235
|
+
if isinstance(value, bool) or not isinstance(value, int) or value < 0:
|
|
236
|
+
raise ValidationError(
|
|
237
|
+
f"trace counter {name!r} must be a non-negative integer; got {value!r}"
|
|
238
|
+
)
|
|
239
|
+
return value
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _trace_float_counter(counters: Mapping[str, object], name: str) -> float:
|
|
243
|
+
value = counters.get(name, 0.0)
|
|
244
|
+
if (
|
|
245
|
+
isinstance(value, bool)
|
|
246
|
+
or not isinstance(value, (int, float))
|
|
247
|
+
or value < 0
|
|
248
|
+
or not math.isfinite(value)
|
|
249
|
+
):
|
|
250
|
+
raise ValidationError(
|
|
251
|
+
f"trace counter {name!r} must be finite and non-negative; got {value!r}"
|
|
252
|
+
)
|
|
253
|
+
return float(value)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _reject_hidden_runtime_dependencies(intervention: Intervention) -> None:
|
|
257
|
+
"""Keep executable dependencies on the context, independent of field names.
|
|
258
|
+
|
|
259
|
+
Upstream adapters may call an LLM field ``generator`` or nest a backend in a
|
|
260
|
+
small configuration holder. Looking only for attributes literally named
|
|
261
|
+
``backend`` would let those calls bypass monitoring, budgets, and balance
|
|
262
|
+
fingerprints. This bounded walk inspects the intervention's declared
|
|
263
|
+
state and data containers, but never descends into arbitrary dependency
|
|
264
|
+
implementations.
|
|
265
|
+
"""
|
|
266
|
+
|
|
267
|
+
hidden = _hidden_runtime_dependency_paths(intervention)
|
|
268
|
+
if hidden:
|
|
269
|
+
names = ", ".join(hidden)
|
|
270
|
+
raise ValidationError(
|
|
271
|
+
"runtime dependencies must be injected through InterventionContext "
|
|
272
|
+
f"for monitoring and balance audit; hidden on intervention: {names}"
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _hidden_runtime_dependency_paths(intervention: Intervention) -> list[str]:
|
|
277
|
+
return sorted(
|
|
278
|
+
{
|
|
279
|
+
node.path
|
|
280
|
+
for node in runtime_dependency_nodes(
|
|
281
|
+
intervention,
|
|
282
|
+
root_path="intervention",
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
)
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"""Bounded object-graph inspection for executable runtime dependencies."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from dataclasses import dataclass, fields, is_dataclass
|
|
7
|
+
from functools import partial
|
|
8
|
+
from types import BuiltinFunctionType, FunctionType, MethodType, ModuleType
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from agentinputlab.backends.llm import LLMBackend
|
|
12
|
+
from agentinputlab.backends.retrieval import Retriever
|
|
13
|
+
from agentinputlab.backends.vector import DenseEmbedder, VectorSearcher
|
|
14
|
+
from agentinputlab.connectors.tools import ToolConnector
|
|
15
|
+
from agentinputlab.contracts.errors import ValidationError
|
|
16
|
+
|
|
17
|
+
RUNTIME_DEPENDENCY_TYPES = (
|
|
18
|
+
LLMBackend,
|
|
19
|
+
DenseEmbedder,
|
|
20
|
+
Retriever,
|
|
21
|
+
VectorSearcher,
|
|
22
|
+
ToolConnector,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
_EXTERNAL_EXECUTOR_METHODS = ("call", "invoke", "reformulate", "run")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True, slots=True)
|
|
29
|
+
class ObjectGraphNode:
|
|
30
|
+
path: str
|
|
31
|
+
value: object
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def inspect_object_graph(
|
|
35
|
+
root: object,
|
|
36
|
+
*,
|
|
37
|
+
root_path: str,
|
|
38
|
+
terminal_types: tuple[type[Any], ...] = (),
|
|
39
|
+
traverse_runtime_delegates: bool = False,
|
|
40
|
+
max_depth: int = 8,
|
|
41
|
+
max_nodes: int = 4096,
|
|
42
|
+
) -> tuple[ObjectGraphNode, ...]:
|
|
43
|
+
"""Return a cycle-safe snapshot of declared object state and callable captures.
|
|
44
|
+
|
|
45
|
+
Mapping keys, bound-method owners, function defaults/closures/referenced
|
|
46
|
+
globals, partial arguments, dataclass fields, ``__dict__``, and ``__slots__``
|
|
47
|
+
are included. The walk never executes user callables. Hitting a bound is
|
|
48
|
+
an error rather than a silent partial audit.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
nodes: list[ObjectGraphNode] = []
|
|
52
|
+
visited: set[int] = set()
|
|
53
|
+
|
|
54
|
+
def walk_function_captures(
|
|
55
|
+
function: FunctionType,
|
|
56
|
+
path: str,
|
|
57
|
+
*,
|
|
58
|
+
depth: int,
|
|
59
|
+
include_globals: bool,
|
|
60
|
+
) -> None:
|
|
61
|
+
walk(function.__defaults__, f"{path}.__defaults__", depth=depth + 1)
|
|
62
|
+
walk(function.__kwdefaults__, f"{path}.__kwdefaults__", depth=depth + 1)
|
|
63
|
+
for index, cell in enumerate(function.__closure__ or ()):
|
|
64
|
+
try:
|
|
65
|
+
captured = cell.cell_contents
|
|
66
|
+
except ValueError: # empty closure cell
|
|
67
|
+
continue
|
|
68
|
+
walk(captured, f"{path}.__closure__[{index}]", depth=depth + 1)
|
|
69
|
+
if include_globals:
|
|
70
|
+
for name in function.__code__.co_names:
|
|
71
|
+
if name in function.__globals__:
|
|
72
|
+
walk(
|
|
73
|
+
function.__globals__[name],
|
|
74
|
+
f"{path}.__globals__[{name}]",
|
|
75
|
+
depth=depth + 1,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def walk(value: object, path: str, *, depth: int) -> None:
|
|
79
|
+
if value is None or isinstance(value, (str, bytes, int, float, bool, type, ModuleType)):
|
|
80
|
+
return
|
|
81
|
+
if depth > max_depth:
|
|
82
|
+
raise ValidationError(
|
|
83
|
+
f"runtime-dependency inspection exceeded depth {max_depth} at {path}"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
identity = id(value)
|
|
87
|
+
if identity in visited:
|
|
88
|
+
return
|
|
89
|
+
visited.add(identity)
|
|
90
|
+
nodes.append(ObjectGraphNode(path, value))
|
|
91
|
+
if len(nodes) > max_nodes:
|
|
92
|
+
raise ValidationError(f"runtime-dependency inspection exceeded {max_nodes} objects")
|
|
93
|
+
if terminal_types and isinstance(value, terminal_types):
|
|
94
|
+
return
|
|
95
|
+
# An executable dependency is normally an auditable boundary: callers
|
|
96
|
+
# bind its public fingerprint and execution instance, while its private
|
|
97
|
+
# model graph (for example a SentenceTransformer/PyTorch module tree)
|
|
98
|
+
# is not part of hidden-dependency discovery. Balance checks may opt
|
|
99
|
+
# into following only direct runtime delegates and ledgers so a proxy
|
|
100
|
+
# cannot conceal a shared executable object without opening the full
|
|
101
|
+
# model graph.
|
|
102
|
+
if is_runtime_dependency(value):
|
|
103
|
+
if traverse_runtime_delegates:
|
|
104
|
+
for name, item in _instance_state_items(value):
|
|
105
|
+
if is_runtime_dependency(item) or (
|
|
106
|
+
terminal_types and isinstance(item, terminal_types)
|
|
107
|
+
):
|
|
108
|
+
walk(item, f"{path}.{name}", depth=depth + 1)
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
if isinstance(value, Mapping):
|
|
112
|
+
for index, (key, item) in enumerate(value.items()):
|
|
113
|
+
walk(key, f"{path}.key[{index}]", depth=depth + 1)
|
|
114
|
+
walk(item, f"{path}.value[{index}]", depth=depth + 1)
|
|
115
|
+
return
|
|
116
|
+
if isinstance(value, (tuple, list, set, frozenset)):
|
|
117
|
+
for index, item in enumerate(value):
|
|
118
|
+
walk(item, f"{path}[{index}]", depth=depth + 1)
|
|
119
|
+
return
|
|
120
|
+
if isinstance(value, partial):
|
|
121
|
+
walk(value.func, f"{path}.func", depth=depth + 1)
|
|
122
|
+
walk(value.args, f"{path}.args", depth=depth + 1)
|
|
123
|
+
walk(value.keywords, f"{path}.keywords", depth=depth + 1)
|
|
124
|
+
return
|
|
125
|
+
if isinstance(value, MethodType):
|
|
126
|
+
walk(value.__self__, f"{path}.__self__", depth=depth + 1)
|
|
127
|
+
walk(value.__func__, f"{path}.__func__", depth=depth + 1)
|
|
128
|
+
return
|
|
129
|
+
if isinstance(value, FunctionType):
|
|
130
|
+
walk_function_captures(value, path, depth=depth, include_globals=True)
|
|
131
|
+
return
|
|
132
|
+
if isinstance(value, BuiltinFunctionType):
|
|
133
|
+
owner = getattr(value, "__self__", None)
|
|
134
|
+
if owner is not None:
|
|
135
|
+
walk(owner, f"{path}.__self__", depth=depth + 1)
|
|
136
|
+
return
|
|
137
|
+
if is_dataclass(value) and not isinstance(value, type):
|
|
138
|
+
for declared in fields(value):
|
|
139
|
+
walk(
|
|
140
|
+
getattr(value, declared.name),
|
|
141
|
+
f"{path}.{declared.name}",
|
|
142
|
+
depth=depth + 1,
|
|
143
|
+
)
|
|
144
|
+
else:
|
|
145
|
+
attributes = getattr(value, "__dict__", {})
|
|
146
|
+
if isinstance(attributes, Mapping):
|
|
147
|
+
for name, item in attributes.items():
|
|
148
|
+
walk(item, f"{path}.{name}", depth=depth + 1)
|
|
149
|
+
for owner in type(value).__mro__:
|
|
150
|
+
declared_slots = owner.__dict__.get("__slots__", ())
|
|
151
|
+
if isinstance(declared_slots, str):
|
|
152
|
+
declared_slots = (declared_slots,)
|
|
153
|
+
for name in declared_slots:
|
|
154
|
+
if name in {"__dict__", "__weakref__"} or not hasattr(value, name):
|
|
155
|
+
continue
|
|
156
|
+
walk(getattr(value, name), f"{path}.{name}", depth=depth + 1)
|
|
157
|
+
ignored_class_names = {
|
|
158
|
+
"__annotations__",
|
|
159
|
+
"__dict__",
|
|
160
|
+
"__doc__",
|
|
161
|
+
"__module__",
|
|
162
|
+
"__slots__",
|
|
163
|
+
"__weakref__",
|
|
164
|
+
}
|
|
165
|
+
for owner in type(value).__mro__:
|
|
166
|
+
for name, declared in owner.__dict__.items():
|
|
167
|
+
if name in ignored_class_names or (name.startswith("__") and name.endswith("__")):
|
|
168
|
+
continue
|
|
169
|
+
function: FunctionType | None = None
|
|
170
|
+
if isinstance(declared, (classmethod, staticmethod)):
|
|
171
|
+
unwrapped = declared.__func__
|
|
172
|
+
if isinstance(unwrapped, FunctionType):
|
|
173
|
+
function = unwrapped
|
|
174
|
+
elif isinstance(declared, FunctionType):
|
|
175
|
+
function = declared
|
|
176
|
+
if function is not None:
|
|
177
|
+
walk_function_captures(
|
|
178
|
+
function,
|
|
179
|
+
f"{path}.__class__.{name}",
|
|
180
|
+
depth=depth + 1,
|
|
181
|
+
include_globals=False,
|
|
182
|
+
)
|
|
183
|
+
continue
|
|
184
|
+
if isinstance(declared, property):
|
|
185
|
+
for accessor_name, accessor in (
|
|
186
|
+
("fget", declared.fget),
|
|
187
|
+
("fset", declared.fset),
|
|
188
|
+
("fdel", declared.fdel),
|
|
189
|
+
):
|
|
190
|
+
if isinstance(accessor, FunctionType):
|
|
191
|
+
walk_function_captures(
|
|
192
|
+
accessor,
|
|
193
|
+
f"{path}.__class__.{name}.{accessor_name}",
|
|
194
|
+
depth=depth + 1,
|
|
195
|
+
include_globals=False,
|
|
196
|
+
)
|
|
197
|
+
continue
|
|
198
|
+
if hasattr(declared, "__get__"):
|
|
199
|
+
continue
|
|
200
|
+
walk(declared, f"{path}.__class__.{name}", depth=depth + 1)
|
|
201
|
+
|
|
202
|
+
walk(root, root_path, depth=0)
|
|
203
|
+
return tuple(nodes)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _instance_state_items(value: object) -> tuple[tuple[str, object], ...]:
|
|
207
|
+
"""Return direct instance state once, without executing descriptors."""
|
|
208
|
+
|
|
209
|
+
items: dict[str, object] = {}
|
|
210
|
+
if is_dataclass(value) and not isinstance(value, type):
|
|
211
|
+
for declared in fields(value):
|
|
212
|
+
items[declared.name] = getattr(value, declared.name)
|
|
213
|
+
attributes = getattr(value, "__dict__", {})
|
|
214
|
+
if isinstance(attributes, Mapping):
|
|
215
|
+
items.update((str(name), item) for name, item in attributes.items())
|
|
216
|
+
for owner in type(value).__mro__:
|
|
217
|
+
declared_slots = owner.__dict__.get("__slots__", ())
|
|
218
|
+
if isinstance(declared_slots, str):
|
|
219
|
+
declared_slots = (declared_slots,)
|
|
220
|
+
for name in declared_slots:
|
|
221
|
+
if name in {"__dict__", "__weakref__"} or name in items:
|
|
222
|
+
continue
|
|
223
|
+
if hasattr(value, name):
|
|
224
|
+
items[name] = getattr(value, name)
|
|
225
|
+
return tuple(items.items())
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def runtime_dependency_nodes(
|
|
229
|
+
root: object,
|
|
230
|
+
*,
|
|
231
|
+
root_path: str,
|
|
232
|
+
terminal_types: tuple[type[Any], ...] = (),
|
|
233
|
+
) -> tuple[ObjectGraphNode, ...]:
|
|
234
|
+
return tuple(
|
|
235
|
+
node
|
|
236
|
+
for node in inspect_object_graph(
|
|
237
|
+
root,
|
|
238
|
+
root_path=root_path,
|
|
239
|
+
terminal_types=terminal_types,
|
|
240
|
+
)
|
|
241
|
+
if is_runtime_dependency(node.value)
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def is_runtime_dependency(value: object) -> bool:
|
|
246
|
+
"""Return whether ``value`` can perform an in-scope external execution.
|
|
247
|
+
|
|
248
|
+
The core backend protocols are nominally identifiable. Pinned upstream
|
|
249
|
+
bridges intentionally use small structural seams instead (``call``,
|
|
250
|
+
``run``, or ``reformulate`` plus a stable fingerprint), so they must also
|
|
251
|
+
be treated as executable dependencies regardless of their field name.
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
if isinstance(value, RUNTIME_DEPENDENCY_TYPES):
|
|
255
|
+
return True
|
|
256
|
+
fingerprint = getattr(value, "fingerprint", None)
|
|
257
|
+
return callable(fingerprint) and any(
|
|
258
|
+
callable(getattr(value, method, None)) for method in _EXTERNAL_EXECUTOR_METHODS
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
__all__ = [
|
|
263
|
+
"RUNTIME_DEPENDENCY_TYPES",
|
|
264
|
+
"ObjectGraphNode",
|
|
265
|
+
"inspect_object_graph",
|
|
266
|
+
"is_runtime_dependency",
|
|
267
|
+
"runtime_dependency_nodes",
|
|
268
|
+
]
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Strict external-worker clients.
|
|
2
|
+
|
|
3
|
+
The subprocess transport accepts an argv tuple and never invokes a shell.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from collections.abc import Callable, Mapping
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Protocol, runtime_checkable
|
|
12
|
+
|
|
13
|
+
from agentinputlab.contracts.errors import ExternalDependencyError
|
|
14
|
+
from agentinputlab.contracts.serialization import to_jsonable
|
|
15
|
+
from agentinputlab.contracts.worker import WorkerRequest, WorkerResponse
|
|
16
|
+
from agentinputlab.integrations.external_workers.process import run_bounded_process
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@runtime_checkable
|
|
20
|
+
class WorkerClient(Protocol):
|
|
21
|
+
def invoke(self, request: WorkerRequest) -> WorkerResponse: ...
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(slots=True)
|
|
25
|
+
class FunctionWorkerClient(WorkerClient):
|
|
26
|
+
fn: Callable[[WorkerRequest], WorkerResponse]
|
|
27
|
+
|
|
28
|
+
def invoke(self, request: WorkerRequest) -> WorkerResponse:
|
|
29
|
+
return self.fn(request)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(slots=True)
|
|
33
|
+
class JsonLineWorkerClient(WorkerClient):
|
|
34
|
+
argv: tuple[str, ...]
|
|
35
|
+
timeout_seconds: float = 300.0
|
|
36
|
+
max_request_bytes: int = 8 * 1024 * 1024
|
|
37
|
+
max_response_bytes: int = 8 * 1024 * 1024
|
|
38
|
+
max_stderr_bytes: int = 1024 * 1024
|
|
39
|
+
cwd: str | None = None
|
|
40
|
+
env: Mapping[str, str] = field(default_factory=dict)
|
|
41
|
+
|
|
42
|
+
def __post_init__(self) -> None:
|
|
43
|
+
self.argv = tuple(self.argv)
|
|
44
|
+
if not self.argv:
|
|
45
|
+
raise ValueError("worker argv must not be empty")
|
|
46
|
+
if min(self.max_request_bytes, self.max_response_bytes, self.max_stderr_bytes) < 1:
|
|
47
|
+
raise ValueError("worker byte limits must be positive")
|
|
48
|
+
|
|
49
|
+
def invoke(self, request: WorkerRequest) -> WorkerResponse:
|
|
50
|
+
payload = json.dumps(to_jsonable(request), sort_keys=True) + "\n"
|
|
51
|
+
completed = run_bounded_process(
|
|
52
|
+
self.argv,
|
|
53
|
+
input_text=payload,
|
|
54
|
+
timeout_seconds=self.timeout_seconds,
|
|
55
|
+
max_input_bytes=self.max_request_bytes,
|
|
56
|
+
max_stdout_bytes=self.max_response_bytes,
|
|
57
|
+
max_stderr_bytes=self.max_stderr_bytes,
|
|
58
|
+
cwd=self.cwd,
|
|
59
|
+
environment=self.env,
|
|
60
|
+
process_name="external worker",
|
|
61
|
+
)
|
|
62
|
+
if completed.returncode != 0:
|
|
63
|
+
stderr = completed.stderr[-2000:]
|
|
64
|
+
raise ExternalDependencyError(
|
|
65
|
+
f"external worker exited {completed.returncode}: {stderr}"
|
|
66
|
+
)
|
|
67
|
+
lines = [line for line in completed.stdout.splitlines() if line.strip()]
|
|
68
|
+
if len(lines) != 1:
|
|
69
|
+
raise ExternalDependencyError("external worker must emit exactly one JSON line")
|
|
70
|
+
try:
|
|
71
|
+
data = json.loads(lines[0])
|
|
72
|
+
except json.JSONDecodeError as exc:
|
|
73
|
+
raise ExternalDependencyError("external worker returned invalid JSON") from exc
|
|
74
|
+
try:
|
|
75
|
+
response = WorkerResponse(**data)
|
|
76
|
+
except (TypeError, ValueError) as exc:
|
|
77
|
+
raise ExternalDependencyError("external worker returned an invalid envelope") from exc
|
|
78
|
+
if response.request_id != request.request_id:
|
|
79
|
+
raise ExternalDependencyError("external worker response request_id mismatch")
|
|
80
|
+
return response
|