agentprdiff 0.2.0__tar.gz → 0.2.2__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.
Files changed (29) hide show
  1. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/.gitignore +1 -0
  2. agentprdiff-0.2.2/CHANGELOG.md +243 -0
  3. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/PKG-INFO +117 -12
  4. agentprdiff-0.2.2/README.md +296 -0
  5. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/pyproject.toml +6 -2
  6. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/__init__.py +1 -1
  7. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/adapters/openai.py +273 -73
  8. agentprdiff-0.2.2/src/agentprdiff/cli.py +358 -0
  9. agentprdiff-0.2.2/src/agentprdiff/filtering.py +125 -0
  10. agentprdiff-0.2.2/src/agentprdiff/reporters.py +438 -0
  11. agentprdiff-0.2.2/src/agentprdiff/scaffold.py +528 -0
  12. agentprdiff-0.2.0/CHANGELOG.md +0 -103
  13. agentprdiff-0.2.0/README.md +0 -193
  14. agentprdiff-0.2.0/src/agentprdiff/cli.py +0 -124
  15. agentprdiff-0.2.0/src/agentprdiff/reporters.py +0 -127
  16. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/LICENSE +0 -0
  17. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/examples/quickstart/README.md +0 -0
  18. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/examples/regression-tour/README.md +0 -0
  19. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/adapters/__init__.py +0 -0
  20. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/adapters/anthropic.py +0 -0
  21. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/adapters/pricing.py +0 -0
  22. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/core.py +0 -0
  23. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/differ.py +0 -0
  24. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/graders/__init__.py +0 -0
  25. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/graders/deterministic.py +0 -0
  26. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/graders/semantic.py +0 -0
  27. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/loader.py +0 -0
  28. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/runner.py +0 -0
  29. {agentprdiff-0.2.0 → agentprdiff-0.2.2}/src/agentprdiff/store.py +0 -0
@@ -30,3 +30,4 @@ env/
30
30
  # Users SHOULD commit .agentprdiff/baselines; they should NOT commit run artifacts.
31
31
  .agentprdiff/runs/
32
32
  .agentprdiff/cache/
33
+ .pypirc
@@ -0,0 +1,243 @@
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
+ ## [Unreleased]
10
+
11
+ ## [0.2.2] — 2026-04-28
12
+
13
+ ### Added
14
+
15
+ - **Native `AsyncOpenAI` support in `agentprdiff.adapters.openai`.** The same
16
+ `instrument_client` and `instrument_tools` API now works with the async
17
+ OpenAI client — and any async OpenAI-compatible provider (Groq, Gemini,
18
+ OpenRouter, Ollama, vLLM, Together, Fireworks, DeepInfra). The adapter
19
+ inspects `client.chat.completions.create` at `with`-block entry; if it's
20
+ a coroutine function, an awaitable patched method is installed and the
21
+ user's `await client.chat.completions.create(...)` call sites work
22
+ unchanged. `instrument_tools` matches per-tool: `async def` tools come
23
+ back as `async def` wrappers (`await tools[name](**args)`), sync tools
24
+ stay sync — a single `TOOL_MAP` may freely mix the two. The `with` block
25
+ is a regular `with`, not `async with`, since the patch is bound to the
26
+ client instance rather than the running event loop. agentprdiff's runner
27
+ remains sync; async agents bridge with `asyncio.run` in their
28
+ `eval_agent` entry point. Removes the previous adoption recommendation
29
+ to use manual `Trace.record_llm_call` instrumentation for async agents.
30
+ - **Updated `--recipe async-openai` scaffold** to use the new adapter
31
+ natively. The generated `_eval_agent.py` no longer carries TODO markers
32
+ for manual instrumentation; it imports `instrument_client` /
33
+ `instrument_tools` and wraps an async tool-calling loop with an
34
+ `asyncio.run` bridge to agentprdiff's sync runner.
35
+ - **`agentprdiff review <suite_file>`** — new subcommand for local iteration
36
+ on a single failing case. Runs the same comparison `check` does, but
37
+ renders one verbose panel per case (input echo, full assertion table with
38
+ `was → now` baseline-vs-current marks, per-metric deltas for cost /
39
+ latency / prompt and completion tokens, tool-sequence diff, and a unified
40
+ output diff in its own panel when output changed) and **always exits 0**
41
+ so it can sit inside watcher / `entr` / `fzf` loops without flipping the
42
+ shell red on every regression. Accepts the same `--case` / `--skip` /
43
+ `--list` flags as `record` and `check`. The CI gate stays `agentprdiff
44
+ check`; `review` is the `pytest -k` of agentprdiff. New `ReviewReporter`
45
+ in `agentprdiff.reporters` powers the rendering and is reusable by
46
+ third-party tooling.
47
+ - **`agentprdiff scaffold <name>`** — new subcommand that stamps out the
48
+ canonical adoption layout (`suites/__init__.py`, `_eval_agent.py`,
49
+ `_stubs.py`, `<name>.py`, `<name>_cases.md`, `suites/README.md`, and
50
+ `.github/workflows/agentprdiff.yml`). Three recipes via `--recipe`:
51
+ `sync-openai` (default; uses `instrument_client`), `async-openai` (manual
52
+ asyncio wrapper, until the async adapter ships in 0.3), and `stubbed`
53
+ (substitutes a single LLM helper — see the new "stubbed LLM-boundary
54
+ pattern" recipe in `docs/adapters.md`). The generated workflow includes
55
+ `permissions: contents: read` so GitHub Advanced Security stops flagging
56
+ it. Pre-existing files are never overwritten — they're reported as
57
+ `[skip]` and the rest are still written.
58
+ - **Case dossier** (`suites/<name>_cases.md`) — new mandatory artifact
59
+ produced by `scaffold` and documented in AGENTS.md and
60
+ `docs/suite-layout.md`. Reviewer-facing markdown with one block per case
61
+ using a fixed five-field structure: *What it tests*, *Input*,
62
+ *Assertions* (plain English), *Code impacted* (file:line references back
63
+ to production code), and *Application impact* (one concrete sentence
64
+ about what breaks for end users on regression). Closes the gap between
65
+ case names that look meaningful in CI output ("article_summary_preserves_acquisition_entities")
66
+ and reviewers who need to know what each case actually pins.
67
+ - New "stubbed LLM-boundary pattern" recipe in `docs/adapters.md` for
68
+ agents whose LLM call is wrapped in a single helper (summarization,
69
+ classification, embedding-prep). Stubbing the helper is cleaner than
70
+ stubbing the SDK client and works equally well for sync and async clients.
71
+ - `agentprdiff record` and `agentprdiff check` now accept `--case PATTERN` and
72
+ `--skip PATTERN` for narrowing a run to a subset of cases. Patterns are
73
+ case-insensitive substrings by default and use `fnmatch` semantics when they
74
+ contain `*`, `?`, or `[`. Both flags are repeatable, accept comma-separated
75
+ lists (`--case refund,policy`), and support qualifier syntax
76
+ (`--case billing:refund*`). A leading `~` (or `!`) negates a pattern, so
77
+ `--case ~slow` is equivalent to `--skip slow`.
78
+ - `agentprdiff record --list` / `check --list` prints suite and case names
79
+ without running anything, so you can discover what's filterable before
80
+ reaching for `--case`.
81
+ - When a filter is active, the CLI now prints a per-suite header
82
+ (`running 2 of 4 cases in customer_support: ...`) so a partial selection is
83
+ visible at a glance. A filter that matches zero cases exits with code 2 and
84
+ prints the available case names — previously a typo'd filter would have
85
+ silently exited 0.
86
+
87
+ ### Changed
88
+
89
+ - The CI workflow templates in `AGENTS.md`, `README.md`, and
90
+ `docs/ci-integration.md` now declare `permissions: contents: read`
91
+ explicitly. GitHub Advanced Security flags workflows without an explicit
92
+ permissions block, and least-privilege is the right default anyway.
93
+ - Documented the recommended `.gitignore` entry (`artifacts/agentprdiff*.json`)
94
+ alongside every CI snippet that uses `--json-out artifacts/...`. The path
95
+ uploads cleanly as a CI build artifact, but the same file lands on every
96
+ local run; without an ignore line it eventually gets `git add`-ed by
97
+ accident.
98
+
99
+ ### Documentation
100
+
101
+ - New "API keys" section in `AGENTS.md` covering both key surfaces (the
102
+ production agent's own keys vs. agentprdiff's semantic-judge keys —
103
+ `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `AGENTGUARD_JUDGE` with the
104
+ silent fake_judge fallback), local setup options (.env / shell export /
105
+ direnv), CI secret wiring, and a short list of "never do this." Adopting
106
+ AI agents are now instructed to explicitly prompt the user about which
107
+ env var their production agent reads, whether to use a real semantic
108
+ judge in CI, and to verify `.env` is gitignored.
109
+ - The scaffolded `.github/workflows/agentprdiff.yml` now includes both
110
+ `OPENAI_API_KEY` and an optional `ANTHROPIC_API_KEY` (for the semantic
111
+ judge) with explanatory comments. The scaffolded `suites/README.md` has a
112
+ new "Setup" section walking through local key configuration.
113
+ - New "Rerun semantics" section in `AGENTS.md` (referenced from README and
114
+ `docs/ci-integration.md`) covering what every subcommand does on the
115
+ second invocation: `record` overwrites baselines in place, `check`
116
+ accumulates a timestamped directory under `.agentprdiff/runs/` on every
117
+ call (gitignored; `rm -rf` to clean), `--json-out PATH` overwrites a
118
+ single file, and `scaffold`/`init` refuse-to-overwrite / are idempotent.
119
+ Adopting AI agents are now instructed to surface the `runs/` accumulation
120
+ behavior to the human user during handoff — it's the only one of the
121
+ four that creates new files on every invocation.
122
+
123
+ ## [0.2.1] — 2026-04-26
124
+
125
+ ### Changed
126
+
127
+ - README links to `AGENTS.md`, `docs/adapters.md`, `docs/ai-driven-adoption.md`,
128
+ `docs/suite-layout.md`, `docs/ci-integration.md`, `LICENSE`, and `CHANGELOG.md`
129
+ are now absolute GitHub URLs instead of relative paths. PyPI's project page
130
+ and Libraries.io render the README but cannot resolve relative repo paths;
131
+ the previous links rendered as broken from those surfaces. Absolute URLs
132
+ fix the click-through from PyPI / Libraries.io directly to the docs on
133
+ GitHub.
134
+ - Status section refreshed: 0.2.x is the current alpha line; OpenAI and
135
+ Anthropic SDK adapters are now shipped (previously listed as 0.2 roadmap).
136
+ LangChain/LangGraph adapters and the JS companion package moved to the
137
+ 0.3 roadmap.
138
+
139
+ ### Fixed
140
+
141
+ - Wheel metadata now emits a separate `Author:` header in addition to
142
+ `Author-email:`. Previously, the PEP 621 `authors = [{ name = ..., email = ... }]`
143
+ form generated only `Author-email: "Name" <email>`, which downstream
144
+ parsers like pypistats.org could not read (showing "Author: None").
145
+ Splitting `authors` into a name-only entry plus an email-only entry,
146
+ and adding a parallel `maintainers` field, makes the package author
147
+ display correctly across PyPI, Libraries.io, and pypistats.
148
+
149
+ ## [0.2.0] — 2026-04-26
150
+
151
+ ### Added
152
+
153
+ - **SDK adapters** for the two dominant agent toolchains, eliminating the need
154
+ for manual `Trace` instrumentation:
155
+ - `agentprdiff.adapters.openai.instrument_client` — context manager that
156
+ monkey-patches `client.chat.completions.create` for the duration of one
157
+ agent call. Records each invocation as an `LLMCall` (provider, model,
158
+ input messages, output text, tool calls, tokens, cost, latency) and
159
+ restores the original on exit. Works with **OpenAI, Groq, Gemini's
160
+ OpenAI-compatible endpoint, OpenRouter, Ollama, vLLM, Together,
161
+ Fireworks, DeepInfra**, and any other SDK that follows the OpenAI client
162
+ shape.
163
+ - `agentprdiff.adapters.anthropic.instrument_client` — equivalent for the
164
+ Anthropic Messages API (`client.messages.create`). Handles the
165
+ content-block response shape (text + `tool_use` blocks) and the
166
+ Messages-API token field names.
167
+ - `instrument_tools(tool_map, trace)` — wraps a dict of callables so each
168
+ invocation records a `ToolCall` with name, arguments, result, latency,
169
+ and any raised exception. Shared between both adapters.
170
+ - `agentprdiff.adapters.pricing` — curated model→price table for cost
171
+ estimation, with `register_prices()` and per-call `prices=` overrides.
172
+ Unknown models record `cost_usd=0.0` and emit a single `RuntimeWarning`
173
+ per process so missing pricing is loud rather than silent.
174
+ - Documentation: `docs/adapters.md` (full reference) and
175
+ `docs/adapters-vercel.md` (manual integration recipe for the Vercel AI
176
+ SDK, which is JS-only and lives in a future companion package).
177
+ - `AGENTS.md` at the repo root — an instruction set written for AI
178
+ coding agents (Claude Code, Cursor, Aider, etc.) that have been asked
179
+ to add `agentprdiff` to a codebase. Covers codebase discovery,
180
+ contract identification, wrap-the-agent recipes (OpenAI / Anthropic /
181
+ custom), stub patterns, suite scaffolding, baseline recording, CI
182
+ wiring, common pitfalls, and a validation checklist. Optimized for
183
+ AI-agent-driven adoption with copy-paste templates.
184
+ - `docs/ai-driven-adoption.md` — human-facing companion to AGENTS.md.
185
+ Three prompt templates (minimum viable / recommended / contract-driven)
186
+ for adopters using Claude Code / Cursor / Aider, plus a sample
187
+ first-session transcript and tips for working with the AI agent
188
+ through the adoption flow.
189
+ - `docs/suite-layout.md` — canonical reference for the suite directory
190
+ structure. Lists each file (`suites/<project>.py`, `_eval_agent.py`,
191
+ `_stubs.py`, baselines, CI workflow, etc.), classifies them as
192
+ mandatory / recommended / optional, and specifies what each must
193
+ and must not contain. Cross-referenced from AGENTS.md and the
194
+ validation checklist.
195
+
196
+ ### Changed
197
+
198
+ - The suite loader now inserts the current working directory onto
199
+ `sys.path` in addition to the suite file's parent directory. Adopters
200
+ who run `agentprdiff record suites/foo.py` from their project root no
201
+ longer have to manually patch `sys.path` to import their own modules
202
+ (e.g. `from agent.agent import ...`, `from config import ...`).
203
+ Both insertions are reverted after the suite loads, so no path leakage
204
+ between runs.
205
+
206
+ ### Notes
207
+
208
+ - The base `pip install agentprdiff` does **not** require the `openai` or
209
+ `anthropic` packages. The adapters operate on a client object's shape,
210
+ not on imported SDK modules — so installing only the SDKs you actually
211
+ use keeps the dependency footprint small. Optional extras are still
212
+ declared (`agentprdiff[openai]`, `agentprdiff[anthropic]`) for adopters
213
+ who prefer to pin the SDK version alongside agentprdiff itself.
214
+
215
+ ## [0.1.0] — 2026-04-22
216
+
217
+ Initial public release.
218
+
219
+ ### Added
220
+
221
+ - Core `Suite` / `Case` / `Trace` model for defining agent regression tests.
222
+ - Deterministic graders: `contains`, `contains_any`, `regex_match`, `tool_called`,
223
+ `tool_sequence`, `output_length_lt`, `latency_lt_ms`, `cost_lt_usd`,
224
+ `no_tool_called`.
225
+ - Semantic grader (`semantic`) with a pluggable `judge` callable and built-in
226
+ fake judge for CI environments without API keys.
227
+ - Baseline store (JSON files under `.agentprdiff/baselines/`) designed to be
228
+ committed to version control.
229
+ - Trace diff engine producing a structured `TraceDelta` (assertion pass/fail
230
+ changes, cost delta, latency delta, tool-call sequence changes, output
231
+ change).
232
+ - CLI: `agentprdiff init`, `agentprdiff record`, `agentprdiff check`, `agentprdiff diff`.
233
+ - Rich-formatted terminal reporter and machine-readable JSON reporter for CI.
234
+ - Quickstart example with a mock agent that runs without any API keys.
235
+ - Pytest test suite covering graders, runner, differ, store, and CLI smoke.
236
+ - GitHub Actions CI workflow.
237
+
238
+ ### Known limitations
239
+
240
+ - Only a manual instrumentation API for provider SDKs is shipped in 0.1.0.
241
+ Drop-in wrappers for OpenAI / Anthropic / Vercel AI SDK are planned for 0.2.
242
+ - The semantic grader's built-in judge supports OpenAI and Anthropic via user-
243
+ supplied API keys; hosted judge endpoints are not yet offered.
@@ -1,12 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentprdiff
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Guard your LLM agents in CI. Snapshot tests that catch behavioral regressions when models, prompts, or vendors change.
5
5
  Project-URL: Homepage, https://github.com/vnageshwaran-de/agentprdiff
6
6
  Project-URL: Documentation, https://github.com/vnageshwaran-de/agentprdiff#readme
7
7
  Project-URL: Issues, https://github.com/vnageshwaran-de/agentprdiff/issues
8
8
  Project-URL: Repository, https://github.com/vnageshwaran-de/agentprdiff
9
- Author-email: Vinoth Nageshwaran <vnageshwaran@gmail.com>
9
+ Author: Vinoth Nageshwaran
10
+ Author-email: vnageshwaran@gmail.com
11
+ Maintainer-email: Vinoth Nageshwaran <vnageshwaran@gmail.com>
10
12
  License: MIT
11
13
  License-File: LICENSE
12
14
  Keywords: agent,ci,evaluation,llm,observability,regression-testing,snapshot-testing
@@ -48,9 +50,9 @@ pip install agentprdiff
48
50
  [![CI](https://github.com/vnageshwaran-de/agentprdiff/actions/workflows/ci.yml/badge.svg)](https://github.com/vnageshwaran-de/agentprdiff/actions/workflows/ci.yml)
49
51
  [![PyPI](https://img.shields.io/pypi/v/agentprdiff.svg)](https://pypi.org/project/agentprdiff/)
50
52
  [![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)
53
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/vnageshwaran-de/agentprdiff/blob/main/LICENSE)
52
54
 
53
- > **Adopting with an AI coding agent?** Point Claude Code, Cursor, Aider, or any agentic IDE at [`AGENTS.md`](./AGENTS.md) — a step-by-step adoption playbook the agent reads directly. Humans driving the adoption: see [`docs/ai-driven-adoption.md`](./docs/ai-driven-adoption.md) for copy-paste prompt templates. The canonical file layout — what's mandatory, what's recommended, what's optional — is at [`docs/suite-layout.md`](./docs/suite-layout.md).
55
+ > **Adopting with an AI coding agent?** Point Claude Code, Cursor, Aider, or any agentic IDE at [`AGENTS.md`](https://github.com/vnageshwaran-de/agentprdiff/blob/main/AGENTS.md) — a step-by-step adoption playbook the agent reads directly. Humans driving the adoption: see [`docs/ai-driven-adoption.md`](https://github.com/vnageshwaran-de/agentprdiff/blob/main/docs/ai-driven-adoption.md) for copy-paste prompt templates. The canonical file layout — what's mandatory, what's recommended, what's optional — is at [`docs/suite-layout.md`](https://github.com/vnageshwaran-de/agentprdiff/blob/main/docs/suite-layout.md).
54
56
 
55
57
  ## Why
56
58
 
@@ -92,7 +94,7 @@ agentprdiff record suite.py # save this run as the baseline
92
94
  agentprdiff check suite.py # in CI: diff vs baseline, exit 1 on regression
93
95
  ```
94
96
 
95
- That's the whole product. Four CLI commands. One Python file. Zero framework lock-in.
97
+ That's the whole product. Five CLI commands (`init`, `record`, `check`, `review`, `scaffold`). One Python file. Zero framework lock-in.
96
98
 
97
99
  ## What's in the box
98
100
 
@@ -102,7 +104,7 @@ That's the whole product. Four CLI commands. One Python file. Zero framework loc
102
104
  - **Diff engine** — per-case `TraceDelta` with assertion pass/fail changes, cost delta, latency delta, tool-sequence changes, and a unified output diff.
103
105
  - **CI-ready CLI** — exit 1 on regression, `--json-out` for artifact archiving, Rich-formatted terminal output.
104
106
  - **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.
105
- - **One-line SDK adapters** — `with instrument_client(client) as trace:` automatically records every LLM and tool call when you're on the OpenAI Python SDK (or any OpenAI-compatible provider Groq / Gemini / OpenRouter / Ollama / vLLM) or the Anthropic SDK. No manual `Trace` wiring required.
107
+ - **One-line SDK adapters** — `with instrument_client(client) as trace:` automatically records every LLM and tool call when you're on the OpenAI Python SDK (sync **or** async — `AsyncOpenAI` is supported by the same context manager) or any OpenAI-compatible provider (Groq / Gemini / OpenRouter / Ollama / vLLM / Together / Fireworks / DeepInfra) or the Anthropic SDK. No manual `Trace` wiring required.
106
108
 
107
109
  ## How it compares
108
110
 
@@ -125,13 +127,49 @@ The value is in the combination: deterministic assertions for the 80% of behavio
125
127
 
126
128
  This is the same loop as Jest snapshot tests or VCR cassettes — applied to LLM agents.
127
129
 
130
+ ### API keys
131
+
132
+ `agentprdiff` doesn't read your agent's API key — your agent does, through whatever env var it already uses. Set that locally (in `.env`, your shell, direnv, whatever) and as a GitHub Actions secret in CI. The scaffold's workflow YAML has the right shape; you fill in the env var name to match your agent.
133
+
134
+ The `semantic()` grader is the one piece of agentprdiff that can use an API key directly — for the LLM judge. Without one, it silently falls back to keyword matching. Set `ANTHROPIC_API_KEY` (cheaper) or `OPENAI_API_KEY` if you want a real judge in CI; leave both unset to keep CI free with fake_judge.
135
+
136
+ See [AGENTS.md → API keys](https://github.com/vnageshwaran-de/agentprdiff/blob/main/AGENTS.md#api-keys--what-to-set-where-and-how-to-ask-the-user-about-them) for the full setup (local options, CI secrets, what never to do).
137
+
138
+ ### What each command does on rerun
139
+
140
+ A common first-day question. Short version:
141
+
142
+ - `record` — overwrites baselines in place. Re-recording an intentional change shows up as a regular git diff in your PR; that's the review surface.
143
+ - `check` — creates a new timestamped directory under `.agentprdiff/runs/` on every invocation. It's gitignored by default, so it never reaches CI; clean local history any time with `rm -rf .agentprdiff/runs/`. `--json-out PATH` overwrites a single file at PATH.
144
+ - `review` — same comparison as `check`, but renders one verbose panel per case and **always exits 0**. Designed for local iteration loops; not meant for CI. Writes to the same `.agentprdiff/runs/` directory.
145
+ - `scaffold` — never overwrites. Skips files that already exist (`[skip]`) and writes the rest.
146
+ - `init` — idempotent; running it twice does nothing the second time.
147
+
148
+ See [AGENTS.md → Rerun semantics](https://github.com/vnageshwaran-de/agentprdiff/blob/main/AGENTS.md#rerun-semantics--what-each-command-does-on-the-second-run) for examples.
149
+
150
+ ### Scaffolding a new suite
151
+
152
+ Skip the copy-paste from [AGENTS.md](https://github.com/vnageshwaran-de/agentprdiff/blob/main/AGENTS.md):
153
+
154
+ ```bash
155
+ agentprdiff scaffold ai_content_summary --recipe sync-openai
156
+ ```
157
+
158
+ Writes the canonical layout (`suites/__init__.py`, `_eval_agent.py`, `_stubs.py`, `<name>.py`, `<name>_cases.md`, `suites/README.md`, and `.github/workflows/agentprdiff.yml`) with TODO markers where you wire in your agent. The `<name>_cases.md` file is a *case dossier* — reviewer-facing prose with one block per case (what it tests, input, assertions in plain English, file:line references to production code, and the application impact if the case regresses). Three recipes:
159
+
160
+ - `sync-openai` (default): uses `instrument_client` from the OpenAI adapter with a sync `OpenAI()` client.
161
+ - `async-openai`: same `instrument_client`, paired with an `asyncio.run` bridge so an `AsyncOpenAI` agent works with agentprdiff's sync runner. The adapter detects the async client at entry — no separate API.
162
+ - `stubbed`: substitutes a single LLM helper instead of the SDK client. Best for summarization / classification / embedding-prep agents — see [`docs/adapters.md`](https://github.com/vnageshwaran-de/agentprdiff/blob/main/docs/adapters.md#stubbed-llm-boundary-pattern).
163
+
164
+ The generated workflow includes `permissions: contents: read` so GHAS doesn't flag it. Pre-existing files are never overwritten.
165
+
128
166
  ## Instrumenting your agent
129
167
 
130
168
  You have two paths. Most agents need the first.
131
169
 
132
170
  ### Option A — SDK adapters (zero manual work)
133
171
 
134
- If your agent uses the OpenAI Python SDK (or any OpenAI-compatible provider Groq, Gemini, OpenRouter, Ollama, vLLM, Together, Fireworks, DeepInfra) or the Anthropic SDK, the SDK adapter captures every model and tool call automatically:
172
+ If your agent uses the OpenAI Python SDK — sync `OpenAI` **or** async `AsyncOpenAI`, including any OpenAI-compatible provider (Groq, Gemini, OpenRouter, Ollama, vLLM, Together, Fireworks, DeepInfra) or the Anthropic SDK, the SDK adapter captures every model and tool call automatically:
135
173
 
136
174
  ```python
137
175
  from openai import OpenAI
@@ -148,9 +186,28 @@ def my_agent(query: str):
148
186
  return final_text, trace
149
187
  ```
150
188
 
151
- The patch is scoped to the specific client instance and reversed when the `with` block exits no global SDK state is touched. Anthropic adopters use `agentprdiff.adapters.anthropic` with the same shape.
189
+ For `AsyncOpenAI`, the same `instrument_client` works it inspects `client.chat.completions.create` at entry and installs an awaitable patched method when the underlying one is `async def`. `instrument_tools` mirrors per-tool: `async def` tools come back awaitable, sync tools stay sync. The `with` block is still a regular `with`:
190
+
191
+ ```python
192
+ import asyncio
193
+ from openai import AsyncOpenAI
194
+ from agentprdiff.adapters.openai import instrument_client, instrument_tools
195
+
196
+ async def my_agent_async(query: str):
197
+ client = AsyncOpenAI()
198
+ with instrument_client(client) as trace:
199
+ tools = instrument_tools(TOOL_MAP, trace)
200
+ response = await client.chat.completions.create(...)
201
+ # ... await tools[name](**args) for async tools, tools[name](**args) for sync ...
202
+ return final_text, trace
203
+
204
+ def my_agent(query: str):
205
+ return asyncio.run(my_agent_async(query))
206
+ ```
207
+
208
+ The patch is scoped to the specific client instance and reversed when the `with` block exits — no global SDK state is touched. Anthropic adopters use `agentprdiff.adapters.anthropic` with the same shape (sync clients today; async Anthropic is on the roadmap).
152
209
 
153
- See [`docs/adapters.md`](./docs/adapters.md) for the full reference, including pricing overrides, custom provider tags, and recipes for nested agents.
210
+ See [`docs/adapters.md`](https://github.com/vnageshwaran-de/agentprdiff/blob/main/docs/adapters.md) for the full reference, including pricing overrides, custom provider tags, and recipes for nested agents.
154
211
 
155
212
  ### Option B — Manual instrumentation
156
213
 
@@ -184,6 +241,8 @@ Agents that return just an output still work — `agentprdiff` wraps them and ca
184
241
  # .github/workflows/agents.yml
185
242
  name: agent-regression
186
243
  on: [pull_request]
244
+ permissions:
245
+ contents: read # least-privilege; GHAS flags workflows without this.
187
246
  jobs:
188
247
  agentprdiff:
189
248
  runs-on: ubuntu-latest
@@ -198,7 +257,9 @@ jobs:
198
257
  with: { name: agentprdiff, path: artifacts/ }
199
258
  ```
200
259
 
201
- See [`docs/ci-integration.md`](./docs/ci-integration.md) for GitLab, CircleCI, and Buildkite.
260
+ If you use `--json-out artifacts/...`, add `artifacts/agentprdiff*.json` (or the broader `artifacts/`) to your project's `.gitignore` — the CI artifact upload doesn't prevent a contributor from accidentally `git add`ing it locally.
261
+
262
+ See [`docs/ci-integration.md`](https://github.com/vnageshwaran-de/agentprdiff/blob/main/docs/ci-integration.md) for GitLab, CircleCI, and Buildkite.
202
263
 
203
264
  ## Quickstart
204
265
 
@@ -219,12 +280,56 @@ sed -i "s/refund/noundr/g" agent.py
219
280
  agentprdiff check suite.py # exit 1; see the diff
220
281
  ```
221
282
 
283
+ ### Running a subset of cases
284
+
285
+ Iterating on a single failing case shouldn't require commenting out the rest. `record`, `check`, and `review` all accept `--case` and `--skip` for narrowing a run:
286
+
287
+ ```bash
288
+ # Discover what's available.
289
+ agentprdiff check suite.py --list
290
+
291
+ # Single case (case-insensitive substring).
292
+ agentprdiff check suite.py --case refund_happy_path
293
+
294
+ # Glob across cases.
295
+ agentprdiff check suite.py --case "*order*"
296
+
297
+ # Multiple patterns (repeated flag or comma-separated).
298
+ agentprdiff check suite.py --case refund --case policy
299
+ agentprdiff check suite.py --case refund,policy
300
+
301
+ # Everything except slow cases.
302
+ agentprdiff check suite.py --skip slow
303
+ agentprdiff check suite.py --case ~slow # equivalent
304
+
305
+ # Qualify by suite when names collide across suites.
306
+ agentprdiff check suite.py --case "billing:refund*"
307
+ ```
308
+
309
+ A filter that matches zero cases exits 2 and prints the available case names — `--list` is the discoverable counterpart. The selection summary (`running 2 of 4 cases in <suite>: ...`) is printed before each suite runs so a partial match is never silent.
310
+
311
+ ### Reviewing one case (the local-iteration loop)
312
+
313
+ `agentprdiff check` is built for CI: a compact summary table and exit 1 on regression. While you're iterating on a single case, that's the wrong shape — you want to see *everything* about that one case, and you don't want your shell going red between every keystroke. That's `agentprdiff review`:
314
+
315
+ ```bash
316
+ # Verbose per-case panel: input, every assertion's was→now verdict,
317
+ # cost/latency/token deltas, tool-sequence diff, output diff.
318
+ agentprdiff review suite.py --case refund_happy_path
319
+
320
+ # Same filter syntax as check / record — globs, negation, multi-pattern.
321
+ agentprdiff review suite.py --case "*refund*"
322
+ agentprdiff review suite.py --skip slow
323
+ ```
324
+
325
+ `review` runs the same comparison `check` does (and writes to the same `.agentprdiff/runs/` directory) but **always exits 0**, even on regression — so it sits cleanly inside watcher loops (`entr`, `watchexec`, `fzf` previews). Use `check` when you want CI's exit semantics locally; reach for `review` while you're working. Think `pytest -k`.
326
+
222
327
  ## Status
223
328
 
224
- `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).
329
+ `agentprdiff` is **alpha** (0.2.x). The core model, CLI, and OpenAI / Anthropic SDK adapters are stable. The OpenAI adapter covers both sync `OpenAI` and async `AsyncOpenAI` clients via the same `instrument_client` context manager. Async Anthropic, LangChain/LangGraph adapters, and a JS companion package for the Vercel AI SDK are on the 0.3 roadmap. See [`CHANGELOG.md`](https://github.com/vnageshwaran-de/agentprdiff/blob/main/CHANGELOG.md).
225
330
 
226
331
  Feedback, bug reports, and PRs extremely welcome. Open an issue or @ me.
227
332
 
228
333
  ## License
229
334
 
230
- MIT. See [`LICENSE`](./LICENSE).
335
+ MIT. See [`LICENSE`](https://github.com/vnageshwaran-de/agentprdiff/blob/main/LICENSE).