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.
- {ciagent-0.6.0 → ciagent-0.7.0}/CHANGELOG.md +100 -0
- ciagent-0.7.0/PKG-INFO +263 -0
- ciagent-0.7.0/README.md +220 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/pyproject.toml +1 -1
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/cli.py +698 -17
- ciagent-0.7.0/src/agentci/engine/check_generator.py +330 -0
- ciagent-0.7.0/src/agentci/engine/judge_audit.py +427 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/mock_runner.py +19 -5
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/parallel.py +50 -7
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/path.py +15 -3
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/reporter.py +259 -6
- ciagent-0.7.0/src/agentci/engine/stability.py +375 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/schema/spec_models.py +6 -2
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/templates/report.html.j2 +45 -0
- ciagent-0.6.0/PKG-INFO +0 -156
- ciagent-0.6.0/README.md +0 -113
- ciagent-0.6.0/src/agentci/_version.py +0 -3
- {ciagent-0.6.0 → ciagent-0.7.0}/.gitignore +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/LICENSE +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/__init__.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/adapters/__init__.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/adapters/base.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/adapters/generic.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/adapters/langgraph.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/adapters/openai_agents.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/assertions.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/baselines.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/capture.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/config.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/cost.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/diff_engine.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/__init__.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/correctness.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/cost.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/cost_estimator.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/diff.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/judge.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/metrics.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/results.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/runner.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/engine/span_assertions.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/exceptions.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/loader.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/mocks.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/models.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/py.typed +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/pytest_plugin.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/report.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/runner.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/schema/__init__.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/schema/agentci_spec.schema.json +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/schema/generate_schema.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/templates/__init__.py +0 -0
- {ciagent-0.6.0 → ciagent-0.7.0}/src/agentci/templates/github_action.yml.j2 +0 -0
- {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
|
+
[](https://pypi.org/project/ciagent/)
|
|
49
|
+
[](https://github.com/suniel12/AgentCI/actions/workflows/ci.yml)
|
|
50
|
+
[](LICENSE)
|
|
51
|
+
[](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
|
+

|
|
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
|
+
---
|
ciagent-0.7.0/README.md
ADDED
|
@@ -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
|
+
[](https://pypi.org/project/ciagent/)
|
|
6
|
+
[](https://github.com/suniel12/AgentCI/actions/workflows/ci.yml)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
[](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
|
+

|
|
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
|
+
---
|