Skip to content

Commit 79b61b2

Browse files
feat(agent): expand agent-native tooling and schemas
1 parent 52d376f commit 79b61b2

72 files changed

Lines changed: 126986 additions & 9758 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ All notable changes to StatsPAI will be documented in this file.
3232
`sp.llm_dag_propose` (and friends) can reuse the connected agent's own
3333
model with no extra API key, falling back to the deterministic heuristic
3434
when sampling is unavailable.
35+
- **`interpret_result` MCP tool** — natural-language explanation of a
36+
fitted result from its cached handle. Wires `resolve_llm_client()` into
37+
the server's tool-dispatch path: when the client advertised sampling it
38+
reuses the agent's own model (grounded in the result's own numbers — the
39+
model is told not to invent estimates), and degrades to a deterministic
40+
structured brief otherwise. Mid-call sampling failures fall back loudly
41+
(the error is surfaced in `sampling_error`, never swallowed). Optional
42+
`question` / `audience` knobs; exposed as a dataless tool so strict-schema
43+
clients dispatch it without a `data_path`.
3544
- **Auto-tool citation enrichment**`_enrichment.build_citations` now
3645
falls back to verified citation tokens in a function's registry
3746
`reference` field, so hundreds of carded estimators carry citations in

docs/agent_cards_spec.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ nothing.
196196
The floor in
197197
[`scripts/agent_card_coverage_floor.json`](../scripts/agent_card_coverage_floor.json)
198198
tracks 15 counters: per-tier totals + per-field counts + per-validation-status
199-
counts for `certified` / `validated`. Each may only go up. To
199+
counts for `certified` / `validated-or-better`. Each may only go up. To
200200
intentionally raise the bar, run:
201201

202202
```bash

docs/cookbook.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Cookbook — recipes by research question
2+
3+
Find the method by the question you are actually asking, not by its textbook
4+
name. Each recipe is a minimal, runnable starting point; follow the linked
5+
guide or [API reference](reference/api/index.md) for the full options.
6+
7+
!!! tip "Let StatsPAI choose"
8+
If you are unsure, `sp.recommend(df, y=..., treat=...)` and
9+
`sp.detect_design(df)` will suggest an estimator from the data shape.
10+
11+
---
12+
13+
## "A policy turned on for different units at different times"
14+
15+
Staggered-adoption difference-in-differences. Two-way fixed effects is biased
16+
here; use a heterogeneity-robust estimator.
17+
18+
```python
19+
import statspai as sp
20+
df = sp.datasets.mpdta()
21+
r = sp.callaway_santanna(df, y="lemp", g="first_treat", t="year", i="countyreal")
22+
r.summary()
23+
```
24+
25+
[Choosing a DID estimator](guides/choosing_did_estimator.md) ·
26+
[Callaway–Sant'Anna guide](guides/callaway_santanna.md)
27+
28+
## "One unit got treated and I have many untreated comparison units"
29+
30+
Synthetic control — build a weighted combination of donors that tracks the
31+
treated unit before treatment.
32+
33+
```python
34+
r = sp.synth(df, y="outcome", unit="state", time="year",
35+
treated="California", treat_period=1989)
36+
r.plot()
37+
```
38+
39+
[Synthetic control guide](guides/synth.md) ·
40+
[`sp.synth` family](reference/synth.md)
41+
42+
## "Treatment is endogenous but I have an instrument"
43+
44+
Instrumental variables. Check the first stage before trusting the estimate.
45+
46+
```python
47+
data = sp.datasets.card_1995()
48+
r = sp.ivreg("lwage ~ (educ ~ nearc4) + exper + black + south", data=data)
49+
r.summary()
50+
# weak-instrument-robust reporting bundle:
51+
sp.iv_diag(data, y="lwage", endog="educ", instruments="nearc4")
52+
```
53+
54+
[Choosing an IV estimator](guides/choosing_iv_estimator.md) ·
55+
[IV reference](reference/iv.md)
56+
57+
## "Treatment is assigned by a cutoff on a running variable"
58+
59+
Regression discontinuity.
60+
61+
```python
62+
data = sp.datasets.lee_2008_senate()
63+
r = sp.rdrobust(data["vote_t1"], data["margin"], c=0.0)
64+
r.summary()
65+
```
66+
67+
[Choosing an RD estimator](guides/choosing_rd_estimator.md) ·
68+
[RD reference](reference/rd.md)
69+
70+
## "I want the effect for everyone, not just the average (heterogeneity)"
71+
72+
Conditional average treatment effects (CATE) via meta-learners, causal
73+
forest, or double ML.
74+
75+
```python
76+
r = sp.dml(df, y="y", treat="d", covariates=["x1", "x2", "x3"], model="irm")
77+
cate = sp.auto_cate(df, y="y", treat="d", covariates=["x1", "x2", "x3"])
78+
```
79+
80+
[Choosing an ML causal estimator](guides/choosing_ml_causal_estimator.md)
81+
82+
## "I have rich confounders and want a robust observational estimate"
83+
84+
Double/debiased ML or TMLE — both doubly robust, both need overlap.
85+
86+
```python
87+
r = sp.dml(df, y="y", treat="d", covariates=[...], model="irm", ml_g="rf", ml_m="rf")
88+
r = sp.tmle(df, y="y", treat="d", covariates=[...])
89+
```
90+
91+
[`sp.dml` vs DoubleML](guides/sp_dml_vs_doubleml.md)
92+
93+
## "Why is the gap between two groups what it is?" (decomposition)
94+
95+
Oaxaca–Blinder and RIF/recentered-influence-function decompositions.
96+
97+
```python
98+
r = sp.decompose(df, y="wage", group="female", covariates=["edu", "exp"],
99+
method="oaxaca")
100+
```
101+
102+
[Decomposition family](guides/decomposition_family.md) ·
103+
[Decomposition reference](reference/decomposition.md)
104+
105+
## "Match treated and control units on covariates"
106+
107+
Propensity-score / entropy-balancing / optimal matching.
108+
109+
```python
110+
ps = sp.propensity_score(df, treat="d", covariates=["x1", "x2"])
111+
w = sp.ebalance(df, treat="d", covariates=["x1", "x2"]) # entropy balancing
112+
sp.love_plot(sp.balance_diagnostics(df, treat="d", covariates=["x1", "x2"]))
113+
```
114+
115+
[Choosing a matching estimator](guides/choosing_matching_estimator.md)
116+
117+
## "Panel regression with many fixed effects"
118+
119+
reghdfe-style high-dimensional fixed effects.
120+
121+
```python
122+
r = sp.hdfe_ols("y ~ x1 + x2 | firm + year", data=df, cluster="firm")
123+
```
124+
125+
[Panel reference](reference/panel.md)
126+
127+
---
128+
129+
## After any estimate: the agent-native follow-ups
130+
131+
```python
132+
r.summary() # human-readable
133+
r.to_dict() # structured payload for agents
134+
sp.audit(r) # what robustness checks are missing?
135+
r.cite() # verified BibTeX
136+
r.to_latex(...) # publication export
137+
```

docs/faq.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# FAQ & troubleshooting
2+
3+
## Installation & imports
4+
5+
**Do I need PyTorch / JAX / PyMC?**
6+
No. The core install has no heavy ML dependencies. Those back specific
7+
estimators and are lazily imported, so you only hit an `ImportError` if you
8+
call an estimator that needs an extra you have not installed. The error tells
9+
you which extra to add, e.g.:
10+
11+
```bash
12+
pip install "StatsPAI[bayes]" # PyMC + ArviZ
13+
pip install "StatsPAI[neural]" # PyTorch (neural causal, DeepIV)
14+
pip install "StatsPAI[performance]" # JAX
15+
```
16+
17+
**`import statspai as sp` — is there a second import I need?**
18+
No. Every public function is reachable as `sp.<name>`. If you cannot find
19+
something, `sp.search_functions("keyword")` or `sp.help(search="keyword")`
20+
will locate it.
21+
22+
## Discovering functionality
23+
24+
**How do I find the right function?**
25+
26+
```python
27+
sp.recommend(df, y="y", treat="d") # suggest an estimator from the data
28+
sp.detect_design(df) # what study design is this?
29+
sp.search_functions("synthetic control")
30+
sp.help("did") # category / function help
31+
```
32+
33+
**How do I see a function's assumptions before I run it?**
34+
35+
```python
36+
sp.agent_card("callaway_santanna") # assumptions, pre-conditions, failure modes
37+
sp.function_schema("did", agent_native=True) # same, as an LLM tool schema
38+
```
39+
40+
## Reading the output
41+
42+
**What do the warnings mean?**
43+
StatsPAI fails loudly rather than returning silent `NaN`s. Common warnings:
44+
45+
- `AssumptionWarning` / `AssumptionViolation` — an identifying assumption looks
46+
violated (e.g. pre-trends, overlap). Inspect `result.diagnostics`.
47+
- `ConvergenceWarning` — an iterative/MCMC fit did not converge cleanly
48+
(e.g. `rhat > 1.01` or low ESS for Bayesian estimators). Increase
49+
iterations/draws.
50+
- `WorkflowDegradedWarning` — an orchestration step (`sp.paper`, `smart`
51+
workflows) degraded a section; the reason is recorded in
52+
`result.degradations`.
53+
54+
**My DiD pre-trends look violated — now what?**
55+
Quantify how sensitive the conclusion is with Rambachan–Roth honest bounds:
56+
57+
```python
58+
sp.honest_did(r)
59+
```
60+
61+
[Sensitivity analysis guide](guides/honest_did.md)
62+
63+
**My IV estimate has a huge confidence interval.**
64+
Almost always a weak first stage. Check it and switch to weak-instrument-robust
65+
inference:
66+
67+
```python
68+
sp.iv_diag(data, y="y", endog="d", instruments="z") # effective F + AR interval
69+
```
70+
71+
**"Poor overlap" / extreme propensity scores.**
72+
Treated and control covariate distributions barely overlap. Trim or restrict
73+
to the common-support region:
74+
75+
```python
76+
sp.trimming(df, treat="d", covariates=[...])
77+
sp.overlap_plot(sp.ps_balance(df, treat="d", covariates=[...]))
78+
```
79+
80+
## Reproducibility
81+
82+
**How do I make results deterministic?**
83+
84+
```python
85+
with sp.session(seed=42):
86+
r = sp.callaway_santanna(df, y="lemp", g="first_treat", t="year", i="countyreal")
87+
```
88+
89+
`sp.session` fixes the global RNG state for bootstrap / permutation / MCMC
90+
draws inside the block.
91+
92+
## Citations
93+
94+
**How do I cite an estimator correctly?**
95+
96+
```python
97+
r.cite() # verified BibTeX for the method you ran
98+
sp.bib_for(r) # structured citation payload
99+
```
100+
101+
StatsPAI never invents references — every citation is verified against
102+
`paper.bib`.
103+
104+
## Using StatsPAI from an agent / LLM
105+
106+
Every function returns structured results and carries a self-describing
107+
schema. The typical agent loop:
108+
109+
```python
110+
sp.detect_design(df) # 1. identify the design
111+
sp.preflight(df, method="callaway_santanna") # 2. will it run?
112+
r = sp.callaway_santanna(df, ...) # 3. fit
113+
r.to_dict(detail="agent") # 4. structured payload
114+
sp.audit(r) # 5. missing robustness checks
115+
r.cite() # 6. verified citation
116+
```
117+
118+
[Agent-native API surface](guides/agent_api.md)
119+
120+
## Numerical correctness
121+
122+
**Did the numbers change between versions?**
123+
Correctness fixes are flagged with **⚠️ correctness** in the
124+
[changelog](changelog.md) and recorded in `MIGRATION.md`. If you are
125+
reproducing an older analysis, check those notes for the modules you use.

docs/getting-started.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Getting started — your first analysis in 5 minutes
2+
3+
This page takes you from `pip install` to a publication-ready difference-in-
4+
differences estimate, with citation, in well under five minutes. Every code
5+
block below is runnable as-is against a bundled dataset.
6+
7+
## 1. Install
8+
9+
```bash
10+
pip install StatsPAI
11+
```
12+
13+
That is all you need for the core estimators. Optional extras pull in heavier
14+
backends only when you want them:
15+
16+
```bash
17+
pip install "StatsPAI[plotting]" # matplotlib / seaborn / plotly figures
18+
pip install "StatsPAI[bayes]" # PyMC + ArviZ for Bayesian estimators
19+
pip install "StatsPAI[performance]"# JAX backend for fast feols / bootstrap
20+
```
21+
22+
## 2. One import
23+
24+
```python
25+
import statspai as sp
26+
```
27+
28+
Everything lives under `sp.` — there is no second-level import to remember.
29+
`sp.list_functions()` enumerates all 1,000+ registered functions.
30+
31+
## 3. Load bundled data
32+
33+
StatsPAI ships the canonical teaching datasets so you can run real analyses
34+
with zero setup:
35+
36+
```python
37+
df = sp.datasets.mpdta() # Callaway–Sant'Anna county teen employment
38+
df.head()
39+
# countyreal year lemp first_treat treat
40+
# 0 0 2003 8.162509 2004 0
41+
# 1 0 2004 8.275744 2004 1
42+
```
43+
44+
`sp.datasets.list_datasets()` shows the rest (Card 1995 schooling, Lee 2008
45+
Senate RD, California Prop 99 synthetic control, LaLonde/NSW, …).
46+
47+
## 4. Let StatsPAI read the study design
48+
49+
Not sure which estimator fits? Ask:
50+
51+
```python
52+
sp.detect_design(df)["design"]
53+
# 'panel'
54+
```
55+
56+
`sp.detect_design` inspects the data shape (cross-section / panel / RD / …)
57+
and `sp.recommend(...)` suggests an estimator. This is the same machinery an
58+
LLM agent uses to plan an analysis.
59+
60+
## 5. Estimate
61+
62+
`first_treat` is the year each county was first treated (the cohort), `year`
63+
is time, `countyreal` is the unit, and `lemp` is log employment. That is a
64+
staggered-adoption DiD, so use the heterogeneity-robust Callaway–Sant'Anna
65+
estimator:
66+
67+
```python
68+
r = sp.callaway_santanna(df, y="lemp", g="first_treat", t="year", i="countyreal")
69+
print(r.summary())
70+
# ==============================================================================
71+
# Callaway and Sant'Anna (2021)
72+
# ==============================================================================
73+
# ATT: -0.032977 ***
74+
# Std. Error: (0.007740)
75+
# [95% CI]: [-0.048146, -0.017807]
76+
# P-value: 0.0
77+
```
78+
79+
## 6. Check assumptions and sensitivity
80+
81+
```python
82+
sp.agent_card("callaway_santanna")["assumptions"]
83+
# ['Parallel trends conditional on X ...', 'No anticipation', 'SUTVA', ...]
84+
85+
sp.audit(r) # which robustness checks are still missing?
86+
sp.honest_did(r) # Rambachan–Roth bounds on parallel-trends violations
87+
```
88+
89+
## 7. Export for the paper
90+
91+
Every result object speaks the same export protocol:
92+
93+
```python
94+
r.to_latex("att.tex") # publication table
95+
r.to_word("att.docx")
96+
r.cite() # verified BibTeX for the estimator
97+
```
98+
99+
## Where to next
100+
101+
- **[Cookbook](cookbook.md)** — recipes organised by research question.
102+
- **[Choosing a DID estimator](guides/choosing_did_estimator.md)** and the
103+
other decision guides.
104+
- **[FAQ](faq.md)** — common errors and how to read the diagnostics.
105+
- **[Full API reference](reference/api/index.md)** — all 86 sub-packages.

0 commit comments

Comments
 (0)