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,187 @@
|
|
|
1
|
+
"""Intervention-space tiers for the fix module (post-loop repair).
|
|
2
|
+
|
|
3
|
+
A *fix tier* names the space a candidate repair intervenes in. The ladder is
|
|
4
|
+
ordered by invasiveness into the model — each step gives up some deployability
|
|
5
|
+
for more causal reach:
|
|
6
|
+
|
|
7
|
+
L0 runtime config decoding limits / retry and timeout policy
|
|
8
|
+
L1 input space prompt rewrites, instruction strategies
|
|
9
|
+
L2 scaffold space agent-designed pipelines around the unchanged
|
|
10
|
+
model: multi-call, external tools (zoom, contrast
|
|
11
|
+
enhancement, …), aggregation
|
|
12
|
+
L3a internals (read) read attention/logits to guide scaffold actions
|
|
13
|
+
(attention-guided crop, contrastive decoding,
|
|
14
|
+
confidence routing)
|
|
15
|
+
L3b internals (write) modify the forward pass: attention reweighting,
|
|
16
|
+
sink suppression, activation steering
|
|
17
|
+
L4 parameter space build a dataset, fine-tune, re-test
|
|
18
|
+
|
|
19
|
+
The allowed tier is an **input** to the fix module (default L2) — there is no
|
|
20
|
+
automatic escalation. When every candidate within the allowed tier fails
|
|
21
|
+
validation, the fix module *recommends* raising the tier instead, routed from
|
|
22
|
+
the verified hypotheses via :func:`route_min_tier`.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import re
|
|
28
|
+
from enum import IntEnum
|
|
29
|
+
from typing import TYPE_CHECKING
|
|
30
|
+
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
from evalrx.eval_agent.hypothesis import Hypothesis
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class FixTier(IntEnum):
|
|
36
|
+
"""Where a candidate fix intervenes, ordered by invasiveness."""
|
|
37
|
+
|
|
38
|
+
L0_RUNTIME_CONFIG = 0
|
|
39
|
+
L1_PROMPT = 1
|
|
40
|
+
L2_SCAFFOLD = 2
|
|
41
|
+
L3A_INTERNALS_READ = 3
|
|
42
|
+
L3B_INTERNALS_WRITE = 4
|
|
43
|
+
L4_PARAMETERS = 5
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def label(self) -> str:
|
|
47
|
+
return _LABELS[self]
|
|
48
|
+
|
|
49
|
+
def describe(self) -> str:
|
|
50
|
+
return f"{self.label} ({_DESCRIPTIONS[self]})"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
_LABELS = {
|
|
54
|
+
FixTier.L0_RUNTIME_CONFIG: "L0",
|
|
55
|
+
FixTier.L1_PROMPT: "L1",
|
|
56
|
+
FixTier.L2_SCAFFOLD: "L2",
|
|
57
|
+
FixTier.L3A_INTERNALS_READ: "L3a",
|
|
58
|
+
FixTier.L3B_INTERNALS_WRITE: "L3b",
|
|
59
|
+
FixTier.L4_PARAMETERS: "L4",
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
_DESCRIPTIONS = {
|
|
63
|
+
FixTier.L0_RUNTIME_CONFIG: "runtime configuration: decoding limits / retry policy",
|
|
64
|
+
FixTier.L1_PROMPT: "input space: prompt/instruction changes",
|
|
65
|
+
FixTier.L2_SCAFFOLD: "scaffold space: pipelines + external tools around the model",
|
|
66
|
+
FixTier.L3A_INTERNALS_READ: "internals, read-only: attention/logits guide the scaffold",
|
|
67
|
+
FixTier.L3B_INTERNALS_WRITE: "internals, write: attention/activation modification",
|
|
68
|
+
FixTier.L4_PARAMETERS: "parameter space: dataset construction + fine-tuning",
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_PARSE = {
|
|
72
|
+
"l0": FixTier.L0_RUNTIME_CONFIG,
|
|
73
|
+
"l1": FixTier.L1_PROMPT,
|
|
74
|
+
"l2": FixTier.L2_SCAFFOLD,
|
|
75
|
+
"l3a": FixTier.L3A_INTERNALS_READ,
|
|
76
|
+
"l3b": FixTier.L3B_INTERNALS_WRITE,
|
|
77
|
+
"l3": FixTier.L3A_INTERNALS_READ, # bare "L3" means the read side
|
|
78
|
+
"l4": FixTier.L4_PARAMETERS,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def parse_tier(value: "str | FixTier") -> FixTier:
|
|
83
|
+
"""Parse ``"L1"``/``"l3a"``/… (or pass through a :class:`FixTier`)."""
|
|
84
|
+
if isinstance(value, FixTier):
|
|
85
|
+
return value
|
|
86
|
+
key = str(value).strip().lower()
|
|
87
|
+
if key not in _PARSE:
|
|
88
|
+
raise ValueError(
|
|
89
|
+
f"unknown fix tier {value!r}; expected one of "
|
|
90
|
+
f"{sorted({t.label for t in FixTier})}"
|
|
91
|
+
)
|
|
92
|
+
return _PARSE[key]
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# ---------------------------------------------------------------------------
|
|
96
|
+
# Hypothesis → minimum effective tier routing
|
|
97
|
+
# ---------------------------------------------------------------------------
|
|
98
|
+
# A hypothesis's verified mechanism tells you the *space* the failure lives in,
|
|
99
|
+
# hence the minimum tier whose interventions can causally address it. Routing
|
|
100
|
+
# prefers an explicit, structured signal (``hypothesis.metadata["fix_tier"]`` or
|
|
101
|
+
# ``["intervention_space"]``) — that is the mechanism, not its phrasing. Only
|
|
102
|
+
# when no structured field is present does it fall back to keyword matching.
|
|
103
|
+
#
|
|
104
|
+
# Keyword fallback, ordered most-invasive-first so specific vocabulary
|
|
105
|
+
# ("suppress attention sink") wins over generic vocabulary ("attention"). Two
|
|
106
|
+
# precautions distinguish a mechanism from a passing mention of its words:
|
|
107
|
+
# * stems are matched at a word boundary (``\bcrop``), so "constraint" no
|
|
108
|
+
# longer matches the L4 stem "train" mid-word;
|
|
109
|
+
# * negated qualifiers ("training-free", "without fine-tuning", "no retraining")
|
|
110
|
+
# are stripped first — they assert the OPPOSITE of needing that tier.
|
|
111
|
+
|
|
112
|
+
_TIER_KEYWORDS: "list[tuple[FixTier, tuple[str, ...]]]" = [
|
|
113
|
+
(FixTier.L4_PARAMETERS, (
|
|
114
|
+
"train", "finetun", "fine-tun", "retrain", "pretrain", "lora",
|
|
115
|
+
"knowledge gap", "frequency prior", "language prior", "memoriz",
|
|
116
|
+
"dataset bias",
|
|
117
|
+
)),
|
|
118
|
+
(FixTier.L3B_INTERNALS_WRITE, (
|
|
119
|
+
"suppress", "steer", "reweight", "re-weight", "knockout",
|
|
120
|
+
"activation patch", "modify attention", "edit attention",
|
|
121
|
+
"attention interven",
|
|
122
|
+
)),
|
|
123
|
+
(FixTier.L3A_INTERNALS_READ, (
|
|
124
|
+
"attention", "logit", "logprob", "contrastive decoding", "vcd",
|
|
125
|
+
"hidden state", "internal", "entropy", "sink",
|
|
126
|
+
)),
|
|
127
|
+
(FixTier.L2_SCAFFOLD, (
|
|
128
|
+
"resolution", "downsampl", "image token", "patch grid", "zoom",
|
|
129
|
+
"crop", "contrast", "conspicuity", "small", "subtle", "low-contrast",
|
|
130
|
+
"preprocess", "multi-call", "pipeline", "tool", "enhanc",
|
|
131
|
+
)),
|
|
132
|
+
(FixTier.L0_RUNTIME_CONFIG, (
|
|
133
|
+
"truncat", "finish reason", "finish_reason", "token budget",
|
|
134
|
+
"max token", "max_tokens", "output limit", "decode limit",
|
|
135
|
+
"completion length", "stopped early", "timeout", "rate limit",
|
|
136
|
+
)),
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
# Phrases that NEGATE a tier's vocabulary ("training-free" ≠ "needs training").
|
|
140
|
+
# Stripped before keyword matching so the negated stem cannot route upward.
|
|
141
|
+
_NEGATION_PATTERNS = (
|
|
142
|
+
re.compile(r"\b(?:training|train|fine[- ]?tun\w*|finetun\w*|retrain\w*)[- ]free\b"),
|
|
143
|
+
re.compile(r"\b(?:without|no|avoid(?:s|ing)?|skip(?:s|ping)?|free of)\s+"
|
|
144
|
+
r"(?:any\s+|re-?\s*)?(?:training|fine[- ]?tuning|finetuning|retraining)\b"),
|
|
145
|
+
re.compile(r"\b(?:does not|doesn't|do not|don't|cannot|can't|won't|will not|"
|
|
146
|
+
r"no need to|without needing to)\s+(?:require\s+|need\s+|involve\s+)?"
|
|
147
|
+
r"(?:any\s+)?(?:re-?\s*)?(?:train\w*|fine[- ]?tun\w*|finetun\w*)\b"),
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Compiled stem matchers: a word boundary before the stem, suffix free after.
|
|
151
|
+
_TIER_PATTERNS: "list[tuple[FixTier, tuple[tuple[str, re.Pattern[str]], ...]]]" = [
|
|
152
|
+
(tier, tuple((kw, re.compile(r"\b" + re.escape(kw))) for kw in keywords))
|
|
153
|
+
for tier, keywords in _TIER_KEYWORDS
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def route_min_tier(hypothesis: "Hypothesis") -> "tuple[FixTier, str]":
|
|
158
|
+
"""Return the minimum tier that can causally address *hypothesis*.
|
|
159
|
+
|
|
160
|
+
Order of precedence:
|
|
161
|
+
|
|
162
|
+
1. An explicit ``hypothesis.metadata["fix_tier"]`` / ``["intervention_space"]``
|
|
163
|
+
— the structured mechanism wins over any prose.
|
|
164
|
+
2. Keyword fallback over ``predicted_failure_mode`` + ``statement`` +
|
|
165
|
+
``test_design`` (negation-stripped, word-boundary-anchored).
|
|
166
|
+
3. L1 (cheapest first) when nothing matches.
|
|
167
|
+
"""
|
|
168
|
+
meta = getattr(hypothesis, "metadata", None) or {}
|
|
169
|
+
explicit = meta.get("fix_tier") or meta.get("intervention_space")
|
|
170
|
+
if explicit:
|
|
171
|
+
try:
|
|
172
|
+
tier = parse_tier(explicit)
|
|
173
|
+
return tier, f"explicit metadata fix_tier={explicit!r} -> {tier.label}"
|
|
174
|
+
except ValueError:
|
|
175
|
+
pass # malformed hint — fall through to keyword routing
|
|
176
|
+
|
|
177
|
+
text = " ".join(
|
|
178
|
+
str(getattr(hypothesis, attr, "") or "")
|
|
179
|
+
for attr in ("predicted_failure_mode", "statement", "test_design")
|
|
180
|
+
).lower()
|
|
181
|
+
for pat in _NEGATION_PATTERNS:
|
|
182
|
+
text = pat.sub(" ", text)
|
|
183
|
+
for tier, patterns in _TIER_PATTERNS:
|
|
184
|
+
hits = [kw for kw, pat in patterns if pat.search(text)]
|
|
185
|
+
if hits:
|
|
186
|
+
return tier, f"matched {hits[:3]} -> {tier.label}"
|
|
187
|
+
return FixTier.L1_PROMPT, "no mechanism keywords matched -> L1 (cheapest first)"
|