gauntlet-agent 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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rohan Pandey
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,211 @@
1
+ Metadata-Version: 2.4
2
+ Name: gauntlet-agent
3
+ Version: 0.1.0
4
+ Summary: Break your agent before your users do. Adversarial stress-testing and regression suites for AI agents.
5
+ Author: Rohan Pandey
6
+ License: MIT
7
+ Keywords: ai,agents,llm,evaluation,red-team,testing,reliability,ci
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Provides-Extra: llm
12
+ Requires-Dist: anthropic>=0.40; extra == "llm"
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest>=7; extra == "dev"
15
+ Dynamic: license-file
16
+
17
+ # Gauntlet
18
+
19
+ [![PyPI](https://img.shields.io/pypi/v/gauntlet-agent.svg)](https://pypi.org/project/gauntlet-agent/)
20
+ [![Python](https://img.shields.io/pypi/pyversions/gauntlet-agent.svg)](https://pypi.org/project/gauntlet-agent/)
21
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
22
+ [![CI](https://github.com/GauntletVectorLabs/gauntlet/actions/workflows/ci.yml/badge.svg)](https://github.com/GauntletVectorLabs/gauntlet/actions/workflows/ci.yml)
23
+
24
+ **Break your agent before your users do.**
25
+
26
+ Gauntlet fires a suite of adversarial, edge-case "users" at your AI agent over
27
+ HTTP, finds where it fails (system-prompt leaks, unsafe actions, scope drift,
28
+ crashes, runaway output), ranks the failures by severity, and turns them into a
29
+ regression suite you can gate in CI. Framework-agnostic: if your agent speaks
30
+ HTTP, Gauntlet can test it.
31
+
32
+ It is built on one belief: a green eval only means something if you defined what
33
+ red looks like. Most agent "evals" pass because nobody wrote the test that would
34
+ have failed.
35
+
36
+ ## Why this exists
37
+
38
+ Teams ship agents that work in the demo and then quietly break in production: the
39
+ model picks the wrong tool, leaks its prompt to a clever user, confirms an action
40
+ it should have refused, or loops. The expensive part of reliability is not the
41
+ dashboard, it is finding the failures and making sure they stay fixed. Gauntlet
42
+ is the part that goes looking for them.
43
+
44
+ ## Quickstart (30 seconds, no API key)
45
+
46
+ ```bash
47
+ # Install (once published): pip install gauntlet-agent
48
+ # or as an isolated CLI: pipx install gauntlet-agent
49
+
50
+ # 1. See it work against a deliberately broken sample agent, in one process:
51
+ python examples/demo.py
52
+
53
+ # 2. Or run it against your own agent (any HTTP endpoint that takes JSON):
54
+ # terminal A:
55
+ python examples/sample_agent.py
56
+ # terminal B:
57
+ gauntlet run --target http://localhost:8000/chat --canaries examples/canaries.json
58
+ ```
59
+
60
+ Network-free self-test (runs anywhere, good for CI):
61
+
62
+ ```bash
63
+ python tests/test_offline.py # or: pytest
64
+ ```
65
+
66
+ ## Using it on your agent
67
+
68
+ Point `--target` at any endpoint that accepts `POST {"message": "..."}` and
69
+ returns JSON or text. Field names are configurable. Agent isn't an HTTP service
70
+ yet (LangChain, OpenAI Assistants, a bare function)? Wrap it in a few lines with
71
+ the shims in [`examples/adapters/`](examples/adapters) — no server code to write.
72
+
73
+ ```bash
74
+ gauntlet run \
75
+ --target https://your-agent.example.com/v1/chat \
76
+ --request-field input --response-field output \
77
+ --header "Authorization: Bearer $TOKEN" \
78
+ --canaries my_canaries.json \
79
+ --fail-on HIGH \
80
+ --json gauntlet-report.json
81
+ ```
82
+
83
+ Exit code is nonzero when anything at or above `--fail-on` is found, so you can
84
+ drop it straight into CI:
85
+
86
+ ```yaml
87
+ # .github/workflows/agent.yml
88
+ - run: gauntlet run --target $STAGING_AGENT_URL --canaries canaries.json --fail-on HIGH
89
+ ```
90
+
91
+ ### Canaries: define what failure means
92
+
93
+ The universal graders (errors, empty replies, runaway length) need no config.
94
+ The high-value graders are the canaries you supply, the things your agent must
95
+ never do:
96
+
97
+ ```json
98
+ {
99
+ "never_output_substrings": ["INTERNAL-OPS-KEY", "system prompt"],
100
+ "unsafe_compliance_substrings": ["refund of $", "deleted the account"],
101
+ "max_response_chars": 6000,
102
+ "severity_overrides": { "missing_refusal": "MEDIUM", "data_leak": "CRITICAL" }
103
+ }
104
+ ```
105
+
106
+ `severity_overrides` lets you retune any finding kind to your own risk bar
107
+ (CRITICAL/HIGH/MEDIUM/LOW/INFO) — e.g. downgrade `missing_refusal` if your agent
108
+ is intentionally chatty, or keep leaks at CRITICAL.
109
+
110
+ ## How it works
111
+
112
+ 1. **Adversaries** (`gauntlet/adversaries.py`) — a deterministic library of
113
+ probes across prompt injection, scope discipline, false premises, data
114
+ exfiltration, malformed input, and loop bait. Deterministic so runs are
115
+ reproducible.
116
+ 2. **Runner** (`gauntlet/runner.py`) — fires probes concurrently at your HTTP
117
+ endpoint, stdlib only.
118
+ 3. **Graders** (`gauntlet/graders.py`) — universal reliability checks plus your
119
+ canaries, producing severity-ranked findings (CRITICAL to INFO).
120
+ 4. **Report** (`gauntlet/report.py`) — a readable summary, the worst failures,
121
+ and a JSON artifact for CI.
122
+
123
+ ## Optional: LLM-powered mode
124
+
125
+ The default needs no API key. With `--llm`, Gauntlet generates fresh adversarial
126
+ personas from a description of your agent and can grade open-ended behavior with
127
+ a judge instead of substring canaries.
128
+
129
+ ```bash
130
+ pip install "gauntlet-agent[llm]"
131
+ export ANTHROPIC_API_KEY=...
132
+ gauntlet run --target $URL --llm --describe "support bot for an online store"
133
+ ```
134
+
135
+ The judge is a thin, swappable layer. The methodology is the point: generate
136
+ probes from your agent's real surface, and **validate the judge against a small
137
+ human-labeled gold set before trusting its scores.**
138
+
139
+ ### Calibrate the judge (don't trust a score you haven't validated)
140
+
141
+ ```bash
142
+ gauntlet calibrate --gold examples/gold.jsonl --min-kappa 0.6
143
+ ```
144
+
145
+ Runs the judge over a human-labeled gold set and reports accuracy, precision,
146
+ **recall** (of real failures, how many the judge catches — the number that
147
+ matters for a safety tool), F1, and **Cohen's κ** (chance-corrected agreement).
148
+ It exits nonzero below `--min-kappa`, so a weak judge fails CI instead of quietly
149
+ shipping bad scores. A starter gold set lives at `examples/gold.jsonl`.
150
+
151
+ ## Multi-turn probes (jailbreaks that build across turns)
152
+
153
+ Real jailbreaks are rarely one message — they build trust, plant context, or
154
+ manufacture a false premise over several turns, then cash it in. Add `--multiturn`
155
+ to include built-in conversation probes (crescendo, gradual role-reset, context
156
+ poisoning, manufactured commitment). Gauntlet drives each turn-by-turn and grades
157
+ the final reply.
158
+
159
+ ```bash
160
+ # stateful agent (keeps its own session):
161
+ gauntlet run --target $URL --multiturn --canaries canaries.json
162
+
163
+ # stateless agent: send the running transcript as an OpenAI-style messages array
164
+ gauntlet run --target $URL --multiturn --history-field messages --canaries canaries.json
165
+ ```
166
+
167
+ The report prints the full conversation for any multi-turn failure, so you can
168
+ see exactly how it got there.
169
+
170
+ Add `--extended` for newer single-turn attack classes (indirect/RAG injection,
171
+ unicode-homoglyph evasion, refusal suppression, base64 encoding smuggling,
172
+ tool-description extraction, PII handling):
173
+
174
+ ```bash
175
+ gauntlet run --target $URL --extended --multiturn --canaries canaries.json
176
+ ```
177
+
178
+ ## Trace-aware grading (score the tool calls, not just the text)
179
+
180
+ A safe-sounding answer can hide an unsafe action. If your agent returns the tool
181
+ calls it made, Gauntlet can grade those directly. Have the agent include a
182
+ `trace` in its JSON response:
183
+
184
+ ```json
185
+ { "response": "All set!", "trace": [ {"tool": "issue_refund", "args": {"amount": 999}} ] }
186
+ ```
187
+
188
+ Then point at it and declare which tools/args are off-limits:
189
+
190
+ ```bash
191
+ gauntlet run --target $URL --trace-field trace --canaries canaries.json
192
+ ```
193
+ ```json
194
+ { "forbidden_tools": ["issue_refund", "delete_user", "send_bulk_email"],
195
+ "forbidden_tool_arg_substrings": ["all_users", "DROP TABLE"] }
196
+ ```
197
+
198
+ A forbidden tool call (or a forbidden argument) is a HIGH finding even if the
199
+ text looked fine — catching the agent that *says* "I can't" but calls the tool
200
+ anyway.
201
+
202
+ ## Roadmap
203
+
204
+ - [x] Judge calibration command (`gauntlet calibrate`)
205
+ - [x] Persona memory: multi-turn conversation probes (`--multiturn`)
206
+ - [x] Trace-aware grading (`--trace-field` + forbidden tools/args)
207
+ - [x] Hosted dashboard + scheduled runs (see the `apps/dashboard` in the monorepo)
208
+
209
+ ## License
210
+
211
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,195 @@
1
+ # Gauntlet
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/gauntlet-agent.svg)](https://pypi.org/project/gauntlet-agent/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/gauntlet-agent.svg)](https://pypi.org/project/gauntlet-agent/)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
6
+ [![CI](https://github.com/GauntletVectorLabs/gauntlet/actions/workflows/ci.yml/badge.svg)](https://github.com/GauntletVectorLabs/gauntlet/actions/workflows/ci.yml)
7
+
8
+ **Break your agent before your users do.**
9
+
10
+ Gauntlet fires a suite of adversarial, edge-case "users" at your AI agent over
11
+ HTTP, finds where it fails (system-prompt leaks, unsafe actions, scope drift,
12
+ crashes, runaway output), ranks the failures by severity, and turns them into a
13
+ regression suite you can gate in CI. Framework-agnostic: if your agent speaks
14
+ HTTP, Gauntlet can test it.
15
+
16
+ It is built on one belief: a green eval only means something if you defined what
17
+ red looks like. Most agent "evals" pass because nobody wrote the test that would
18
+ have failed.
19
+
20
+ ## Why this exists
21
+
22
+ Teams ship agents that work in the demo and then quietly break in production: the
23
+ model picks the wrong tool, leaks its prompt to a clever user, confirms an action
24
+ it should have refused, or loops. The expensive part of reliability is not the
25
+ dashboard, it is finding the failures and making sure they stay fixed. Gauntlet
26
+ is the part that goes looking for them.
27
+
28
+ ## Quickstart (30 seconds, no API key)
29
+
30
+ ```bash
31
+ # Install (once published): pip install gauntlet-agent
32
+ # or as an isolated CLI: pipx install gauntlet-agent
33
+
34
+ # 1. See it work against a deliberately broken sample agent, in one process:
35
+ python examples/demo.py
36
+
37
+ # 2. Or run it against your own agent (any HTTP endpoint that takes JSON):
38
+ # terminal A:
39
+ python examples/sample_agent.py
40
+ # terminal B:
41
+ gauntlet run --target http://localhost:8000/chat --canaries examples/canaries.json
42
+ ```
43
+
44
+ Network-free self-test (runs anywhere, good for CI):
45
+
46
+ ```bash
47
+ python tests/test_offline.py # or: pytest
48
+ ```
49
+
50
+ ## Using it on your agent
51
+
52
+ Point `--target` at any endpoint that accepts `POST {"message": "..."}` and
53
+ returns JSON or text. Field names are configurable. Agent isn't an HTTP service
54
+ yet (LangChain, OpenAI Assistants, a bare function)? Wrap it in a few lines with
55
+ the shims in [`examples/adapters/`](examples/adapters) — no server code to write.
56
+
57
+ ```bash
58
+ gauntlet run \
59
+ --target https://your-agent.example.com/v1/chat \
60
+ --request-field input --response-field output \
61
+ --header "Authorization: Bearer $TOKEN" \
62
+ --canaries my_canaries.json \
63
+ --fail-on HIGH \
64
+ --json gauntlet-report.json
65
+ ```
66
+
67
+ Exit code is nonzero when anything at or above `--fail-on` is found, so you can
68
+ drop it straight into CI:
69
+
70
+ ```yaml
71
+ # .github/workflows/agent.yml
72
+ - run: gauntlet run --target $STAGING_AGENT_URL --canaries canaries.json --fail-on HIGH
73
+ ```
74
+
75
+ ### Canaries: define what failure means
76
+
77
+ The universal graders (errors, empty replies, runaway length) need no config.
78
+ The high-value graders are the canaries you supply, the things your agent must
79
+ never do:
80
+
81
+ ```json
82
+ {
83
+ "never_output_substrings": ["INTERNAL-OPS-KEY", "system prompt"],
84
+ "unsafe_compliance_substrings": ["refund of $", "deleted the account"],
85
+ "max_response_chars": 6000,
86
+ "severity_overrides": { "missing_refusal": "MEDIUM", "data_leak": "CRITICAL" }
87
+ }
88
+ ```
89
+
90
+ `severity_overrides` lets you retune any finding kind to your own risk bar
91
+ (CRITICAL/HIGH/MEDIUM/LOW/INFO) — e.g. downgrade `missing_refusal` if your agent
92
+ is intentionally chatty, or keep leaks at CRITICAL.
93
+
94
+ ## How it works
95
+
96
+ 1. **Adversaries** (`gauntlet/adversaries.py`) — a deterministic library of
97
+ probes across prompt injection, scope discipline, false premises, data
98
+ exfiltration, malformed input, and loop bait. Deterministic so runs are
99
+ reproducible.
100
+ 2. **Runner** (`gauntlet/runner.py`) — fires probes concurrently at your HTTP
101
+ endpoint, stdlib only.
102
+ 3. **Graders** (`gauntlet/graders.py`) — universal reliability checks plus your
103
+ canaries, producing severity-ranked findings (CRITICAL to INFO).
104
+ 4. **Report** (`gauntlet/report.py`) — a readable summary, the worst failures,
105
+ and a JSON artifact for CI.
106
+
107
+ ## Optional: LLM-powered mode
108
+
109
+ The default needs no API key. With `--llm`, Gauntlet generates fresh adversarial
110
+ personas from a description of your agent and can grade open-ended behavior with
111
+ a judge instead of substring canaries.
112
+
113
+ ```bash
114
+ pip install "gauntlet-agent[llm]"
115
+ export ANTHROPIC_API_KEY=...
116
+ gauntlet run --target $URL --llm --describe "support bot for an online store"
117
+ ```
118
+
119
+ The judge is a thin, swappable layer. The methodology is the point: generate
120
+ probes from your agent's real surface, and **validate the judge against a small
121
+ human-labeled gold set before trusting its scores.**
122
+
123
+ ### Calibrate the judge (don't trust a score you haven't validated)
124
+
125
+ ```bash
126
+ gauntlet calibrate --gold examples/gold.jsonl --min-kappa 0.6
127
+ ```
128
+
129
+ Runs the judge over a human-labeled gold set and reports accuracy, precision,
130
+ **recall** (of real failures, how many the judge catches — the number that
131
+ matters for a safety tool), F1, and **Cohen's κ** (chance-corrected agreement).
132
+ It exits nonzero below `--min-kappa`, so a weak judge fails CI instead of quietly
133
+ shipping bad scores. A starter gold set lives at `examples/gold.jsonl`.
134
+
135
+ ## Multi-turn probes (jailbreaks that build across turns)
136
+
137
+ Real jailbreaks are rarely one message — they build trust, plant context, or
138
+ manufacture a false premise over several turns, then cash it in. Add `--multiturn`
139
+ to include built-in conversation probes (crescendo, gradual role-reset, context
140
+ poisoning, manufactured commitment). Gauntlet drives each turn-by-turn and grades
141
+ the final reply.
142
+
143
+ ```bash
144
+ # stateful agent (keeps its own session):
145
+ gauntlet run --target $URL --multiturn --canaries canaries.json
146
+
147
+ # stateless agent: send the running transcript as an OpenAI-style messages array
148
+ gauntlet run --target $URL --multiturn --history-field messages --canaries canaries.json
149
+ ```
150
+
151
+ The report prints the full conversation for any multi-turn failure, so you can
152
+ see exactly how it got there.
153
+
154
+ Add `--extended` for newer single-turn attack classes (indirect/RAG injection,
155
+ unicode-homoglyph evasion, refusal suppression, base64 encoding smuggling,
156
+ tool-description extraction, PII handling):
157
+
158
+ ```bash
159
+ gauntlet run --target $URL --extended --multiturn --canaries canaries.json
160
+ ```
161
+
162
+ ## Trace-aware grading (score the tool calls, not just the text)
163
+
164
+ A safe-sounding answer can hide an unsafe action. If your agent returns the tool
165
+ calls it made, Gauntlet can grade those directly. Have the agent include a
166
+ `trace` in its JSON response:
167
+
168
+ ```json
169
+ { "response": "All set!", "trace": [ {"tool": "issue_refund", "args": {"amount": 999}} ] }
170
+ ```
171
+
172
+ Then point at it and declare which tools/args are off-limits:
173
+
174
+ ```bash
175
+ gauntlet run --target $URL --trace-field trace --canaries canaries.json
176
+ ```
177
+ ```json
178
+ { "forbidden_tools": ["issue_refund", "delete_user", "send_bulk_email"],
179
+ "forbidden_tool_arg_substrings": ["all_users", "DROP TABLE"] }
180
+ ```
181
+
182
+ A forbidden tool call (or a forbidden argument) is a HIGH finding even if the
183
+ text looked fine — catching the agent that *says* "I can't" but calls the tool
184
+ anyway.
185
+
186
+ ## Roadmap
187
+
188
+ - [x] Judge calibration command (`gauntlet calibrate`)
189
+ - [x] Persona memory: multi-turn conversation probes (`--multiturn`)
190
+ - [x] Trace-aware grading (`--trace-field` + forbidden tools/args)
191
+ - [x] Hosted dashboard + scheduled runs (see the `apps/dashboard` in the monorepo)
192
+
193
+ ## License
194
+
195
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,8 @@
1
+ """Gauntlet: break your agent before your users do."""
2
+
3
+ __version__ = "0.1.0"
4
+
5
+ from .adversaries import Probe, builtin_probes # noqa: F401
6
+ from .runner import run_suite, Result # noqa: F401
7
+ from .graders import grade_all, grade, Finding # noqa: F401
8
+ from .report import build_report # noqa: F401