ciagent 0.6.0__tar.gz → 0.7.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.
Files changed (55) hide show
  1. {ciagent-0.6.0 → ciagent-0.7.0}/CHANGELOG.md +100 -0
  2. ciagent-0.7.0/PKG-INFO +263 -0
  3. ciagent-0.7.0/README.md +220 -0
  4. {ciagent-0.6.0 → ciagent-0.7.0}/pyproject.toml +1 -1
  5. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/cli.py +698 -17
  6. ciagent-0.7.0/src/agentci/engine/check_generator.py +330 -0
  7. ciagent-0.7.0/src/agentci/engine/judge_audit.py +427 -0
  8. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/mock_runner.py +19 -5
  9. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/parallel.py +50 -7
  10. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/path.py +15 -3
  11. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/reporter.py +259 -6
  12. ciagent-0.7.0/src/agentci/engine/stability.py +375 -0
  13. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/schema/spec_models.py +6 -2
  14. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/templates/report.html.j2 +45 -0
  15. ciagent-0.6.0/PKG-INFO +0 -156
  16. ciagent-0.6.0/README.md +0 -113
  17. ciagent-0.6.0/src/agentci/_version.py +0 -3
  18. {ciagent-0.6.0 → ciagent-0.7.0}/.gitignore +0 -0
  19. {ciagent-0.6.0 → ciagent-0.7.0}/LICENSE +0 -0
  20. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/__init__.py +0 -0
  21. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/adapters/__init__.py +0 -0
  22. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/adapters/base.py +0 -0
  23. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/adapters/generic.py +0 -0
  24. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/adapters/langgraph.py +0 -0
  25. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/adapters/openai_agents.py +0 -0
  26. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/assertions.py +0 -0
  27. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/baselines.py +0 -0
  28. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/capture.py +0 -0
  29. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/config.py +0 -0
  30. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/cost.py +0 -0
  31. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/diff_engine.py +0 -0
  32. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/__init__.py +0 -0
  33. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/correctness.py +0 -0
  34. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/cost.py +0 -0
  35. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/cost_estimator.py +0 -0
  36. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/diff.py +0 -0
  37. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/judge.py +0 -0
  38. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/metrics.py +0 -0
  39. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/results.py +0 -0
  40. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/runner.py +0 -0
  41. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/span_assertions.py +0 -0
  42. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/exceptions.py +0 -0
  43. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/loader.py +0 -0
  44. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/mocks.py +0 -0
  45. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/models.py +0 -0
  46. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/py.typed +0 -0
  47. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/pytest_plugin.py +0 -0
  48. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/report.py +0 -0
  49. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/runner.py +0 -0
  50. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/schema/__init__.py +0 -0
  51. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/schema/agentci_spec.schema.json +0 -0
  52. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/schema/generate_schema.py +0 -0
  53. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/templates/__init__.py +0 -0
  54. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/templates/github_action.yml.j2 +0 -0
  55. {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/templates/pre_push_hook.sh.j2 +0 -0
@@ -5,6 +5,106 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ### Changed — stability report hardening (pre-launch fixes from eng review)
11
+ - **Flip attribution now compares per-layer sub-verdicts first**: if every
12
+ deterministic check returned the same outcome across runs and only the LLM judge's
13
+ verdict changed, the flip is `judge-flake` even when the answer text was
14
+ paraphrased (previously mislabeled `agent-variance`)
15
+ - **New flip source `infra-error`**: a judge API failure counted as a fail no longer
16
+ reads as `judge-flake` — one transient hiccup must not say "fix your rubric"
17
+ - **Console shows observed facts only** (verdict history + pass rate); pass@k /
18
+ pass^k move to JSON output as clearly labeled estimates (at small k they restate
19
+ the pass rate)
20
+ - Duplicate query texts in a spec are flagged (they merge into one stability
21
+ record); queries missing from some runs are marked `partial (k/N runs)`
22
+ - `agentci run` (legacy suite runner) now prints a deprecation warning pointing at
23
+ `agentci test`; removal planned for 0.9.0
24
+ - Removed stale `src/agentci/_version.py` (said 0.1.0; version comes from package
25
+ metadata)
26
+
27
+ ## [0.7.0] - 2026-07-05
28
+
29
+ ### Added
30
+
31
+ #### KB-Derived Fact Checks — `agentci generate-checks`
32
+ Mines the knowledge base for hard facts (prices, rates, SKUs, versions,
33
+ explicit quantities) and proposes them as deterministic assertions on
34
+ existing spec queries. One LLM call at authoring time; the checks run
35
+ deterministically forever at zero cost.
36
+
37
+ - **Brittleness gate**: every candidate is validated against recorded golden
38
+ answers before it is offered — a check that would fail a known-good answer
39
+ is rejected automatically with the failing answer shown
40
+ - Only non-paraphrasable facts; prose facts become variant sets
41
+ (`any_expected_in_answer`), never single literal strings; only
42
+ `any_expected_in_answer` / `not_in_answer` / `regex_match` are proposed
43
+ - Candidates without a golden answer are `unvalidated` and never
44
+ auto-accepted, even with `--yes`; interactive review for everything else
45
+ - Merge never overwrites user-written assertions; `.bak` backup on write;
46
+ `--dry-run` mode
47
+ - New module `agentci.engine.check_generator`; 21 new tests
48
+
49
+ #### Judge Audit — `agentci judge-audit`
50
+ Meta-evaluation of the LLM judge against ground truth you already have,
51
+ re-scoring recorded golden baselines (the agent is never re-run):
52
+
53
+ - **Mode 1 — judge vs. deterministic checks**: independent verdicts on the
54
+ same recorded answer; reports the disagreement matrix. The killer row:
55
+ answers the judge PASSED that a deterministic fact-check FAILED
56
+ (shared-context judge blindness, detected automatically)
57
+ - **Mode 2 — retest stability** (`--repeats K`, default 3): same answer
58
+ judged K times; verdict flips on identical input are the judge's noise floor
59
+ - **Mode 3 — hand labels** (`--labels FILE`): agreement + Cohen's κ against
60
+ human review, with standard trust thresholds
61
+ - Scoped claim stated in the report itself: measured on fact-checkable
62
+ queries; one-directional (disqualifying) signal for judgment-only queries
63
+ - Verdicts: TRUSTWORTHY / NEEDS CALIBRATION / UNRELIABLE (exit 1) /
64
+ ERROR when the judge never ran (exit 2 — a judge that couldn't run is
65
+ never scored)
66
+ - `--sample N` cost cap; console + JSON output
67
+ - New module `agentci.engine.judge_audit`; 27 new tests
68
+
69
+ #### Stability Report — `agentci test --runs N`
70
+ A stable suite score can hide per-query verdict flips: the aggregate holds
71
+ because the errors move around. `--runs N` executes the whole suite N times
72
+ and reports what a single run cannot show:
73
+
74
+ - Per-query verdict history (✅❌✅), pass rate, pass@k and pass^k estimates
75
+ - Suite score per run printed side by side with the queries that flipped
76
+ - **Flip-source attribution** — every flip is labelled:
77
+ - `agent-variance`: the agent's output changed → fix the agent
78
+ - `judge-flake`: same output, the LLM judge changed its verdict → fix the eval
79
+ - `mixed`: near-identical paraphrase with a judge configured — not guessed
80
+ Attribution rests on a structural fact: deterministic checks cannot flip on
81
+ identical output, so identical answer + tools + flipped verdict = judge.
82
+ - Exit semantics: flaky-but-passing exits 0 (warnings only); queries failing
83
+ in EVERY run exit 1; `--fail-on-flaky` escalates flips to exit 1
84
+ - Works in every format: console section, GitHub `::warning` annotations,
85
+ `stability` block in JSON, stability card in the HTML report
86
+ - Mock mode support: `AGENTCI_MOCK_FLAKY=1 agentci test --mock --runs 3`
87
+ demonstrates the report with zero API keys
88
+ - New module `agentci.engine.stability` (`build_stability_report`,
89
+ `StabilityReport`, `QueryStability`, `FlipSource`); 21 new tests
90
+
91
+ ### Changed
92
+ - **`expected_tools` now asserts by default**: a missing expected tool produces a WARN
93
+ (tool recall gates at 1.0 unless `min_tool_recall` explicitly loosens it). Previously,
94
+ without `min_tool_recall`, a recall of 0.0 displayed as PASS with a checkmark.
95
+ - **`expected_tools: []` now asserts that no tools are called**: an explicit empty list
96
+ produces a WARN if the agent called any tool. Previously it was silently skipped.
97
+ - `agentci doctor` no longer reports numpy as a required dependency (it was never used
98
+ by AgentCI, so every fresh install showed a false failure).
99
+
100
+ ### Docs
101
+ - README: fixed the quickstart spec example (was missing the required `agent:` field),
102
+ added CI badge, "Check facts in code" section, docs index
103
+ - Rewrote `docs/quickstart.md`, `docs/ci-cd.md`, `docs/cost-tracking.md`, and
104
+ `docs/golden-traces.md` to match the current `agentci test` workflow
105
+ - Fixed dead clone URLs in CONTRIBUTING.md and quickstart
106
+ - Removed unused demo GIF variants and cast recordings (6 files, ~2 MB)
107
+
8
108
  ## [0.6.0] - 2026-03-05
9
109
 
10
110
  ### Added
ciagent-0.7.0/PKG-INFO ADDED
@@ -0,0 +1,263 @@
1
+ Metadata-Version: 2.4
2
+ Name: ciagent
3
+ Version: 0.7.0
4
+ Summary: Continuous Integration for AI Agents. Catch cost spikes and logic regressions before production.
5
+ Project-URL: Documentation, https://github.com/suniel12/AgentCI#readme
6
+ Project-URL: Repository, https://github.com/suniel12/AgentCI.git
7
+ Project-URL: Issues, https://github.com/suniel12/AgentCI/issues
8
+ License: Apache-2.0
9
+ License-File: LICENSE
10
+ Keywords: agents,ai,ci-cd,llm,regression,testing
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Framework :: Pytest
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Topic :: Software Development :: Testing
15
+ Requires-Python: >=3.10
16
+ Requires-Dist: click>=8.0
17
+ Requires-Dist: jinja2>=3.0
18
+ Requires-Dist: opentelemetry-api>=1.20
19
+ Requires-Dist: opentelemetry-sdk>=1.20
20
+ Requires-Dist: pydantic>=2.0
21
+ Requires-Dist: pytest>=7.0
22
+ Requires-Dist: python-dotenv>=0.19
23
+ Requires-Dist: pyyaml>=6.0
24
+ Requires-Dist: rich>=13.0
25
+ Provides-Extra: all
26
+ Requires-Dist: anthropic>=0.20; extra == 'all'
27
+ Requires-Dist: jsonschema>=4.0; extra == 'all'
28
+ Requires-Dist: langgraph>=0.1; extra == 'all'
29
+ Requires-Dist: openai>=1.0; extra == 'all'
30
+ Provides-Extra: anthropic
31
+ Requires-Dist: anthropic>=0.20; extra == 'anthropic'
32
+ Provides-Extra: dev
33
+ Requires-Dist: mypy; extra == 'dev'
34
+ Requires-Dist: pytest>=8.0; extra == 'dev'
35
+ Requires-Dist: ruff; extra == 'dev'
36
+ Provides-Extra: jsonschema
37
+ Requires-Dist: jsonschema>=4.0; extra == 'jsonschema'
38
+ Provides-Extra: langgraph
39
+ Requires-Dist: langgraph>=0.1; extra == 'langgraph'
40
+ Provides-Extra: openai
41
+ Requires-Dist: openai>=1.0; extra == 'openai'
42
+ Description-Content-Type: text/markdown
43
+
44
+ # AgentCI
45
+
46
+ **Pytest-native regression testing for AI agents.** Catch routing changes, tool call drift, and cost spikes before production.
47
+
48
+ [![PyPI](https://img.shields.io/pypi/v/ciagent)](https://pypi.org/project/ciagent/)
49
+ [![CI](https://github.com/suniel12/AgentCI/actions/workflows/ci.yml/badge.svg)](https://github.com/suniel12/AgentCI/actions/workflows/ci.yml)
50
+ [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
51
+ [![AGENTS.md](https://img.shields.io/badge/AGENTS.md-supported-blue)](AGENTS.md)
52
+
53
+ You changed a prompt. Your agent broke in production. Three days later, a user complained. You had no tests, no diff, no idea what went wrong.
54
+
55
+ Works with OpenAI, Anthropic, and LangGraph. Runs inside pytest.
56
+
57
+ ## Add to Your Project
58
+
59
+ ```bash
60
+ pip install ciagent
61
+ ```
62
+
63
+ Write your golden queries — what should your agent handle, and what should it refuse?
64
+
65
+ ```yaml
66
+ # agentci_spec.yaml
67
+ agent: my-agent
68
+ # runner: any function that takes a query string and returns a response
69
+ runner: my_app.agent:run_for_agentci
70
+ queries:
71
+ - query: "How do I install AgentCI?"
72
+ correctness:
73
+ any_expected_in_answer: ["pip install", "ciagent"]
74
+ path:
75
+ expected_tools: [retrieve_docs]
76
+ cost:
77
+ max_llm_calls: 8
78
+
79
+ - query: "What's the CEO's favorite restaurant?"
80
+ correctness:
81
+ not_in_answer: ["restaurant", "favorite"]
82
+ path:
83
+ expected_tools: [] # expect no tools called for out-of-scope queries
84
+ ```
85
+
86
+ Run:
87
+
88
+ ```bash
89
+ agentci test --mock # start here: zero-cost with synthetic traces
90
+ agentci test # run live against your real agent
91
+ ```
92
+
93
+ `agentci test` evaluates each query through 3 layers — correctness, path, and cost:
94
+
95
+ ```
96
+ ============================================================
97
+
98
+ Query: How do I install AgentCI?
99
+ Answer: To install AgentCI, you can use pip with the following command:
100
+ pip install ciagent. Make sure you have Python 3.10 or later.
101
+
102
+ ✅ CORRECTNESS: PASS
103
+ ✓ Found keywords: "pip install ciagent"
104
+ ✓ LLM judge passed (score: 5 ≥ 0.6)
105
+ 📈 PATH: PASS
106
+ ✓ Tool recall: 1.000 (expected: [retrieve_docs])
107
+ ✓ Tool precision: 0.500
108
+ ✓ No loops detected
109
+ 💰 COST: PASS
110
+ ✓ LLM calls: 8 ≤ max 8
111
+
112
+ ============================================================
113
+
114
+ Query: What Python version does AgentCI require and what frameworks does it support?
115
+ Answer: AgentCI currently does not specify a required Python version
116
+ in the provided context, so I don't have that information...
117
+
118
+ ❌ CORRECTNESS: FAIL
119
+ • Expected '3.10' not found in answer
120
+ 📈 PATH: PASS
121
+ ✓ Tool recall: 1.000 (expected: [retrieve_docs])
122
+ ✓ Loops: 1 ≤ max 3
123
+ 💰 COST: PASS
124
+ ✓ LLM calls: 4 ≤ max 5
125
+
126
+ ============================================================
127
+ ```
128
+
129
+ Don't have golden queries yet? `agentci init --generate` scans your code and generates a starter spec.
130
+
131
+ ## A stable score is not a stable system
132
+
133
+ Run the identical eval three times and you can get 96% / 95% / 96% — rock solid — while
134
+ individual queries flip verdicts every run. The aggregate holds because the errors move
135
+ around. `--runs N` shows what a single run can't:
136
+
137
+ ```bash
138
+ agentci test --runs 3
139
+ ```
140
+
141
+ ```
142
+ Run 1/3: 18/19 passed
143
+ Run 2/3: 18/19 passed
144
+ Run 3/3: 18/19 passed
145
+
146
+ ────────────────────────────────────────────────────────────
147
+ Stability Report
148
+ ────────────────────────────────────────────────────────────
149
+ Suite score across 3 runs: 95% / 95% / 95%
150
+
151
+ ⚠️ FLAKY — 2/19 queries flipped verdicts across runs:
152
+ "What's your return window?" ✅❌✅ pass_rate=0.67 source: agent-variance (answer changed)
153
+ "Do you sell gift cards?" ❌✅✅ pass_rate=0.67 source: judge-flake (same answer, verdict flipped)
154
+
155
+ Flip sources: 1 agent-variance (fix the agent) │ 1 judge-flake (fix the eval) │ 0 infra-error (retry) │ 0 mixed
156
+
157
+ Stability verdict: FLAKY
158
+ ```
159
+
160
+ Every flip is attributed to its source, so it's a routed work item, not a scary number:
161
+ **agent-variance** means the agent produced different output (fix the prompt, retrieval, or
162
+ temperature); **judge-flake** means the output — or every deterministic check's outcome —
163
+ was identical but the LLM judge changed its mind (fix the rubric, or replace the judge with
164
+ a deterministic check); **infra-error** means a judge API call failed (retry, fix nothing).
165
+ Attribution is structural, not guessed: deterministic checks cannot flip on identical
166
+ output, and per-layer sub-verdicts are compared across runs. The console shows observed
167
+ facts; pass@k/pass^k estimates live in the JSON output, labeled as estimates.
168
+
169
+ Flaky-but-passing exits 0 so adoption won't break your CI; add `--fail-on-flaky` when
170
+ you're ready to gate on it. Try it with zero API keys:
171
+ `AGENTCI_MOCK_FLAKY=1 agentci test --mock --runs 3`. Details: [docs/stability.md](docs/stability.md).
172
+
173
+ ## Audit the judge itself
174
+
175
+ An LLM judge that shares your agent's context inherits your agent's blind spots: when
176
+ retrieval comes up empty, the agent answers from nothing — and the judge, reading the same
177
+ nothing, passes it. `judge-audit` measures your judge against ground truth you already have,
178
+ by re-scoring recorded baselines (the agent is never re-run):
179
+
180
+ ```bash
181
+ agentci judge-audit
182
+ ```
183
+
184
+ 1. **Judge vs. deterministic checks** — the disagreement matrix. The row that matters:
185
+ answers the judge PASSED that a hard fact-check FAILED.
186
+ 2. **Retest stability** — the same answer judged `--repeats` times; flips on identical
187
+ input are the judge's own noise floor.
188
+ 3. **Hand labels** (`--labels`) — agreement + Cohen's κ against your own review.
189
+
190
+ The claim is deliberately one-directional: a judge that fails where you *can* check it
191
+ shouldn't be trusted where you can't. Verdict: `TRUSTWORTHY` / `NEEDS CALIBRATION` /
192
+ `UNRELIABLE`. Details: [docs/judge-audit.md](docs/judge-audit.md).
193
+
194
+ ## Check facts in code. Save the judge for judgment.
195
+
196
+ Most agent failures that matter involve a hard fact — a product name, a price, a version number. Those are checkable deterministically, for free. And an LLM judge grading against the same context as your agent inherits your agent's blind spots: when retrieval comes up empty, the agent answers from nothing and the judge — reading the same nothing — passes it.
197
+
198
+ So AgentCI runs deterministic checks first and treats the judge as the last resort, not the default:
199
+
200
+ 1. **Fact checks in code** — `expected_in_answer`, `not_in_answer`, `regex_match`, `json_schema`. Zero LLM calls, zero flakiness, same verdict every run.
201
+ 2. **Path checks** — did the agent call the tools it should have? A missing expected tool warns; a forbidden tool fails.
202
+ 3. **Cost budgets** — LLM calls, tokens, dollars per query.
203
+ 4. **LLM judge** (`llm_judge` rubrics, optional) — only for answers that genuinely need judgment, evaluated after every deterministic check has run.
204
+
205
+ Don't write the fact checks by hand — mine them from your knowledge base:
206
+
207
+ ```bash
208
+ agentci generate-checks
209
+ ```
210
+
211
+ It extracts hard facts (prices, rates, SKUs, "30 days") as variant-set assertions, and
212
+ **validates every candidate against your recorded golden answers first** — a check that
213
+ would fail a known-good answer is rejected before you ever see it. One LLM call at
214
+ authoring time; the checks run free forever. Details: [docs/generate-checks.md](docs/generate-checks.md).
215
+
216
+ ## Demo
217
+
218
+ Here's a RAG agent demo where someone "optimizes for latency" by reducing retriever docs from 8 to 1. AgentCI catches the correctness regression:
219
+
220
+ ![AgentCI Demo](demo/agentci-rag-demo.gif)
221
+
222
+ ## CLI
223
+
224
+ ```bash
225
+ agentci init --generate # Scan project, generate test spec
226
+ agentci init # Generate GitHub Actions workflow + pre-push hook
227
+ agentci test --mock --yes # Zero-cost synthetic traces, CI-friendly (no keys, no prompts)
228
+ agentci test # Run 3-layer evaluation (correctness → path → cost)
229
+ agentci test --runs 3 # Stability report: verdict flips + flip-source attribution
230
+ agentci judge-audit # Audit the LLM judge against checks, retests, hand labels
231
+ agentci generate-checks # Mine KB facts into deterministic assertions (gated)
232
+ agentci test --format html -o report.html # HTML report with per-query details
233
+ agentci calibrate # Measure real agent metrics, auto-tune spec budgets
234
+ agentci doctor # Health check: spec, deps, API keys
235
+ agentci record <test> # Record golden baseline
236
+ agentci diff # Diff against baseline
237
+ agentci report -i results.json # Generate HTML report from JSON results
238
+ ```
239
+ ## Docs
240
+
241
+ - [Quickstart](docs/quickstart.md) — install to first green run
242
+ - [Stability testing](docs/stability.md) — `--runs N`, flip-source attribution
243
+ - [Judge audit](docs/judge-audit.md) — is your LLM judge lying to you?
244
+ - [Generate checks](docs/generate-checks.md) — mine KB facts into gated assertions
245
+ - [Writing tests](docs/writing-tests.md) — the full spec reference
246
+ - [Cost tracking](docs/cost-tracking.md) — budgets and spike detection
247
+ - [Golden traces](docs/golden-traces.md) — record baselines, diff regressions
248
+ - [CI/CD integration](docs/ci-cd.md) — GitHub Actions setup
249
+ - [LangGraph](docs/langgraph.md) — graph-based agent support
250
+ - [Metrics reference](docs/metrics_reference.md) — every metric, defined
251
+
252
+ ## Why not just an LLM judge?
253
+
254
+ Judge-only evals are expensive, flaky, and blind to their own context. AgentCI is pytest-native regression testing: deterministic checks catch the factual failures, golden traces catch behavioral drift, cost budgets catch spend regressions — and the judge handles only what genuinely needs judgment. Mock mode (`agentci test --mock`) runs the whole suite with zero API keys and zero cost, so it can gate every PR.
255
+
256
+ ## Contributing
257
+
258
+ [GitHub Issues](https://github.com/suniel12/AgentCI/issues) ·
259
+ [DemoAgents](https://github.com/suniel12/DemoAgents) — working examples for OpenAI, Anthropic, and LangGraph agents
260
+
261
+ Apache 2.0. If you build an agent and test it with AgentCI, I'd love to hear about it.
262
+
263
+ ---
@@ -0,0 +1,220 @@
1
+ # AgentCI
2
+
3
+ **Pytest-native regression testing for AI agents.** Catch routing changes, tool call drift, and cost spikes before production.
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/ciagent)](https://pypi.org/project/ciagent/)
6
+ [![CI](https://github.com/suniel12/AgentCI/actions/workflows/ci.yml/badge.svg)](https://github.com/suniel12/AgentCI/actions/workflows/ci.yml)
7
+ [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
8
+ [![AGENTS.md](https://img.shields.io/badge/AGENTS.md-supported-blue)](AGENTS.md)
9
+
10
+ You changed a prompt. Your agent broke in production. Three days later, a user complained. You had no tests, no diff, no idea what went wrong.
11
+
12
+ Works with OpenAI, Anthropic, and LangGraph. Runs inside pytest.
13
+
14
+ ## Add to Your Project
15
+
16
+ ```bash
17
+ pip install ciagent
18
+ ```
19
+
20
+ Write your golden queries — what should your agent handle, and what should it refuse?
21
+
22
+ ```yaml
23
+ # agentci_spec.yaml
24
+ agent: my-agent
25
+ # runner: any function that takes a query string and returns a response
26
+ runner: my_app.agent:run_for_agentci
27
+ queries:
28
+ - query: "How do I install AgentCI?"
29
+ correctness:
30
+ any_expected_in_answer: ["pip install", "ciagent"]
31
+ path:
32
+ expected_tools: [retrieve_docs]
33
+ cost:
34
+ max_llm_calls: 8
35
+
36
+ - query: "What's the CEO's favorite restaurant?"
37
+ correctness:
38
+ not_in_answer: ["restaurant", "favorite"]
39
+ path:
40
+ expected_tools: [] # expect no tools called for out-of-scope queries
41
+ ```
42
+
43
+ Run:
44
+
45
+ ```bash
46
+ agentci test --mock # start here: zero-cost with synthetic traces
47
+ agentci test # run live against your real agent
48
+ ```
49
+
50
+ `agentci test` evaluates each query through 3 layers — correctness, path, and cost:
51
+
52
+ ```
53
+ ============================================================
54
+
55
+ Query: How do I install AgentCI?
56
+ Answer: To install AgentCI, you can use pip with the following command:
57
+ pip install ciagent. Make sure you have Python 3.10 or later.
58
+
59
+ ✅ CORRECTNESS: PASS
60
+ ✓ Found keywords: "pip install ciagent"
61
+ ✓ LLM judge passed (score: 5 ≥ 0.6)
62
+ 📈 PATH: PASS
63
+ ✓ Tool recall: 1.000 (expected: [retrieve_docs])
64
+ ✓ Tool precision: 0.500
65
+ ✓ No loops detected
66
+ 💰 COST: PASS
67
+ ✓ LLM calls: 8 ≤ max 8
68
+
69
+ ============================================================
70
+
71
+ Query: What Python version does AgentCI require and what frameworks does it support?
72
+ Answer: AgentCI currently does not specify a required Python version
73
+ in the provided context, so I don't have that information...
74
+
75
+ ❌ CORRECTNESS: FAIL
76
+ • Expected '3.10' not found in answer
77
+ 📈 PATH: PASS
78
+ ✓ Tool recall: 1.000 (expected: [retrieve_docs])
79
+ ✓ Loops: 1 ≤ max 3
80
+ 💰 COST: PASS
81
+ ✓ LLM calls: 4 ≤ max 5
82
+
83
+ ============================================================
84
+ ```
85
+
86
+ Don't have golden queries yet? `agentci init --generate` scans your code and generates a starter spec.
87
+
88
+ ## A stable score is not a stable system
89
+
90
+ Run the identical eval three times and you can get 96% / 95% / 96% — rock solid — while
91
+ individual queries flip verdicts every run. The aggregate holds because the errors move
92
+ around. `--runs N` shows what a single run can't:
93
+
94
+ ```bash
95
+ agentci test --runs 3
96
+ ```
97
+
98
+ ```
99
+ Run 1/3: 18/19 passed
100
+ Run 2/3: 18/19 passed
101
+ Run 3/3: 18/19 passed
102
+
103
+ ────────────────────────────────────────────────────────────
104
+ Stability Report
105
+ ────────────────────────────────────────────────────────────
106
+ Suite score across 3 runs: 95% / 95% / 95%
107
+
108
+ ⚠️ FLAKY — 2/19 queries flipped verdicts across runs:
109
+ "What's your return window?" ✅❌✅ pass_rate=0.67 source: agent-variance (answer changed)
110
+ "Do you sell gift cards?" ❌✅✅ pass_rate=0.67 source: judge-flake (same answer, verdict flipped)
111
+
112
+ Flip sources: 1 agent-variance (fix the agent) │ 1 judge-flake (fix the eval) │ 0 infra-error (retry) │ 0 mixed
113
+
114
+ Stability verdict: FLAKY
115
+ ```
116
+
117
+ Every flip is attributed to its source, so it's a routed work item, not a scary number:
118
+ **agent-variance** means the agent produced different output (fix the prompt, retrieval, or
119
+ temperature); **judge-flake** means the output — or every deterministic check's outcome —
120
+ was identical but the LLM judge changed its mind (fix the rubric, or replace the judge with
121
+ a deterministic check); **infra-error** means a judge API call failed (retry, fix nothing).
122
+ Attribution is structural, not guessed: deterministic checks cannot flip on identical
123
+ output, and per-layer sub-verdicts are compared across runs. The console shows observed
124
+ facts; pass@k/pass^k estimates live in the JSON output, labeled as estimates.
125
+
126
+ Flaky-but-passing exits 0 so adoption won't break your CI; add `--fail-on-flaky` when
127
+ you're ready to gate on it. Try it with zero API keys:
128
+ `AGENTCI_MOCK_FLAKY=1 agentci test --mock --runs 3`. Details: [docs/stability.md](docs/stability.md).
129
+
130
+ ## Audit the judge itself
131
+
132
+ An LLM judge that shares your agent's context inherits your agent's blind spots: when
133
+ retrieval comes up empty, the agent answers from nothing — and the judge, reading the same
134
+ nothing, passes it. `judge-audit` measures your judge against ground truth you already have,
135
+ by re-scoring recorded baselines (the agent is never re-run):
136
+
137
+ ```bash
138
+ agentci judge-audit
139
+ ```
140
+
141
+ 1. **Judge vs. deterministic checks** — the disagreement matrix. The row that matters:
142
+ answers the judge PASSED that a hard fact-check FAILED.
143
+ 2. **Retest stability** — the same answer judged `--repeats` times; flips on identical
144
+ input are the judge's own noise floor.
145
+ 3. **Hand labels** (`--labels`) — agreement + Cohen's κ against your own review.
146
+
147
+ The claim is deliberately one-directional: a judge that fails where you *can* check it
148
+ shouldn't be trusted where you can't. Verdict: `TRUSTWORTHY` / `NEEDS CALIBRATION` /
149
+ `UNRELIABLE`. Details: [docs/judge-audit.md](docs/judge-audit.md).
150
+
151
+ ## Check facts in code. Save the judge for judgment.
152
+
153
+ Most agent failures that matter involve a hard fact — a product name, a price, a version number. Those are checkable deterministically, for free. And an LLM judge grading against the same context as your agent inherits your agent's blind spots: when retrieval comes up empty, the agent answers from nothing and the judge — reading the same nothing — passes it.
154
+
155
+ So AgentCI runs deterministic checks first and treats the judge as the last resort, not the default:
156
+
157
+ 1. **Fact checks in code** — `expected_in_answer`, `not_in_answer`, `regex_match`, `json_schema`. Zero LLM calls, zero flakiness, same verdict every run.
158
+ 2. **Path checks** — did the agent call the tools it should have? A missing expected tool warns; a forbidden tool fails.
159
+ 3. **Cost budgets** — LLM calls, tokens, dollars per query.
160
+ 4. **LLM judge** (`llm_judge` rubrics, optional) — only for answers that genuinely need judgment, evaluated after every deterministic check has run.
161
+
162
+ Don't write the fact checks by hand — mine them from your knowledge base:
163
+
164
+ ```bash
165
+ agentci generate-checks
166
+ ```
167
+
168
+ It extracts hard facts (prices, rates, SKUs, "30 days") as variant-set assertions, and
169
+ **validates every candidate against your recorded golden answers first** — a check that
170
+ would fail a known-good answer is rejected before you ever see it. One LLM call at
171
+ authoring time; the checks run free forever. Details: [docs/generate-checks.md](docs/generate-checks.md).
172
+
173
+ ## Demo
174
+
175
+ Here's a RAG agent demo where someone "optimizes for latency" by reducing retriever docs from 8 to 1. AgentCI catches the correctness regression:
176
+
177
+ ![AgentCI Demo](demo/agentci-rag-demo.gif)
178
+
179
+ ## CLI
180
+
181
+ ```bash
182
+ agentci init --generate # Scan project, generate test spec
183
+ agentci init # Generate GitHub Actions workflow + pre-push hook
184
+ agentci test --mock --yes # Zero-cost synthetic traces, CI-friendly (no keys, no prompts)
185
+ agentci test # Run 3-layer evaluation (correctness → path → cost)
186
+ agentci test --runs 3 # Stability report: verdict flips + flip-source attribution
187
+ agentci judge-audit # Audit the LLM judge against checks, retests, hand labels
188
+ agentci generate-checks # Mine KB facts into deterministic assertions (gated)
189
+ agentci test --format html -o report.html # HTML report with per-query details
190
+ agentci calibrate # Measure real agent metrics, auto-tune spec budgets
191
+ agentci doctor # Health check: spec, deps, API keys
192
+ agentci record <test> # Record golden baseline
193
+ agentci diff # Diff against baseline
194
+ agentci report -i results.json # Generate HTML report from JSON results
195
+ ```
196
+ ## Docs
197
+
198
+ - [Quickstart](docs/quickstart.md) — install to first green run
199
+ - [Stability testing](docs/stability.md) — `--runs N`, flip-source attribution
200
+ - [Judge audit](docs/judge-audit.md) — is your LLM judge lying to you?
201
+ - [Generate checks](docs/generate-checks.md) — mine KB facts into gated assertions
202
+ - [Writing tests](docs/writing-tests.md) — the full spec reference
203
+ - [Cost tracking](docs/cost-tracking.md) — budgets and spike detection
204
+ - [Golden traces](docs/golden-traces.md) — record baselines, diff regressions
205
+ - [CI/CD integration](docs/ci-cd.md) — GitHub Actions setup
206
+ - [LangGraph](docs/langgraph.md) — graph-based agent support
207
+ - [Metrics reference](docs/metrics_reference.md) — every metric, defined
208
+
209
+ ## Why not just an LLM judge?
210
+
211
+ Judge-only evals are expensive, flaky, and blind to their own context. AgentCI is pytest-native regression testing: deterministic checks catch the factual failures, golden traces catch behavioral drift, cost budgets catch spend regressions — and the judge handles only what genuinely needs judgment. Mock mode (`agentci test --mock`) runs the whole suite with zero API keys and zero cost, so it can gate every PR.
212
+
213
+ ## Contributing
214
+
215
+ [GitHub Issues](https://github.com/suniel12/AgentCI/issues) ·
216
+ [DemoAgents](https://github.com/suniel12/DemoAgents) — working examples for OpenAI, Anthropic, and LangGraph agents
217
+
218
+ Apache 2.0. If you build an agent and test it with AgentCI, I'd love to hear about it.
219
+
220
+ ---
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ciagent"
3
- version = "0.6.0"
3
+ version = "0.7.0"
4
4
  description = "Continuous Integration for AI Agents. Catch cost spikes and logic regressions before production."
5
5
  readme = "README.md"
6
6
  license = {text = "Apache-2.0"}