ciagent 0.5.1__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 (60) hide show
  1. ciagent-0.7.0/.gitignore +43 -0
  2. ciagent-0.7.0/CHANGELOG.md +223 -0
  3. {ciagent-0.5.1 → ciagent-0.7.0}/LICENSE +2 -0
  4. ciagent-0.7.0/PKG-INFO +263 -0
  5. ciagent-0.7.0/README.md +220 -0
  6. {ciagent-0.5.1 → ciagent-0.7.0}/pyproject.toml +4 -4
  7. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/__init__.py +2 -0
  8. ciagent-0.7.0/src/agentci/adapters/__init__.py +5 -0
  9. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/adapters/base.py +2 -0
  10. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/adapters/generic.py +2 -0
  11. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/adapters/langgraph.py +12 -2
  12. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/adapters/openai_agents.py +17 -1
  13. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/assertions.py +2 -0
  14. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/baselines.py +2 -0
  15. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/capture.py +60 -3
  16. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/cli.py +965 -59
  17. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/config.py +2 -0
  18. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/cost.py +2 -0
  19. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/diff_engine.py +2 -0
  20. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/__init__.py +2 -0
  21. ciagent-0.7.0/src/agentci/engine/check_generator.py +330 -0
  22. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/correctness.py +2 -0
  23. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/cost.py +2 -0
  24. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/cost_estimator.py +2 -0
  25. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/diff.py +2 -0
  26. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/judge.py +2 -0
  27. ciagent-0.7.0/src/agentci/engine/judge_audit.py +427 -0
  28. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/metrics.py +2 -0
  29. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/mock_runner.py +22 -6
  30. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/parallel.py +69 -3
  31. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/path.py +47 -5
  32. ciagent-0.7.0/src/agentci/engine/reporter.py +694 -0
  33. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/results.py +2 -0
  34. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/runner.py +2 -0
  35. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/engine/span_assertions.py +2 -0
  36. ciagent-0.7.0/src/agentci/engine/stability.py +375 -0
  37. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/exceptions.py +2 -0
  38. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/loader.py +2 -0
  39. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/mocks.py +2 -0
  40. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/models.py +2 -0
  41. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/pytest_plugin.py +2 -0
  42. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/report.py +2 -0
  43. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/runner.py +2 -0
  44. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/schema/__init__.py +2 -0
  45. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/schema/agentci_spec.schema.json +33 -1
  46. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/schema/generate_schema.py +2 -0
  47. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/schema/spec_models.py +16 -2
  48. ciagent-0.7.0/src/agentci/templates/report.html.j2 +239 -0
  49. ciagent-0.5.1/.gitignore +0 -24
  50. ciagent-0.5.1/CHANGELOG.md +0 -87
  51. ciagent-0.5.1/PKG-INFO +0 -407
  52. ciagent-0.5.1/README.md +0 -364
  53. ciagent-0.5.1/src/agentci/_version.py +0 -1
  54. ciagent-0.5.1/src/agentci/adapters/__init__.py +0 -3
  55. ciagent-0.5.1/src/agentci/engine/reporter.py +0 -315
  56. ciagent-0.5.1/src/agentci/templates/agentci.yaml +0 -16
  57. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/py.typed +0 -0
  58. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/templates/__init__.py +0 -0
  59. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/templates/github_action.yml.j2 +0 -0
  60. {ciagent-0.5.1 → ciagent-0.7.0}/src/agentci/templates/pre_push_hook.sh.j2 +0 -0
@@ -0,0 +1,43 @@
1
+
2
+ # Python
3
+ __pycache__/
4
+ *.py[cod]
5
+ *$py.class
6
+ venv/
7
+ .venv/
8
+ env/
9
+ .env
10
+
11
+ # Distribution
12
+ dist/
13
+ build/
14
+ *.egg-info/
15
+
16
+ # IDEs
17
+ .idea/
18
+ .vscode/
19
+ *.swp
20
+ .DS_Store
21
+
22
+ # Testing cache
23
+ .pytest_cache/
24
+
25
+ # Agent CI
26
+ golden/
27
+ test_results/
28
+
29
+ # Internal planning & development
30
+ Plan_docs/
31
+ phase1.md
32
+ Vision.md
33
+ llms.txt
34
+ demo_ux/
35
+ scripts/
36
+ README_v2.md
37
+
38
+ # Local config
39
+ agentci.yaml
40
+ agentci_spec.yaml
41
+
42
+ # Claude context
43
+ .claude/
@@ -0,0 +1,223 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
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
+
108
+ ## [0.6.0] - 2026-03-05
109
+
110
+ ### Added
111
+
112
+ #### `final_output` Auto-Capture
113
+ - `TraceContext._auto_extract_final_output()` called in `__exit__()` — automatically extracts the agent's answer from traces
114
+ - Extraction priority: LangGraph state messages > span `output_data` (string) > span `output_data` (dict with `content`/`message`/`text`/`output` keys) > last LLM call `output_text`
115
+ - Manual `trace.metadata["final_output"]` still takes precedence (no overwrite)
116
+ - LangGraph adapter: auto-sets `final_output` from last AI message in `parse_state()`
117
+ - OpenAI Agents adapter: auto-sets `final_output` from last span output in `on_trace_end()`
118
+
119
+ #### `agentci calibrate` Command
120
+ - Runs N sample queries against the live agent, measures actual metrics, shows Rich comparison table
121
+ - Updates spec budgets with headroom: +50% for LLM/tool calls, +100% for tokens/cost
122
+ - Flags: `--samples N` (default 2), `--dry-run`, `--yes`, `--spec PATH`
123
+
124
+ #### Strict Tool Sequence Assertions
125
+ - `PathSpec.expected_tool_sequence: Optional[list[str]]` — strict ordered tool call check
126
+ - Mismatch = WARN (soft warning) with position-level diff via `_format_sequence_diff()`
127
+
128
+ #### HTML Trace Report
129
+ - Self-contained `report.html.j2` Jinja2 template with dark theme
130
+ - Summary dashboard (pass/fail/warn counts, total cost)
131
+ - Per-query cards with status badges, answer preview, three-layer details
132
+ - Collapsible trace tree with JS toggle
133
+ - Available via `agentci test --format html --output report.html` or `agentci report -i results.json`
134
+
135
+ ### Changed
136
+ - `max_llm_calls` default in spec generator raised from 8 to 10 (better headroom for real agents)
137
+ - `max_llm_calls` fallback in mock runner raised from 3 to 10
138
+ - Calibrate command floor raised from 8 to 10
139
+ - `--format` choices in `test` and `eval` commands now include `html`
140
+ - `--output / -o` option added to `test` and `eval` commands for HTML file path
141
+ - `agentci report` command fully implemented (was stub) — converts JSON results to HTML
142
+ - 22 new tests added (570 total, up from 548 in v0.5.1)
143
+
144
+ ## [0.5.0] - 2026-03-01
145
+
146
+ ### Added
147
+
148
+ #### Three-Layer Evaluation Engine
149
+ - **Correctness layer** (Layer 1 — hard fail): keyword matching, LLM-as-a-judge, safety checks, hallucination checks, regex/exact match, JSON schema validation
150
+ - **Path layer** (Layer 2 — soft warn): tool trajectory validation, loop detection (default `max_loops=3`), routing assertions, handoff expectations
151
+ - **Cost layer** (Layer 3 — soft warn): token budgets, cost caps, LLM call limits, latency thresholds
152
+ - `runner.py` orchestrates all three layers per query
153
+ - `parallel.py` for parallel query execution across specs
154
+
155
+ #### OR-Logic Keywords
156
+ - `any_expected_in_answer` field — at least one keyword must match (complementing `expected_in_answer` which requires all)
157
+
158
+ #### LLM Judge Enhancements
159
+ - `context_file` support in `JudgeRubric` — doc-grounded judging against reference documents
160
+ - `refutes_premise` flag — injects built-in premise-correction rubric for trick questions
161
+
162
+ #### Span Assertions
163
+ - `SpanAssertionSpec` schema model for span-level assertions
164
+ - `Span.attributes: dict[str, Any]` — OTel-style span-level data propagation
165
+ - Span-level LLM judge support
166
+
167
+ #### Mock Testing Mode
168
+ - `agentci test --mock` — generates synthetic traces, zero API cost
169
+ - `mock_runner.py` — synthetic trace generation from spec expectations
170
+ - `--golden-file` flag — load Q&A pairs from JSON/CSV for mock mode
171
+
172
+ #### Cost Estimator
173
+ - `cost_estimator.py` — pre-execution cost estimates with pricing table
174
+ - Cost estimate shown before live test runs; `--yes`/`-y` skips confirmation
175
+
176
+ #### CLI Improvements
177
+ - `agentci init --generate` — AI-assisted spec generation with guided interview
178
+ - `agentci doctor` — health-check command (spec, runner, API keys, deps, CI)
179
+ - Scan-first flow: auto-scan project before questions, show summary
180
+ - Agent type auto-detected via `_detect_agent_type_from_code()`
181
+ - Skeleton template generation with TODO placeholders for zero-API-key usage
182
+ - Context-aware "Next Steps" based on mode (mock vs live)
183
+ - Non-interactive flags: `--kb-path`, `--mode`
184
+
185
+ #### Diff Engine
186
+ - Three-tier diff engine for baseline comparison
187
+ - 11 `DiffType` categories including `ROUTING_CHANGED`, `GUARDRAILS_CHANGED`
188
+ - `agentci diff` CLI command
189
+
190
+ #### Reporting
191
+ - GitHub annotations with budget cap (`MAX_INLINE_ANNOTATIONS = 10` for warnings; errors uncapped)
192
+ - JSON output format
193
+ - Prometheus metrics export
194
+
195
+ #### Trace Helpers
196
+ - `Trace.called(tool)` / `never_called(tool)` / `loop_count(tool)` — readable assertion helpers
197
+ - `Trace.cost_under(usd)` / `llm_calls_under(n)` — budget assertion helpers
198
+ - `langgraph_trace(agent_name)` — context manager shortcut for LangGraph
199
+ - `TraceContext.attach(state)` — alias for `attach_langgraph_state()`
200
+
201
+ #### Adapters
202
+ - OpenAI Agents SDK adapter (`openai_agents.py`)
203
+ - LangGraph adapter (`langgraph.py`)
204
+
205
+ #### Other
206
+ - `python-dotenv` added as core dependency
207
+ - Deep KB sampling: 2000 chars/file for spec generation
208
+ - Progressive spec building: smoke queries (3) then full queries (10-12)
209
+ - Pytest plugin entry point (`pytest11: agentci`)
210
+ - GUARDRAIL span type, HANDOFF span type
211
+
212
+ ### Changed
213
+ - `PathSpec.max_loops` now defaults to `3` (was `None`)
214
+ - Development status upgraded from Alpha to Beta
215
+ - Package version bumped to 0.5.0
216
+
217
+ ## [0.4.1] - 2026-02-20
218
+
219
+ ### Added
220
+ - Initial project structure and core models
221
+ - Basic trace capture and assertion framework
222
+ - CLI scaffolding with `agentci init`
223
+ - PyPI publishing as `ciagent`
@@ -1,3 +1,5 @@
1
+ Copyright 2025-2026 The AgentCI Authors
2
+
1
3
  Apache License
2
4
  Version 2.0, January 2004
3
5
  http://www.apache.org/licenses/
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
+ ---