ai-agent-risk 0.1.0__tar.gz

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.
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (2026-10-11)
4
+
5
+ First public release accompanying the preprint "agent-risk: Risk Assessment for Changes to AI Agents".
6
+ Provides episode data representations, counterfactual replay of stopping and retry gates,
7
+ exact Clopper-Pearson harm certification, and paired equivalence testing for AI agents.
@@ -0,0 +1,24 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2026, Yue Zhao, Zixiang Xu, Angela Huyue Zhang, S. Alex Yang, Xiyang Hu
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,9 @@
1
+ include CHANGELOG.md
2
+ recursive-include tests *.py
3
+ prune checks
4
+ prune experiments
5
+ prune registrations
6
+ prune data
7
+ prune survey
8
+ prune supplement
9
+ exclude ARTIFACT.md
@@ -0,0 +1,206 @@
1
+ Metadata-Version: 2.4
2
+ Name: ai-agent-risk
3
+ Version: 0.1.0
4
+ Summary: Risk modeling for AI agents from logs: replay a proposed change over logged episodes and separate what the log settles, what a declared stop valuation fixes, and what needs bounds.
5
+ Author: Zixiang Xu, Angela Huyue Zhang, S. Alex Yang, Xiyang Hu
6
+ Author-email: Yue Zhao <yzhao062@gmail.com>
7
+ License-Expression: BSD-2-Clause
8
+ Project-URL: Homepage, https://github.com/yzhao062/agent-risk
9
+ Project-URL: Repository, https://github.com/yzhao062/agent-risk
10
+ Project-URL: Issues, https://github.com/yzhao062/agent-risk/issues
11
+ Project-URL: Dataset, https://huggingface.co/datasets/yzhao062/agent-risk-logs
12
+ Keywords: ai agents,risk,monitoring,counterfactual replay,clopper-pearson,paired proportions
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.9
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: numpy>=1.20
30
+ Requires-Dist: scipy>=1.7
31
+ Provides-Extra: test
32
+ Requires-Dist: pytest>=7; extra == "test"
33
+ Dynamic: license-file
34
+
35
+ <a name="readme-top"></a>
36
+
37
+ <div align="center">
38
+
39
+ # agent-risk
40
+
41
+ **Risk assessment for changes to AI agents, starting from the logs you already have**
42
+
43
+ [![PyPI](https://img.shields.io/pypi/v/ai-agent-risk.svg?color=blue)](https://pypi.org/project/ai-agent-risk/)
44
+ [![Python](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
45
+ [![CI](https://github.com/yzhao062/agent-risk/actions/workflows/ci.yml/badge.svg)](https://github.com/yzhao062/agent-risk/actions/workflows/ci.yml)
46
+ [![License](https://img.shields.io/badge/License-BSD_2--Clause-blue.svg)](https://github.com/yzhao062/agent-risk/blob/main/LICENSE)
47
+ [![Dataset](https://img.shields.io/badge/Hugging%20Face-agent--risk--logs-yellow.svg)](https://huggingface.co/datasets/yzhao062/agent-risk-logs)
48
+
49
+ [What It Answers](#what-it-answers) · [Key Results](#key-results) · [Install](#install) · [Quickstart](#quickstart) · [Reproduce the Paper](#reproduce-the-paper) · [Citation](#citation)
50
+
51
+ <img src="https://raw.githubusercontent.com/yzhao062/agent-risk/main/docs/figure1.png" alt="Replaying a logged episode under a proposed change: the log settles agreeing episodes, a declared stop value settles stopped ones, and continuing ones need logged support, a snapshot run, or a bound" width="100%">
52
+
53
+ </div>
54
+
55
+ Before changing a deployed AI agent (a stricter safety gate, a new model), organizations must approve the change, starting from existing logs. `agent-risk` extends classical risk analysis to partial records and partial changes to running systems: it replays logged episodes under the proposed change, assuming nothing else changes and the agent does not anticipate the change. The log settles episodes that act as before, a declared stop value settles stopped ones, and the rest need logged support, a saved-state rerun, or a bound.
56
+
57
+ > [!NOTE]
58
+ > This repository accompanies the paper *agent-risk: Risk Assessment for Changes to AI Agents* by Yue Zhao, Zixiang Xu, Angela Huyue Zhang, S. Alex Yang, and Xiyang Hu (arXiv preprint, 2026). It holds the Python package, the 15 finite checks, the experiment code, the registrations, and the survey; the 3.5 GB of run logs are on [Hugging Face](https://huggingface.co/datasets/yzhao062/agent-risk-logs).
59
+
60
+ ## What It Answers
61
+
62
+ Replay a proposed change over each logged episode and sort the episode by what happens at its first deviation from the log:
63
+
64
+ | Case | Under the change, the episode... | What settles it | In this repository |
65
+ |---|---|---|---|
66
+ | **Agree** | acts exactly as logged | The log itself | `replay_stop` |
67
+ | **Stop** | is stopped at its first deviation | A declared stop value (needs per-step harm in the log) | `replay_stop`, `certify_replay` |
68
+ | **Continue** | continues past its first deviation | Logged support, a rerun from a saved state, or a bound | `retry_harm_bounds`; saved-state reruns in [`experiments/`](https://github.com/yzhao062/agent-risk/tree/main/experiments) |
69
+
70
+ ## Key Results
71
+
72
+ **One log, two gates, half the agent calls.** In a bash sandbox, a 7,200-episode log alone decided neither of two retry gates, which let the agent act after refusals the log never shows. Rerunning only each gate's blocked episodes from saved states reached both live decisions at half the agent calls of a live test sized post hoc for them, given the log.
73
+
74
+ **Per-step harm decides whether a stop can be replayed.** Without per-step harm, a stopping gate's certified harm ceiling rose up to 2.5-fold, since the log hides whether harm preceded the stop.
75
+
76
+ **A new model needs new evidence.** The new model reproduced none of 99 logged episodes, so replay settled none; the same model reproduced every one at logged inputs and seeds. A model release needs support, bounds, or new runs from step 0.
77
+
78
+ ## Install
79
+
80
+ ```bash
81
+ pip install ai-agent-risk
82
+ ```
83
+
84
+ Or install from GitHub with `pip install git+https://github.com/yzhao062/agent-risk`, or clone the repository and run `pip install .` at its root. The distribution name is `ai-agent-risk`; the import name is `agent_risk`. Requires Python 3.9 or later, NumPy (>= 1.20), and SciPy (>= 1.7).
85
+
86
+ ## Quickstart
87
+
88
+ The snippet below replays three episodes under a stopping gate (theta = 0.94), computes replayed harm, failure, and cost, certifies an exact Clopper-Pearson upper bound on harm, and bounds harm under a retry gate:
89
+
90
+ ```python
91
+ from agent_risk import Episode, certify_replay, replay_stop, retry_harm_bounds
92
+
93
+ scores, cost = [0.10, 0.20, 0.97, 0.30], [10, 20, 30, 40]
94
+ episodes = [
95
+ Episode(scores, [False, True, False, False], cost, failed=False), # harm at step 1
96
+ Episode(scores, [False, False, False, True], cost, failed=False), # harm at step 3
97
+ Episode([0.10, 0.20], [False, False], [10, 20], failed=False), # never above 0.94
98
+ ]
99
+
100
+ replay = replay_stop(episodes, theta=0.94)
101
+ print(replay.branches, replay.stop_steps) # ('stop', 'stop', 'agree') (2, 2, None)
102
+ print(round(replay.p_harm, 3)) # 0.333: only the step-1 harm survives
103
+ print(round(replay.p_failure, 3)) # 0.667: a stop counts as a failure by default
104
+ print(replay.mean_cost) # 50.0 = (60 + 60 + 30) / 3
105
+ print(round(replay.stop_mass, 3), round(replay.stop_clean_share, 3)) # 0.667 0.333
106
+
107
+ cert = certify_replay(replay, alpha=0.05)
108
+ print(cert.n_harmed, cert.n, round(cert.upper, 3)) # 1 3 0.865
109
+
110
+ bounds = retry_harm_bounds(episodes, theta=0.94, cap=2)
111
+ print([round(v, 3) for v in bounds.interval]) # [0.333, 0.667]
112
+ ```
113
+
114
+ <details>
115
+ <summary><b>Loading logs and comparing two policies</b></summary>
116
+
117
+ Logs load from JSON Lines, with `null` marking unobserved harm:
118
+
119
+ ```python
120
+ from agent_risk import load_jsonl
121
+
122
+ lines = ['{"scores": [0.1, 0.97], "harm": [false, null], "cost": [5, 6], "failed": false}']
123
+ episodes = load_jsonl(lines) # or load_jsonl("log.jsonl")
124
+ ```
125
+
126
+ Paired comparisons and equivalence tests:
127
+
128
+ ```python
129
+ from agent_risk import is_equivalent, newcombe_paired_interval
130
+
131
+ ci = newcombe_paired_interval(both=40, first_only=1, second_only=2, neither=57, level=0.90)
132
+ print(round(ci.estimate, 3), round(ci.lower, 3), round(ci.upper, 3)) # -0.01 -0.043 0.023
133
+ print(is_equivalent(ci, margin=0.10)) # True: equivalent at alpha = 0.05
134
+ ```
135
+
136
+ </details>
137
+
138
+ ## Reproduce the Paper
139
+
140
+ 1. **Get the logs.** Download the dataset into `data/` from the repository root; [`data/README.md`](https://github.com/yzhao062/agent-risk/blob/main/data/README.md) explains the layout, checksums, and redactions.
141
+
142
+ ```bash
143
+ hf download yzhao062/agent-risk-logs --repo-type dataset --local-dir data \
144
+ --include "logs/*" "arm-e/*" MANIFEST.tsv REDACTIONS.tsv
145
+ ```
146
+
147
+ 2. **Regenerate the numbers.** [`ARTIFACT.md`](https://github.com/yzhao062/agent-risk/blob/main/ARTIFACT.md) maps every table and figure of the paper to its logs, its registration, and its command (A1 to A39). The commands write to `outputs/` and leave `data/` untouched.
148
+ 3. **Check the theory.** `python checks/run_all.py` runs the 15 finite checks of the formal results ([`checks/README.md`](https://github.com/yzhao062/agent-risk/blob/main/checks/README.md)).
149
+
150
+ > [!TIP]
151
+ > On the released logs, the documented commands reproduce every number of the registered analyses, and the figure script regenerates the paper's Figures D.1 to D.3. To rerun experiments live (served models, ControlArena, tau2-bench), see [`experiments/RUNNING.md`](https://github.com/yzhao062/agent-risk/blob/main/experiments/RUNNING.md).
152
+
153
+ <details>
154
+ <summary><b>Repository map</b></summary>
155
+
156
+ | Directory / File | Description |
157
+ |---|---|
158
+ | [`src/agent_risk/`](https://github.com/yzhao062/agent-risk/tree/main/src/agent_risk) | Core Python package: episode representation, stopping replay, retry bounds, exact Clopper-Pearson certification, and paired Newcombe confidence intervals. |
159
+ | [`tests/`](https://github.com/yzhao062/agent-risk/tree/main/tests) | Unit and regression tests (149) covering replay algorithms, stop valuations, bounds, and paper test vectors. |
160
+ | [`checks/`](https://github.com/yzhao062/agent-risk/tree/main/checks) | 15 finite-instance check scripts verifying the theorems, combinatorial bounds, and design invariants. |
161
+ | [`experiments/`](https://github.com/yzhao062/agent-risk/tree/main/experiments) | Experiment harness, run scripts, analysis and post hoc scripts, and the figure script. |
162
+ | [`registrations/`](https://github.com/yzhao062/agent-risk/tree/main/registrations) | Registration documents for the paper's runs (sample sizes, analysis rules, margins, prediction hashes), each with its registration time, and the run records. |
163
+ | [`data/`](https://github.com/yzhao062/agent-risk/tree/main/data) | Log manifest, SHA-256 checksums, redaction records, run manifests, and download instructions. |
164
+ | [`survey/`](https://github.com/yzhao062/agent-risk/tree/main/survey) | The characteristic survey: 23 coded sources with their recorded versions, 30 AI Incident Database incidents, the 20-code codebook, both coders' matrices, and the agreement script. |
165
+ | [`supplement/`](https://github.com/yzhao062/agent-risk/tree/main/supplement) | Companion files for the paper's appendices. |
166
+ | [`ARTIFACT.md`](https://github.com/yzhao062/agent-risk/blob/main/ARTIFACT.md) | The artifact guide: paper names and run codes, verbatim prompts and policies, and every reproduction command. |
167
+
168
+ </details>
169
+
170
+ <details>
171
+ <summary><b>Running the tests</b></summary>
172
+
173
+ ```bash
174
+ pip install ".[test]"
175
+ pytest
176
+ ```
177
+
178
+ This runs the 149 tests in [`tests/`](https://github.com/yzhao062/agent-risk/tree/main/tests). Without the optional `statsmodels`, two comparison tests are skipped (147 passed, 2 skipped).
179
+
180
+ </details>
181
+
182
+ ## Citation
183
+
184
+ ```bibtex
185
+ @article{zhao2026agentrisk,
186
+ title = {agent-risk: Risk Assessment for Changes to AI Agents},
187
+ author = {Zhao, Yue and Xu, Zixiang and Zhang, Angela Huyue and Yang, S. Alex and Hu, Xiyang},
188
+ journal = {arXiv preprint},
189
+ year = {2026}
190
+ }
191
+ ```
192
+
193
+ ## License
194
+
195
+ The code is under the [BSD 2-Clause License](https://github.com/yzhao062/agent-risk/blob/main/LICENSE). The logs on [Hugging Face](https://huggingface.co/datasets/yzhao062/agent-risk-logs) are under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) ([`LICENSE-DATA.md`](https://github.com/yzhao062/agent-risk/blob/main/LICENSE-DATA.md)).
196
+
197
+ <details>
198
+ <summary><b>Third-party components</b></summary>
199
+
200
+ - **ControlArena**: task definitions, environments, and bash tool harnesses (used in all bash-environment runs) derive from [ControlArena](https://github.com/UKGovernmentBEIS/control-arena), under the [MIT License](https://opensource.org/licenses/MIT).
201
+ - **tau2-bench**: airline customer-support tasks, dialogue environments, and the customer simulator (used in the airline runs, E3 and E5) derive from [tau2-bench](https://github.com/sierra-research/tau2-bench), under the [MIT License](https://opensource.org/licenses/MIT).
202
+ - **Qwen models**: the agent and monitor models (Qwen3-14B-FP8, Qwen3-14B, Qwen3-4B-Instruct-2507, Qwen3.5-27B-FP8, Qwen2.5-14B-Instruct) are released by their developers under the [Apache-2.0 License](https://www.apache.org/licenses/LICENSE-2.0). Neither this repository nor the dataset contains model weights.
203
+
204
+ </details>
205
+
206
+ <p align="right"><a href="#readme-top">↑ back to top</a></p>
@@ -0,0 +1,172 @@
1
+ <a name="readme-top"></a>
2
+
3
+ <div align="center">
4
+
5
+ # agent-risk
6
+
7
+ **Risk assessment for changes to AI agents, starting from the logs you already have**
8
+
9
+ [![PyPI](https://img.shields.io/pypi/v/ai-agent-risk.svg?color=blue)](https://pypi.org/project/ai-agent-risk/)
10
+ [![Python](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
11
+ [![CI](https://github.com/yzhao062/agent-risk/actions/workflows/ci.yml/badge.svg)](https://github.com/yzhao062/agent-risk/actions/workflows/ci.yml)
12
+ [![License](https://img.shields.io/badge/License-BSD_2--Clause-blue.svg)](https://github.com/yzhao062/agent-risk/blob/main/LICENSE)
13
+ [![Dataset](https://img.shields.io/badge/Hugging%20Face-agent--risk--logs-yellow.svg)](https://huggingface.co/datasets/yzhao062/agent-risk-logs)
14
+
15
+ [What It Answers](#what-it-answers) · [Key Results](#key-results) · [Install](#install) · [Quickstart](#quickstart) · [Reproduce the Paper](#reproduce-the-paper) · [Citation](#citation)
16
+
17
+ <img src="https://raw.githubusercontent.com/yzhao062/agent-risk/main/docs/figure1.png" alt="Replaying a logged episode under a proposed change: the log settles agreeing episodes, a declared stop value settles stopped ones, and continuing ones need logged support, a snapshot run, or a bound" width="100%">
18
+
19
+ </div>
20
+
21
+ Before changing a deployed AI agent (a stricter safety gate, a new model), organizations must approve the change, starting from existing logs. `agent-risk` extends classical risk analysis to partial records and partial changes to running systems: it replays logged episodes under the proposed change, assuming nothing else changes and the agent does not anticipate the change. The log settles episodes that act as before, a declared stop value settles stopped ones, and the rest need logged support, a saved-state rerun, or a bound.
22
+
23
+ > [!NOTE]
24
+ > This repository accompanies the paper *agent-risk: Risk Assessment for Changes to AI Agents* by Yue Zhao, Zixiang Xu, Angela Huyue Zhang, S. Alex Yang, and Xiyang Hu (arXiv preprint, 2026). It holds the Python package, the 15 finite checks, the experiment code, the registrations, and the survey; the 3.5 GB of run logs are on [Hugging Face](https://huggingface.co/datasets/yzhao062/agent-risk-logs).
25
+
26
+ ## What It Answers
27
+
28
+ Replay a proposed change over each logged episode and sort the episode by what happens at its first deviation from the log:
29
+
30
+ | Case | Under the change, the episode... | What settles it | In this repository |
31
+ |---|---|---|---|
32
+ | **Agree** | acts exactly as logged | The log itself | `replay_stop` |
33
+ | **Stop** | is stopped at its first deviation | A declared stop value (needs per-step harm in the log) | `replay_stop`, `certify_replay` |
34
+ | **Continue** | continues past its first deviation | Logged support, a rerun from a saved state, or a bound | `retry_harm_bounds`; saved-state reruns in [`experiments/`](https://github.com/yzhao062/agent-risk/tree/main/experiments) |
35
+
36
+ ## Key Results
37
+
38
+ **One log, two gates, half the agent calls.** In a bash sandbox, a 7,200-episode log alone decided neither of two retry gates, which let the agent act after refusals the log never shows. Rerunning only each gate's blocked episodes from saved states reached both live decisions at half the agent calls of a live test sized post hoc for them, given the log.
39
+
40
+ **Per-step harm decides whether a stop can be replayed.** Without per-step harm, a stopping gate's certified harm ceiling rose up to 2.5-fold, since the log hides whether harm preceded the stop.
41
+
42
+ **A new model needs new evidence.** The new model reproduced none of 99 logged episodes, so replay settled none; the same model reproduced every one at logged inputs and seeds. A model release needs support, bounds, or new runs from step 0.
43
+
44
+ ## Install
45
+
46
+ ```bash
47
+ pip install ai-agent-risk
48
+ ```
49
+
50
+ Or install from GitHub with `pip install git+https://github.com/yzhao062/agent-risk`, or clone the repository and run `pip install .` at its root. The distribution name is `ai-agent-risk`; the import name is `agent_risk`. Requires Python 3.9 or later, NumPy (>= 1.20), and SciPy (>= 1.7).
51
+
52
+ ## Quickstart
53
+
54
+ The snippet below replays three episodes under a stopping gate (theta = 0.94), computes replayed harm, failure, and cost, certifies an exact Clopper-Pearson upper bound on harm, and bounds harm under a retry gate:
55
+
56
+ ```python
57
+ from agent_risk import Episode, certify_replay, replay_stop, retry_harm_bounds
58
+
59
+ scores, cost = [0.10, 0.20, 0.97, 0.30], [10, 20, 30, 40]
60
+ episodes = [
61
+ Episode(scores, [False, True, False, False], cost, failed=False), # harm at step 1
62
+ Episode(scores, [False, False, False, True], cost, failed=False), # harm at step 3
63
+ Episode([0.10, 0.20], [False, False], [10, 20], failed=False), # never above 0.94
64
+ ]
65
+
66
+ replay = replay_stop(episodes, theta=0.94)
67
+ print(replay.branches, replay.stop_steps) # ('stop', 'stop', 'agree') (2, 2, None)
68
+ print(round(replay.p_harm, 3)) # 0.333: only the step-1 harm survives
69
+ print(round(replay.p_failure, 3)) # 0.667: a stop counts as a failure by default
70
+ print(replay.mean_cost) # 50.0 = (60 + 60 + 30) / 3
71
+ print(round(replay.stop_mass, 3), round(replay.stop_clean_share, 3)) # 0.667 0.333
72
+
73
+ cert = certify_replay(replay, alpha=0.05)
74
+ print(cert.n_harmed, cert.n, round(cert.upper, 3)) # 1 3 0.865
75
+
76
+ bounds = retry_harm_bounds(episodes, theta=0.94, cap=2)
77
+ print([round(v, 3) for v in bounds.interval]) # [0.333, 0.667]
78
+ ```
79
+
80
+ <details>
81
+ <summary><b>Loading logs and comparing two policies</b></summary>
82
+
83
+ Logs load from JSON Lines, with `null` marking unobserved harm:
84
+
85
+ ```python
86
+ from agent_risk import load_jsonl
87
+
88
+ lines = ['{"scores": [0.1, 0.97], "harm": [false, null], "cost": [5, 6], "failed": false}']
89
+ episodes = load_jsonl(lines) # or load_jsonl("log.jsonl")
90
+ ```
91
+
92
+ Paired comparisons and equivalence tests:
93
+
94
+ ```python
95
+ from agent_risk import is_equivalent, newcombe_paired_interval
96
+
97
+ ci = newcombe_paired_interval(both=40, first_only=1, second_only=2, neither=57, level=0.90)
98
+ print(round(ci.estimate, 3), round(ci.lower, 3), round(ci.upper, 3)) # -0.01 -0.043 0.023
99
+ print(is_equivalent(ci, margin=0.10)) # True: equivalent at alpha = 0.05
100
+ ```
101
+
102
+ </details>
103
+
104
+ ## Reproduce the Paper
105
+
106
+ 1. **Get the logs.** Download the dataset into `data/` from the repository root; [`data/README.md`](https://github.com/yzhao062/agent-risk/blob/main/data/README.md) explains the layout, checksums, and redactions.
107
+
108
+ ```bash
109
+ hf download yzhao062/agent-risk-logs --repo-type dataset --local-dir data \
110
+ --include "logs/*" "arm-e/*" MANIFEST.tsv REDACTIONS.tsv
111
+ ```
112
+
113
+ 2. **Regenerate the numbers.** [`ARTIFACT.md`](https://github.com/yzhao062/agent-risk/blob/main/ARTIFACT.md) maps every table and figure of the paper to its logs, its registration, and its command (A1 to A39). The commands write to `outputs/` and leave `data/` untouched.
114
+ 3. **Check the theory.** `python checks/run_all.py` runs the 15 finite checks of the formal results ([`checks/README.md`](https://github.com/yzhao062/agent-risk/blob/main/checks/README.md)).
115
+
116
+ > [!TIP]
117
+ > On the released logs, the documented commands reproduce every number of the registered analyses, and the figure script regenerates the paper's Figures D.1 to D.3. To rerun experiments live (served models, ControlArena, tau2-bench), see [`experiments/RUNNING.md`](https://github.com/yzhao062/agent-risk/blob/main/experiments/RUNNING.md).
118
+
119
+ <details>
120
+ <summary><b>Repository map</b></summary>
121
+
122
+ | Directory / File | Description |
123
+ |---|---|
124
+ | [`src/agent_risk/`](https://github.com/yzhao062/agent-risk/tree/main/src/agent_risk) | Core Python package: episode representation, stopping replay, retry bounds, exact Clopper-Pearson certification, and paired Newcombe confidence intervals. |
125
+ | [`tests/`](https://github.com/yzhao062/agent-risk/tree/main/tests) | Unit and regression tests (149) covering replay algorithms, stop valuations, bounds, and paper test vectors. |
126
+ | [`checks/`](https://github.com/yzhao062/agent-risk/tree/main/checks) | 15 finite-instance check scripts verifying the theorems, combinatorial bounds, and design invariants. |
127
+ | [`experiments/`](https://github.com/yzhao062/agent-risk/tree/main/experiments) | Experiment harness, run scripts, analysis and post hoc scripts, and the figure script. |
128
+ | [`registrations/`](https://github.com/yzhao062/agent-risk/tree/main/registrations) | Registration documents for the paper's runs (sample sizes, analysis rules, margins, prediction hashes), each with its registration time, and the run records. |
129
+ | [`data/`](https://github.com/yzhao062/agent-risk/tree/main/data) | Log manifest, SHA-256 checksums, redaction records, run manifests, and download instructions. |
130
+ | [`survey/`](https://github.com/yzhao062/agent-risk/tree/main/survey) | The characteristic survey: 23 coded sources with their recorded versions, 30 AI Incident Database incidents, the 20-code codebook, both coders' matrices, and the agreement script. |
131
+ | [`supplement/`](https://github.com/yzhao062/agent-risk/tree/main/supplement) | Companion files for the paper's appendices. |
132
+ | [`ARTIFACT.md`](https://github.com/yzhao062/agent-risk/blob/main/ARTIFACT.md) | The artifact guide: paper names and run codes, verbatim prompts and policies, and every reproduction command. |
133
+
134
+ </details>
135
+
136
+ <details>
137
+ <summary><b>Running the tests</b></summary>
138
+
139
+ ```bash
140
+ pip install ".[test]"
141
+ pytest
142
+ ```
143
+
144
+ This runs the 149 tests in [`tests/`](https://github.com/yzhao062/agent-risk/tree/main/tests). Without the optional `statsmodels`, two comparison tests are skipped (147 passed, 2 skipped).
145
+
146
+ </details>
147
+
148
+ ## Citation
149
+
150
+ ```bibtex
151
+ @article{zhao2026agentrisk,
152
+ title = {agent-risk: Risk Assessment for Changes to AI Agents},
153
+ author = {Zhao, Yue and Xu, Zixiang and Zhang, Angela Huyue and Yang, S. Alex and Hu, Xiyang},
154
+ journal = {arXiv preprint},
155
+ year = {2026}
156
+ }
157
+ ```
158
+
159
+ ## License
160
+
161
+ The code is under the [BSD 2-Clause License](https://github.com/yzhao062/agent-risk/blob/main/LICENSE). The logs on [Hugging Face](https://huggingface.co/datasets/yzhao062/agent-risk-logs) are under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) ([`LICENSE-DATA.md`](https://github.com/yzhao062/agent-risk/blob/main/LICENSE-DATA.md)).
162
+
163
+ <details>
164
+ <summary><b>Third-party components</b></summary>
165
+
166
+ - **ControlArena**: task definitions, environments, and bash tool harnesses (used in all bash-environment runs) derive from [ControlArena](https://github.com/UKGovernmentBEIS/control-arena), under the [MIT License](https://opensource.org/licenses/MIT).
167
+ - **tau2-bench**: airline customer-support tasks, dialogue environments, and the customer simulator (used in the airline runs, E3 and E5) derive from [tau2-bench](https://github.com/sierra-research/tau2-bench), under the [MIT License](https://opensource.org/licenses/MIT).
168
+ - **Qwen models**: the agent and monitor models (Qwen3-14B-FP8, Qwen3-14B, Qwen3-4B-Instruct-2507, Qwen3.5-27B-FP8, Qwen2.5-14B-Instruct) are released by their developers under the [Apache-2.0 License](https://www.apache.org/licenses/LICENSE-2.0). Neither this repository nor the dataset contains model weights.
169
+
170
+ </details>
171
+
172
+ <p align="right"><a href="#readme-top">↑ back to top</a></p>
@@ -0,0 +1,67 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ai-agent-risk"
7
+ dynamic = ["version"]
8
+ description = "Risk modeling for AI agents from logs: replay a proposed change over logged episodes and separate what the log settles, what a declared stop valuation fixes, and what needs bounds."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "BSD-2-Clause"
12
+ license-files = ["LICENSE"]
13
+ authors = [
14
+ { name = "Yue Zhao", email = "yzhao062@gmail.com" },
15
+ { name = "Zixiang Xu" },
16
+ { name = "Angela Huyue Zhang" },
17
+ { name = "S. Alex Yang" },
18
+ { name = "Xiyang Hu" },
19
+ ]
20
+
21
+ keywords = [
22
+ "ai agents",
23
+ "risk",
24
+ "monitoring",
25
+ "counterfactual replay",
26
+ "clopper-pearson",
27
+ "paired proportions",
28
+ ]
29
+ classifiers = [
30
+ "Development Status :: 3 - Alpha",
31
+ "Intended Audience :: Science/Research",
32
+ "Intended Audience :: Developers",
33
+ "Operating System :: OS Independent",
34
+ "Programming Language :: Python :: 3",
35
+ "Programming Language :: Python :: 3 :: Only",
36
+ "Programming Language :: Python :: 3.9",
37
+ "Programming Language :: Python :: 3.10",
38
+ "Programming Language :: Python :: 3.11",
39
+ "Programming Language :: Python :: 3.12",
40
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
41
+ "Topic :: Scientific/Engineering :: Mathematics",
42
+ "Typing :: Typed",
43
+ ]
44
+ dependencies = ["numpy>=1.20", "scipy>=1.7"]
45
+
46
+ [project.urls]
47
+ Homepage = "https://github.com/yzhao062/agent-risk"
48
+ Repository = "https://github.com/yzhao062/agent-risk"
49
+ Issues = "https://github.com/yzhao062/agent-risk/issues"
50
+ Dataset = "https://huggingface.co/datasets/yzhao062/agent-risk-logs"
51
+
52
+ [project.optional-dependencies]
53
+ test = ["pytest>=7"]
54
+
55
+ [tool.setuptools.dynamic]
56
+ version = { attr = "agent_risk.__version__" }
57
+
58
+ [tool.setuptools.packages.find]
59
+ where = ["src"]
60
+
61
+ [tool.setuptools.package-data]
62
+ agent_risk = ["py.typed"]
63
+
64
+ [tool.pytest.ini_options]
65
+ testpaths = ["tests"]
66
+ pythonpath = ["src"]
67
+ filterwarnings = ["error"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,53 @@
1
+ """Risk modeling for AI agents from logs.
2
+
3
+ Replay a proposed change over logged episodes and separate what the log
4
+ settles, what a declared stop valuation fixes, and what needs bounds.
5
+
6
+ Main entry points:
7
+
8
+ * :class:`Episode`, :func:`load_episodes`, :func:`load_jsonl`: logged data.
9
+ * :func:`replay_stop`, :class:`StopValuation`: replay of a stopping gate.
10
+ * :func:`retry_harm_bounds`: outer interval for a retry gate.
11
+ * :func:`clopper_pearson_upper`, :func:`certify`, :func:`certify_replay`,
12
+ :func:`compare_logging_schemes`: certified harm bounds.
13
+ * :func:`newcombe_paired_interval`, :func:`is_equivalent`: paired comparison.
14
+ """
15
+
16
+ from .certify import (
17
+ Certificate,
18
+ LoggingComparison,
19
+ certify,
20
+ certify_replay,
21
+ clopper_pearson_upper,
22
+ compare_logging_schemes,
23
+ )
24
+ from .episode import Episode, any_harm, load_episodes, load_jsonl
25
+ from .paired import PairedInterval, is_equivalent, newcombe_paired_interval, wilson_interval
26
+ from .retry import RetryBounds, retry_harm_bounds
27
+ from .stopping import EpisodeReplay, StopReplay, StopValuation, replay_stop
28
+
29
+ __version__ = "0.1.0"
30
+
31
+ __all__ = [
32
+ "__version__",
33
+ "Certificate",
34
+ "Episode",
35
+ "EpisodeReplay",
36
+ "LoggingComparison",
37
+ "PairedInterval",
38
+ "RetryBounds",
39
+ "StopReplay",
40
+ "StopValuation",
41
+ "any_harm",
42
+ "certify",
43
+ "certify_replay",
44
+ "clopper_pearson_upper",
45
+ "compare_logging_schemes",
46
+ "is_equivalent",
47
+ "load_episodes",
48
+ "load_jsonl",
49
+ "newcombe_paired_interval",
50
+ "replay_stop",
51
+ "retry_harm_bounds",
52
+ "wilson_interval",
53
+ ]
@@ -0,0 +1,25 @@
1
+ """Shared input checks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numbers
6
+
7
+
8
+ def check_count(value: object, name: str) -> int:
9
+ """Return ``value`` as a non-negative ``int`` or raise."""
10
+ if isinstance(value, bool) or not isinstance(value, numbers.Integral):
11
+ raise TypeError(f"{name} must be an integer, got {value!r}")
12
+ value = int(value)
13
+ if value < 0:
14
+ raise ValueError(f"{name} must be non-negative, got {value}")
15
+ return value
16
+
17
+
18
+ def check_open_unit(value: object, name: str) -> float:
19
+ """Return ``value`` as a ``float`` in the open interval (0, 1) or raise."""
20
+ if isinstance(value, bool) or not isinstance(value, numbers.Real):
21
+ raise TypeError(f"{name} must be a real number, got {value!r}")
22
+ value = float(value)
23
+ if not 0.0 < value < 1.0:
24
+ raise ValueError(f"{name} must lie in (0, 1), got {value}")
25
+ return value