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.
- ai_agent_risk-0.1.0/CHANGELOG.md +7 -0
- ai_agent_risk-0.1.0/LICENSE +24 -0
- ai_agent_risk-0.1.0/MANIFEST.in +9 -0
- ai_agent_risk-0.1.0/PKG-INFO +206 -0
- ai_agent_risk-0.1.0/README.md +172 -0
- ai_agent_risk-0.1.0/pyproject.toml +67 -0
- ai_agent_risk-0.1.0/setup.cfg +4 -0
- ai_agent_risk-0.1.0/src/agent_risk/__init__.py +53 -0
- ai_agent_risk-0.1.0/src/agent_risk/_checks.py +25 -0
- ai_agent_risk-0.1.0/src/agent_risk/certify.py +203 -0
- ai_agent_risk-0.1.0/src/agent_risk/episode.py +254 -0
- ai_agent_risk-0.1.0/src/agent_risk/paired.py +197 -0
- ai_agent_risk-0.1.0/src/agent_risk/py.typed +0 -0
- ai_agent_risk-0.1.0/src/agent_risk/retry.py +146 -0
- ai_agent_risk-0.1.0/src/agent_risk/stopping.py +282 -0
- ai_agent_risk-0.1.0/src/ai_agent_risk.egg-info/PKG-INFO +206 -0
- ai_agent_risk-0.1.0/src/ai_agent_risk.egg-info/SOURCES.txt +26 -0
- ai_agent_risk-0.1.0/src/ai_agent_risk.egg-info/dependency_links.txt +1 -0
- ai_agent_risk-0.1.0/src/ai_agent_risk.egg-info/requires.txt +5 -0
- ai_agent_risk-0.1.0/src/ai_agent_risk.egg-info/top_level.txt +1 -0
- ai_agent_risk-0.1.0/tests/conftest.py +20 -0
- ai_agent_risk-0.1.0/tests/test_certify.py +150 -0
- ai_agent_risk-0.1.0/tests/test_episode.py +151 -0
- ai_agent_risk-0.1.0/tests/test_paired.py +158 -0
- ai_agent_risk-0.1.0/tests/test_readme.py +47 -0
- ai_agent_risk-0.1.0/tests/test_retry.py +72 -0
- ai_agent_risk-0.1.0/tests/test_stopping.py +157 -0
- ai_agent_risk-0.1.0/tests/toydata.py +5 -0
|
@@ -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,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
|
+
[](https://pypi.org/project/ai-agent-risk/)
|
|
44
|
+
[](https://www.python.org/downloads/)
|
|
45
|
+
[](https://github.com/yzhao062/agent-risk/actions/workflows/ci.yml)
|
|
46
|
+
[](https://github.com/yzhao062/agent-risk/blob/main/LICENSE)
|
|
47
|
+
[](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
|
+
[](https://pypi.org/project/ai-agent-risk/)
|
|
10
|
+
[](https://www.python.org/downloads/)
|
|
11
|
+
[](https://github.com/yzhao062/agent-risk/actions/workflows/ci.yml)
|
|
12
|
+
[](https://github.com/yzhao062/agent-risk/blob/main/LICENSE)
|
|
13
|
+
[](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,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
|