evalrun 0.4.0__py3-none-any.whl

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 (100) hide show
  1. agents/__init__.py +6 -0
  2. agents/auditor/__init__.py +13 -0
  3. agents/auditor/budget_auditor.py +91 -0
  4. agents/auditor/parser.py +139 -0
  5. agents/auditor/prompts.py +64 -0
  6. agents/auditor/schema.py +67 -0
  7. agents/base.py +20 -0
  8. agents/reflection/__init__.py +3 -0
  9. agents/reflection/agent.py +77 -0
  10. agents/reflection/prompts.py +18 -0
  11. agents/research/__init__.py +4 -0
  12. agents/research/agent.py +45 -0
  13. agents/research/planner.py +52 -0
  14. agents/research/prompts.py +14 -0
  15. agents/support/__init__.py +5 -0
  16. agents/support/triage_agent.py +45 -0
  17. agents/travel/__init__.py +11 -0
  18. agents/travel/agent.py +377 -0
  19. agents/travel/prompts.py +30 -0
  20. agents/travel/session.py +110 -0
  21. cli/__init__.py +6 -0
  22. cli/demo.py +47 -0
  23. cli/formatter.py +93 -0
  24. cli/html_reporter.py +647 -0
  25. cli/main.py +423 -0
  26. cli/progress.py +38 -0
  27. cli/resolver.py +99 -0
  28. evalrun-0.4.0.dist-info/METADATA +268 -0
  29. evalrun-0.4.0.dist-info/RECORD +100 -0
  30. evalrun-0.4.0.dist-info/WHEEL +5 -0
  31. evalrun-0.4.0.dist-info/entry_points.txt +2 -0
  32. evalrun-0.4.0.dist-info/licenses/LICENSE +0 -0
  33. evalrun-0.4.0.dist-info/top_level.txt +4 -0
  34. framework/__init__.py +70 -0
  35. framework/core/__init__.py +17 -0
  36. framework/core/adapters.py +118 -0
  37. framework/core/contracts.py +88 -0
  38. framework/core/suite.py +44 -0
  39. framework/evaluation/__init__.py +22 -0
  40. framework/evaluation/base.py +29 -0
  41. framework/evaluation/dimensions.py +7 -0
  42. framework/evaluation/engine.py +110 -0
  43. framework/evaluation/evaluators/__init__.py +7 -0
  44. framework/evaluation/evaluators/adaptability.py +27 -0
  45. framework/evaluation/evaluators/base_llm.py +104 -0
  46. framework/evaluation/evaluators/constraint.py +27 -0
  47. framework/evaluation/evaluators/information_accuracy.py +41 -0
  48. framework/evaluation/evaluators/personalization.py +27 -0
  49. framework/evaluation/evaluators/planning.py +27 -0
  50. framework/evaluation/evaluators/support.py +81 -0
  51. framework/evaluation/prompts/__init__.py +11 -0
  52. framework/evaluation/prompts/adaptability.py +57 -0
  53. framework/evaluation/prompts/base.py +52 -0
  54. framework/evaluation/prompts/constraint.py +41 -0
  55. framework/evaluation/prompts/information_accuracy.py +79 -0
  56. framework/evaluation/prompts/personalization.py +57 -0
  57. framework/evaluation/prompts/planning.py +61 -0
  58. framework/evaluation/runner.py +363 -0
  59. framework/evaluation/testing.py +25 -0
  60. framework/exceptions.py +49 -0
  61. framework/llms/__init__.py +8 -0
  62. framework/llms/base.py +37 -0
  63. framework/llms/factory.py +38 -0
  64. framework/llms/gemini.py +85 -0
  65. framework/llms/mock.py +25 -0
  66. framework/llms/openai.py +94 -0
  67. framework/llms/openai_compatible.py +139 -0
  68. framework/mcp/__init__.py +20 -0
  69. framework/mcp/client.py +62 -0
  70. framework/mcp/constraints.py +125 -0
  71. framework/mcp/revision_summary.py +122 -0
  72. framework/mcp/server.py +49 -0
  73. framework/memory/__init__.py +3 -0
  74. framework/memory/base.py +17 -0
  75. framework/models.py +83 -0
  76. framework/parser.py +45 -0
  77. framework/parsers/__init__.py +12 -0
  78. framework/parsers/frontmatter.py +28 -0
  79. framework/parsers/mapper.py +66 -0
  80. framework/parsers/markdown.py +122 -0
  81. framework/parsers/transformers.py +112 -0
  82. framework/profiles/__init__.py +28 -0
  83. framework/profiles/registry.py +104 -0
  84. framework/profiles/support.py +27 -0
  85. framework/profiles/travel.py +78 -0
  86. framework/regression/__init__.py +17 -0
  87. framework/regression/comparator.py +273 -0
  88. framework/regression/loader.py +145 -0
  89. framework/sdk.py +151 -0
  90. framework/utils.py +41 -0
  91. framework/verification/__init__.py +13 -0
  92. framework/verification/base.py +32 -0
  93. framework/verification/extractor.py +105 -0
  94. framework/verification/local.py +122 -0
  95. framework/verification/models.py +112 -0
  96. framework/verification/pipeline.py +36 -0
  97. framework/verification/prompts.py +24 -0
  98. framework/verification/utils.py +54 -0
  99. ui/__init__.py +1 -0
  100. ui/server.py +255 -0
@@ -0,0 +1,268 @@
1
+ Metadata-Version: 2.4
2
+ Name: evalrun
3
+ Version: 0.4.0
4
+ Summary: Provider-agnostic evaluation and regression-testing toolkit for tool-using AI agents.
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: openai>=1.0.0
9
+ Requires-Dist: requests>=2.28.0
10
+ Requires-Dist: pydantic>=2.0.0
11
+ Requires-Dist: python-frontmatter>=1.0.0
12
+ Requires-Dist: PyYAML>=6.0
13
+ Requires-Dist: langfuse>=2.0.0
14
+ Requires-Dist: fastmcp>=0.1.0
15
+ Dynamic: license-file
16
+
17
+ # evalrun
18
+
19
+ > **Quality Score $\neq$ Release Decision.** An LLM evaluator can rate an itinerary 95/100 while an independent auditor blocks it for hard financial violations.
20
+
21
+ `evalrun` is a local-first toolkit for testing AI agents. You bring the agent, model, and API key; `evalrun` runs the checks on your machine, saves the evidence locally, and tells you whether the result should be released.
22
+
23
+ The toolkit works with hosted APIs and models running on your own computer. It does not host models, provide API credits, provision GPUs, or require a hosted account.
24
+
25
+ ---
26
+
27
+ ## 🌟 Key Capabilities
28
+
29
+ - **3-Tier Release Gatekeeping**:
30
+ - **Evaluator Thresholds**: Qualitative dimension scoring (0–100) via LLM judges.
31
+ - **Independent Auditor Gate**: Hard financial, policy, and math validation (blocks releases on unbudgeted items or currency hallucinations).
32
+ - **Baseline Regression Gate**: Automatically detects score drops ($\Delta \text{score}$) against stored baselines.
33
+ - **Local-First & Multi-Model**: Compatible with hosted APIs (OpenAI GPT-5.6, NVIDIA NIM, Gemini) and local model servers (vLLM, Ollama, LM Studio) on `http://localhost:8000/v1`.
34
+ - **Standalone HTML Review Reports**: Interactive local HTML report with failure quick-jump bars, auto-opened failing cards, search/filter controls, visual score progress bars, and raw model output inspection.
35
+ - **CI Exit Code Contract**:
36
+ - `0`: All scenarios passed evaluator, auditor gate passed, and no regression detected.
37
+ - `1`: Release blocked due to evaluator threshold failure, auditor violation, or baseline score regression.
38
+ - `2`: Runtime error, missing file, or invalid configuration.
39
+
40
+ ---
41
+
42
+ ## 🚀 Quick Start
43
+
44
+ ### 1. Installation
45
+
46
+ ```bash
47
+ git clone https://github.com/imshivamb/agent-eval-platform.git
48
+ cd agent-eval-platform
49
+ pip install -e .
50
+ ```
51
+
52
+ If your shell says `evalrun: command not found`, activate the virtual environment and install the repository first:
53
+
54
+ ```bash
55
+ source .venv/bin/activate
56
+ python -m pip install -e .
57
+ rehash # zsh only, refreshes the command cache
58
+ ```
59
+
60
+ ### 2. Zero-Cost Offline Demo
61
+
62
+ Try EvalRun without an API key or network request:
63
+
64
+ ```bash
65
+ evalrun demo
66
+ open results/demo/report.html # macOS
67
+ ```
68
+
69
+ ### 3. Single Scenario Run (Hosted Model)
70
+
71
+ ```bash
72
+ export OPENAI_API_KEY="sk-proj-..."
73
+
74
+ evalrun run \
75
+ --scenario evals/scenarios/travel-agent/budget-constrained-itinerary.md \
76
+ --agent agents.travel:TravelPlanningAgent \
77
+ --model gpt-5.6-terra \
78
+ --judge-model gpt-5.6-terra \
79
+ --output results/run-001
80
+ ```
81
+
82
+ ### Choosing a model endpoint
83
+
84
+ EvalRun does not lock you to one model provider. The `--base-url` value is the address where the model accepts OpenAI-compatible requests:
85
+
86
+ | Provider | Base URL example |
87
+ | --- | --- |
88
+ | OpenAI-compatible hosted service | `https://api.openai.com/v1` |
89
+ | Gemini | `https://generativelanguage.googleapis.com/v1beta/openai/` |
90
+ | OpenRouter | `https://openrouter.ai/api/v1` |
91
+ | Local vLLM, Ollama, or LM Studio | `http://localhost:8000/v1` |
92
+
93
+ The judge normally uses the same endpoint and API key as the target model. You only need `--judge-base-url` or `--judge-api-key` when the judge is hosted somewhere different. The endpoint URL is not a credential; it simply tells EvalRun where to send the request.
94
+
95
+ For example, a Gemini run can be written as:
96
+
97
+ ```bash
98
+ export GEMINI_API_KEY="your-key"
99
+
100
+ evalrun run \
101
+ --scenario evals/scenarios/travel-agent/budget-constrained-itinerary.md \
102
+ --agent agents.travel:TravelPlanningAgent \
103
+ --model gemini-3.7-flash \
104
+ --base-url https://generativelanguage.googleapis.com/v1beta/openai/ \
105
+ --api-key "$GEMINI_API_KEY" \
106
+ --judge-model gemini-3.7-flash \
107
+ --output results/gemini-run
108
+ ```
109
+
110
+ ### 4. Local Model Server Run (vLLM / Ollama)
111
+
112
+ ```bash
113
+ # Users host their own local OpenAI-compatible server at http://localhost:8000/v1
114
+ evalrun run \
115
+ --scenario evals/scenarios/travel-agent/budget-constrained-itinerary.md \
116
+ --agent agents.travel:TravelPlanningAgent \
117
+ --model qwen2.5-72b-instruct \
118
+ --base-url http://localhost:8000/v1 \
119
+ --api-key EMPTY \
120
+ --judge-model gpt-5.6-terra \
121
+ --output results/local-run
122
+ ```
123
+
124
+ ### 5. Guided Local Web UI
125
+
126
+ Launch the zero-dependency local web interface:
127
+
128
+ ```bash
129
+ evalrun ui --port 8501
130
+ ```
131
+
132
+ Open `http://127.0.0.1:8501` in your browser to configure endpoints, select scenarios, run evaluations, view pass/fail/block verdicts, and launch interactive HTML reports.
133
+
134
+ ---
135
+
136
+ ## 🐍 Python SDK Usage
137
+
138
+ Integrate `evalrun` programmatically into Python automation pipelines:
139
+
140
+ ```python
141
+ from framework.sdk import evaluate, compare
142
+
143
+ # 1. Execute Benchmark Evaluation
144
+ results = evaluate(
145
+ scenario="evals/scenarios/travel-agent/budget-constrained-itinerary.md",
146
+ agent="agents.travel:TravelPlanningAgent",
147
+ model="gpt-5.6-terra",
148
+ judge_model="gpt-5.6-terra",
149
+ base_url="http://localhost:8000/v1",
150
+ )
151
+
152
+ # 2. Compare Candidate Results against Baseline
153
+ report = compare(
154
+ candidate_results=results,
155
+ baseline="results/run-001",
156
+ max_overall_drop=5.0,
157
+ )
158
+
159
+ if report.release_blocked:
160
+ print(f"RELEASE BLOCKED: {report.summary['blocked_reason']}")
161
+ ```
162
+
163
+ ---
164
+
165
+ ## 📊 Baseline Regression Testing
166
+
167
+ Compare a candidate prompt, model version, or code change against a prior baseline run:
168
+
169
+ ```bash
170
+ evalrun run \
171
+ --scenario evals/scenarios/travel-agent/budget-constrained-itinerary.md \
172
+ --agent agents.travel:TravelPlanningAgent \
173
+ --model gpt-5.6-terra \
174
+ --judge-model gpt-5.6-terra \
175
+ --baseline results/run-001 \
176
+ --max-regression 5.0 \
177
+ --max-dimension-regression 10.0 \
178
+ --output results/candidate-run
179
+ ```
180
+
181
+ ### Generated Artifacts
182
+
183
+ - `manifest.json`: Execution metadata with redacted API credentials.
184
+ - `regression_report.json`: Machine-readable score deltas ($\Delta \text{score}$) and gate decisions.
185
+ - `report.html`: Standalone interactive HTML report for human inspection.
186
+
187
+ ---
188
+
189
+ ## Distribution and deployment
190
+
191
+ There is no central service to deploy for the current product. The recommended path is:
192
+
193
+ 1. Publish the repository on GitHub.
194
+ 2. Add tagged releases and a clear quick-start guide.
195
+ 3. Users install it locally with `pip install -e .` from a clone.
196
+ 4. Later publish the package to PyPI so users can run `pip install evalrun`.
197
+ 5. Host documentation on GitHub Pages if useful; the evaluation engine itself remains local.
198
+ 6. Users provide their own hosted-model API keys or run their own local model server.
199
+
200
+ The local UI is intended for local use, not public internet deployment. A shared hosted deployment would be a separate project requiring authentication, secret management, isolation, and hosted execution.
201
+
202
+ ### Credential promise
203
+
204
+ EvalRun does not provide, collect, or store model credentials. A key is read by the local process and passed to the selected model endpoint for that run. Keys are never written to `manifest.json`, `report.html`, or `regression_report.json`; reports contain only `[REDACTED]`. Prefer environment variables such as `OPENAI_API_KEY`, `GEMINI_API_KEY`, or `OPENROUTER_API_KEY`. Avoid putting real keys directly in shell commands because your terminal may save command history.
205
+
206
+ ## How a run works
207
+
208
+ ```text
209
+ Choose a scenario
210
+ ↓
211
+ Run your agent with your chosen model
212
+ ↓
213
+ Score the result against the criteria
214
+ ↓
215
+ Run the independent auditor
216
+ ↓
217
+ Compare with a previous run, if supplied
218
+ ↓
219
+ Write JSON and HTML evidence
220
+ ↓
221
+ Return PASS or BLOCK
222
+ ```
223
+
224
+ The command line is useful for repeatable runs, the Python SDK is useful inside scripts and pipelines, and the local browser interface is useful when you prefer a form. All three use the same evaluation engine.
225
+
226
+ ## Add your own evaluation scenario
227
+
228
+ Scenarios are ordinary Markdown files. Copy [`templates/scenario_template.md`](templates/scenario_template.md), edit the prompt and criteria, and save the file under a folder such as `evals/scenarios/my-domain/my-scenario.md`.
229
+
230
+ Each scenario defines:
231
+
232
+ - the request sent to the agent;
233
+ - hard constraints that must not be violated;
234
+ - the expected behavior;
235
+ - the dimensions to score;
236
+ - what counts as a pass or failure.
237
+
238
+ Run one custom scenario with `--scenario`:
239
+
240
+ ```bash
241
+ evalrun run \
242
+ --scenario evals/scenarios/my-domain/my-scenario.md \
243
+ --agent my_agent:MyAgent \
244
+ --model gemini-3.7-flash \
245
+ --base-url https://generativelanguage.googleapis.com/v1beta/openai/ \
246
+ --api-key "$GEMINI_API_KEY" \
247
+ --judge-model gemini-3.7-flash \
248
+ --output results/my-scenario
249
+ ```
250
+
251
+ Or place multiple `.md` files in a folder and use `--suite path/to/folder`.
252
+
253
+ ## 🏗️ Architecture & Documentation
254
+
255
+ For detailed system component diagrams, dual-pass auditor sequence flows, and release gate decision trees, see [`docs/architecture.md`](file:///Users/shivam/Projects/AI/agent-eval-platform/docs/architecture.md).
256
+
257
+ - Hosted Models Guide: [`docs/quickstart-hosted.md`](file:///Users/shivam/Projects/AI/agent-eval-platform/docs/quickstart-hosted.md)
258
+ - Local Models Guide: [`docs/quickstart-local.md`](file:///Users/shivam/Projects/AI/agent-eval-platform/docs/quickstart-local.md)
259
+ - CLI Specification: [`docs/phase4-local-cli-design.md`](file:///Users/shivam/Projects/AI/agent-eval-platform/docs/phase4-local-cli-design.md)
260
+ - Regression Engine Design: [`docs/phase5-regression-gates-design.md`](file:///Users/shivam/Projects/AI/agent-eval-platform/docs/phase5-regression-gates-design.md)
261
+
262
+ ---
263
+
264
+ ## ⚠️ Limitations & Reproducibility Guidelines
265
+
266
+ - **Judge Variance**: LLM judge evaluations can exhibit non-zero variance. For baseline regression testing, fix model versions and set deterministic sampling parameters where available.
267
+ - **Local Model Requirements**: Local evaluation throughput depends on server VRAM and concurrency settings. Ensure your local server handles parallel requests cleanly.
268
+ - **Credential Security**: Credentials in `manifest.json` and `regression_report.json` are automatically redacted into `"[REDACTED]"`. Never commit unredacted API keys.
@@ -0,0 +1,100 @@
1
+ agents/__init__.py,sha256=d--Be1pW03iwvln-9Oz6IEN0w_pGHW4jGa8as7s_JIk,248
2
+ agents/base.py,sha256=rZ56Uah1k16iUWVjpwZ4UCQc85cRdNL3lD0-dGE0VMQ,550
3
+ agents/auditor/__init__.py,sha256=BF5VNlhZ5ZZOkv9EZjG_YLEpFSP9S6ExDleauRp0ADw,367
4
+ agents/auditor/budget_auditor.py,sha256=7zknzQQbqzmuBC_qyaECAe-GTvOViWk4dJ5SouKvWiM,3720
5
+ agents/auditor/parser.py,sha256=cBViw59CCOxz1yM4cZm2dfN5S-OVcBP5RCValZCZcLI,5859
6
+ agents/auditor/prompts.py,sha256=ss7LKHdH3Dwbfj-0CTsSDIOEP1lBTdURujxIWLyd-k8,3073
7
+ agents/auditor/schema.py,sha256=lRePzbr8etfOGrZAHFzH9HqTtfeedEWK_O1uBEEdmAE,2260
8
+ agents/reflection/__init__.py,sha256=V0cqZwu-2PgNFQzuTfGm1Kawupwy9yYyHgAC_EU3DmM,85
9
+ agents/reflection/agent.py,sha256=oqjU2Wp57wVQ6mImNIiQe2mJVcJ0lVoZHqlPldesHYk,2479
10
+ agents/reflection/prompts.py,sha256=kEwlBOfdZLSTFmU8WgfzvwanRzwyvACHWBiWcRnZbMI,1439
11
+ agents/research/__init__.py,sha256=XjSpY9_A7Qr6Q0W947xp1QPv1rc8Um_57OwB0rafpP4,131
12
+ agents/research/agent.py,sha256=bpyCHW0kkZ4BWVS2K9BsgKnq0UXc5LVOHebr7CVjwTg,1295
13
+ agents/research/planner.py,sha256=-IeYxGY1sqgGrswvyMhVuLpxoXKZmBVMBOnxyGVMVQ8,1889
14
+ agents/research/prompts.py,sha256=xPJgsAccHS_dYOSu3Yjjk0LXgEoigBXRtE5lyRoihAM,851
15
+ agents/support/__init__.py,sha256=XIcVllA_AqwZ5N9lH4Wpnk0AiFXcTacEDg8HSFLLmr8,109
16
+ agents/support/triage_agent.py,sha256=I9In6PYNBZyUu0pcKvBIxatmVHTNUwkGBx-LwFqh6Ec,1531
17
+ agents/travel/__init__.py,sha256=RI8awH0GtmEVd24GO5uidK0VvXu5azdQ-a8T4AEHwx8,254
18
+ agents/travel/agent.py,sha256=C6nvDMUq92BMlAnweQC-1aBmhRusV74vDl8-C87LDtQ,17612
19
+ agents/travel/prompts.py,sha256=y2WK0ouC_eO3_dYa6haXjYPzn9Qoxysgz230YVvj0XQ,1834
20
+ agents/travel/session.py,sha256=Zha_5cFTmtW3F05mnnJRTQCAC65sMwZ3VHsCVUmcNko,3726
21
+ cli/__init__.py,sha256=nyDigv65BJqXf5iizLyHca8b6drvFXDEnxo63GKbbas,170
22
+ cli/demo.py,sha256=kkj-nQJ9DUgccco02hauoCZXq4jUd_cN-1oevzEo0To,2192
23
+ cli/formatter.py,sha256=ljfJr9pnXwBVdgU1E_-TlzWvJ2MjNAfIXJME6f6AsfE,3935
24
+ cli/html_reporter.py,sha256=GwzLiTUlNFqR0VguAbrIoJKW0ECDZUM-vbDXuCXksP4,25086
25
+ cli/main.py,sha256=rpyXbtce6157_PHBj7B5AMoY_1iB5T7ShVOQ2a8Dj-g,15786
26
+ cli/progress.py,sha256=XPvmIiMPCGRxcgQEmu6Vng3P1PzyIqw7WfFfKuixBps,1284
27
+ cli/resolver.py,sha256=O4dsC0nb-cP4GCJzK2qo-jk43U7y9qeoxwZ1oMgjdOI,3754
28
+ evalrun-0.4.0.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ framework/__init__.py,sha256=elFon9ugWqcdvdDw4wONfWOtfN_TkT7SCxdpFTK6Ing,1505
30
+ framework/exceptions.py,sha256=Y6A2hjD5u2_OKF2KIfTLTVtUJ0gGOgcRcVt4-QZz7VM,1026
31
+ framework/models.py,sha256=zd_l8AJxpPxwLEYqOpPr1iBEDhXVd3qUtcPl3kW_iDQ,1902
32
+ framework/parser.py,sha256=AG-htozoexjOwwkYyzpBuQR3rAW99rYn5_IOGFlhpAg,1563
33
+ framework/sdk.py,sha256=H30QbGhIbZDPc38vI3HGT1H2lwFRQYX2S2Odcw--heU,5684
34
+ framework/utils.py,sha256=YxwLPXtzAzArb5-0F1NF5Hxm6WzepAZfilBcPG90Y34,1335
35
+ framework/core/__init__.py,sha256=FMRWwu22MB2S0nR1oX_8RRLjQTmA-u2Ttg43GlrMYoU,485
36
+ framework/core/adapters.py,sha256=gYGDMwE-LbWJIrvLFXTilq_CbhtSPSGgLtDzYNW-gc8,4764
37
+ framework/core/contracts.py,sha256=KjDCphztYrZlAq7o7YLRGRveJ9KumbrwKCNhhFsSKYY,2903
38
+ framework/core/suite.py,sha256=R9EMoyqsMNnKcBFj3ZXtp7qe-aeYKs4xWbkJ4soCb7c,1623
39
+ framework/evaluation/__init__.py,sha256=KjkPL80haNd7hUFBFYMBkB31V3F0uu864nZYS5leqc8,801
40
+ framework/evaluation/base.py,sha256=zRNvQ8rRrWVX5VfgDPMbRdeTAqXRHwW5p-29TtCg33s,867
41
+ framework/evaluation/dimensions.py,sha256=jdfgCKXicWsNg0Y-Tidcrnbm7UckdjKOXsfTi4chat0,250
42
+ framework/evaluation/engine.py,sha256=6rPNUlBsUBeRso62IFtN3Refyl334hqhlAiZGYCRNjg,3893
43
+ framework/evaluation/runner.py,sha256=uGxWuyGnHcx2IjUNgiD-BbF06xFHOLnVKIgcrCs09QY,16036
44
+ framework/evaluation/testing.py,sha256=vmSpNrQMhXnd2M-l0JjXR5SHBQEfJKhaiya6QIScrCI,907
45
+ framework/evaluation/evaluators/__init__.py,sha256=X80klkpKl5p1wDTSwuytXwTDqcxBjDM0sZhHKVSVYzU,479
46
+ framework/evaluation/evaluators/adaptability.py,sha256=9oNGE_qEwbZYImibyUKzUGPYNCVdlRVrno0qsMERx0U,898
47
+ framework/evaluation/evaluators/base_llm.py,sha256=EK8bSho3LvTYbB8tbsmIMIoGq1gS9p5X7BdZCHn0REQ,3081
48
+ framework/evaluation/evaluators/constraint.py,sha256=pvkHVZmb85H0QaB4xL0mho3ov1tcC0kmT7hfg0JUoK4,892
49
+ framework/evaluation/evaluators/information_accuracy.py,sha256=Lv0Bb0KXNMP2_yl_Kh7s7AVq3aNLBn7OzIJX9Ph0Vn0,1562
50
+ framework/evaluation/evaluators/personalization.py,sha256=ISHcUN13S5pxT2JU0vmSgc0XdnGg1rsgDU0AtEqcmV4,931
51
+ framework/evaluation/evaluators/planning.py,sha256=9Kx0pLvrmaj05wVxlq_MNAKwHWRIBAaM3DwvIAN55aU,897
52
+ framework/evaluation/evaluators/support.py,sha256=dqT0khLnhbmlDoooMcufZbhATKThTJYc-xEFWbrY-Ug,3118
53
+ framework/evaluation/prompts/__init__.py,sha256=aa4gxNX77ds3UwDeExifMO2857n5dBbkXUq7NrssSJg,549
54
+ framework/evaluation/prompts/adaptability.py,sha256=8GC9uDd0lgd3gJgaIhIlNa3aZKyQd30zEq8iP1YCsQU,3239
55
+ framework/evaluation/prompts/base.py,sha256=YwGagUdKVv1fKXmlR9GJVla_6ocYoDQIVtoly1hMH9U,1662
56
+ framework/evaluation/prompts/constraint.py,sha256=Yf1THuImU-YKpkAQQHgZkIDmAC7ua_yLHD2j-Wh5Cwk,1254
57
+ framework/evaluation/prompts/information_accuracy.py,sha256=kjAHUKLrOSnnnD4HJ3PvoPKEdxQEVrF8DhJBSwauzxA,4080
58
+ framework/evaluation/prompts/personalization.py,sha256=_gyKMs4kS3pBjG8DPHD2lpukw5GWw0FSo6eb0OEXeOM,3377
59
+ framework/evaluation/prompts/planning.py,sha256=KnSRCQjtVBWvI7bqrEr3gg70-opHQcXipnISRZSEIMA,3391
60
+ framework/llms/__init__.py,sha256=9pgFMd1MO97Cjbo-RvKdOMl859NV3MNGThfJz0aJR3c,368
61
+ framework/llms/base.py,sha256=SQnpgoK8g5v7k3dVSJ3caZnShhWHtObN5Zp07tuPVts,870
62
+ framework/llms/factory.py,sha256=Nq1TKKcCkvK4mWEe2J0B5L8Z7IJPVy0FDa_0PdSvWR4,1153
63
+ framework/llms/gemini.py,sha256=tza5D4h4vx4wMAzicMLDnbWb6z_ZOOPg1AAN3abN3Kc,3109
64
+ framework/llms/mock.py,sha256=Yp3M4bg9XOu4XcI9I8pVqWqdSNUPscMoMP_1ntewpnw,921
65
+ framework/llms/openai.py,sha256=BGtnEmXuYBJmbA0dHV_W96tI-y7tWB-oJYSMecKDbEI,3475
66
+ framework/llms/openai_compatible.py,sha256=zMjBKGuTgT6vNhv9wvz1LlbjqwYkfJkzCLRcQCgDxco,5333
67
+ framework/mcp/__init__.py,sha256=31aISAqLDwAASTtp7QRsc4tbiVchRYu7GO5n2r8wRYQ,551
68
+ framework/mcp/client.py,sha256=dKVGRoi9iXXZkUzFic6SrQyrO_EuKwPuq8DT6sQlGIU,2576
69
+ framework/mcp/constraints.py,sha256=QyWUKNVN1OYp8dNlQKvwLRN1-rvGU6pxjAejohbBQ3U,4402
70
+ framework/mcp/revision_summary.py,sha256=X9lJA3C_o6Uq03ZuNxgWfEYtHnJ0TfIjL1GNCov58dE,4600
71
+ framework/mcp/server.py,sha256=7sWwGc49su1o4-PchA1r3Z6rKGL5sIJE3hHPYyxHd9U,1410
72
+ framework/memory/__init__.py,sha256=DRmERPlTFg5GvPnOSc0XAd0OCGcJRRSqfIFHzuTOG-o,105
73
+ framework/memory/base.py,sha256=G5c_dzV6nvGxvTQ3Rf3fHWkvCKvLKyXZq2ZWd-yggHs,474
74
+ framework/parsers/__init__.py,sha256=ElWVaNALXXgv28dBL4L4OirLdvX2xQ73qDfCWob8Q-o,442
75
+ framework/parsers/frontmatter.py,sha256=09wJenN6vcLnUqgsUJ-yjApVJ9o2qTLCz3eBvcRs0fE,959
76
+ framework/parsers/mapper.py,sha256=keiKEfEaUxTun9n_pIIRljz7mDPSMRPkLbwKjaQICoE,2376
77
+ framework/parsers/markdown.py,sha256=PkbAY3rvOF0a0-IMtRZEgdrKdWoqzVCw4XiKI1Td1_k,4316
78
+ framework/parsers/transformers.py,sha256=PPFjv8C8S7q6iFiwuoJ-kZ8eiegJarWBD6Wc-MwOq90,3546
79
+ framework/profiles/__init__.py,sha256=_uo6Pckt8gjSOVCiEQ8TxdALg8LMdwlVNXJwXah0rZI,842
80
+ framework/profiles/registry.py,sha256=QG3w2-KmWRWdaNmXvpD8DD304AuIKQKF3aJM2diWQIs,3679
81
+ framework/profiles/support.py,sha256=Ay1NnR-s_ATRkWzFvk-0pX4iqi0gQK3P8cLNlyV6BHI,853
82
+ framework/profiles/travel.py,sha256=IVz3N8h88jCKNrH1Zjph3T9hNshBLtjJNSjSrMblia4,2232
83
+ framework/regression/__init__.py,sha256=e4eEOZg6nHZ3r0oV3qQjvJqQVoKa7xY1AcbWRiZRZOg,392
84
+ framework/regression/comparator.py,sha256=ozSUNBQAZbbh-3KI0SaIdDJJFyjwi0ia5NaigQMSOqI,10646
85
+ framework/regression/loader.py,sha256=aTOJEtbze-WfYttugQGXuv2VJQBmnsJ0ohObvv2Qz4I,6111
86
+ framework/verification/__init__.py,sha256=6Y9k7OU13lx0p3MmNXQ4fl3kJ08m8sDUcxojW12I1-k,458
87
+ framework/verification/base.py,sha256=hdNWPYaPZysTrL5poS0akyAxLtnIGtcx5WRfCoUnZsc,861
88
+ framework/verification/extractor.py,sha256=MMKbK8WpnO7U-z2KeUDfGmyRzxxd8A8bTU49ODJZLg8,3548
89
+ framework/verification/local.py,sha256=7JJrSIdkkO-k3n0ffbJn1VXkt4o5m4WeL1MOTwllVtQ,4691
90
+ framework/verification/models.py,sha256=8eRL6UfX4rYdzX-WRPZVOmpazpF4564lbOxQUGeZanw,3556
91
+ framework/verification/pipeline.py,sha256=XQOyO7JYQ_kUswsS9Y51SdUj5w28eTcN72SROBwpFF4,1248
92
+ framework/verification/prompts.py,sha256=HV-BqZ-donfYbBF5I6BJZd2gjQg37Q-NoMptjLbu3f4,1440
93
+ framework/verification/utils.py,sha256=LiYtT5Ft-wE3b9Ge0w0YO8AuZ9IB1LZqoV77htQEpMY,1443
94
+ ui/__init__.py,sha256=ngbjUI_X8nA_lsdEx0VzvyJSG5SlRxdhMSVKzNkxrBc,47
95
+ ui/server.py,sha256=v0ljSOo6BnXPKPlLa24iVgx5c_K7LEEHkTe2ehg4QwU,10954
96
+ evalrun-0.4.0.dist-info/METADATA,sha256=69C9cajBRn5wQcWtkhyGH2MOcIZ27-V9_CrEkJtMHpY,10361
97
+ evalrun-0.4.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
98
+ evalrun-0.4.0.dist-info/entry_points.txt,sha256=UIXWZUtcjtFuFD9v54VS6meRdbHcEKhINU8nZ3UNU1c,42
99
+ evalrun-0.4.0.dist-info/top_level.txt,sha256=vsUSUEXYBjHS6azZmZe9-0ZcSChVK5i17tzCi0eS2BM,24
100
+ evalrun-0.4.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ evalrun = cli.main:main
File without changes
@@ -0,0 +1,4 @@
1
+ agents
2
+ cli
3
+ framework
4
+ ui
framework/__init__.py ADDED
@@ -0,0 +1,70 @@
1
+ """Generic evaluation framework for AI agents."""
2
+
3
+ from .models import (
4
+ Benchmark,
5
+ AgentOutput,
6
+ DimensionScore,
7
+ EvaluationResult,
8
+ EvaluationProfile,
9
+ ParsedSections,
10
+ ParsedBenchmark,
11
+ )
12
+ from .parser import parse_benchmark, parse_benchmark_text
13
+ from .evaluation import (
14
+ BaseEvaluator,
15
+ BaseLLMEvaluator,
16
+ EvaluationEngine,
17
+ BenchmarkRunner,
18
+ ConstraintEvaluator,
19
+ PlanningQualityEvaluator,
20
+ PersonalizationEvaluator,
21
+ AdaptabilityEvaluator,
22
+ InformationAccuracyEvaluator,
23
+ DummyEvaluator,
24
+ CONSTRAINT_SATISFACTION,
25
+ PLANNING_QUALITY,
26
+ INFORMATION_ACCURACY,
27
+ PERSONALIZATION,
28
+ ADAPTABILITY,
29
+ )
30
+ from .llms import (
31
+ BaseLLM,
32
+ Message,
33
+ MockLLM,
34
+ OpenAILLM,
35
+ GeminiLLM,
36
+ create_llm,
37
+ )
38
+ from .profiles import (
39
+ TRAVEL_PROFILE,
40
+ TRAVEL_ROUTE_OPTIMIZATION_PROFILE,
41
+ TRAVEL_REMOTE_WORKER_TIMEZONES_PROFILE,
42
+ TRAVEL_MID_TRIP_REPLANNING_PROFILE,
43
+ TRAVEL_INFORMATION_GATHERING_UNCERTAINTY_PROFILE,
44
+ PROFILE_REGISTRY,
45
+ )
46
+ from .verification import (
47
+ ClaimType,
48
+ VerificationStatus,
49
+ Claim,
50
+ Evidence,
51
+ VerificationReport,
52
+ BaseVerifier,
53
+ LocalKnowledgeBaseVerifier,
54
+ ClaimExtractor,
55
+ VerificationPipeline,
56
+ )
57
+ from .memory import BaseSessionMemory
58
+ from .sdk import evaluate, compare
59
+
60
+ __all__ = [
61
+ "evaluate",
62
+ "compare",
63
+ "Benchmark",
64
+ "AgentOutput",
65
+ "DimensionScore",
66
+ "EvaluationResult",
67
+ "EvaluationProfile",
68
+ "BenchmarkRunner",
69
+ "BaseSessionMemory",
70
+ ]
@@ -0,0 +1,17 @@
1
+ """Generic evaluation core module exports."""
2
+
3
+ from framework.core.contracts import Scenario, RunTrace, to_scenario, to_benchmark
4
+ from framework.core.adapters import AgentAdapter, PythonAgentAdapter, HttpAgentAdapter, CliAgentAdapter
5
+ from framework.core.suite import EvaluationSuite
6
+
7
+ __all__ = [
8
+ "Scenario",
9
+ "RunTrace",
10
+ "to_scenario",
11
+ "to_benchmark",
12
+ "AgentAdapter",
13
+ "PythonAgentAdapter",
14
+ "HttpAgentAdapter",
15
+ "CliAgentAdapter",
16
+ "EvaluationSuite",
17
+ ]
@@ -0,0 +1,118 @@
1
+ """Agent adapters for wrapping internal Python agents, HTTP endpoints, or CLI binaries."""
2
+
3
+ import json
4
+ import subprocess
5
+ import requests
6
+ from abc import ABC, abstractmethod
7
+ from typing import Any, Dict, Optional
8
+
9
+ from framework.core.contracts import Scenario
10
+ from framework.models import AgentOutput
11
+
12
+
13
+ class AgentAdapter(ABC):
14
+ """Abstract adapter interface decoupling agent evaluation from specific implementations."""
15
+
16
+ @abstractmethod
17
+ def run(self, scenario: Any, **kwargs) -> AgentOutput:
18
+ """Executes the wrapped agent on a scenario or prompt string and returns standardized AgentOutput."""
19
+ pass
20
+
21
+
22
+ class PythonAgentAdapter(AgentAdapter):
23
+ """Adapter wrapping any in-process Python agent object (e.g. TravelPlanningAgent)."""
24
+
25
+ def __init__(self, agent: Any, agent_id: Optional[str] = None):
26
+ self.agent = agent
27
+ self.agent_id = agent_id or getattr(agent, "agent_name", agent.__class__.__name__)
28
+
29
+ def run(self, scenario: Any, **kwargs) -> AgentOutput:
30
+ """Invokes the underlying Python agent instance."""
31
+ prompt_text = scenario if isinstance(scenario, str) else getattr(scenario, "prompt", str(scenario))
32
+ if hasattr(self.agent, "run"):
33
+ result = self.agent.run(prompt_text, **kwargs)
34
+ if isinstance(result, AgentOutput):
35
+ return result
36
+ elif isinstance(result, str):
37
+ return AgentOutput(content=result, metadata={"adapter": "PythonAgentAdapter"})
38
+ else:
39
+ return AgentOutput(content=str(result), metadata={"adapter": "PythonAgentAdapter"})
40
+ else:
41
+ raise AttributeError(f"Wrapped agent object {self.agent} has no 'run' method.")
42
+
43
+
44
+ class HttpAgentAdapter(AgentAdapter):
45
+ """Adapter wrapping an external HTTP/REST API agent endpoint."""
46
+
47
+ def __init__(self, endpoint_url: str, headers: Optional[Dict[str, str]] = None, timeout: float = 120.0):
48
+ self.endpoint_url = endpoint_url
49
+ self.headers = headers or {"Content-Type": "application/json"}
50
+ self.timeout = timeout
51
+
52
+ def run(self, scenario: Any, **kwargs) -> AgentOutput:
53
+ if isinstance(scenario, str):
54
+ prompt_text = scenario
55
+ scenario_id = "scenario-001"
56
+ constraints = {}
57
+ else:
58
+ prompt_text = getattr(scenario, "prompt", str(scenario))
59
+ scenario_id = getattr(scenario, "id", "scenario-001")
60
+ constraints = getattr(scenario, "constraints", {})
61
+
62
+ payload = {
63
+ "scenario_id": scenario_id,
64
+ "prompt": prompt_text,
65
+ "constraints": constraints,
66
+ }
67
+ try:
68
+ resp = requests.post(self.endpoint_url, json=payload, headers=self.headers, timeout=self.timeout)
69
+ resp.raise_for_status()
70
+ except requests.exceptions.Timeout as e:
71
+ raise TimeoutError(f"HTTP Agent endpoint timed out after {self.timeout}s: {e}") from e
72
+
73
+ data = resp.json()
74
+ content = data.get("content") or data.get("output") or resp.text
75
+ metadata = data.get("metadata", {})
76
+ metadata["adapter"] = "HttpAgentAdapter"
77
+ return AgentOutput(content=content, metadata=metadata)
78
+
79
+
80
+ class CliAgentAdapter(AgentAdapter):
81
+ """Adapter wrapping a CLI command-line binary agent."""
82
+
83
+ def __init__(self, command: Any, timeout: float = 120.0):
84
+ if isinstance(command, str):
85
+ import shlex
86
+ self.command_args = shlex.split(command)
87
+ else:
88
+ self.command_args = command
89
+ self.timeout = timeout
90
+
91
+ def run(self, scenario: Any, **kwargs) -> AgentOutput:
92
+ prompt_text = scenario if isinstance(scenario, str) else getattr(scenario, "prompt", str(scenario))
93
+ try:
94
+ proc = subprocess.run(
95
+ self.command_args,
96
+ input=prompt_text,
97
+ text=True,
98
+ capture_output=True,
99
+ timeout=self.timeout,
100
+ )
101
+ except subprocess.TimeoutExpired as e:
102
+ raise TimeoutError(f"CLI Agent command timed out after {self.timeout}s: {e}") from e
103
+
104
+ if proc.returncode != 0:
105
+ raise RuntimeError(f"CLI Agent command failed (code {proc.returncode}): {proc.stderr}")
106
+
107
+ stdout_text = proc.stdout.strip()
108
+ try:
109
+ parsed = json.loads(stdout_text)
110
+ if isinstance(parsed, dict) and "content" in parsed:
111
+ content = parsed["content"]
112
+ metadata = parsed.get("metadata", {})
113
+ metadata["adapter"] = "CliAgentAdapter"
114
+ return AgentOutput(content=content, metadata=metadata)
115
+ except Exception:
116
+ pass
117
+
118
+ return AgentOutput(content=stdout_text, metadata={"adapter": "CliAgentAdapter"})