evalrx 0.1.2__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.
- evalrx/__init__.py +139 -0
- evalrx/agent_assets/__init__.py +2 -0
- evalrx/agent_assets/skills/README.md +28 -0
- evalrx/agent_assets/skills/eval-chart-style/SKILL.md +172 -0
- evalrx/agent_assets/skills/evalrx-report-ui/SKILL.md +116 -0
- evalrx/agent_assets/skills/nature-figure/LICENSE +201 -0
- evalrx/agent_assets/skills/nature-figure/README.md +412 -0
- evalrx/agent_assets/skills/nature-figure/SKILL.md +60 -0
- evalrx/agent_assets/skills/nature-figure/manifest.yaml +59 -0
- evalrx/agent_assets/skills/nature-figure/references/api.md +436 -0
- evalrx/agent_assets/skills/nature-figure/references/backend-selection.md +100 -0
- evalrx/agent_assets/skills/nature-figure/references/chart-types.md +281 -0
- evalrx/agent_assets/skills/nature-figure/references/common-patterns.md +350 -0
- evalrx/agent_assets/skills/nature-figure/references/demos.md +65 -0
- evalrx/agent_assets/skills/nature-figure/references/design-theory.md +439 -0
- evalrx/agent_assets/skills/nature-figure/references/figure-contract.md +93 -0
- evalrx/agent_assets/skills/nature-figure/references/figure-legend-conventions.md +71 -0
- evalrx/agent_assets/skills/nature-figure/references/nature-2026-observations.md +112 -0
- evalrx/agent_assets/skills/nature-figure/references/qa-contract.md +119 -0
- evalrx/agent_assets/skills/nature-figure/references/r-template-index.md +66 -0
- evalrx/agent_assets/skills/nature-figure/references/r-workflow.md +161 -0
- evalrx/agent_assets/skills/nature-figure/references/tutorials.md +251 -0
- evalrx/agent_assets/skills/nature-figure/static/core/contract.md +29 -0
- evalrx/agent_assets/skills/nature-figure/static/core/stance.md +37 -0
- evalrx/agent_assets/skills/nature-figure/static/fragments/backend/python.md +37 -0
- evalrx/agent_assets/skills/nature-figure/static/fragments/backend/r.md +44 -0
- evalrx/agent_assets/skills/outcome-driver-analysis/SKILL.md +213 -0
- evalrx/agent_assets/skills/outcome-driver-analysis/assets/analysis_report_template.md +53 -0
- evalrx/agent_assets/skills/outcome-driver-analysis/references/model_selection.md +72 -0
- evalrx/agent_assets/skills/outcome-driver-analysis/scripts/explanatory_var_eda.R +130 -0
- evalrx/agent_assets/skills/outcome-driver-analysis/scripts/explanatory_var_eda.py +150 -0
- evalrx/agent_assets/skills/outcome-driver-analysis/scripts/fit_outcome_model.R +181 -0
- evalrx/agent_assets/skills/outcome-driver-analysis/scripts/fit_outcome_model.py +186 -0
- evalrx/agent_assets/skills/outcome-driver-analysis/scripts/univariate_eda.R +149 -0
- evalrx/agent_assets/skills/outcome-driver-analysis/scripts/univariate_eda.py +177 -0
- evalrx/agent_assets/skills.py +27 -0
- evalrx/agent_runtime/__init__.py +78 -0
- evalrx/agent_runtime/_docker_runner.py +89 -0
- evalrx/agent_runtime/cli_runtime.py +103 -0
- evalrx/agent_runtime/cli_transcript.py +138 -0
- evalrx/agent_runtime/cli_types.py +68 -0
- evalrx/agent_runtime/codegen/__init__.py +5 -0
- evalrx/agent_runtime/codegen/runner.py +94 -0
- evalrx/agent_runtime/experiment_harness.py +117 -0
- evalrx/agent_runtime/factory.py +102 -0
- evalrx/agent_runtime/json_shape.py +44 -0
- evalrx/agent_runtime/judges/__init__.py +28 -0
- evalrx/agent_runtime/judges/agy.py +179 -0
- evalrx/agent_runtime/judges/autodetect.py +135 -0
- evalrx/agent_runtime/judges/claude.py +159 -0
- evalrx/agent_runtime/judges/codex.py +120 -0
- evalrx/agent_runtime/providers/__init__.py +21 -0
- evalrx/agent_runtime/providers/antigravity.py +31 -0
- evalrx/agent_runtime/providers/base.py +145 -0
- evalrx/agent_runtime/providers/claude_code.py +49 -0
- evalrx/agent_runtime/providers/codex.py +37 -0
- evalrx/agent_runtime/providers/gemini_cli.py +26 -0
- evalrx/agent_runtime/providers/kimi_cli.py +27 -0
- evalrx/agent_runtime/providers/opencode.py +27 -0
- evalrx/agent_runtime/providers/registry.py +58 -0
- evalrx/agent_runtime/sandbox.py +517 -0
- evalrx/agent_runtime/skill_audit.py +143 -0
- evalrx/agent_runtime/skills/__init__.py +19 -0
- evalrx/agent_runtime/skills/installer.py +68 -0
- evalrx/agent_runtime/skills/prompt_policy.py +86 -0
- evalrx/agent_runtime/skills/resolver.py +19 -0
- evalrx/analysis/__init__.py +132 -0
- evalrx/analysis/adjudicate.py +154 -0
- evalrx/analysis/analysis_module.py +361 -0
- evalrx/analysis/api.py +171 -0
- evalrx/analysis/case_studio.py +651 -0
- evalrx/analysis/cli.py +114 -0
- evalrx/analysis/dashboard.py +350 -0
- evalrx/analysis/eval_case_matrix.py +118 -0
- evalrx/analysis/eval_viz_theme.py +833 -0
- evalrx/analysis/explore_run.py +333 -0
- evalrx/analysis/explorer.py +1276 -0
- evalrx/analysis/failure_modes.py +607 -0
- evalrx/analysis/fused_pipeline.py +489 -0
- evalrx/analysis/holdout.py +300 -0
- evalrx/analysis/hypothesis_agent.py +230 -0
- evalrx/analysis/narration.py +177 -0
- evalrx/analysis/operationalize.py +442 -0
- evalrx/analysis/plain_language.py +42 -0
- evalrx/analysis/planner.py +283 -0
- evalrx/analysis/probe_search.py +203 -0
- evalrx/analysis/profile.py +268 -0
- evalrx/analysis/prompts/__init__.py +0 -0
- evalrx/analysis/prompts/explorer.py +417 -0
- evalrx/analysis/prompts/failure_modes.py +33 -0
- evalrx/analysis/prompts/holdout.py +27 -0
- evalrx/analysis/prompts/hypothesis_agent.py +78 -0
- evalrx/analysis/prompts/run_codebase.py +47 -0
- evalrx/analysis/prompts/stats_agent.py +72 -0
- evalrx/analysis/prompts/stats_tool_generator.py +43 -0
- evalrx/analysis/result_marker.py +47 -0
- evalrx/analysis/run_codebase.py +242 -0
- evalrx/analysis/run_view.py +205 -0
- evalrx/analysis/stage_views.py +93 -0
- evalrx/analysis/stats_agent.py +944 -0
- evalrx/analysis/stats_tool_agent.py +261 -0
- evalrx/analysis/stats_tool_generator.py +415 -0
- evalrx/analysis/stats_tools.py +1153 -0
- evalrx/analysis/trajectory_records.py +193 -0
- evalrx/analysis/workbench.py +431 -0
- evalrx/analyzers/__init__.py +42 -0
- evalrx/analyzers/agent/__init__.py +25 -0
- evalrx/analyzers/agent/counterfactual.py +84 -0
- evalrx/analyzers/agent/first_error_judge.py +96 -0
- evalrx/analyzers/agent/ignored_obs.py +81 -0
- evalrx/analyzers/agent/loop_detect.py +79 -0
- evalrx/analyzers/agent/reliability.py +165 -0
- evalrx/analyzers/agent/tool_shap.py +225 -0
- evalrx/analyzers/agent/trajectory_rubric.py +168 -0
- evalrx/analyzers/attention/__init__.py +19 -0
- evalrx/analyzers/attention/relative_attn.py +610 -0
- evalrx/analyzers/attention/rollout.py +73 -0
- evalrx/analyzers/attention/sink.py +56 -0
- evalrx/analyzers/attention/summary.py +190 -0
- evalrx/analyzers/attribution/__init__.py +6 -0
- evalrx/analyzers/attribution/generic_attn.py +31 -0
- evalrx/analyzers/attribution/gradcam.py +30 -0
- evalrx/analyzers/base.py +12 -0
- evalrx/analyzers/geometry/__init__.py +6 -0
- evalrx/analyzers/geometry/cka.py +70 -0
- evalrx/analyzers/geometry/linear_probe.py +157 -0
- evalrx/analyzers/hallucination/__init__.py +9 -0
- evalrx/analyzers/hallucination/chair.py +78 -0
- evalrx/analyzers/hallucination/opera.py +29 -0
- evalrx/analyzers/hallucination/pope.py +119 -0
- evalrx/analyzers/hallucination/selfcheck.py +155 -0
- evalrx/analyzers/hallucination/vcd.py +29 -0
- evalrx/analyzers/lens/__init__.py +7 -0
- evalrx/analyzers/lens/layer_contrast.py +133 -0
- evalrx/analyzers/lens/logit_lens.py +138 -0
- evalrx/analyzers/lens/tuned_lens.py +30 -0
- evalrx/analyzers/patching/__init__.py +5 -0
- evalrx/analyzers/patching/causal_trace.py +30 -0
- evalrx/analyzers/perturbation/__init__.py +23 -0
- evalrx/analyzers/perturbation/_shapley.py +54 -0
- evalrx/analyzers/perturbation/context_shap.py +174 -0
- evalrx/analyzers/perturbation/cot_faithfulness.py +239 -0
- evalrx/analyzers/perturbation/format_sensitivity.py +237 -0
- evalrx/analyzers/perturbation/mm_shap.py +146 -0
- evalrx/analyzers/perturbation/modality_ablation.py +196 -0
- evalrx/analyzers/perturbation/perturbation_battery.py +274 -0
- evalrx/analyzers/perturbation/prompt_contrast.py +265 -0
- evalrx/analyzers/perturbation/rise.py +94 -0
- evalrx/analyzers/perturbation/vl_shap.py +102 -0
- evalrx/analyzers/reasoning/__init__.py +33 -0
- evalrx/analyzers/reasoning/_text.py +328 -0
- evalrx/analyzers/reasoning/answer_extraction_audit.py +327 -0
- evalrx/analyzers/reasoning/arith_audit.py +226 -0
- evalrx/analyzers/reasoning/contamination.py +214 -0
- evalrx/analyzers/reasoning/knowledge_split.py +253 -0
- evalrx/analyzers/reasoning/self_repair.py +246 -0
- evalrx/analyzers/reasoning/step_rollout_value.py +216 -0
- evalrx/analyzers/reasoning/termination_audit.py +258 -0
- evalrx/analyzers/uncertainty/__init__.py +18 -0
- evalrx/analyzers/uncertainty/calibration.py +174 -0
- evalrx/analyzers/uncertainty/coverage_gap.py +199 -0
- evalrx/analyzers/uncertainty/entropy.py +90 -0
- evalrx/analyzers/uncertainty/logprob_entropy.py +69 -0
- evalrx/analyzers/uncertainty/self_consistency.py +204 -0
- evalrx/analyzers/uncertainty/verbalized_conf.py +64 -0
- evalrx/cli.py +411 -0
- evalrx/config.py +77 -0
- evalrx/contract/__init__.py +179 -0
- evalrx/contract/common.py +452 -0
- evalrx/contract/emit.py +948 -0
- evalrx/contract/export.py +237 -0
- evalrx/contract/m1.py +325 -0
- evalrx/contract/m2.py +317 -0
- evalrx/contract/m3.py +165 -0
- evalrx/contract/m4.py +130 -0
- evalrx/contract/m5.py +292 -0
- evalrx/contract/methodology.py +76 -0
- evalrx/contract/pre_m1.py +58 -0
- evalrx/contract/typescript.py +140 -0
- evalrx/core/__init__.py +85 -0
- evalrx/core/analyzer.py +174 -0
- evalrx/core/capability.py +54 -0
- evalrx/core/case.py +443 -0
- evalrx/core/experiment.py +106 -0
- evalrx/core/model.py +198 -0
- evalrx/core/pipeline.py +42 -0
- evalrx/core/registry.py +142 -0
- evalrx/core/result.py +64 -0
- evalrx/core/spec.py +173 -0
- evalrx/core/tokentype.py +165 -0
- evalrx/core/tool.py +92 -0
- evalrx/datasets/__init__.py +41 -0
- evalrx/datasets/base.py +68 -0
- evalrx/datasets/gui_os.py +52 -0
- evalrx/datasets/llm_qa.py +57 -0
- evalrx/datasets/pure_qa.py +12 -0
- evalrx/datasets/vlm_qa.py +695 -0
- evalrx/datasets/web_search_qa.py +52 -0
- evalrx/eval_agent/__init__.py +341 -0
- evalrx/eval_agent/_tools.py +81 -0
- evalrx/eval_agent/ab_runner.py +50 -0
- evalrx/eval_agent/agentic/__init__.py +43 -0
- evalrx/eval_agent/agentic/actions.py +216 -0
- evalrx/eval_agent/agentic/board.py +107 -0
- evalrx/eval_agent/agentic/loop.py +190 -0
- evalrx/eval_agent/agentic/tools.py +538 -0
- evalrx/eval_agent/checkpoint.py +57 -0
- evalrx/eval_agent/cli_agent.py +59 -0
- evalrx/eval_agent/cli_skills.py +5 -0
- evalrx/eval_agent/evolution.py +396 -0
- evalrx/eval_agent/git_manager.py +215 -0
- evalrx/eval_agent/hypothesis.py +172 -0
- evalrx/eval_agent/label_quarantine.py +209 -0
- evalrx/eval_agent/legacy.py +530 -0
- evalrx/eval_agent/log_schema.py +497 -0
- evalrx/eval_agent/loop.py +2159 -0
- evalrx/eval_agent/loop_reports.py +116 -0
- evalrx/eval_agent/model_instrumentation.py +282 -0
- evalrx/eval_agent/narration.py +193 -0
- evalrx/eval_agent/nl_runner.py +460 -0
- evalrx/eval_agent/orchestrator.py +61 -0
- evalrx/eval_agent/preregister.py +93 -0
- evalrx/eval_agent/prompts/__init__.py +1 -0
- evalrx/eval_agent/prompts/agentic.py +46 -0
- evalrx/eval_agent/prompts/case_discovery.py +25 -0
- evalrx/eval_agent/prompts/diagnosis.py +125 -0
- evalrx/eval_agent/prompts/experiment_writer.py +265 -0
- evalrx/eval_agent/prompts/explore_step.py +37 -0
- evalrx/eval_agent/prompts/fix_agent.py +257 -0
- evalrx/eval_agent/prompts/hypothesis_tester.py +15 -0
- evalrx/eval_agent/prompts/nl_runner.py +38 -0
- evalrx/eval_agent/prompts/probe_agent.py +25 -0
- evalrx/eval_agent/prompts/probe_candidate_generator.py +14 -0
- evalrx/eval_agent/prompts/probe_generator.py +35 -0
- evalrx/eval_agent/prompts/whitebox_probe_generator.py +38 -0
- evalrx/eval_agent/report.py +58 -0
- evalrx/eval_agent/run_context.py +354 -0
- evalrx/eval_agent/run_log.schema.json +1215 -0
- evalrx/eval_agent/run_logger_v2.py +1764 -0
- evalrx/eval_agent/run_metadata.py +208 -0
- evalrx/eval_agent/stages/__init__.py +56 -0
- evalrx/eval_agent/stages/case_discovery.py +293 -0
- evalrx/eval_agent/stages/diagnosis.py +1017 -0
- evalrx/eval_agent/stages/experiment_writer.py +1634 -0
- evalrx/eval_agent/stages/fix_agent.py +3916 -0
- evalrx/eval_agent/stages/fix_internals.py +499 -0
- evalrx/eval_agent/stages/fix_pipeline.py +725 -0
- evalrx/eval_agent/stages/fix_tiers.py +187 -0
- evalrx/eval_agent/stages/fix_tools.py +1034 -0
- evalrx/eval_agent/stages/hypothesis_tester.py +1014 -0
- evalrx/eval_agent/stages/probe.py +439 -0
- evalrx/eval_agent/stages/probe_agent.py +1079 -0
- evalrx/eval_agent/stages/probe_candidate_generator.py +128 -0
- evalrx/eval_agent/stages/probe_generator.py +326 -0
- evalrx/eval_agent/stages/probe_search_agent.py +106 -0
- evalrx/eval_agent/stages/protocol.py +112 -0
- evalrx/eval_agent/stages/repair_catalog.py +273 -0
- evalrx/eval_agent/stages/surgery.py +524 -0
- evalrx/eval_agent/stages/whitebox_probe_generator.py +351 -0
- evalrx/eval_agent/store.py +231 -0
- evalrx/logging_utils.py +112 -0
- evalrx/models/__init__.py +161 -0
- evalrx/models/_discover.py +101 -0
- evalrx/models/agent.py +380 -0
- evalrx/models/backends/__init__.py +58 -0
- evalrx/models/backends/api.py +169 -0
- evalrx/models/backends/base.py +57 -0
- evalrx/models/backends/gemini_compat.py +579 -0
- evalrx/models/backends/hf_local.py +2074 -0
- evalrx/models/backends/openai_compat.py +301 -0
- evalrx/models/backends/vllm_offline.py +116 -0
- evalrx/models/base.py +24 -0
- evalrx/models/blackbox/__init__.py +4 -0
- evalrx/models/blackbox/agent.py +31 -0
- evalrx/models/blackbox/base.py +29 -0
- evalrx/models/blackbox/gemini.py +279 -0
- evalrx/models/blackbox/llm_api.py +17 -0
- evalrx/models/blackbox/vlm_api.py +17 -0
- evalrx/models/compose.py +66 -0
- evalrx/models/inference.py +88 -0
- evalrx/models/paper_methods/__init__.py +8 -0
- evalrx/models/paper_methods/aad.py +53 -0
- evalrx/models/paper_methods/ifcd.py +204 -0
- evalrx/models/paper_methods/pai.py +164 -0
- evalrx/models/paper_methods/tcd.py +202 -0
- evalrx/models/paper_methods/vcd.py +45 -0
- evalrx/models/paper_methods/vicrop.py +137 -0
- evalrx/models/toolcodec.py +143 -0
- evalrx/models/tools/__init__.py +20 -0
- evalrx/models/tools/perception.py +300 -0
- evalrx/models/tools/visual.py +174 -0
- evalrx/models/whitebox/__init__.py +26 -0
- evalrx/models/whitebox/agent.py +31 -0
- evalrx/models/whitebox/base.py +24 -0
- evalrx/models/whitebox/qwen.py +61 -0
- evalrx/models/whitebox/qwen2_5_omni.py +29 -0
- evalrx/models/whitebox/qwen2_audio.py +25 -0
- evalrx/models/whitebox/qwen_omni.py +53 -0
- evalrx/models/whitebox/qwen_vl.py +62 -0
- evalrx/observability/__init__.py +21 -0
- evalrx/observability/envelope.py +122 -0
- evalrx/observability/outbox.py +111 -0
- evalrx/observability/tracer.py +882 -0
- evalrx/reporting/__init__.py +28 -0
- evalrx/reporting/case_study.py +947 -0
- evalrx/reporting/compiler.py +587 -0
- evalrx/reporting/dynamic.py +1882 -0
- evalrx/reporting/html_report.py +2225 -0
- evalrx/reporting/langfuse_exporter.py +38 -0
- evalrx/reporting/langfuse_source.py +155 -0
- evalrx/reporting/model.py +151 -0
- evalrx/reporting/run_events.py +184 -0
- evalrx/reporting/server.py +557 -0
- evalrx/reporting/stages.py +58 -0
- evalrx/reporting/static_export.py +142 -0
- evalrx/reporting/web_dist/index.html +146 -0
- evalrx/specs.py +727 -0
- evalrx/stats/__init__.py +47 -0
- evalrx/stats/api.py +192 -0
- evalrx/stats/bootstrap.py +86 -0
- evalrx/stats/ebh.py +27 -0
- evalrx/stats/evalue.py +98 -0
- evalrx/stats/friedman.py +138 -0
- evalrx/stats/mcnemar.py +40 -0
- evalrx/stats/multiplicity.py +159 -0
- evalrx/stats/subset_sampling.py +55 -0
- evalrx/term_links.py +43 -0
- evalrx/viz/__init__.py +7 -0
- evalrx/viz/labels.py +77 -0
- evalrx/viz/prompts.py +39 -0
- evalrx/viz/renderer.py +590 -0
- evalrx/viz/schema.py +36 -0
- evalrx/viz/style.py +134 -0
- evalrx-0.1.2.dist-info/METADATA +532 -0
- evalrx-0.1.2.dist-info/RECORD +339 -0
- evalrx-0.1.2.dist-info/WHEEL +5 -0
- evalrx-0.1.2.dist-info/entry_points.txt +3 -0
- evalrx-0.1.2.dist-info/licenses/LICENSE +121 -0
- evalrx-0.1.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Backends — runtimes that turn a ModelSpec into a Model.
|
|
2
|
+
|
|
3
|
+
Capabilities come from the backend; identity from the spec. All three import
|
|
4
|
+
torch-free (heavy deps are lazy inside ``build``/``load``), so the registry and
|
|
5
|
+
``compose()`` work on the light install.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from evalrx.models.backends.api import (
|
|
9
|
+
APIBackend,
|
|
10
|
+
APIModel,
|
|
11
|
+
call_vision_api_chat_fn,
|
|
12
|
+
call_vision_api_generate_fn,
|
|
13
|
+
parse_openai_logprobs,
|
|
14
|
+
)
|
|
15
|
+
from evalrx.models.backends.base import Backend, RuntimeConfig
|
|
16
|
+
from evalrx.models.backends.gemini_compat import (
|
|
17
|
+
ThinkingPolicy,
|
|
18
|
+
gemini_chat_fn,
|
|
19
|
+
gemini_generate_fn,
|
|
20
|
+
gemini_logprobs_fn,
|
|
21
|
+
gemini_runtime,
|
|
22
|
+
)
|
|
23
|
+
from evalrx.models.backends.hf_local import HFLocalBackend, HFLocalModel
|
|
24
|
+
from evalrx.models.backends.openai_compat import (
|
|
25
|
+
openai_chat_fn,
|
|
26
|
+
openai_generate_fn,
|
|
27
|
+
openai_runtime,
|
|
28
|
+
)
|
|
29
|
+
from evalrx.models.backends.vllm_offline import VLLMOfflineBackend
|
|
30
|
+
|
|
31
|
+
#: name -> backend class. Plain dict (no import-side-effect decorator).
|
|
32
|
+
BACKENDS: dict[str, type[Backend]] = {
|
|
33
|
+
"api": APIBackend,
|
|
34
|
+
"hf_local": HFLocalBackend,
|
|
35
|
+
"vllm_offline": VLLMOfflineBackend,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
"Backend",
|
|
40
|
+
"RuntimeConfig",
|
|
41
|
+
"APIBackend",
|
|
42
|
+
"APIModel",
|
|
43
|
+
"HFLocalBackend",
|
|
44
|
+
"HFLocalModel",
|
|
45
|
+
"VLLMOfflineBackend",
|
|
46
|
+
"call_vision_api_generate_fn",
|
|
47
|
+
"call_vision_api_chat_fn",
|
|
48
|
+
"parse_openai_logprobs",
|
|
49
|
+
"openai_chat_fn",
|
|
50
|
+
"openai_generate_fn",
|
|
51
|
+
"openai_runtime",
|
|
52
|
+
"ThinkingPolicy",
|
|
53
|
+
"gemini_chat_fn",
|
|
54
|
+
"gemini_generate_fn",
|
|
55
|
+
"gemini_logprobs_fn",
|
|
56
|
+
"gemini_runtime",
|
|
57
|
+
"BACKENDS",
|
|
58
|
+
]
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""API backend — remote / OpenAI-compatible models (incl. ``vllm serve``).
|
|
2
|
+
|
|
3
|
+
Capabilities: ``GENERATE`` + ``TOOL_CALLS`` (+ ``LOGPROBS`` when the endpoint
|
|
4
|
+
returns top-logprobs, e.g. OpenAI but not Gemini). No internals: ``forward``
|
|
5
|
+
raises, and capability matching means white-box analyzers are simply never
|
|
6
|
+
offered for an API model.
|
|
7
|
+
|
|
8
|
+
Reuse of your existing engine is by **dependency injection**: pass your
|
|
9
|
+
``call_vision_api`` adapted through :func:`call_vision_api_generate_fn` as
|
|
10
|
+
``RuntimeConfig.generate_fn`` — no cross-repo import, no rewrite. A ``vllm serve``
|
|
11
|
+
endpoint is just this backend pointed at ``localhost`` (the answer to "is
|
|
12
|
+
vllm_local the same as api?": *for serving, yes* — see ``vllm_offline`` for the
|
|
13
|
+
distinct in-process batch path).
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import Any, Callable
|
|
19
|
+
|
|
20
|
+
from evalrx.core.capability import Capability, CapabilityError
|
|
21
|
+
from evalrx.core.case import Inputs
|
|
22
|
+
from evalrx.core.model import Model, TokenLogprob, Trace
|
|
23
|
+
from evalrx.core.tool import ChatTurn
|
|
24
|
+
from evalrx.models.backends.base import Backend, RuntimeConfig
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def parse_openai_logprobs(content_logprobs) -> list[TokenLogprob]:
|
|
28
|
+
"""Parse OpenAI ``choices[0].logprobs.content`` into ``list[TokenLogprob]``.
|
|
29
|
+
|
|
30
|
+
Use inside a ``logprobs_fn`` after calling an OpenAI-compatible endpoint with
|
|
31
|
+
``logprobs=True, top_logprobs=k``.
|
|
32
|
+
"""
|
|
33
|
+
out: list[TokenLogprob] = []
|
|
34
|
+
for item in content_logprobs or []:
|
|
35
|
+
top = {t["token"]: float(t["logprob"]) for t in item.get("top_logprobs", [])}
|
|
36
|
+
out.append(TokenLogprob(token=item.get("token", ""), logprob=float(item["logprob"]), top=top))
|
|
37
|
+
return out
|
|
38
|
+
|
|
39
|
+
_WHITEBOX = {
|
|
40
|
+
Capability.ATTENTION,
|
|
41
|
+
Capability.HIDDEN_STATES,
|
|
42
|
+
Capability.LOGITS,
|
|
43
|
+
Capability.GRADIENTS,
|
|
44
|
+
Capability.ACTIVATIONS,
|
|
45
|
+
Capability.EMBEDDINGS,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def call_vision_api_generate_fn(
|
|
50
|
+
call_vision_api: Callable,
|
|
51
|
+
*,
|
|
52
|
+
default_sampling: dict | None = None,
|
|
53
|
+
) -> Callable[..., str]:
|
|
54
|
+
"""Adapt an existing ``call_vision_api(model, messages, sampling_params, tools)``
|
|
55
|
+
into the simple ``generate_fn(prompt, model=..., **kw) -> str`` an APIModel needs.
|
|
56
|
+
|
|
57
|
+
This is the one-liner that reuses your XSkill engine verbatim::
|
|
58
|
+
|
|
59
|
+
from engine.api_caller import call_vision_api
|
|
60
|
+
rt = RuntimeConfig(generate_fn=call_vision_api_generate_fn(call_vision_api))
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def _fn(prompt: str, model: str, **kw) -> str:
|
|
64
|
+
messages = [{"role": "user", "content": prompt}]
|
|
65
|
+
sampling = {**(default_sampling or {}), **kw}
|
|
66
|
+
resp = call_vision_api(model, messages, sampling)
|
|
67
|
+
if isinstance(resp, dict): # tool/reasoning shape -> pull text
|
|
68
|
+
return resp.get("content") or str(resp)
|
|
69
|
+
return resp
|
|
70
|
+
|
|
71
|
+
return _fn
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def call_vision_api_chat_fn(call_vision_api: Callable) -> Callable[..., ChatTurn]:
|
|
75
|
+
"""Adapt ``call_vision_api(model, messages, sampling, tools)`` into a tool-aware
|
|
76
|
+
``chat_fn(messages, tools, model) -> ChatTurn`` for agent mode.
|
|
77
|
+
|
|
78
|
+
The engine already returns structured tool_calls when present, so this just
|
|
79
|
+
normalises its reply shape::
|
|
80
|
+
|
|
81
|
+
rt = RuntimeConfig(chat_fn=call_vision_api_chat_fn(call_vision_api))
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
def _fn(messages: list, tools=None, model: str = "") -> ChatTurn:
|
|
85
|
+
resp = call_vision_api(model, messages, {}, tools=tools)
|
|
86
|
+
if isinstance(resp, dict):
|
|
87
|
+
return ChatTurn(text=resp.get("content") or "", raw_tool_calls=resp.get("tool_calls"))
|
|
88
|
+
return ChatTurn(text=resp, raw_tool_calls=None)
|
|
89
|
+
|
|
90
|
+
return _fn
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class APIModel(Model):
|
|
94
|
+
"""A model reachable only through a text-in / text-out API."""
|
|
95
|
+
|
|
96
|
+
def __init__(self, spec, runtime: RuntimeConfig) -> None:
|
|
97
|
+
self.spec = spec
|
|
98
|
+
self.runtime = runtime
|
|
99
|
+
self._generate_fn = runtime.generate_fn
|
|
100
|
+
self._chat_fn = runtime.chat_fn
|
|
101
|
+
self._logprobs_fn = runtime.logprobs_fn
|
|
102
|
+
caps = {Capability.GENERATE, Capability.TOOL_CALLS}
|
|
103
|
+
if runtime.logprobs_fn is not None: # only claim LOGPROBS if we can actually retrieve them
|
|
104
|
+
caps.add(Capability.LOGPROBS)
|
|
105
|
+
self.capabilities = frozenset(caps)
|
|
106
|
+
self.modalities = frozenset(spec.modalities) # text / image / audio / video, from the spec
|
|
107
|
+
|
|
108
|
+
def generate(self, inputs: Any, **kwargs) -> str:
|
|
109
|
+
if self._generate_fn is None:
|
|
110
|
+
raise RuntimeError(
|
|
111
|
+
f"APIModel({self.spec.key!r}) has no generate_fn. Inject one via "
|
|
112
|
+
"RuntimeConfig(generate_fn=...), e.g. call_vision_api_generate_fn(call_vision_api)."
|
|
113
|
+
)
|
|
114
|
+
prompt = inputs.prompt if isinstance(inputs, Inputs) else str(inputs)
|
|
115
|
+
model_name = self.spec.hf_repo or self.spec.key
|
|
116
|
+
return self._generate_fn(prompt, model=model_name, **self._media(inputs), **kwargs)
|
|
117
|
+
|
|
118
|
+
def chat(self, messages: list, tools=None) -> ChatTurn:
|
|
119
|
+
model_name = self.spec.hf_repo or self.spec.key
|
|
120
|
+
if self._chat_fn is not None:
|
|
121
|
+
return self._chat_fn(messages, tools=tools, model=model_name)
|
|
122
|
+
# Fallback: no tool-aware chat wired -> text-only (no tool calls possible).
|
|
123
|
+
if self._generate_fn is None:
|
|
124
|
+
raise RuntimeError(
|
|
125
|
+
f"APIModel({self.spec.key!r}) needs a chat_fn (tool-aware) or generate_fn. "
|
|
126
|
+
"Inject one, e.g. call_vision_api_chat_fn(call_vision_api)."
|
|
127
|
+
)
|
|
128
|
+
prompt = messages[-1].get("content", "") if messages else ""
|
|
129
|
+
return ChatTurn(text=self._generate_fn(prompt, model=model_name), raw_tool_calls=None)
|
|
130
|
+
|
|
131
|
+
def logprobs(self, inputs: Any, **kwargs) -> list[TokenLogprob]:
|
|
132
|
+
if self._logprobs_fn is None:
|
|
133
|
+
raise CapabilityError(analyzer="logprobs", model=repr(self), missing={Capability.LOGPROBS})
|
|
134
|
+
prompt = inputs.prompt if isinstance(inputs, Inputs) else str(inputs)
|
|
135
|
+
return self._logprobs_fn(
|
|
136
|
+
prompt, model=self.spec.hf_repo or self.spec.key, **self._media(inputs), **kwargs
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
def _media(self, inputs: Any) -> dict:
|
|
140
|
+
"""The filled media slots of *inputs* that the spec declares.
|
|
141
|
+
|
|
142
|
+
``image`` / ``audio`` go to ``generate_fn`` / ``logprobs_fn`` as
|
|
143
|
+
keyword arguments; a text-only spec never forwards them, and a slot
|
|
144
|
+
the case leaves empty is not sent. Without this the api backend
|
|
145
|
+
answered every VLM/ALM case from the prompt alone.
|
|
146
|
+
"""
|
|
147
|
+
if not isinstance(inputs, Inputs):
|
|
148
|
+
return {}
|
|
149
|
+
media = {}
|
|
150
|
+
if "image" in self.modalities and inputs.image is not None:
|
|
151
|
+
media["image"] = inputs.image
|
|
152
|
+
if "audio" in self.modalities and inputs.audio is not None:
|
|
153
|
+
media["audio"] = inputs.audio
|
|
154
|
+
return media
|
|
155
|
+
|
|
156
|
+
def forward(self, inputs: Any, capture: set[Capability], spec=None) -> Trace:
|
|
157
|
+
missing = set(capture) & _WHITEBOX
|
|
158
|
+
raise CapabilityError(analyzer="forward", model=repr(self), missing=missing or set(capture))
|
|
159
|
+
|
|
160
|
+
def __repr__(self) -> str:
|
|
161
|
+
return f"APIModel(key={self.spec.key!r}, caps={sorted(c.value for c in self.capabilities)})"
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class APIBackend(Backend):
|
|
165
|
+
kind = "api"
|
|
166
|
+
capabilities = frozenset({Capability.GENERATE, Capability.TOOL_CALLS, Capability.LOGPROBS})
|
|
167
|
+
|
|
168
|
+
def build(self, spec, runtime: RuntimeConfig) -> APIModel:
|
|
169
|
+
return APIModel(spec, runtime)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Backend — a runtime that turns a ModelSpec into a Model.
|
|
2
|
+
|
|
3
|
+
The orthogonal decomposition: **capabilities come from the backend**,
|
|
4
|
+
**identity comes from the spec**. The same :class:`~evalrx.core.spec.ModelSpec`
|
|
5
|
+
drives an API call (``api``), a high-throughput logprob batch (``vllm_offline``),
|
|
6
|
+
or a full internals capture (``hf_local``) — only the capability set differs.
|
|
7
|
+
|
|
8
|
+
This module is torch-free; concrete backends import their heavy deps lazily.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from abc import ABC, abstractmethod
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from typing import TYPE_CHECKING, Any, Callable, Optional
|
|
16
|
+
|
|
17
|
+
from evalrx.core.capability import Capability
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from evalrx.core.model import Model
|
|
21
|
+
from evalrx.core.spec import ModelSpec
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class RuntimeConfig:
|
|
26
|
+
"""How to run a model — orthogonal to *which* model (that's the spec)."""
|
|
27
|
+
|
|
28
|
+
device: str = "auto"
|
|
29
|
+
dtype: str = "bfloat16"
|
|
30
|
+
attn_impl: Optional[str] = None # hf_local forces "eager" when attention is wanted
|
|
31
|
+
max_new_tokens: int = 512
|
|
32
|
+
#: hf_local, TEXT-ONLY specs: render ``inputs.prompt`` as one user turn through
|
|
33
|
+
#: the tokenizer's chat template (with ``spec.chat_template_kwargs``, e.g.
|
|
34
|
+
#: ``enable_thinking=False``) before generate()/logprobs(). Off by default: a
|
|
35
|
+
#: raw prompt is tokenised verbatim (completion mode), which is what every
|
|
36
|
+
#: caller got before 2026-08-21 and what a pre-formatted prompt needs. The
|
|
37
|
+
#: multimodal encode path always renders the template.
|
|
38
|
+
apply_chat_template: bool = False
|
|
39
|
+
engine_kwargs: dict[str, Any] = field(default_factory=dict) # vllm_offline LLM(**)
|
|
40
|
+
client_kwargs: dict[str, Any] = field(default_factory=dict) # api client opts (e.g. logprobs=True)
|
|
41
|
+
generate_fn: Optional[Callable[..., str]] = None # api: simple text generate
|
|
42
|
+
chat_fn: Optional[Callable[..., Any]] = None # api: tool-aware chat (returns ChatTurn)
|
|
43
|
+
logprobs_fn: Optional[Callable[..., Any]] = None # api: returns list[TokenLogprob]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Backend(ABC):
|
|
47
|
+
"""Base for runtimes. Declares the capability set it can provide."""
|
|
48
|
+
|
|
49
|
+
kind: str = "base"
|
|
50
|
+
capabilities: frozenset[Capability] = frozenset()
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
def build(self, spec: "ModelSpec", runtime: RuntimeConfig) -> "Model":
|
|
54
|
+
"""Construct a :class:`~evalrx.core.model.Model` for *spec* (lazy load)."""
|
|
55
|
+
|
|
56
|
+
def __repr__(self) -> str: # pragma: no cover - cosmetic
|
|
57
|
+
return f"{type(self).__name__}(kind={self.kind!r})"
|