agentprdiff 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,32 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ *.egg
11
+ .pytest_cache/
12
+ .coverage
13
+ .coverage.*
14
+ htmlcov/
15
+ .mypy_cache/
16
+ .ruff_cache/
17
+
18
+ # Virtual envs
19
+ .venv/
20
+ venv/
21
+ env/
22
+
23
+ # Editor / OS
24
+ .DS_Store
25
+ .idea/
26
+ .vscode/
27
+ *.swp
28
+
29
+ # agentguard runtime
30
+ # Users SHOULD commit .agentguard/baselines; they should NOT commit run artifacts.
31
+ .agentguard/runs/
32
+ .agentguard/cache/
@@ -0,0 +1,37 @@
1
+ # Changelog
2
+
3
+ All notable changes to `agentprdiff` are documented in this file. Originally
4
+ prototyped under the name `tracediff`; renamed before first public release.
5
+
6
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
7
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
+
9
+ ## [0.1.0] — 2026-04-22
10
+
11
+ Initial public release.
12
+
13
+ ### Added
14
+
15
+ - Core `Suite` / `Case` / `Trace` model for defining agent regression tests.
16
+ - Deterministic graders: `contains`, `contains_any`, `regex_match`, `tool_called`,
17
+ `tool_sequence`, `output_length_lt`, `latency_lt_ms`, `cost_lt_usd`,
18
+ `no_tool_called`.
19
+ - Semantic grader (`semantic`) with a pluggable `judge` callable and built-in
20
+ fake judge for CI environments without API keys.
21
+ - Baseline store (JSON files under `.agentprdiff/baselines/`) designed to be
22
+ committed to version control.
23
+ - Trace diff engine producing a structured `TraceDelta` (assertion pass/fail
24
+ changes, cost delta, latency delta, tool-call sequence changes, output
25
+ change).
26
+ - CLI: `agentprdiff init`, `agentprdiff record`, `agentprdiff check`, `agentprdiff diff`.
27
+ - Rich-formatted terminal reporter and machine-readable JSON reporter for CI.
28
+ - Quickstart example with a mock agent that runs without any API keys.
29
+ - Pytest test suite covering graders, runner, differ, store, and CLI smoke.
30
+ - GitHub Actions CI workflow.
31
+
32
+ ### Known limitations
33
+
34
+ - Only a manual instrumentation API for provider SDKs is shipped in 0.1.0.
35
+ Drop-in wrappers for OpenAI / Anthropic / Vercel AI SDK are planned for 0.2.
36
+ - The semantic grader's built-in judge supports OpenAI and Anthropic via user-
37
+ supplied API keys; hosted judge endpoints are not yet offered.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vinoth Nageshwaran
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,200 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentprdiff
3
+ Version: 0.1.0
4
+ Summary: Guard your LLM agents in CI. Snapshot tests that catch behavioral regressions when models, prompts, or vendors change.
5
+ Project-URL: Homepage, https://github.com/vnageshwaran-de/agentprdiff
6
+ Project-URL: Documentation, https://github.com/vnageshwaran-de/agentprdiff#readme
7
+ Project-URL: Issues, https://github.com/vnageshwaran-de/agentprdiff/issues
8
+ Project-URL: Repository, https://github.com/vnageshwaran-de/agentprdiff
9
+ Author-email: Vinoth Nageshwaran <vnageshwaran@gmail.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: agent,ci,evaluation,llm,observability,regression-testing,snapshot-testing
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Topic :: Software Development :: Testing
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: click>=8.1
24
+ Requires-Dist: pydantic>=2.0
25
+ Requires-Dist: pyyaml>=6.0
26
+ Requires-Dist: rich>=13.0
27
+ Provides-Extra: anthropic
28
+ Requires-Dist: anthropic>=0.30; extra == 'anthropic'
29
+ Provides-Extra: dev
30
+ Requires-Dist: mypy>=1.8; extra == 'dev'
31
+ Requires-Dist: pytest-cov>=4.1; extra == 'dev'
32
+ Requires-Dist: pytest>=7.4; extra == 'dev'
33
+ Requires-Dist: ruff>=0.5; extra == 'dev'
34
+ Provides-Extra: openai
35
+ Requires-Dist: openai>=1.0; extra == 'openai'
36
+ Description-Content-Type: text/markdown
37
+
38
+ # agentprdiff
39
+
40
+ **Guard your LLM agents in CI.** Snapshot tests that catch behavioral regressions when models, prompts, or vendors change.
41
+
42
+ > You upgraded Claude. You tweaked a system prompt. You swapped `gpt-4o` for `gpt-4o-mini` in the cheap path. Which of your agent's behaviors just changed? `agentprdiff` tells you — before the PR merges.
43
+
44
+ ```bash
45
+ pip install agentprdiff
46
+ ```
47
+
48
+ [![CI](https://github.com/vnageshwaran-de/agentprdiff/actions/workflows/ci.yml/badge.svg)](https://github.com/vnageshwaran-de/agentprdiff/actions/workflows/ci.yml)
49
+ [![PyPI](https://img.shields.io/pypi/v/agentprdiff.svg)](https://pypi.org/project/agentprdiff/)
50
+ [![Python](https://img.shields.io/pypi/pyversions/agentprdiff.svg)](https://pypi.org/project/agentprdiff/)
51
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](./LICENSE)
52
+
53
+ ## Why
54
+
55
+ Unit tests assume determinism. Agents aren't deterministic, but they do have *behaviors you rely on* — a specific tool gets called, a refund amount is quoted, a latency budget is respected, a safety guardrail fires. When a model or prompt changes, those behaviors drift. Today most teams find out in production.
56
+
57
+ `agentprdiff` turns those behaviors into versioned, diffable baselines you check into git, and a CI command that fails the build when they regress.
58
+
59
+ It is **not** a framework. Your agent stays exactly the way it is. `agentprdiff` records what it did, lets you assert what should be true about what it did, and compares runs across time.
60
+
61
+ ## 10-line hello world
62
+
63
+ ```python
64
+ # suite.py
65
+ from agentprdiff import case, suite
66
+ from agentprdiff.graders import contains, tool_called, latency_lt_ms, semantic
67
+ from my_agent import run # your agent — unchanged
68
+
69
+ support = suite(
70
+ name="customer_support",
71
+ agent=run,
72
+ cases=[
73
+ case(
74
+ name="refund_happy_path",
75
+ input="I want a refund for order #1234",
76
+ expect=[
77
+ contains("refund"),
78
+ tool_called("lookup_order"),
79
+ semantic("agent acknowledges the refund and explains the timeline"),
80
+ latency_lt_ms(10_000),
81
+ ],
82
+ ),
83
+ ],
84
+ )
85
+ ```
86
+
87
+ ```bash
88
+ agentprdiff init
89
+ agentprdiff record suite.py # save this run as the baseline
90
+ agentprdiff check suite.py # in CI: diff vs baseline, exit 1 on regression
91
+ ```
92
+
93
+ That's the whole product. Four CLI commands. One Python file. Zero framework lock-in.
94
+
95
+ ## What's in the box
96
+
97
+ - **Case + Suite model** — tiny, opinionated, no magic.
98
+ - **10 batteries-included graders** — `contains`, `contains_any`, `regex_match`, `tool_called`, `tool_sequence`, `no_tool_called`, `output_length_lt`, `latency_lt_ms`, `cost_lt_usd`, `semantic` (LLM-as-judge with pluggable backend).
99
+ - **Baseline store** — JSON files under `.agentprdiff/baselines/`, meant to be **committed**. Reviewers see trace changes in pull requests.
100
+ - **Diff engine** — per-case `TraceDelta` with assertion pass/fail changes, cost delta, latency delta, tool-sequence changes, and a unified output diff.
101
+ - **CI-ready CLI** — exit 1 on regression, `--json-out` for artifact archiving, Rich-formatted terminal output.
102
+ - **Zero SDK lock-in** — works with OpenAI, Anthropic, Gemini, Bedrock, LangChain, LangGraph, LlamaIndex, Vercel AI SDK, custom wrappers — if you can wrap your agent in a function, `agentprdiff` can test it.
103
+
104
+ ## How it compares
105
+
106
+ | | Unit tests | LLM-as-judge eval | `agentprdiff` |
107
+ |---|---|---|---|
108
+ | Deterministic pass/fail | yes | no | **yes** (when assertions are deterministic) |
109
+ | Catches behavioral drift | no | yes | **yes** |
110
+ | Runs in CI on every PR | yes | too expensive | **yes** |
111
+ | Human-readable diff of what changed | n/a | rare | **yes** |
112
+ | Works without API keys | yes | no | **yes** (deterministic graders + fake judge) |
113
+
114
+ The value is in the combination: deterministic assertions for the 80% of behaviors you can encode as rules ("this tool was called", "this word appeared", "cost stayed under $0.02"), plus a semantic grader for the 20% that need a judge — with a fake-judge fallback so your CI stays green and free when API keys aren't available.
115
+
116
+ ## The workflow
117
+
118
+ 1. Write a `Suite` alongside your agent code.
119
+ 2. Run `agentprdiff record` once on a known-good version. Commit the resulting `.agentprdiff/baselines/` directory.
120
+ 3. In CI, on every PR, run `agentprdiff check`. If any assertion regresses, or cost/latency budgets are breached, the job fails.
121
+ 4. When behavior intentionally changes, the PR author re-runs `agentprdiff record`, commits the new baseline, and explains the change in the PR description. Reviewers see the before/after in the diff.
122
+
123
+ This is the same loop as Jest snapshot tests or VCR cassettes — applied to LLM agents.
124
+
125
+ ## Instrumenting your agent
126
+
127
+ `agentprdiff` doesn't monkey-patch anything. Your agent returns `(output, Trace)`:
128
+
129
+ ```python
130
+ from agentprdiff import Trace, LLMCall, ToolCall
131
+
132
+ def my_agent(query: str) -> tuple[str, Trace]:
133
+ trace = Trace(suite_name="", case_name="", input=query)
134
+
135
+ # ... call your model, record what happened ...
136
+ trace.record_llm_call(LLMCall(
137
+ provider="anthropic",
138
+ model="claude-sonnet-4-6",
139
+ prompt_tokens=120, completion_tokens=80,
140
+ cost_usd=0.0012, latency_ms=340,
141
+ ))
142
+
143
+ # ... call a tool, record what happened ...
144
+ trace.record_tool_call(ToolCall(name="lookup_order", arguments={"id": "1234"}))
145
+
146
+ return final_output, trace
147
+ ```
148
+
149
+ Agents that return just an output still work — `agentprdiff` wraps them and captures wall-clock latency. You can backfill richer instrumentation incrementally, assertion by assertion.
150
+
151
+ ## CI integration
152
+
153
+ ```yaml
154
+ # .github/workflows/agents.yml
155
+ name: agent-regression
156
+ on: [pull_request]
157
+ jobs:
158
+ agentprdiff:
159
+ runs-on: ubuntu-latest
160
+ steps:
161
+ - uses: actions/checkout@v4
162
+ - uses: actions/setup-python@v5
163
+ with: { python-version: "3.11" }
164
+ - run: pip install -e ".[dev]"
165
+ - run: agentprdiff check suites/*.py --json-out artifacts/agentprdiff.json
166
+ - uses: actions/upload-artifact@v4
167
+ if: always()
168
+ with: { name: agentprdiff, path: artifacts/ }
169
+ ```
170
+
171
+ See [`docs/ci-integration.md`](./docs/ci-integration.md) for GitLab, CircleCI, and Buildkite.
172
+
173
+ ## Quickstart
174
+
175
+ A runnable end-to-end demo, no API keys needed:
176
+
177
+ ```bash
178
+ git clone https://github.com/vnageshwaran-de/agentprdiff
179
+ cd agentprdiff
180
+ pip install -e ".[dev]"
181
+
182
+ cd examples/quickstart
183
+ agentprdiff init
184
+ agentprdiff record suite.py
185
+ agentprdiff check suite.py # exit 0
186
+
187
+ # now break the agent and watch agentprdiff catch it
188
+ sed -i "s/refund/noundr/g" agent.py
189
+ agentprdiff check suite.py # exit 1; see the diff
190
+ ```
191
+
192
+ ## Status
193
+
194
+ `agentprdiff` is **alpha** (0.1.0). The core model and CLI are stable; provider-specific SDK wrappers and a LangChain/LangGraph integration are on the 0.2 roadmap. See [`CHANGELOG.md`](./CHANGELOG.md).
195
+
196
+ Feedback, bug reports, and PRs extremely welcome. Open an issue or @ me.
197
+
198
+ ## License
199
+
200
+ MIT. See [`LICENSE`](./LICENSE).
@@ -0,0 +1,163 @@
1
+ # agentprdiff
2
+
3
+ **Guard your LLM agents in CI.** Snapshot tests that catch behavioral regressions when models, prompts, or vendors change.
4
+
5
+ > You upgraded Claude. You tweaked a system prompt. You swapped `gpt-4o` for `gpt-4o-mini` in the cheap path. Which of your agent's behaviors just changed? `agentprdiff` tells you — before the PR merges.
6
+
7
+ ```bash
8
+ pip install agentprdiff
9
+ ```
10
+
11
+ [![CI](https://github.com/vnageshwaran-de/agentprdiff/actions/workflows/ci.yml/badge.svg)](https://github.com/vnageshwaran-de/agentprdiff/actions/workflows/ci.yml)
12
+ [![PyPI](https://img.shields.io/pypi/v/agentprdiff.svg)](https://pypi.org/project/agentprdiff/)
13
+ [![Python](https://img.shields.io/pypi/pyversions/agentprdiff.svg)](https://pypi.org/project/agentprdiff/)
14
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](./LICENSE)
15
+
16
+ ## Why
17
+
18
+ Unit tests assume determinism. Agents aren't deterministic, but they do have *behaviors you rely on* — a specific tool gets called, a refund amount is quoted, a latency budget is respected, a safety guardrail fires. When a model or prompt changes, those behaviors drift. Today most teams find out in production.
19
+
20
+ `agentprdiff` turns those behaviors into versioned, diffable baselines you check into git, and a CI command that fails the build when they regress.
21
+
22
+ It is **not** a framework. Your agent stays exactly the way it is. `agentprdiff` records what it did, lets you assert what should be true about what it did, and compares runs across time.
23
+
24
+ ## 10-line hello world
25
+
26
+ ```python
27
+ # suite.py
28
+ from agentprdiff import case, suite
29
+ from agentprdiff.graders import contains, tool_called, latency_lt_ms, semantic
30
+ from my_agent import run # your agent — unchanged
31
+
32
+ support = suite(
33
+ name="customer_support",
34
+ agent=run,
35
+ cases=[
36
+ case(
37
+ name="refund_happy_path",
38
+ input="I want a refund for order #1234",
39
+ expect=[
40
+ contains("refund"),
41
+ tool_called("lookup_order"),
42
+ semantic("agent acknowledges the refund and explains the timeline"),
43
+ latency_lt_ms(10_000),
44
+ ],
45
+ ),
46
+ ],
47
+ )
48
+ ```
49
+
50
+ ```bash
51
+ agentprdiff init
52
+ agentprdiff record suite.py # save this run as the baseline
53
+ agentprdiff check suite.py # in CI: diff vs baseline, exit 1 on regression
54
+ ```
55
+
56
+ That's the whole product. Four CLI commands. One Python file. Zero framework lock-in.
57
+
58
+ ## What's in the box
59
+
60
+ - **Case + Suite model** — tiny, opinionated, no magic.
61
+ - **10 batteries-included graders** — `contains`, `contains_any`, `regex_match`, `tool_called`, `tool_sequence`, `no_tool_called`, `output_length_lt`, `latency_lt_ms`, `cost_lt_usd`, `semantic` (LLM-as-judge with pluggable backend).
62
+ - **Baseline store** — JSON files under `.agentprdiff/baselines/`, meant to be **committed**. Reviewers see trace changes in pull requests.
63
+ - **Diff engine** — per-case `TraceDelta` with assertion pass/fail changes, cost delta, latency delta, tool-sequence changes, and a unified output diff.
64
+ - **CI-ready CLI** — exit 1 on regression, `--json-out` for artifact archiving, Rich-formatted terminal output.
65
+ - **Zero SDK lock-in** — works with OpenAI, Anthropic, Gemini, Bedrock, LangChain, LangGraph, LlamaIndex, Vercel AI SDK, custom wrappers — if you can wrap your agent in a function, `agentprdiff` can test it.
66
+
67
+ ## How it compares
68
+
69
+ | | Unit tests | LLM-as-judge eval | `agentprdiff` |
70
+ |---|---|---|---|
71
+ | Deterministic pass/fail | yes | no | **yes** (when assertions are deterministic) |
72
+ | Catches behavioral drift | no | yes | **yes** |
73
+ | Runs in CI on every PR | yes | too expensive | **yes** |
74
+ | Human-readable diff of what changed | n/a | rare | **yes** |
75
+ | Works without API keys | yes | no | **yes** (deterministic graders + fake judge) |
76
+
77
+ The value is in the combination: deterministic assertions for the 80% of behaviors you can encode as rules ("this tool was called", "this word appeared", "cost stayed under $0.02"), plus a semantic grader for the 20% that need a judge — with a fake-judge fallback so your CI stays green and free when API keys aren't available.
78
+
79
+ ## The workflow
80
+
81
+ 1. Write a `Suite` alongside your agent code.
82
+ 2. Run `agentprdiff record` once on a known-good version. Commit the resulting `.agentprdiff/baselines/` directory.
83
+ 3. In CI, on every PR, run `agentprdiff check`. If any assertion regresses, or cost/latency budgets are breached, the job fails.
84
+ 4. When behavior intentionally changes, the PR author re-runs `agentprdiff record`, commits the new baseline, and explains the change in the PR description. Reviewers see the before/after in the diff.
85
+
86
+ This is the same loop as Jest snapshot tests or VCR cassettes — applied to LLM agents.
87
+
88
+ ## Instrumenting your agent
89
+
90
+ `agentprdiff` doesn't monkey-patch anything. Your agent returns `(output, Trace)`:
91
+
92
+ ```python
93
+ from agentprdiff import Trace, LLMCall, ToolCall
94
+
95
+ def my_agent(query: str) -> tuple[str, Trace]:
96
+ trace = Trace(suite_name="", case_name="", input=query)
97
+
98
+ # ... call your model, record what happened ...
99
+ trace.record_llm_call(LLMCall(
100
+ provider="anthropic",
101
+ model="claude-sonnet-4-6",
102
+ prompt_tokens=120, completion_tokens=80,
103
+ cost_usd=0.0012, latency_ms=340,
104
+ ))
105
+
106
+ # ... call a tool, record what happened ...
107
+ trace.record_tool_call(ToolCall(name="lookup_order", arguments={"id": "1234"}))
108
+
109
+ return final_output, trace
110
+ ```
111
+
112
+ Agents that return just an output still work — `agentprdiff` wraps them and captures wall-clock latency. You can backfill richer instrumentation incrementally, assertion by assertion.
113
+
114
+ ## CI integration
115
+
116
+ ```yaml
117
+ # .github/workflows/agents.yml
118
+ name: agent-regression
119
+ on: [pull_request]
120
+ jobs:
121
+ agentprdiff:
122
+ runs-on: ubuntu-latest
123
+ steps:
124
+ - uses: actions/checkout@v4
125
+ - uses: actions/setup-python@v5
126
+ with: { python-version: "3.11" }
127
+ - run: pip install -e ".[dev]"
128
+ - run: agentprdiff check suites/*.py --json-out artifacts/agentprdiff.json
129
+ - uses: actions/upload-artifact@v4
130
+ if: always()
131
+ with: { name: agentprdiff, path: artifacts/ }
132
+ ```
133
+
134
+ See [`docs/ci-integration.md`](./docs/ci-integration.md) for GitLab, CircleCI, and Buildkite.
135
+
136
+ ## Quickstart
137
+
138
+ A runnable end-to-end demo, no API keys needed:
139
+
140
+ ```bash
141
+ git clone https://github.com/vnageshwaran-de/agentprdiff
142
+ cd agentprdiff
143
+ pip install -e ".[dev]"
144
+
145
+ cd examples/quickstart
146
+ agentprdiff init
147
+ agentprdiff record suite.py
148
+ agentprdiff check suite.py # exit 0
149
+
150
+ # now break the agent and watch agentprdiff catch it
151
+ sed -i "s/refund/noundr/g" agent.py
152
+ agentprdiff check suite.py # exit 1; see the diff
153
+ ```
154
+
155
+ ## Status
156
+
157
+ `agentprdiff` is **alpha** (0.1.0). The core model and CLI are stable; provider-specific SDK wrappers and a LangChain/LangGraph integration are on the 0.2 roadmap. See [`CHANGELOG.md`](./CHANGELOG.md).
158
+
159
+ Feedback, bug reports, and PRs extremely welcome. Open an issue or @ me.
160
+
161
+ ## License
162
+
163
+ MIT. See [`LICENSE`](./LICENSE).
@@ -0,0 +1,22 @@
1
+ # agentprdiff quickstart
2
+
3
+ A minimal, runnable example. No API keys required.
4
+
5
+ ```bash
6
+ # from the repo root:
7
+ pip install -e .
8
+ cd examples/quickstart
9
+
10
+ agentprdiff init
11
+ agentprdiff record suite.py # records baselines for every case
12
+ agentprdiff check suite.py # re-runs every case, diffs against the baseline
13
+ ```
14
+
15
+ The first `check` after `record` should exit 0 with all cases passing. Now
16
+ edit `agent.py` — change the refund wording or remove the `lookup_order`
17
+ tool call for a particular input — and re-run `agentprdiff check`. You'll see
18
+ the specific grader that now fails, a cost and latency delta, and a unified
19
+ diff of the output.
20
+
21
+ That's the whole loop. Swap `support_agent` for whatever production agent
22
+ you want to guard.
@@ -0,0 +1,80 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "agentprdiff"
7
+ version = "0.1.0"
8
+ description = "Guard your LLM agents in CI. Snapshot tests that catch behavioral regressions when models, prompts, or vendors change."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Vinoth Nageshwaran", email = "vnageshwaran@gmail.com" }]
13
+ keywords = [
14
+ "llm",
15
+ "agent",
16
+ "evaluation",
17
+ "regression-testing",
18
+ "snapshot-testing",
19
+ "ci",
20
+ "observability",
21
+ ]
22
+ classifiers = [
23
+ "Development Status :: 3 - Alpha",
24
+ "Intended Audience :: Developers",
25
+ "License :: OSI Approved :: MIT License",
26
+ "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3.10",
28
+ "Programming Language :: Python :: 3.11",
29
+ "Programming Language :: Python :: 3.12",
30
+ "Topic :: Software Development :: Testing",
31
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
32
+ ]
33
+ dependencies = [
34
+ "click>=8.1",
35
+ "rich>=13.0",
36
+ "pydantic>=2.0",
37
+ "pyyaml>=6.0",
38
+ ]
39
+
40
+ [project.optional-dependencies]
41
+ openai = ["openai>=1.0"]
42
+ anthropic = ["anthropic>=0.30"]
43
+ dev = [
44
+ "pytest>=7.4",
45
+ "pytest-cov>=4.1",
46
+ "ruff>=0.5",
47
+ "mypy>=1.8",
48
+ ]
49
+
50
+ [project.urls]
51
+ Homepage = "https://github.com/vnageshwaran-de/agentprdiff"
52
+ Documentation = "https://github.com/vnageshwaran-de/agentprdiff#readme"
53
+ Issues = "https://github.com/vnageshwaran-de/agentprdiff/issues"
54
+ Repository = "https://github.com/vnageshwaran-de/agentprdiff"
55
+
56
+ [project.scripts]
57
+ agentprdiff = "agentprdiff.cli:main"
58
+
59
+ [tool.hatch.build.targets.wheel]
60
+ packages = ["src/agentprdiff"]
61
+
62
+ [tool.hatch.build.targets.sdist]
63
+ include = ["src/agentprdiff", "README.md", "LICENSE", "CHANGELOG.md"]
64
+
65
+ [tool.pytest.ini_options]
66
+ testpaths = ["tests"]
67
+ addopts = "-ra -q"
68
+
69
+ [tool.ruff]
70
+ line-length = 100
71
+ target-version = "py310"
72
+
73
+ [tool.ruff.lint]
74
+ select = ["E", "F", "W", "I", "UP", "B", "SIM"]
75
+ ignore = ["E501"]
76
+
77
+ [tool.mypy]
78
+ python_version = "3.10"
79
+ strict = false
80
+ ignore_missing_imports = true
@@ -0,0 +1,81 @@
1
+ """agentprdiff — snapshot testing for LLM agents.
2
+
3
+ The one-happy-path public API:
4
+
5
+ from agentprdiff import suite, case
6
+ from agentprdiff.graders import contains, tool_called, latency_lt_ms, semantic
7
+
8
+ def my_agent(query: str) -> str:
9
+ ...
10
+
11
+ billing_suite = suite(
12
+ name="billing",
13
+ agent=my_agent,
14
+ cases=[
15
+ case(
16
+ name="refund_happy_path",
17
+ input="I want a refund for order #1234",
18
+ expect=[
19
+ contains("refund"),
20
+ tool_called("lookup_order"),
21
+ semantic("agent acknowledges the refund and provides next steps"),
22
+ latency_lt_ms(10_000),
23
+ ],
24
+ ),
25
+ ],
26
+ )
27
+
28
+ Run from the shell::
29
+
30
+ agentprdiff init
31
+ agentprdiff record path/to/my_suite.py # save baselines
32
+ agentprdiff check path/to/my_suite.py # diff against baselines; exit 1 on regression
33
+ """
34
+
35
+ from __future__ import annotations
36
+
37
+ from .core import (
38
+ AgentFn,
39
+ Case,
40
+ Grader,
41
+ GradeResult,
42
+ LLMCall,
43
+ Suite,
44
+ ToolCall,
45
+ Trace,
46
+ case,
47
+ run_agent,
48
+ suite,
49
+ )
50
+ from .differ import AssertionChange, TraceDelta, diff_traces
51
+ from .runner import CaseReport, Runner, RunReport
52
+ from .store import BaselineStore
53
+
54
+ __version__ = "0.1.0"
55
+
56
+ __all__ = [
57
+ # core
58
+ "Suite",
59
+ "Case",
60
+ "Trace",
61
+ "LLMCall",
62
+ "ToolCall",
63
+ "Grader",
64
+ "GradeResult",
65
+ "AgentFn",
66
+ "suite",
67
+ "case",
68
+ "run_agent",
69
+ # diffing
70
+ "TraceDelta",
71
+ "AssertionChange",
72
+ "diff_traces",
73
+ # runner
74
+ "Runner",
75
+ "RunReport",
76
+ "CaseReport",
77
+ # storage
78
+ "BaselineStore",
79
+ # version
80
+ "__version__",
81
+ ]