applexus-iris-evals 1.0.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.
- applexus_iris_evals-1.0.0/PKG-INFO +185 -0
- applexus_iris_evals-1.0.0/README.md +170 -0
- applexus_iris_evals-1.0.0/pyproject.toml +30 -0
- applexus_iris_evals-1.0.0/setup.cfg +4 -0
- applexus_iris_evals-1.0.0/src/applexus_iris_evals.egg-info/PKG-INFO +185 -0
- applexus_iris_evals-1.0.0/src/applexus_iris_evals.egg-info/SOURCES.txt +26 -0
- applexus_iris_evals-1.0.0/src/applexus_iris_evals.egg-info/dependency_links.txt +1 -0
- applexus_iris_evals-1.0.0/src/applexus_iris_evals.egg-info/requires.txt +9 -0
- applexus_iris_evals-1.0.0/src/applexus_iris_evals.egg-info/top_level.txt +1 -0
- applexus_iris_evals-1.0.0/src/iris_evals/__init__.py +64 -0
- applexus_iris_evals-1.0.0/src/iris_evals/_transport.py +80 -0
- applexus_iris_evals-1.0.0/src/iris_evals/aicore.py +118 -0
- applexus_iris_evals-1.0.0/src/iris_evals/evaluators/__init__.py +17 -0
- applexus_iris_evals-1.0.0/src/iris_evals/evaluators/deterministic.py +66 -0
- applexus_iris_evals-1.0.0/src/iris_evals/evaluators/llm_judge.py +145 -0
- applexus_iris_evals-1.0.0/src/iris_evals/evaluators/performance.py +91 -0
- applexus_iris_evals-1.0.0/src/iris_evals/evaluators/probabilistic.py +109 -0
- applexus_iris_evals-1.0.0/src/iris_evals/evaluators/safety.py +111 -0
- applexus_iris_evals-1.0.0/src/iris_evals/evaluators/trace.py +108 -0
- applexus_iris_evals-1.0.0/src/iris_evals/registry.py +281 -0
- applexus_iris_evals-1.0.0/src/iris_evals/results.py +82 -0
- applexus_iris_evals-1.0.0/src/iris_evals/runner.py +111 -0
- applexus_iris_evals-1.0.0/src/iris_evals/schemas.py +134 -0
- applexus_iris_evals-1.0.0/src/iris_evals/self_eval.py +285 -0
- applexus_iris_evals-1.0.0/tests/test_deterministic.py +75 -0
- applexus_iris_evals-1.0.0/tests/test_probabilistic.py +70 -0
- applexus_iris_evals-1.0.0/tests/test_safety.py +65 -0
- applexus_iris_evals-1.0.0/tests/test_self_eval.py +106 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: applexus-iris-evals
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Reusable evaluation framework for IRIS SAP Joule A2A agents
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: httpx>=0.27.0
|
|
8
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
9
|
+
Requires-Dist: rich>=13.0.0
|
|
10
|
+
Requires-Dist: pydantic>=2.0.0
|
|
11
|
+
Requires-Dist: anthropic>=0.30.0
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
14
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
15
|
+
|
|
16
|
+
# iris-evals
|
|
17
|
+
|
|
18
|
+
Self-evaluation library for Applexus IRIS SAP Joule agents.
|
|
19
|
+
|
|
20
|
+
Install once — every agent evaluates itself on startup, runs a background loop every 5 minutes, and exposes a `/health/evals` CI gate endpoint. All golden datasets, rubrics, and thresholds are bundled inside the library. Zero eval data files needed per agent.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install git+https://github.com/applexus/iris-evals.git@v1.0.0
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Add to your agent's `requirements.txt`:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
iris-evals @ git+https://github.com/applexus/iris-evals.git@v1.0.0
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
Add three blocks to your agent's `app.py`:
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import asyncio, os
|
|
44
|
+
from iris_evals import run_self_eval, self_eval_loop
|
|
45
|
+
|
|
46
|
+
AGENT_URL = os.getenv("AGENT_URL", "http://localhost:8080")
|
|
47
|
+
|
|
48
|
+
@app.on_event("startup")
|
|
49
|
+
async def startup_self_eval():
|
|
50
|
+
report = await run_self_eval(agent_url=AGENT_URL)
|
|
51
|
+
if not report.overall_passed:
|
|
52
|
+
logger.warning("[IRIS EVALS] Self-eval FAILED — %s", report.summary)
|
|
53
|
+
|
|
54
|
+
@app.on_event("startup")
|
|
55
|
+
async def start_eval_loop():
|
|
56
|
+
asyncio.create_task(
|
|
57
|
+
self_eval_loop(agent_url=AGENT_URL, interval_seconds=300)
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
@app.route("/health/evals", methods=["GET"])
|
|
61
|
+
async def eval_health(request):
|
|
62
|
+
from starlette.responses import JSONResponse
|
|
63
|
+
report = await run_self_eval(agent_url=AGENT_URL)
|
|
64
|
+
return JSONResponse({"passed": report.overall_passed, "summary": report.summary})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Add to your agent's `agent-card.json`:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
"x_evals": {
|
|
71
|
+
"evaluators": ["deterministic", "safety"],
|
|
72
|
+
"dataset": "builtin",
|
|
73
|
+
"threshold_profile": "deterministic_strict"
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 7 Eval Types
|
|
80
|
+
|
|
81
|
+
| # | Type | Needs AI | Use when |
|
|
82
|
+
|---|------|----------|----------|
|
|
83
|
+
| 1 | `deterministic` | No | Rule-based agents — exact verdict match |
|
|
84
|
+
| 2 | `probabilistic` | No | Classifiers — accuracy / F1 ≥ 85% |
|
|
85
|
+
| 3 | `llm_as_judge` | Yes (AI Core) | Free-text output quality — rubric scored |
|
|
86
|
+
| 4 | `agent_as_judge` | Yes (A2A) | Complex SAP domain — peer agent reviews |
|
|
87
|
+
| 5 | `trace` | No | Multi-step agents — correct tool call sequence |
|
|
88
|
+
| 6 | `safety` | No | Every agent — PII + injection checks |
|
|
89
|
+
| 7 | `performance` | No | SLA-critical — latency p95 ≤ 5000ms |
|
|
90
|
+
|
|
91
|
+
**Quick picks:**
|
|
92
|
+
- Rule-based agent → `1, 6`
|
|
93
|
+
- Triage / classifier → `2, 3, 6`
|
|
94
|
+
- Multi-step → `1, 5, 6`
|
|
95
|
+
- SLA-critical → `1, 5, 6, 7`
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## How it works
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
cf push
|
|
103
|
+
└─ pip installs iris-evals from GitHub
|
|
104
|
+
└─ startup: run_self_eval() calls agent via A2A with golden records
|
|
105
|
+
└─ CI polls GET /health/evals → passed: true → promote
|
|
106
|
+
└─ background: self_eval_loop() re-runs every 5 minutes
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
iris-evals runs **inside your agent's process** as an asyncio task — no separate BTP service, no extra cost.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## LLM Judge (type 3)
|
|
114
|
+
|
|
115
|
+
Uses SAP AI Core orchestration. Requires these env vars in your agent's `manifest.yml` (gitignored):
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
AICORE_CLIENT_ID
|
|
119
|
+
AICORE_CLIENT_SECRET
|
|
120
|
+
AICORE_AUTH_URL
|
|
121
|
+
AICORE_BASE_URL
|
|
122
|
+
AICORE_RESOURCE_GROUP
|
|
123
|
+
ORCHESTRATION_URL
|
|
124
|
+
AICORE_JUDGE_MODEL (default: gpt-4o)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
If your agent already has AI Core credentials, iris-evals picks them up automatically — no extra config.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Skill Integration
|
|
132
|
+
|
|
133
|
+
The `iris-sap-agent-skill` asks **Q_EVAL** as its last interview question:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
Which evaluation types does this agent need?
|
|
137
|
+
→ deterministic / probabilistic / llm_as_judge / agent_as_judge / trace / safety / performance
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Answering generates all wiring automatically — `x_evals` block, `app.py` startup/loop/health, and `requirements.txt` entry.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Running Tests
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
pip install -e ".[dev]"
|
|
148
|
+
pytest
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Project Structure
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
src/iris_evals/
|
|
157
|
+
├── aicore.py SAP AI Core orchestration client
|
|
158
|
+
├── registry.py Built-in golden datasets, rubrics, thresholds
|
|
159
|
+
├── schemas.py EvalType, GoldenRecord, EvalConfig, EvalReport
|
|
160
|
+
├── self_eval.py run_self_eval() and self_eval_loop()
|
|
161
|
+
├── runner.py EvalSuite base class
|
|
162
|
+
├── _transport.py A2A JSON-RPC call helper
|
|
163
|
+
└── evaluators/
|
|
164
|
+
├── deterministic.py
|
|
165
|
+
├── probabilistic.py
|
|
166
|
+
├── llm_judge.py
|
|
167
|
+
├── safety.py
|
|
168
|
+
├── trace.py
|
|
169
|
+
└── performance.py
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Versioning
|
|
175
|
+
|
|
176
|
+
| Version | Notes |
|
|
177
|
+
|---------|-------|
|
|
178
|
+
| v1.0.0 | Initial release — 7 eval types, built-in registry, AI Core LLM judge |
|
|
179
|
+
|
|
180
|
+
Tag a new version and update `requirements.txt` in each agent to upgrade:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
git tag v1.0.1
|
|
184
|
+
git push --tags
|
|
185
|
+
```
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# iris-evals
|
|
2
|
+
|
|
3
|
+
Self-evaluation library for Applexus IRIS SAP Joule agents.
|
|
4
|
+
|
|
5
|
+
Install once — every agent evaluates itself on startup, runs a background loop every 5 minutes, and exposes a `/health/evals` CI gate endpoint. All golden datasets, rubrics, and thresholds are bundled inside the library. Zero eval data files needed per agent.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install git+https://github.com/applexus/iris-evals.git@v1.0.0
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Add to your agent's `requirements.txt`:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
iris-evals @ git+https://github.com/applexus/iris-evals.git@v1.0.0
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
Add three blocks to your agent's `app.py`:
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
import asyncio, os
|
|
29
|
+
from iris_evals import run_self_eval, self_eval_loop
|
|
30
|
+
|
|
31
|
+
AGENT_URL = os.getenv("AGENT_URL", "http://localhost:8080")
|
|
32
|
+
|
|
33
|
+
@app.on_event("startup")
|
|
34
|
+
async def startup_self_eval():
|
|
35
|
+
report = await run_self_eval(agent_url=AGENT_URL)
|
|
36
|
+
if not report.overall_passed:
|
|
37
|
+
logger.warning("[IRIS EVALS] Self-eval FAILED — %s", report.summary)
|
|
38
|
+
|
|
39
|
+
@app.on_event("startup")
|
|
40
|
+
async def start_eval_loop():
|
|
41
|
+
asyncio.create_task(
|
|
42
|
+
self_eval_loop(agent_url=AGENT_URL, interval_seconds=300)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
@app.route("/health/evals", methods=["GET"])
|
|
46
|
+
async def eval_health(request):
|
|
47
|
+
from starlette.responses import JSONResponse
|
|
48
|
+
report = await run_self_eval(agent_url=AGENT_URL)
|
|
49
|
+
return JSONResponse({"passed": report.overall_passed, "summary": report.summary})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Add to your agent's `agent-card.json`:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
"x_evals": {
|
|
56
|
+
"evaluators": ["deterministic", "safety"],
|
|
57
|
+
"dataset": "builtin",
|
|
58
|
+
"threshold_profile": "deterministic_strict"
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 7 Eval Types
|
|
65
|
+
|
|
66
|
+
| # | Type | Needs AI | Use when |
|
|
67
|
+
|---|------|----------|----------|
|
|
68
|
+
| 1 | `deterministic` | No | Rule-based agents — exact verdict match |
|
|
69
|
+
| 2 | `probabilistic` | No | Classifiers — accuracy / F1 ≥ 85% |
|
|
70
|
+
| 3 | `llm_as_judge` | Yes (AI Core) | Free-text output quality — rubric scored |
|
|
71
|
+
| 4 | `agent_as_judge` | Yes (A2A) | Complex SAP domain — peer agent reviews |
|
|
72
|
+
| 5 | `trace` | No | Multi-step agents — correct tool call sequence |
|
|
73
|
+
| 6 | `safety` | No | Every agent — PII + injection checks |
|
|
74
|
+
| 7 | `performance` | No | SLA-critical — latency p95 ≤ 5000ms |
|
|
75
|
+
|
|
76
|
+
**Quick picks:**
|
|
77
|
+
- Rule-based agent → `1, 6`
|
|
78
|
+
- Triage / classifier → `2, 3, 6`
|
|
79
|
+
- Multi-step → `1, 5, 6`
|
|
80
|
+
- SLA-critical → `1, 5, 6, 7`
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## How it works
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
cf push
|
|
88
|
+
└─ pip installs iris-evals from GitHub
|
|
89
|
+
└─ startup: run_self_eval() calls agent via A2A with golden records
|
|
90
|
+
└─ CI polls GET /health/evals → passed: true → promote
|
|
91
|
+
└─ background: self_eval_loop() re-runs every 5 minutes
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
iris-evals runs **inside your agent's process** as an asyncio task — no separate BTP service, no extra cost.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## LLM Judge (type 3)
|
|
99
|
+
|
|
100
|
+
Uses SAP AI Core orchestration. Requires these env vars in your agent's `manifest.yml` (gitignored):
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
AICORE_CLIENT_ID
|
|
104
|
+
AICORE_CLIENT_SECRET
|
|
105
|
+
AICORE_AUTH_URL
|
|
106
|
+
AICORE_BASE_URL
|
|
107
|
+
AICORE_RESOURCE_GROUP
|
|
108
|
+
ORCHESTRATION_URL
|
|
109
|
+
AICORE_JUDGE_MODEL (default: gpt-4o)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If your agent already has AI Core credentials, iris-evals picks them up automatically — no extra config.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Skill Integration
|
|
117
|
+
|
|
118
|
+
The `iris-sap-agent-skill` asks **Q_EVAL** as its last interview question:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
Which evaluation types does this agent need?
|
|
122
|
+
→ deterministic / probabilistic / llm_as_judge / agent_as_judge / trace / safety / performance
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Answering generates all wiring automatically — `x_evals` block, `app.py` startup/loop/health, and `requirements.txt` entry.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Running Tests
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
pip install -e ".[dev]"
|
|
133
|
+
pytest
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Project Structure
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
src/iris_evals/
|
|
142
|
+
├── aicore.py SAP AI Core orchestration client
|
|
143
|
+
├── registry.py Built-in golden datasets, rubrics, thresholds
|
|
144
|
+
├── schemas.py EvalType, GoldenRecord, EvalConfig, EvalReport
|
|
145
|
+
├── self_eval.py run_self_eval() and self_eval_loop()
|
|
146
|
+
├── runner.py EvalSuite base class
|
|
147
|
+
├── _transport.py A2A JSON-RPC call helper
|
|
148
|
+
└── evaluators/
|
|
149
|
+
├── deterministic.py
|
|
150
|
+
├── probabilistic.py
|
|
151
|
+
├── llm_judge.py
|
|
152
|
+
├── safety.py
|
|
153
|
+
├── trace.py
|
|
154
|
+
└── performance.py
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Versioning
|
|
160
|
+
|
|
161
|
+
| Version | Notes |
|
|
162
|
+
|---------|-------|
|
|
163
|
+
| v1.0.0 | Initial release — 7 eval types, built-in registry, AI Core LLM judge |
|
|
164
|
+
|
|
165
|
+
Tag a new version and update `requirements.txt` in each agent to upgrade:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
git tag v1.0.1
|
|
169
|
+
git push --tags
|
|
170
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "applexus-iris-evals"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Reusable evaluation framework for IRIS SAP Joule A2A agents"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"httpx>=0.27.0",
|
|
13
|
+
"python-dotenv>=1.0.1",
|
|
14
|
+
"rich>=13.0.0",
|
|
15
|
+
"pydantic>=2.0.0",
|
|
16
|
+
"anthropic>=0.30.0",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
dev = [
|
|
21
|
+
"pytest>=8.0.0",
|
|
22
|
+
"pytest-asyncio>=0.23.0",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[tool.setuptools.packages.find]
|
|
26
|
+
where = ["src"]
|
|
27
|
+
|
|
28
|
+
[tool.pytest.ini_options]
|
|
29
|
+
asyncio_mode = "auto"
|
|
30
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: applexus-iris-evals
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Reusable evaluation framework for IRIS SAP Joule A2A agents
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: httpx>=0.27.0
|
|
8
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
9
|
+
Requires-Dist: rich>=13.0.0
|
|
10
|
+
Requires-Dist: pydantic>=2.0.0
|
|
11
|
+
Requires-Dist: anthropic>=0.30.0
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
14
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
15
|
+
|
|
16
|
+
# iris-evals
|
|
17
|
+
|
|
18
|
+
Self-evaluation library for Applexus IRIS SAP Joule agents.
|
|
19
|
+
|
|
20
|
+
Install once — every agent evaluates itself on startup, runs a background loop every 5 minutes, and exposes a `/health/evals` CI gate endpoint. All golden datasets, rubrics, and thresholds are bundled inside the library. Zero eval data files needed per agent.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install git+https://github.com/applexus/iris-evals.git@v1.0.0
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Add to your agent's `requirements.txt`:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
iris-evals @ git+https://github.com/applexus/iris-evals.git@v1.0.0
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
Add three blocks to your agent's `app.py`:
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import asyncio, os
|
|
44
|
+
from iris_evals import run_self_eval, self_eval_loop
|
|
45
|
+
|
|
46
|
+
AGENT_URL = os.getenv("AGENT_URL", "http://localhost:8080")
|
|
47
|
+
|
|
48
|
+
@app.on_event("startup")
|
|
49
|
+
async def startup_self_eval():
|
|
50
|
+
report = await run_self_eval(agent_url=AGENT_URL)
|
|
51
|
+
if not report.overall_passed:
|
|
52
|
+
logger.warning("[IRIS EVALS] Self-eval FAILED — %s", report.summary)
|
|
53
|
+
|
|
54
|
+
@app.on_event("startup")
|
|
55
|
+
async def start_eval_loop():
|
|
56
|
+
asyncio.create_task(
|
|
57
|
+
self_eval_loop(agent_url=AGENT_URL, interval_seconds=300)
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
@app.route("/health/evals", methods=["GET"])
|
|
61
|
+
async def eval_health(request):
|
|
62
|
+
from starlette.responses import JSONResponse
|
|
63
|
+
report = await run_self_eval(agent_url=AGENT_URL)
|
|
64
|
+
return JSONResponse({"passed": report.overall_passed, "summary": report.summary})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Add to your agent's `agent-card.json`:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
"x_evals": {
|
|
71
|
+
"evaluators": ["deterministic", "safety"],
|
|
72
|
+
"dataset": "builtin",
|
|
73
|
+
"threshold_profile": "deterministic_strict"
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 7 Eval Types
|
|
80
|
+
|
|
81
|
+
| # | Type | Needs AI | Use when |
|
|
82
|
+
|---|------|----------|----------|
|
|
83
|
+
| 1 | `deterministic` | No | Rule-based agents — exact verdict match |
|
|
84
|
+
| 2 | `probabilistic` | No | Classifiers — accuracy / F1 ≥ 85% |
|
|
85
|
+
| 3 | `llm_as_judge` | Yes (AI Core) | Free-text output quality — rubric scored |
|
|
86
|
+
| 4 | `agent_as_judge` | Yes (A2A) | Complex SAP domain — peer agent reviews |
|
|
87
|
+
| 5 | `trace` | No | Multi-step agents — correct tool call sequence |
|
|
88
|
+
| 6 | `safety` | No | Every agent — PII + injection checks |
|
|
89
|
+
| 7 | `performance` | No | SLA-critical — latency p95 ≤ 5000ms |
|
|
90
|
+
|
|
91
|
+
**Quick picks:**
|
|
92
|
+
- Rule-based agent → `1, 6`
|
|
93
|
+
- Triage / classifier → `2, 3, 6`
|
|
94
|
+
- Multi-step → `1, 5, 6`
|
|
95
|
+
- SLA-critical → `1, 5, 6, 7`
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## How it works
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
cf push
|
|
103
|
+
└─ pip installs iris-evals from GitHub
|
|
104
|
+
└─ startup: run_self_eval() calls agent via A2A with golden records
|
|
105
|
+
└─ CI polls GET /health/evals → passed: true → promote
|
|
106
|
+
└─ background: self_eval_loop() re-runs every 5 minutes
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
iris-evals runs **inside your agent's process** as an asyncio task — no separate BTP service, no extra cost.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## LLM Judge (type 3)
|
|
114
|
+
|
|
115
|
+
Uses SAP AI Core orchestration. Requires these env vars in your agent's `manifest.yml` (gitignored):
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
AICORE_CLIENT_ID
|
|
119
|
+
AICORE_CLIENT_SECRET
|
|
120
|
+
AICORE_AUTH_URL
|
|
121
|
+
AICORE_BASE_URL
|
|
122
|
+
AICORE_RESOURCE_GROUP
|
|
123
|
+
ORCHESTRATION_URL
|
|
124
|
+
AICORE_JUDGE_MODEL (default: gpt-4o)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
If your agent already has AI Core credentials, iris-evals picks them up automatically — no extra config.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Skill Integration
|
|
132
|
+
|
|
133
|
+
The `iris-sap-agent-skill` asks **Q_EVAL** as its last interview question:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
Which evaluation types does this agent need?
|
|
137
|
+
→ deterministic / probabilistic / llm_as_judge / agent_as_judge / trace / safety / performance
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Answering generates all wiring automatically — `x_evals` block, `app.py` startup/loop/health, and `requirements.txt` entry.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Running Tests
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
pip install -e ".[dev]"
|
|
148
|
+
pytest
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Project Structure
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
src/iris_evals/
|
|
157
|
+
├── aicore.py SAP AI Core orchestration client
|
|
158
|
+
├── registry.py Built-in golden datasets, rubrics, thresholds
|
|
159
|
+
├── schemas.py EvalType, GoldenRecord, EvalConfig, EvalReport
|
|
160
|
+
├── self_eval.py run_self_eval() and self_eval_loop()
|
|
161
|
+
├── runner.py EvalSuite base class
|
|
162
|
+
├── _transport.py A2A JSON-RPC call helper
|
|
163
|
+
└── evaluators/
|
|
164
|
+
├── deterministic.py
|
|
165
|
+
├── probabilistic.py
|
|
166
|
+
├── llm_judge.py
|
|
167
|
+
├── safety.py
|
|
168
|
+
├── trace.py
|
|
169
|
+
└── performance.py
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Versioning
|
|
175
|
+
|
|
176
|
+
| Version | Notes |
|
|
177
|
+
|---------|-------|
|
|
178
|
+
| v1.0.0 | Initial release — 7 eval types, built-in registry, AI Core LLM judge |
|
|
179
|
+
|
|
180
|
+
Tag a new version and update `requirements.txt` in each agent to upgrade:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
git tag v1.0.1
|
|
184
|
+
git push --tags
|
|
185
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/applexus_iris_evals.egg-info/PKG-INFO
|
|
4
|
+
src/applexus_iris_evals.egg-info/SOURCES.txt
|
|
5
|
+
src/applexus_iris_evals.egg-info/dependency_links.txt
|
|
6
|
+
src/applexus_iris_evals.egg-info/requires.txt
|
|
7
|
+
src/applexus_iris_evals.egg-info/top_level.txt
|
|
8
|
+
src/iris_evals/__init__.py
|
|
9
|
+
src/iris_evals/_transport.py
|
|
10
|
+
src/iris_evals/aicore.py
|
|
11
|
+
src/iris_evals/registry.py
|
|
12
|
+
src/iris_evals/results.py
|
|
13
|
+
src/iris_evals/runner.py
|
|
14
|
+
src/iris_evals/schemas.py
|
|
15
|
+
src/iris_evals/self_eval.py
|
|
16
|
+
src/iris_evals/evaluators/__init__.py
|
|
17
|
+
src/iris_evals/evaluators/deterministic.py
|
|
18
|
+
src/iris_evals/evaluators/llm_judge.py
|
|
19
|
+
src/iris_evals/evaluators/performance.py
|
|
20
|
+
src/iris_evals/evaluators/probabilistic.py
|
|
21
|
+
src/iris_evals/evaluators/safety.py
|
|
22
|
+
src/iris_evals/evaluators/trace.py
|
|
23
|
+
tests/test_deterministic.py
|
|
24
|
+
tests/test_probabilistic.py
|
|
25
|
+
tests/test_safety.py
|
|
26
|
+
tests/test_self_eval.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
iris_evals
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""
|
|
2
|
+
iris-evals — Reusable evaluation framework for IRIS SAP Joule A2A agents.
|
|
3
|
+
|
|
4
|
+
── Startup self-eval (simplest usage) ──────────────────────────────────────────
|
|
5
|
+
from iris_evals import run_self_eval
|
|
6
|
+
|
|
7
|
+
@app.on_event("startup")
|
|
8
|
+
async def startup():
|
|
9
|
+
report = await run_self_eval(agent_url="http://localhost:8080")
|
|
10
|
+
if not report.overall_passed:
|
|
11
|
+
logger.warning(f"[IRIS EVALS] {report.summary}")
|
|
12
|
+
|
|
13
|
+
── Background loop ──────────────────────────────────────────────────────────────
|
|
14
|
+
from iris_evals import self_eval_loop
|
|
15
|
+
|
|
16
|
+
@app.on_event("startup")
|
|
17
|
+
async def startup():
|
|
18
|
+
asyncio.create_task(self_eval_loop(agent_url="http://localhost:8080", interval_seconds=300))
|
|
19
|
+
|
|
20
|
+
── Health endpoint ───────────────────────────────────────────────────────────────
|
|
21
|
+
@app.get("/health/evals")
|
|
22
|
+
async def eval_health():
|
|
23
|
+
report = await run_self_eval(agent_url="http://localhost:8080")
|
|
24
|
+
return {"passed": report.overall_passed, "summary": report.summary}
|
|
25
|
+
|
|
26
|
+
── Manual / CLI ─────────────────────────────────────────────────────────────────
|
|
27
|
+
iris-evals run --agent http://localhost:8080
|
|
28
|
+
iris-evals run-pipeline --pipeline pipeline.json
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from iris_evals.runner import EvalSuite
|
|
32
|
+
from iris_evals.self_eval import run_self_eval, self_eval_loop
|
|
33
|
+
from iris_evals.schemas import (
|
|
34
|
+
EvalConfig,
|
|
35
|
+
EvalType,
|
|
36
|
+
EvalReport,
|
|
37
|
+
EvalResult,
|
|
38
|
+
GoldenRecord,
|
|
39
|
+
JudgeRubric,
|
|
40
|
+
JudgeCriterion,
|
|
41
|
+
)
|
|
42
|
+
from iris_evals.results import print_report, save_json
|
|
43
|
+
from iris_evals.registry import register_agent
|
|
44
|
+
|
|
45
|
+
__all__ = [
|
|
46
|
+
# self-eval (primary API)
|
|
47
|
+
"run_self_eval",
|
|
48
|
+
"self_eval_loop",
|
|
49
|
+
# manual suite
|
|
50
|
+
"EvalSuite",
|
|
51
|
+
# schemas
|
|
52
|
+
"EvalConfig",
|
|
53
|
+
"EvalType",
|
|
54
|
+
"EvalReport",
|
|
55
|
+
"EvalResult",
|
|
56
|
+
"GoldenRecord",
|
|
57
|
+
"JudgeRubric",
|
|
58
|
+
"JudgeCriterion",
|
|
59
|
+
# output
|
|
60
|
+
"print_report",
|
|
61
|
+
"save_json",
|
|
62
|
+
# registry extension
|
|
63
|
+
"register_agent",
|
|
64
|
+
]
|