aieval-py 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. aieval_py-0.1.0/.github/workflows/publish.yml +34 -0
  2. aieval_py-0.1.0/.github/workflows/test.yml +45 -0
  3. aieval_py-0.1.0/.gitignore +64 -0
  4. aieval_py-0.1.0/IMPLEMENTATION_PLAN.md +187 -0
  5. aieval_py-0.1.0/LICENSE +0 -0
  6. aieval_py-0.1.0/PKG-INFO +200 -0
  7. aieval_py-0.1.0/PROJECT_DISCOVERY.md +1586 -0
  8. aieval_py-0.1.0/README.md +167 -0
  9. aieval_py-0.1.0/examples/01_basic_llm_output.py +77 -0
  10. aieval_py-0.1.0/examples/02_agent_tool_guardrail.py +74 -0
  11. aieval_py-0.1.0/examples/03_async_and_severity_routing.py +78 -0
  12. aieval_py-0.1.0/examples/04_semantic_judge_adapter.py +76 -0
  13. aieval_py-0.1.0/pyproject.toml +99 -0
  14. aieval_py-0.1.0/src/aieval/__init__.py +86 -0
  15. aieval_py-0.1.0/src/aieval/checks/__init__.py +51 -0
  16. aieval_py-0.1.0/src/aieval/checks/base.py +55 -0
  17. aieval_py-0.1.0/src/aieval/checks/constraints.py +243 -0
  18. aieval_py-0.1.0/src/aieval/checks/fields.py +127 -0
  19. aieval_py-0.1.0/src/aieval/checks/json_check.py +59 -0
  20. aieval_py-0.1.0/src/aieval/checks/schema.py +86 -0
  21. aieval_py-0.1.0/src/aieval/checks/tool_call.py +241 -0
  22. aieval_py-0.1.0/src/aieval/cli/__init__.py +3 -0
  23. aieval_py-0.1.0/src/aieval/cli/main.py +205 -0
  24. aieval_py-0.1.0/src/aieval/domain/__init__.py +13 -0
  25. aieval_py-0.1.0/src/aieval/domain/context.py +13 -0
  26. aieval_py-0.1.0/src/aieval/domain/failure.py +130 -0
  27. aieval_py-0.1.0/src/aieval/domain/result.py +65 -0
  28. aieval_py-0.1.0/src/aieval/py.typed +2 -0
  29. aieval_py-0.1.0/src/aieval/runner/__init__.py +16 -0
  30. aieval_py-0.1.0/src/aieval/runner/evaluator.py +184 -0
  31. aieval_py-0.1.0/src/aieval/runner/routing.py +72 -0
  32. aieval_py-0.1.0/src/aieval/semantic/__init__.py +3 -0
  33. aieval_py-0.1.0/src/aieval/semantic/protocol.py +35 -0
  34. aieval_py-0.1.0/tests/fixtures/golden_invalid_tool_call.json +14 -0
  35. aieval_py-0.1.0/tests/fixtures/golden_valid_tool_call.json +17 -0
  36. aieval_py-0.1.0/tests/test_cli.py +49 -0
  37. aieval_py-0.1.0/tests/test_cli_coverage.py +62 -0
  38. aieval_py-0.1.0/tests/unit/test_constraints_check.py +61 -0
  39. aieval_py-0.1.0/tests/unit/test_deep_coverage.py +119 -0
  40. aieval_py-0.1.0/tests/unit/test_domain.py +75 -0
  41. aieval_py-0.1.0/tests/unit/test_evaluator.py +104 -0
  42. aieval_py-0.1.0/tests/unit/test_fields_check.py +38 -0
  43. aieval_py-0.1.0/tests/unit/test_schema_check.py +57 -0
  44. aieval_py-0.1.0/tests/unit/test_tool_call_check.py +77 -0
@@ -0,0 +1,34 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ pypi-publish:
9
+ name: Build and publish Python ๐Ÿ distributions ๐Ÿ“ฆ to PyPI
10
+ runs-on: ubuntu-latest
11
+ environment: pypi
12
+ permissions:
13
+ id-token: write # Mandatory for PyPI Trusted Publishing (OIDC)
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Set up Python
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.12"
22
+
23
+ - name: Install build tooling
24
+ run: |
25
+ python -m pip install --upgrade pip
26
+ pip install build
27
+
28
+ - name: Build sdist and wheel
29
+ run: |
30
+ python -m build
31
+
32
+ - name: Publish to PyPI
33
+ uses: pypa/gh-action-pypi-publish@release/v1
34
+
@@ -0,0 +1,45 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
12
+ runs-on: ${{ matrix.os }}
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ os: [ubuntu-latest]
17
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Set up Python ${{ matrix.python-version }}
23
+ uses: actions/setup-python@v5
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+ cache: "pip"
27
+
28
+ - name: Install dependencies
29
+ run: |
30
+ python -m pip install --upgrade pip
31
+ pip install .[dev]
32
+
33
+ - name: Run Ruff Lint and Format Checks
34
+ run: |
35
+ ruff check src tests
36
+ ruff format --check src tests
37
+
38
+ - name: Run Mypy Type Check
39
+ run: |
40
+ mypy src
41
+
42
+ - name: Run Pytest with Coverage
43
+ run: |
44
+ pytest --cov=aieval --cov-report=term-missing --cov-fail-under=90
45
+
@@ -0,0 +1,64 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # Virtual environments
30
+ .venv/
31
+ venv/
32
+ ENV/
33
+ env/
34
+
35
+ # Testing & Coverage
36
+ .tox/
37
+ .nox/
38
+ .coverage
39
+ .coverage.*
40
+ .cache
41
+ nosetests.xml
42
+ coverage.xml
43
+ *.cover
44
+ *.py,cover
45
+ .hypothesis/
46
+ .pytest_cache/
47
+ cover/
48
+
49
+ # Typing & Linting
50
+ .mypy_cache/
51
+ .dmypy.json
52
+ dmypy.json
53
+ .pyre/
54
+ .pytype/
55
+ .ruff_cache/
56
+
57
+ # IDE / Editor
58
+ .vscode/
59
+ .idea/
60
+ *.swp
61
+ *.swo
62
+ *~
63
+ .DS_Store
64
+
@@ -0,0 +1,187 @@
1
+ # Implementation Plan: `aieval` (Python)
2
+
3
+ This document tracks the phased implementation plan for the Python counterpart of `aieval` (originally created in TypeScript as `@hamza1331/aieval`).
4
+
5
+ ## Guiding Principles
6
+ - **Deterministic-First:** Prioritize zero-cost, sub-millisecond deterministic assertions over expensive, non-deterministic LLM calls.
7
+ - **Zero Bloat:** Minimal external dependencies. Python standard library wherever possible (`dataclasses`, `typing`, `enum`, `re`, `json`, `argparse`, `asyncio`), with `pydantic>=2.0.0` as the standard schema engine (equivalent to Zod in TS).
8
+ - **TypeScript Parity:** Exact equivalence in domain concepts, failure taxonomy codes, severity routing, and golden test fixture schemas.
9
+ - **Idiomatic Python 3.10+:** Dual sync/async execution (`evaluate()` / `aevaluate()`), immutable frozen dataclasses, strict typing (PEP 561 `py.typed`), and modern structural pattern matching/protocols.
10
+
11
+ ---
12
+
13
+ ## Architecture Overview
14
+
15
+ ```text
16
+ aieval-py/
17
+ โ”œโ”€โ”€ pyproject.toml # PEP 621 metadata, Hatchling build backend, dev deps
18
+ โ”œโ”€โ”€ README.md
19
+ โ”œโ”€โ”€ LICENSE
20
+ โ”œโ”€โ”€ IMPLEMENTATION_PLAN.md
21
+ โ”œโ”€โ”€ PROJECT_DISCOVERY.md
22
+ โ”œโ”€โ”€ .gitignore
23
+ โ”œโ”€โ”€ .github/
24
+ โ”‚ โ””โ”€โ”€ workflows/
25
+ โ”‚ โ”œโ”€โ”€ test.yml # Matrix across Python 3.10, 3.11, 3.12, 3.13, 3.14
26
+ โ”‚ โ””โ”€โ”€ publish.yml # PyPI Trusted Publishing (OIDC) on release
27
+ โ””โ”€โ”€ src/
28
+ โ””โ”€โ”€ aieval/
29
+ โ”œโ”€โ”€ __init__.py # Clean public exports (evaluate, aevaluate, checks, models)
30
+ โ”œโ”€โ”€ py.typed # PEP 561 marker
31
+ โ”œโ”€โ”€ domain/
32
+ โ”‚ โ”œโ”€โ”€ __init__.py
33
+ โ”‚ โ”œโ”€โ”€ failure.py # Failure, Severity, FailureCode
34
+ โ”‚ โ”œโ”€โ”€ result.py # EvaluationResult, EvaluationSummary
35
+ โ”‚ โ””โ”€โ”€ context.py # EvaluationContext
36
+ โ”œโ”€โ”€ checks/
37
+ โ”‚ โ”œโ”€โ”€ __init__.py # Check Protocol & standard check exports
38
+ โ”‚ โ”œโ”€โ”€ base.py # Protocol Check, CheckResult
39
+ โ”‚ โ”œโ”€โ”€ schema.py # schema_check (Pydantic v2)
40
+ โ”‚ โ”œโ”€โ”€ fields.py # required_fields, allowed_fields
41
+ โ”‚ โ”œโ”€โ”€ constraints.py # regex_match, allowed_values, range_check, length_check
42
+ โ”‚ โ”œโ”€โ”€ tool_call.py # tool_call_check, tool_call_check.one_of
43
+ โ”‚ โ””โ”€โ”€ json_check.py # valid_json check
44
+ โ”œโ”€โ”€ semantic/
45
+ โ”‚ โ”œโ”€โ”€ __init__.py
46
+ โ”‚ โ””โ”€โ”€ protocol.py # SemanticJudge Protocol (zero-dependency, optional)
47
+ โ”œโ”€โ”€ runner/
48
+ โ”‚ โ”œโ”€โ”€ __init__.py
49
+ โ”‚ โ”œโ”€โ”€ evaluator.py # evaluate() & aevaluate() execution engines
50
+ โ”‚ โ””โ”€โ”€ routing.py # Severity threshold evaluation & summary calculation
51
+ โ””โ”€โ”€ cli/
52
+ โ”œโ”€โ”€ __init__.py
53
+ โ””โ”€โ”€ main.py # `aieval run <fixture>` and `aieval check` CLI
54
+ โ””โ”€โ”€ tests/
55
+ โ”œโ”€โ”€ conftest.py
56
+ โ”œโ”€โ”€ unit/
57
+ โ”‚ โ”œโ”€โ”€ test_failures.py
58
+ โ”‚ โ”œโ”€โ”€ test_schema_check.py
59
+ โ”‚ โ”œโ”€โ”€ test_fields_check.py
60
+ โ”‚ โ”œโ”€โ”€ test_constraints_check.py
61
+ โ”‚ โ”œโ”€โ”€ test_tool_call_check.py
62
+ โ”‚ โ”œโ”€โ”€ test_evaluator_sync.py
63
+ โ”‚ โ”œโ”€โ”€ test_evaluator_async.py
64
+ โ”‚ โ””โ”€โ”€ test_severity_routing.py
65
+ โ”œโ”€โ”€ fixtures/
66
+ โ”‚ โ”œโ”€โ”€ golden_valid_schema.json
67
+ โ”‚ โ”œโ”€โ”€ golden_invalid_tool_call.json
68
+ โ”‚ โ””โ”€โ”€ golden_mixed_severities.json
69
+ โ””โ”€โ”€ test_cli.py
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Failure Code Taxonomy (Parity with TypeScript)
75
+
76
+ | Category | Failure Code | Description |
77
+ |---|---|---|
78
+ | **JSON / Structure** | `INVALID_JSON` | Output is not parseable JSON |
79
+ | **Schema** | `SCHEMA_VALIDATION_ERROR` | Failed Pydantic v2 validation |
80
+ | **Fields** | `MISSING_REQUIRED_FIELD` | Expected object key is absent |
81
+ | **Fields** | `UNEXPECTED_FIELD` | Key present outside allowed whitelist |
82
+ | **Constraints** | `REGEX_MISMATCH` | String does not match required regex pattern |
83
+ | **Constraints** | `ENUM_MISMATCH` | Value not in permitted set / enum |
84
+ | **Constraints** | `VALUE_CONSTRAINT_VIOLATION` | Numeric bounds or custom constraint violated |
85
+ | **Constraints** | `LENGTH_OUT_OF_BOUNDS` | String/list length outside min/max range |
86
+ | **Tool Calls** | `TOOL_CALL_UNKNOWN_TOOL` | Tool name not found in allowed list |
87
+ | **Tool Calls** | `TOOL_CALL_INVALID_ARGS_JSON` | Arguments string could not be parsed as JSON |
88
+ | **Tool Calls** | `TOOL_CALL_MISSING_REQUIRED_ARG` | Required argument missing from tool call |
89
+ | **Tool Calls** | `TOOL_CALL_ARG_TYPE_MISMATCH` | Tool argument failed type or schema check |
90
+ | **Tool Calls** | `TOOL_CALL_UNEXPECTED_ARG` | Tool argument was not in expected schema |
91
+ | **Semantic (Advisory)** | `SEMANTIC_JUDGE_SCORE_LOW` | LLM judge score fell below required threshold |
92
+ | **Semantic (Advisory)** | `SEMANTIC_JUDGE_FAILED` | LLM judge execution failed or raised an error |
93
+
94
+ ---
95
+
96
+ ## Phased Implementation Roadmap
97
+
98
+ ### Phase 1: Repository Setup & Packaging Baseline
99
+ - [x] Configure `pyproject.toml` (PEP 621, Hatchling build backend, Python `>=3.10`).
100
+ - [x] Declare runtime dependencies (`pydantic>=2.0.0`) and dev dependencies (`pytest`, `pytest-asyncio`, `pytest-cov`, `mypy`, `ruff`).
101
+ - [x] Set up package directory structure under `src/aieval`.
102
+ - [x] Add `py.typed` marker (PEP 561).
103
+ - [x] Add `.gitignore` for Python artifacts (`.venv`, `__pycache__`, `.pytest_cache`, `.mypy_cache`, `dist/`).
104
+ - [x] Configure `ruff` and `mypy` strict type checking rules.
105
+
106
+ ### Phase 2: Core Domain Model & Failure Classification
107
+ - [x] Implement `Severity` enum (`INFO`, `WARNING`, `ERROR`, `CRITICAL`).
108
+ - [x] Implement `FailureCode` enum for all taxonomy codes.
109
+ - [x] Implement frozen dataclass `Failure`:
110
+ - `code: str | FailureCode`
111
+ - `message: str`
112
+ - `severity: Severity = Severity.ERROR`
113
+ - `path: str | tuple[str | int, ...] | None = None`
114
+ - `metadata: dict[str, Any] = field(default_factory=dict)`
115
+ - `suggested_repair: str | None = None`
116
+ - [x] Implement frozen dataclass `EvaluationSummary`:
117
+ - `total_checks: int`
118
+ - `passed_checks: int`
119
+ - `failed_checks: int`
120
+ - `warnings_count: int`
121
+ - `duration_ms: float`
122
+ - [x] Implement frozen dataclass `EvaluationResult`:
123
+ - `passed: bool`
124
+ - `failures: tuple[Failure, ...]`
125
+ - `warnings: tuple[Failure, ...]`
126
+ - `summary: EvaluationSummary`
127
+ - `to_dict()` and `raise_for_failures()` helper methods.
128
+ - [x] Implement `CheckResult` and `Check` Protocol (callable supporting `(output, context) -> CheckResult | Sequence[Failure]`).
129
+ - [x] Write unit tests for domain classes and serialization.
130
+
131
+ ### Phase 3: Built-in Deterministic Checks
132
+ - [x] Implement `valid_json()` check (handles raw string and decodes safely).
133
+ - [x] Implement `schema_check(model: type[BaseModel] | TypeAdapter[T])`:
134
+ - Auto-parses JSON string if needed.
135
+ - Converts Pydantic `ValidationError.errors()` to clean `Failure` objects with dot-notation path strings.
136
+ - [x] Implement field checks:
137
+ - `required_fields(fields: Sequence[str])`
138
+ - `allowed_fields(fields: Sequence[str])`
139
+ - [x] Implement value constraint checks:
140
+ - `regex_match(pattern: str | re.Pattern)`
141
+ - `allowed_values(allowed: Collection[Any])`
142
+ - `numeric_range(min_val: float | None = None, max_val: float | None = None)`
143
+ - `length_bounds(min_len: int | None = None, max_len: int | None = None)`
144
+ - [x] Implement agent tool-call checks:
145
+ - Normalize `{name, arguments}` (OpenAI stringified or dict) and `{name, args}`.
146
+ - Check tool name against allowed list.
147
+ - Parse stringified JSON arguments safely.
148
+ - Validate tool argument presence, unexpected arguments, and Pydantic argument schemas.
149
+ - Support `tool_call_check.one_of([...])` for multi-tool options.
150
+ - [x] Write thorough unit tests for each check across valid and invalid inputs.
151
+
152
+ ### Phase 4: Sync & Async Dual Evaluator Engine & Severity Routing
153
+ - [x] Implement severity routing logic:
154
+ - Default: `fail_on="error"` (only `ERROR` and `CRITICAL` cause `passed=False`).
155
+ - Strict mode: `fail_on="warning"` (`WARNING` also causes `passed=False`).
156
+ - [x] Implement synchronous evaluator:
157
+ - `evaluate(output: Any, checks: Sequence[Check], *, context: EvaluationContext | None = None, fail_on: str = "error") -> EvaluationResult`
158
+ - Guard: raise informative `EvaluationConfigError` if an asynchronous check is passed to synchronous `evaluate()`.
159
+ - [x] Implement asynchronous evaluator:
160
+ - `aevaluate(output: Any, checks: Sequence[Check | AsyncCheck], *, context: EvaluationContext | None = None, fail_on: str = "error") -> EvaluationResult`
161
+ - Concurrently runs checks using `asyncio.gather()`.
162
+ - [x] Implement optional, zero-dependency `SemanticJudge` Protocol:
163
+ - Allows injecting user-defined LLM evaluators.
164
+ - Produces advisory results (`SEMANTIC_JUDGE_SCORE_LOW` or `SEMANTIC_JUDGE_FAILED`).
165
+ - [x] Write unit and integration tests for sync/async evaluation and routing behavior.
166
+
167
+ ### Phase 5: CLI & Golden Test Fixtures Parity
168
+ - [x] Implement CLI in `aieval.cli.main`:
169
+ - `aieval run <fixture.json>`: Runs validation on a test fixture.
170
+ - `aieval check <file.json> --specs <specs.json>`: Evaluates an arbitrary output against a check specification.
171
+ - Format human-friendly colored terminal output and support `--json` output flag.
172
+ - Return exit code `0` on pass, `1` on failure.
173
+ - [x] Create golden test fixtures in `tests/fixtures/` matching TypeScript fixture schemas.
174
+ - [x] Write CLI execution tests verifying stdout/stderr and exit codes.
175
+
176
+ ### Phase 6: Documentation, CI/CD & PyPI Release Setup
177
+ - [x] Write comprehensive `README.md` with:
178
+ - Quickstart guide (sync and async).
179
+ - Pydantic v2 schema validation examples.
180
+ - Agent tool call validation examples.
181
+ - Custom check implementation guide.
182
+ - Comparison table / philosophy (deterministic vs semantic).
183
+ - [x] Set up GitHub Actions CI workflow (`.github/workflows/test.yml`):
184
+ - Matrix across Python 3.10, 3.11, 3.12, 3.13, 3.14.
185
+ - Enforce `ruff check`, `ruff format --check`, `mypy`, and `pytest --cov=aieval --cov-fail-under=90`.
186
+ - [x] Set up PyPI Trusted Publishing GitHub Actions workflow (`.github/workflows/publish.yml`).
187
+ - [x] Add `LICENSE` (MIT) and ensure package build verification (`hatch build` / `pip install -e .`).
File without changes
@@ -0,0 +1,200 @@
1
+ Metadata-Version: 2.5
2
+ Name: aieval-py
3
+ Version: 0.1.0
4
+ Summary: Deterministic-first runtime validation and reliability toolkit for LLM outputs and agent actions.
5
+ Project-URL: Homepage, https://github.com/hamza1331/aieval-py
6
+ Project-URL: Repository, https://github.com/hamza1331/aieval-py
7
+ Project-URL: Issues, https://github.com/hamza1331/aieval-py/issues
8
+ Author-email: Hamza <hamza@example.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,ai,evaluation,guardrails,llm,pydantic,runtime-safety,validation
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Classifier: Topic :: Software Development :: Testing
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: pydantic>=2.0.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: mypy>=1.9.0; extra == 'dev'
28
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
29
+ Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
30
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
31
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # aieval
35
+
36
+ [![CI](https://github.com/hamza1331/aieval-py/actions/workflows/test.yml/badge.svg)](https://github.com/hamza1331/aieval-py/actions/workflows/test.yml)
37
+ [![PyPI version](https://img.shields.io/pypi/v/aieval-py.svg)](https://pypi.org/project/aieval-py/)
38
+ [![Python versions](https://img.shields.io/pypi/pyversions/aieval-py.svg)](https://pypi.org/project/aieval-py/)
39
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
40
+
41
+ **Deterministic-first runtime validation and reliability toolkit for LLM outputs and agent actions.**
42
+
43
+ Catch predictable failures (schema violations, missing required keys, JSON format errors, invalid tool call args, policy constraints) in sub-millisecond execution **before** spending latency and money on semantic LLM-as-a-judge scoring.
44
+
45
+ ---
46
+
47
+ ## Key Highlights
48
+
49
+ - โšก **Deterministic First:** Cheap, fast assertions run before calling model judges.
50
+ - ๐Ÿ“ฆ **Zero Bloat:** Minimal external footprint (`pydantic>=2.0.0` as schema engine, pure Python standard library for the rest).
51
+ - ๐Ÿ”„ **Dual Sync & Async:** Native support for synchronous scripts (`evaluate()`) and asynchronous pipelines (`await aevaluate()`).
52
+ - ๐Ÿค– **Agent Tool Call Pre-flight:** Validates function names, required arguments, type safety, and stringified JSON (OpenAI tool call format).
53
+ - ๐ŸŽš๏ธ **Severity Routing:** Flexible threshold routing (`fail_on="error"` vs strict `fail_on="warning"`).
54
+ - ๐Ÿงช **CLI & Golden Fixtures:** Run validation from the command line on JSON test fixtures (`aieval run <fixture.json>`).
55
+ - ๐ŸŽฏ **Full TypeScript Parity:** Shares the exact failure taxonomy, code conventions, and golden test formats with `@hamza1331/aieval`.
56
+
57
+ ---
58
+
59
+ ## Installation
60
+
61
+ ```bash
62
+ pip install aieval-py
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Quickstart
68
+
69
+ ### 1. Synchronous Output Evaluation
70
+
71
+ ```python
72
+ from aieval import evaluate, schema_check, required_fields
73
+ from pydantic import BaseModel, Field
74
+
75
+ class AnalysisReport(BaseModel):
76
+ summary: str
77
+ confidence_score: float = Field(ge=0.0, le=1.0)
78
+ tags: list[str]
79
+
80
+ llm_output = '{"summary": "All systems nominal", "confidence_score": 0.95, "tags": ["ops", "prod"]}'
81
+
82
+ result = evaluate(
83
+ output=llm_output,
84
+ checks=[
85
+ schema_check(AnalysisReport),
86
+ required_fields(["summary", "confidence_score"]),
87
+ ],
88
+ )
89
+
90
+ if result.passed:
91
+ print(f"Passed in {result.summary.duration_ms}ms!")
92
+ else:
93
+ for failure in result.failures:
94
+ print(f"[{failure.code}] {failure.message} (path: {failure.path})")
95
+ ```
96
+
97
+ ### 2. Pre-flight Agent Tool Call Validation
98
+
99
+ Validate tool calls before execution to avoid runtime exceptions and agent failure loops:
100
+
101
+ ```python
102
+ from aieval import evaluate, tool_call_check
103
+ from pydantic import BaseModel
104
+
105
+ class SendEmailArgs(BaseModel):
106
+ recipient: str
107
+ subject: str
108
+ body: str
109
+
110
+ # Works with both native dicts and OpenAI stringified JSON arguments:
111
+ raw_tool_call = {
112
+ "name": "send_email",
113
+ "arguments": '{"recipient": "team@example.com", "subject": "Update"}'
114
+ }
115
+
116
+ result = evaluate(
117
+ output=raw_tool_call,
118
+ checks=[
119
+ tool_call_check("send_email", schema=SendEmailArgs, required_args=["body"]),
120
+ ]
121
+ )
122
+
123
+ print(result.passed) # False - missing required argument 'body'
124
+ ```
125
+
126
+ ### 3. Asynchronous Pipeline (`aevaluate`)
127
+
128
+ ```python
129
+ import asyncio
130
+ from aieval import aevaluate, valid_json, regex_match
131
+
132
+ async def main():
133
+ result = await aevaluate(
134
+ output="Order #12345 confirmed.",
135
+ checks=[
136
+ regex_match(r"Order #\d+"),
137
+ ],
138
+ )
139
+ print("Passed:", result.passed)
140
+
141
+ asyncio.run(main())
142
+ ```
143
+
144
+ ---
145
+
146
+ ## CLI Usage
147
+
148
+ ### Run Golden Test Fixtures
149
+
150
+ ```bash
151
+ aieval run path/to/fixture.json
152
+ ```
153
+
154
+ Or output raw JSON:
155
+
156
+ ```bash
157
+ aieval run path/to/fixture.json --json
158
+ ```
159
+
160
+ ### Check Arbitrary Files
161
+
162
+ ```bash
163
+ aieval check output.json --specs checks.json
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Failure Code Taxonomy
169
+
170
+ | Code | Category | Description |
171
+ |---|---|---|
172
+ | `INVALID_JSON` | Syntax | Output string is not parseable JSON |
173
+ | `SCHEMA_VALIDATION_ERROR` | Schema | Failed Pydantic v2 schema validation |
174
+ | `MISSING_REQUIRED_FIELD` | Fields | Missing expected key |
175
+ | `UNEXPECTED_FIELD` | Fields | Extra key outside allowed whitelist |
176
+ | `REGEX_MISMATCH` | Constraints | Pattern regex search failed |
177
+ | `ENUM_MISMATCH` | Constraints | Value not in permitted set |
178
+ | `VALUE_CONSTRAINT_VIOLATION` | Constraints | Range or boundary violation |
179
+ | `LENGTH_OUT_OF_BOUNDS` | Constraints | Length outside min/max range |
180
+ | `TOOL_CALL_UNKNOWN_TOOL` | Tool Calls | Unknown tool invoked |
181
+ | `TOOL_CALL_INVALID_ARGS_JSON`| Tool Calls | Arguments string is invalid JSON |
182
+ | `TOOL_CALL_MISSING_REQUIRED_ARG` | Tool Calls | Required argument missing |
183
+ | `TOOL_CALL_ARG_TYPE_MISMATCH`| Tool Calls | Argument schema check failed |
184
+
185
+ ---
186
+
187
+ ## Examples
188
+
189
+ Runnable walkthrough scripts are available in the [`examples/`](examples) directory:
190
+
191
+ - [`01_basic_llm_output.py`](examples/01_basic_llm_output.py): Schema and field constraint validation on LLM output.
192
+ - [`02_agent_tool_guardrail.py`](examples/02_agent_tool_guardrail.py): Agent tool call pre-flight validation (OpenAI stringified arguments & multi-tool selection).
193
+ - [`03_async_and_severity_routing.py`](examples/03_async_and_severity_routing.py): Asynchronous concurrent pipeline with severity routing.
194
+ - [`04_semantic_judge_adapter.py`](examples/04_semantic_judge_adapter.py): Integrating advisory LLM-as-a-judge checks via `SemanticJudge`.
195
+
196
+ ---
197
+
198
+ ## License
199
+
200
+ MIT