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,68 @@
|
|
|
1
|
+
"""Skill installation strategies for CLI coding-provider adapters."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import shutil
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SkillInstaller:
|
|
13
|
+
"""Vendor skill directories into a run-local Claude-compatible layout."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, skills: list[str] | tuple[str, ...]) -> None:
|
|
16
|
+
self._skills = list(skills)
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def skills(self) -> list[str]:
|
|
20
|
+
return list(self._skills)
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def enabled(self) -> bool:
|
|
24
|
+
return bool(self._skills)
|
|
25
|
+
|
|
26
|
+
def install(self, workdir: Path) -> None:
|
|
27
|
+
if not self._skills:
|
|
28
|
+
return
|
|
29
|
+
dest_root = workdir / ".claude" / "skills"
|
|
30
|
+
for src in self._skills:
|
|
31
|
+
src_path = Path(src)
|
|
32
|
+
if not src_path.exists() or not src_path.is_dir():
|
|
33
|
+
logger.warning("skill dir not found, skipping: %s", src)
|
|
34
|
+
continue
|
|
35
|
+
try:
|
|
36
|
+
shutil.copytree(src_path, dest_root / src_path.name, dirs_exist_ok=True)
|
|
37
|
+
except OSError as exc:
|
|
38
|
+
logger.warning("could not vendor skill %s: %s", src, exc)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class CodexSkillInstaller(SkillInstaller):
|
|
42
|
+
"""Vendor skills and expose them through AGENTS.md for Codex."""
|
|
43
|
+
|
|
44
|
+
def install(self, workdir: Path) -> None:
|
|
45
|
+
super().install(workdir)
|
|
46
|
+
names = [Path(s).name for s in self._skills if Path(s).is_dir()]
|
|
47
|
+
if not names:
|
|
48
|
+
return
|
|
49
|
+
section = "\n".join([
|
|
50
|
+
"# Agent Skills (vendored)",
|
|
51
|
+
"",
|
|
52
|
+
"Before writing any figure/plot, read and APPLY these style guides:",
|
|
53
|
+
"",
|
|
54
|
+
*[f"- `.claude/skills/{n}/SKILL.md`" for n in names],
|
|
55
|
+
"",
|
|
56
|
+
"They govern chart-type choice and styling only -- never change the "
|
|
57
|
+
"data, the analysis, or the required output format.",
|
|
58
|
+
"",
|
|
59
|
+
])
|
|
60
|
+
agents_md = workdir / "AGENTS.md"
|
|
61
|
+
try:
|
|
62
|
+
existing = (
|
|
63
|
+
agents_md.read_text(encoding="utf-8").rstrip() + "\n\n"
|
|
64
|
+
if agents_md.exists() else ""
|
|
65
|
+
)
|
|
66
|
+
agents_md.write_text(existing + section, encoding="utf-8")
|
|
67
|
+
except OSError as exc:
|
|
68
|
+
logger.warning("could not write AGENTS.md for codex skills: %s", exc)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Prompt addenda for Agent Skill usage."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from evalrx.agent_runtime.cli_types import CliAgentConfig
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def fences_hint(cli_config: "CliAgentConfig | None") -> str:
|
|
13
|
+
if cli_config is not None and cli_config.provider != "llm":
|
|
14
|
+
return ", written to a file named analysis.py"
|
|
15
|
+
return " inside a ```python code block"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def skills_hint(cli_config: "CliAgentConfig | None") -> str:
|
|
19
|
+
"""Prompt addendum steering the agent to apply available Agent Skills."""
|
|
20
|
+
if cli_config is None or not getattr(cli_config, "skills_enabled", False):
|
|
21
|
+
return ""
|
|
22
|
+
|
|
23
|
+
names = [Path(path).name for path in (cli_config.skills or [])]
|
|
24
|
+
is_codex = getattr(cli_config, "provider", "") == "codex"
|
|
25
|
+
|
|
26
|
+
def _use(nlist: list[str]) -> str:
|
|
27
|
+
if not nlist:
|
|
28
|
+
if is_codex:
|
|
29
|
+
return (
|
|
30
|
+
"read the vendored guides under `.claude/skills/` "
|
|
31
|
+
"(also listed in AGENTS.md) and apply them"
|
|
32
|
+
)
|
|
33
|
+
return "invoke any installed Agent Skills via the Skill tool and follow them"
|
|
34
|
+
if is_codex:
|
|
35
|
+
refs = ", ".join(f"`.claude/skills/{name}/SKILL.md`" for name in nlist)
|
|
36
|
+
return f"read the vendored guides ({refs} -- also listed in AGENTS.md) and apply them"
|
|
37
|
+
listed = ", ".join(f"`/{name}`" for name in nlist)
|
|
38
|
+
return f"invoke the {listed} skill(s) via the Skill tool and follow them"
|
|
39
|
+
|
|
40
|
+
parts: list[str] = []
|
|
41
|
+
|
|
42
|
+
if "outcome-driver-analysis" in names:
|
|
43
|
+
parts.append(
|
|
44
|
+
"ANALYSIS METHOD: BEFORE writing any analysis code, "
|
|
45
|
+
+ _use(["outcome-driver-analysis"])
|
|
46
|
+
+ " to choose justified statistical methods for the outcome analysis: "
|
|
47
|
+
"explanatory-variable EDA, per-variable tests WITH effect sizes, "
|
|
48
|
+
"conditioning/confounding (Simpson's) checks, marginal screening, a "
|
|
49
|
+
"justified regression model (state the GLM-vs-mixed-effects reasoning "
|
|
50
|
+
"from the ACTUAL clustering structure -- with very few clusters prefer "
|
|
51
|
+
"a fixed effect over a random effect), and fit diagnostics "
|
|
52
|
+
"(collinearity/VIF, discrimination, calibration). Adopt its "
|
|
53
|
+
"METHODOLOGY, not its file layout or report template -- every output "
|
|
54
|
+
"still flows into the required result-JSON contract, and intake "
|
|
55
|
+
"answers are inferred from the data profile and the question (never "
|
|
56
|
+
"stop to ask). Keep all wording DESCRIPTIVE: takeaways carry effect "
|
|
57
|
+
"sizes + confidence intervals + direction; test statistics/p-values "
|
|
58
|
+
"belong in tables/artifacts and must NOT be phrased as significance "
|
|
59
|
+
"or confirmation verdicts -- validity is adjudicated downstream."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
style = [name for name in names if name != "outcome-driver-analysis"]
|
|
63
|
+
roles = []
|
|
64
|
+
if "eval-chart-style" in style:
|
|
65
|
+
roles.append(
|
|
66
|
+
"`eval-chart-style` governs chart-TYPE choice (distribution-first: "
|
|
67
|
+
"violin/ECDF/heatmap/forest/paired-slope -- never a mean as a bar) and "
|
|
68
|
+
"the palette: FAIL/PASS semantic hues, a categorical series order for "
|
|
69
|
+
"non-outcome dimensions, and single-hue ramps for ordered dimensions "
|
|
70
|
+
"(e.g. model sizes). When any other skill suggests a specific chart "
|
|
71
|
+
"type or color, eval-chart-style's policy and palette take precedence"
|
|
72
|
+
)
|
|
73
|
+
if "nature-figure" in style:
|
|
74
|
+
roles.append("`nature-figure` adds publication-grade matplotlib polish")
|
|
75
|
+
role_line = ("; ".join(roles) + ". ") if roles else ""
|
|
76
|
+
parts.append(
|
|
77
|
+
"FIGURE STYLING: Agent Skills are available -- apply them BY DEFAULT to "
|
|
78
|
+
f"every plot you write under figures/: BEFORE plotting, {_use(style)}. "
|
|
79
|
+
f"{role_line}"
|
|
80
|
+
"This is a non-interactive PYTHON analysis: if a skill asks you to choose "
|
|
81
|
+
"a plotting backend, choose Python and proceed without pausing -- never "
|
|
82
|
+
"stop to ask a question. Use skills for styling only -- they must not "
|
|
83
|
+
"change the data, the analysis, the sandbox workflow, or the final "
|
|
84
|
+
"result JSON."
|
|
85
|
+
)
|
|
86
|
+
return "\n" + "\n\n".join(parts) + "\n"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Resolve bundled and explicitly configured Agent Skills."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from evalrx.agent_assets.skills import SKILL_BACKENDS, bundled_skill_paths
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def resolve_skill_paths(
|
|
9
|
+
*,
|
|
10
|
+
provider: str,
|
|
11
|
+
explicit: list[str] | tuple[str, ...] = (),
|
|
12
|
+
use_bundled: bool = True,
|
|
13
|
+
) -> tuple[str, ...]:
|
|
14
|
+
"""Return ordered skill dirs for a provider, de-duplicating explicit repeats."""
|
|
15
|
+
skill_dirs = list(explicit or [])
|
|
16
|
+
if use_bundled and provider in SKILL_BACKENDS:
|
|
17
|
+
bundled = [path for path in bundled_skill_paths() if path not in skill_dirs]
|
|
18
|
+
skill_dirs = bundled + skill_dirs
|
|
19
|
+
return tuple(skill_dirs)
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Public data-analysis API: exploratory analysis, hypothesis proposal, and
|
|
2
|
+
statistical confirmation.
|
|
3
|
+
|
|
4
|
+
This package exposes EvalRX' data-analysis layer as a standalone
|
|
5
|
+
capability — ``ExploratoryAnalysisAgent`` (M2) for descriptive EDA (no
|
|
6
|
+
hypothesis generation or validation itself), ``HypothesisAgent`` (M3) for
|
|
7
|
+
proposing falsifiable hypotheses from M2's takeaways (proposal only, no
|
|
8
|
+
validation), and ``StatsAnalysisAgent`` for confirmatory effect/CI/e-value/FDR
|
|
9
|
+
verdicts. The eval-agent loops still use the same implementation internally,
|
|
10
|
+
but callers do not need to import from ``evalrx.eval_agent.stages``.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from evalrx.analysis.adjudicate import adjudicate_report, adjudicate_signals
|
|
14
|
+
from evalrx.analysis.api import ExploreRunResult, explore
|
|
15
|
+
from evalrx.analysis.explorer import (
|
|
16
|
+
CandidateSignal,
|
|
17
|
+
ExploratoryAnalysisAgent,
|
|
18
|
+
ExploratoryAnalysisReport,
|
|
19
|
+
Takeaway,
|
|
20
|
+
load_records_from_path,
|
|
21
|
+
scan_folder,
|
|
22
|
+
)
|
|
23
|
+
from evalrx.analysis.failure_modes import FailureMode, FailureModeReport, cluster_failures
|
|
24
|
+
from evalrx.analysis.fused_pipeline import (
|
|
25
|
+
FusedReport,
|
|
26
|
+
FusedSignal,
|
|
27
|
+
run_fused_analysis,
|
|
28
|
+
)
|
|
29
|
+
from evalrx.analysis.hypothesis_agent import Hypothesis, HypothesisAgent
|
|
30
|
+
from evalrx.analysis.operationalize import (
|
|
31
|
+
RecipeError,
|
|
32
|
+
SignalRecipe,
|
|
33
|
+
bridge_recipes_to_result,
|
|
34
|
+
compile_recipe,
|
|
35
|
+
compile_recipes,
|
|
36
|
+
per_case_finding,
|
|
37
|
+
per_case_to_records,
|
|
38
|
+
safe_ident,
|
|
39
|
+
)
|
|
40
|
+
from evalrx.analysis.planner import AnalysisPlanItem, plan_stats_input, ranked_signal_names
|
|
41
|
+
from evalrx.analysis.profile import (
|
|
42
|
+
ColumnProfile,
|
|
43
|
+
DatasetProfile,
|
|
44
|
+
describe_outcome,
|
|
45
|
+
profile_records,
|
|
46
|
+
profile_stats_input,
|
|
47
|
+
)
|
|
48
|
+
from evalrx.analysis.run_codebase import CodebaseRunResult, run_codebase, run_codebase_cli
|
|
49
|
+
from evalrx.analysis.stats_agent import StatsAnalysisAgent, StatsAnalysisReport
|
|
50
|
+
from evalrx.analysis.stats_tools import (
|
|
51
|
+
STATS_TOOL_CATALOG,
|
|
52
|
+
EvidenceResult,
|
|
53
|
+
StatsInput,
|
|
54
|
+
StatsToolResult,
|
|
55
|
+
build_stats_input,
|
|
56
|
+
build_stats_input_from_records,
|
|
57
|
+
default_plan,
|
|
58
|
+
fdr_correct,
|
|
59
|
+
run_stats_tool,
|
|
60
|
+
)
|
|
61
|
+
from evalrx.analysis.workbench import (
|
|
62
|
+
DatasetBundle,
|
|
63
|
+
EventSink,
|
|
64
|
+
ThreadStore,
|
|
65
|
+
UploadLimits,
|
|
66
|
+
extract_archive,
|
|
67
|
+
ingest_directory,
|
|
68
|
+
)
|
|
69
|
+
from evalrx.reporting.compiler import compile_diagnostic_report
|
|
70
|
+
from evalrx.reporting.model import Claim, DiagnosticReport, Evidence, ReportStep
|
|
71
|
+
|
|
72
|
+
__all__ = [
|
|
73
|
+
"explore",
|
|
74
|
+
"ExploreRunResult",
|
|
75
|
+
"run_codebase",
|
|
76
|
+
"run_codebase_cli",
|
|
77
|
+
"CodebaseRunResult",
|
|
78
|
+
"cluster_failures",
|
|
79
|
+
"FailureMode",
|
|
80
|
+
"FailureModeReport",
|
|
81
|
+
"StatsAnalysisAgent",
|
|
82
|
+
"StatsAnalysisReport",
|
|
83
|
+
"ExploratoryAnalysisAgent",
|
|
84
|
+
"ExploratoryAnalysisReport",
|
|
85
|
+
"Takeaway",
|
|
86
|
+
"CandidateSignal",
|
|
87
|
+
"Hypothesis",
|
|
88
|
+
"HypothesisAgent",
|
|
89
|
+
"adjudicate_report",
|
|
90
|
+
"adjudicate_signals",
|
|
91
|
+
"SignalRecipe",
|
|
92
|
+
"compile_recipe",
|
|
93
|
+
"compile_recipes",
|
|
94
|
+
"per_case_finding",
|
|
95
|
+
"per_case_to_records",
|
|
96
|
+
"bridge_recipes_to_result",
|
|
97
|
+
"safe_ident",
|
|
98
|
+
"RecipeError",
|
|
99
|
+
"ColumnProfile",
|
|
100
|
+
"DatasetProfile",
|
|
101
|
+
"describe_outcome",
|
|
102
|
+
"profile_records",
|
|
103
|
+
"profile_stats_input",
|
|
104
|
+
"AnalysisPlanItem",
|
|
105
|
+
"ranked_signal_names",
|
|
106
|
+
"plan_stats_input",
|
|
107
|
+
"run_fused_analysis",
|
|
108
|
+
"FusedReport",
|
|
109
|
+
"FusedSignal",
|
|
110
|
+
"DiagnosticReport",
|
|
111
|
+
"Claim",
|
|
112
|
+
"Evidence",
|
|
113
|
+
"ReportStep",
|
|
114
|
+
"compile_diagnostic_report",
|
|
115
|
+
"load_records_from_path",
|
|
116
|
+
"scan_folder",
|
|
117
|
+
"StatsInput",
|
|
118
|
+
"StatsToolResult",
|
|
119
|
+
"EvidenceResult",
|
|
120
|
+
"STATS_TOOL_CATALOG",
|
|
121
|
+
"build_stats_input",
|
|
122
|
+
"build_stats_input_from_records",
|
|
123
|
+
"default_plan",
|
|
124
|
+
"fdr_correct",
|
|
125
|
+
"run_stats_tool",
|
|
126
|
+
"DatasetBundle",
|
|
127
|
+
"EventSink",
|
|
128
|
+
"ThreadStore",
|
|
129
|
+
"UploadLimits",
|
|
130
|
+
"extract_archive",
|
|
131
|
+
"ingest_directory",
|
|
132
|
+
]
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Host-side adjudication of explorer candidate signals (the firewall).
|
|
2
|
+
|
|
3
|
+
The :mod:`~evalrx.analysis.explorer` PROPOSES candidate signals; it has no
|
|
4
|
+
authority to declare significance. This module is the host firewall: it takes the
|
|
5
|
+
host-adjudicable ``sufficient`` statistics an explorer attached to a candidate and
|
|
6
|
+
recomputes the verdict with the SAME validated, multiplicity-aware core the M2
|
|
7
|
+
stats engine uses — never trusting a ``reject`` / ``e_value`` / ``p_value`` the
|
|
8
|
+
explorer self-declared (the explorer schema does not even carry one).
|
|
9
|
+
|
|
10
|
+
Mechanics (mirror ``stats_tools`` / ``stats_tool_generator`` exactly):
|
|
11
|
+
|
|
12
|
+
- ``_reconstruct_decision`` turns sufficient statistics into
|
|
13
|
+
``(reject, e_value, effect, ci)`` via the validated core.
|
|
14
|
+
- ``fdr_correct`` applies e-BH across every candidate that produced an e-value
|
|
15
|
+
(the ``paired_binary`` shape), so proposing more candidates pays more
|
|
16
|
+
multiplicity — exactly one e-BH family, no per-candidate self-rejection.
|
|
17
|
+
- A ``two_group`` candidate yields a bootstrap-CI reject but no e-value (matching
|
|
18
|
+
the ``signal_label_assoc`` catalog tool). It is host-adjudicated but sits
|
|
19
|
+
OUTSIDE the e-BH family and is flagged ``fdr_corrected=False`` — honest, not
|
|
20
|
+
over-claimed.
|
|
21
|
+
- A candidate with no adjudicable ``sufficient`` is ``descriptive_only`` and never
|
|
22
|
+
rejects.
|
|
23
|
+
|
|
24
|
+
IMPORTANT — split discipline: in the standalone chat path the candidate's
|
|
25
|
+
``sufficient`` is computed on the SAME rows used to discover the signal. That is
|
|
26
|
+
IN-SAMPLE; ``split_label`` records it so nothing over-claims, and an honest caveat
|
|
27
|
+
is appended. Held-out CONFIRM-split adjudication (selecting on EXPLORE, computing
|
|
28
|
+
each e-value on a disjoint CONFIRM split) is the job of the fused pipeline
|
|
29
|
+
(Phase B). This module supplies only the verdict mechanism.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
from typing import TYPE_CHECKING, Any
|
|
35
|
+
|
|
36
|
+
from evalrx.analysis.stats_tool_generator import _reconstruct_decision
|
|
37
|
+
from evalrx.analysis.stats_tools import StatsToolResult, fdr_correct
|
|
38
|
+
|
|
39
|
+
if TYPE_CHECKING:
|
|
40
|
+
from evalrx.analysis.explorer import CandidateSignal, ExploratoryAnalysisReport
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _family_key(candidate: "CandidateSignal", index: int) -> str:
|
|
44
|
+
"""Stable, unique key so an e-BH rejection maps back to the right candidate
|
|
45
|
+
even when two candidates share a name."""
|
|
46
|
+
return f"{candidate.name or 'signal'}#{index}"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def adjudicate_signals(
|
|
50
|
+
candidates: "list[CandidateSignal]",
|
|
51
|
+
*,
|
|
52
|
+
alpha: float = 0.05,
|
|
53
|
+
split_label: str = "in_sample",
|
|
54
|
+
) -> dict[str, Any]:
|
|
55
|
+
"""Annotate each candidate IN PLACE with a host verdict; return family metadata.
|
|
56
|
+
|
|
57
|
+
Reads only ``candidate.sufficient`` — never a self-declared verdict. Returns a
|
|
58
|
+
metadata dict describing the single e-BH family the candidates competed in.
|
|
59
|
+
"""
|
|
60
|
+
# 1) Host reconstruction per candidate; assemble the e-BH family from the
|
|
61
|
+
# candidates that produced an e-value (paired_binary).
|
|
62
|
+
raw_reject: dict[int, bool] = {}
|
|
63
|
+
family: list[StatsToolResult] = []
|
|
64
|
+
family_key: dict[int, str] = {}
|
|
65
|
+
for i, c in enumerate(candidates):
|
|
66
|
+
recon = (
|
|
67
|
+
_reconstruct_decision(c.sufficient, alpha)
|
|
68
|
+
if isinstance(c.sufficient, dict)
|
|
69
|
+
else None
|
|
70
|
+
)
|
|
71
|
+
if recon is None:
|
|
72
|
+
c.host_adjudicated = False
|
|
73
|
+
c.descriptive_only = True
|
|
74
|
+
c.fdr_corrected = False
|
|
75
|
+
c.e_value = None
|
|
76
|
+
c.reject = False
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
reject, e_value, effect, ci = recon
|
|
80
|
+
c.host_adjudicated = True
|
|
81
|
+
c.descriptive_only = False
|
|
82
|
+
c.e_value = e_value
|
|
83
|
+
if effect is not None:
|
|
84
|
+
c.effect = effect
|
|
85
|
+
if ci is not None:
|
|
86
|
+
c.ci = ci
|
|
87
|
+
raw_reject[i] = bool(reject)
|
|
88
|
+
if e_value is not None:
|
|
89
|
+
key = _family_key(c, i)
|
|
90
|
+
family_key[i] = key
|
|
91
|
+
family.append(
|
|
92
|
+
StatsToolResult(
|
|
93
|
+
tool=key, e_value=e_value, effect=effect, ci=ci, reject=bool(reject)
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# 2) ONE e-BH family across the e-value-bearing candidates (the multiplicity
|
|
98
|
+
# firewall). `fdr_correct` only considers results with an e-value.
|
|
99
|
+
fdr = fdr_correct(family, alpha=alpha)
|
|
100
|
+
rejected_keys = set(fdr.get("rejected_tools", []))
|
|
101
|
+
|
|
102
|
+
# 3) Final reject per candidate.
|
|
103
|
+
for i, c in enumerate(candidates):
|
|
104
|
+
if not c.host_adjudicated:
|
|
105
|
+
continue
|
|
106
|
+
if c.e_value is not None:
|
|
107
|
+
# In the e-BH family. `reject` IS the e-BH outcome; `fdr_corrected`
|
|
108
|
+
# means "this rejection is FDR-controlled" — True ONLY when it survived
|
|
109
|
+
# e-BH (matches fused_pipeline; a family member that did not survive is
|
|
110
|
+
# reject=False, fdr_corrected=False). Family membership is recoverable
|
|
111
|
+
# from `e_value is not None`, so no information is lost.
|
|
112
|
+
c.reject = family_key.get(i) in rejected_keys
|
|
113
|
+
c.fdr_corrected = bool(c.reject)
|
|
114
|
+
else:
|
|
115
|
+
# two_group: CI-based reject, outside the e-BH family (mirrors M2's
|
|
116
|
+
# signal_label_assoc). Honest about not being FDR-corrected.
|
|
117
|
+
c.fdr_corrected = False
|
|
118
|
+
c.reject = raw_reject.get(i, False)
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
"method": "e-BH",
|
|
122
|
+
"alpha": alpha,
|
|
123
|
+
"split": split_label,
|
|
124
|
+
"n_candidates": len(candidates),
|
|
125
|
+
"n_host_adjudicated": sum(1 for c in candidates if c.host_adjudicated),
|
|
126
|
+
"n_in_family": len(family), # e-value-bearing candidates under e-BH
|
|
127
|
+
"n_rejected": sum(1 for c in candidates if c.reject),
|
|
128
|
+
"rejected": [c.name for c in candidates if c.reject],
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def adjudicate_report(
|
|
133
|
+
report: "ExploratoryAnalysisReport",
|
|
134
|
+
*,
|
|
135
|
+
alpha: float = 0.05,
|
|
136
|
+
split_label: str = "in_sample",
|
|
137
|
+
) -> "ExploratoryAnalysisReport":
|
|
138
|
+
"""Run :func:`adjudicate_signals` over a report's candidates, record metadata.
|
|
139
|
+
|
|
140
|
+
Mutates and returns *report*. Appends an honest caveat when any verdict is
|
|
141
|
+
in-sample (no held-out CONFIRM split was used to compute the e-values).
|
|
142
|
+
"""
|
|
143
|
+
meta = adjudicate_signals(
|
|
144
|
+
report.candidate_signals, alpha=alpha, split_label=split_label
|
|
145
|
+
)
|
|
146
|
+
report.adjudication = meta
|
|
147
|
+
if meta["n_host_adjudicated"] and split_label == "in_sample":
|
|
148
|
+
caveat = (
|
|
149
|
+
"host verdicts are IN-SAMPLE (computed on the rows used to discover "
|
|
150
|
+
"the signal); confirm on a held-out split before trusting"
|
|
151
|
+
)
|
|
152
|
+
if caveat not in report.caveats:
|
|
153
|
+
report.caveats.append(caveat)
|
|
154
|
+
return report
|