niceeval 0.4.3 → 0.4.5
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.
- package/README.md +21 -12
- package/README.zh.md +8 -9
- package/docs-site/.mintignore +13 -0
- package/docs-site/AGENTS.md +46 -0
- package/docs-site/concepts/adapter.mdx +287 -0
- package/docs-site/concepts/assert.mdx +243 -0
- package/docs-site/concepts/drive.mdx +118 -0
- package/docs-site/concepts/evals.mdx +108 -0
- package/docs-site/concepts/experiment.mdx +37 -0
- package/docs-site/concepts/hitl.mdx +83 -0
- package/docs-site/concepts/judge.mdx +129 -0
- package/docs-site/concepts/overview.mdx +98 -0
- package/docs-site/concepts/tier.mdx +42 -0
- package/docs-site/docs-ref/00-index.md +23 -0
- package/docs-site/docs-ref/01-page-types.md +43 -0
- package/docs-site/docs-ref/03-style-rules.md +45 -0
- package/docs-site/docs-ref/04-code-examples.md +37 -0
- package/docs-site/docs-ref/05-dx-failure-paths.md +45 -0
- package/docs-site/docs-ref/06-checklists.md +53 -0
- package/docs-site/docs.json +256 -0
- package/docs-site/example/ai-agent-application.mdx +148 -0
- package/docs-site/example/claude-code-codex-plugin.mdx +162 -0
- package/docs-site/example/claude-code-codex-skill.mdx +147 -0
- package/docs-site/example/showcase.mdx +39 -0
- package/docs-site/example/tier1-ai-sdk-v7.mdx +136 -0
- package/docs-site/example/tier1-claude-sdk.mdx +119 -0
- package/docs-site/example/tier1-codex-sdk.mdx +111 -0
- package/docs-site/example/tier1-langgraph.mdx +119 -0
- package/docs-site/example/tier1-pi-sdk.mdx +119 -0
- package/docs-site/favicon.svg +5 -0
- package/docs-site/github-diff.css +135 -0
- package/docs-site/github-diff.js +11 -0
- package/docs-site/guides/authoring.mdx +129 -0
- package/docs-site/guides/ci-integration.mdx +97 -0
- package/docs-site/guides/connect-otel.mdx +209 -0
- package/docs-site/guides/connect-your-agent.mdx +221 -0
- package/docs-site/guides/dataset-fanout.mdx +98 -0
- package/docs-site/guides/experiments.mdx +71 -0
- package/docs-site/guides/fixtures.mdx +147 -0
- package/docs-site/guides/reporters.mdx +113 -0
- package/docs-site/guides/runner.mdx +79 -0
- package/docs-site/guides/sandbox-agent.mdx +138 -0
- package/docs-site/guides/sandbox-backends.mdx +64 -0
- package/docs-site/guides/scoring-guide.mdx +92 -0
- package/docs-site/guides/viewing-results.mdx +195 -0
- package/docs-site/guides/write-experiment.mdx +81 -0
- package/docs-site/guides/write-send.mdx +347 -0
- package/docs-site/images/adapter-tiers-zh.svg +60 -0
- package/docs-site/images/agent-turn-roundtrip-en.svg +62 -0
- package/docs-site/images/agent-turn-roundtrip-zh.svg +77 -0
- package/docs-site/images/hitl-handshake-zh.svg +89 -0
- package/docs-site/images/logo.svg +6 -0
- package/docs-site/index.mdx +181 -0
- package/docs-site/introduction.mdx +141 -0
- package/docs-site/quickstart.mdx +136 -0
- package/docs-site/reference/builtin-agents.mdx +161 -0
- package/docs-site/reference/capabilities.mdx +76 -0
- package/docs-site/reference/cli.mdx +120 -0
- package/docs-site/reference/define-agent.mdx +168 -0
- package/docs-site/reference/define-config.mdx +41 -0
- package/docs-site/reference/define-eval.mdx +160 -0
- package/docs-site/reference/events.mdx +131 -0
- package/docs-site/reference/expect.mdx +112 -0
- package/docs-site/tracker.js +8 -0
- package/docs-site/zh/concepts/adapter.mdx +286 -0
- package/docs-site/zh/concepts/assert.mdx +243 -0
- package/docs-site/zh/concepts/drive.mdx +118 -0
- package/docs-site/zh/concepts/evals.mdx +124 -0
- package/docs-site/zh/concepts/experiment.mdx +37 -0
- package/docs-site/zh/concepts/hitl.mdx +83 -0
- package/docs-site/zh/concepts/judge.mdx +130 -0
- package/docs-site/zh/concepts/overview.mdx +109 -0
- package/docs-site/zh/concepts/tier.mdx +44 -0
- package/docs-site/zh/example/ai-agent-application.mdx +152 -0
- package/docs-site/zh/example/claude-code-codex-plugin.mdx +163 -0
- package/docs-site/zh/example/claude-code-codex-skill.mdx +147 -0
- package/docs-site/zh/example/showcase.mdx +39 -0
- package/docs-site/zh/example/tier1-ai-sdk-v7.mdx +140 -0
- package/docs-site/zh/example/tier1-claude-sdk.mdx +122 -0
- package/docs-site/zh/example/tier1-codex-sdk.mdx +117 -0
- package/docs-site/zh/example/tier1-langgraph.mdx +123 -0
- package/docs-site/zh/example/tier1-pi-sdk.mdx +122 -0
- package/docs-site/zh/guides/agent-feedback-loop.mdx +79 -0
- package/docs-site/zh/guides/authoring.mdx +129 -0
- package/docs-site/zh/guides/ci-integration.mdx +97 -0
- package/docs-site/zh/guides/connect-otel.mdx +208 -0
- package/docs-site/zh/guides/connect-your-agent.mdx +226 -0
- package/docs-site/zh/guides/dataset-fanout.mdx +83 -0
- package/docs-site/zh/guides/experiments.mdx +72 -0
- package/docs-site/zh/guides/fixtures.mdx +147 -0
- package/docs-site/zh/guides/official-adapters.mdx +132 -0
- package/docs-site/zh/guides/reporters.mdx +113 -0
- package/docs-site/zh/guides/runner.mdx +82 -0
- package/docs-site/zh/guides/sandbox-agent.mdx +139 -0
- package/docs-site/zh/guides/sandbox-backends.mdx +75 -0
- package/docs-site/zh/guides/scoring-guide.mdx +92 -0
- package/docs-site/zh/guides/viewing-results.mdx +195 -0
- package/docs-site/zh/guides/write-experiment.mdx +101 -0
- package/docs-site/zh/guides/write-send.mdx +353 -0
- package/docs-site/zh/index.mdx +180 -0
- package/docs-site/zh/introduction.mdx +140 -0
- package/docs-site/zh/quickstart.mdx +137 -0
- package/docs-site/zh/reference/builtin-agents.mdx +364 -0
- package/docs-site/zh/reference/capabilities.mdx +76 -0
- package/docs-site/zh/reference/cli.mdx +140 -0
- package/docs-site/zh/reference/define-agent.mdx +461 -0
- package/docs-site/zh/reference/define-config.mdx +107 -0
- package/docs-site/zh/reference/define-eval.mdx +674 -0
- package/docs-site/zh/reference/events.mdx +252 -0
- package/docs-site/zh/reference/expect.mdx +208 -0
- package/package.json +3 -2
- package/src/agents/bub.ts +1 -1
- package/src/agents/claude-code.ts +8 -5
- package/src/agents/codex.ts +9 -5
- package/src/agents/sdk-streams.test.ts +4 -4
- package/src/agents/sdk-streams.ts +14 -9
- package/src/agents/types.ts +40 -1
- package/src/agents/ui-message-stream.ts +1 -0
- package/src/cli.ts +40 -10
- package/src/context/types.ts +140 -0
- package/src/expect/index.ts +15 -8
- package/src/i18n/en.ts +20 -6
- package/src/i18n/zh-CN.ts +20 -6
- package/src/o11y/parsers/bub.test.ts +71 -0
- package/src/o11y/parsers/bub.ts +5 -0
- package/src/o11y/types.ts +27 -2
- package/src/runner/attempt.ts +2 -1
- package/src/runner/reporters/artifacts.ts +11 -3
- package/src/runner/reporters/live.ts +45 -8
- package/src/runner/run.test.ts +50 -0
- package/src/runner/run.ts +135 -41
- package/src/runner/types.ts +55 -2
- package/src/sandbox/types.ts +18 -0
- package/src/scoring/types.ts +5 -0
- package/src/shared/types.ts +3 -0
- package/src/util.test.ts +26 -1
- package/src/util.ts +16 -0
- package/src/view/app/App.tsx +2 -2
- package/src/view/app/components/AttemptModal.tsx +2 -0
- package/src/view/app/components/CopyControls.tsx +87 -28
- package/src/view/app/i18n.ts +3 -3
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +18 -18
- package/docs/README.md +0 -120
- package/docs/adapters/README.md +0 -60
- package/docs/adapters/authoring.md +0 -179
- package/docs/adapters/coding-agent-skills-plugins.md +0 -324
- package/docs/adapters/collection.md +0 -128
- package/docs/adapters/contract.md +0 -264
- package/docs/adapters/reference/agent-eval.md +0 -215
- package/docs/adapters/reference/agent-loop-apis.md +0 -69
- package/docs/adapters/reference/claude-code-otel-telemetry.md +0 -100
- package/docs/adapters/reference/eve-protocol.md +0 -127
- package/docs/adapters/reference/otel-genai.md +0 -107
- package/docs/adapters/reference/otel-instrumentation.md +0 -65
- package/docs/adapters/targets.md +0 -99
- package/docs/architecture.md +0 -140
- package/docs/assertions.md +0 -387
- package/docs/capabilities-by-construction.md +0 -48
- package/docs/cli.md +0 -173
- package/docs/concepts.md +0 -106
- package/docs/e2e-ci.md +0 -332
- package/docs/eval-authoring.md +0 -319
- package/docs/experiments.md +0 -157
- package/docs/getting-started.md +0 -224
- package/docs/multi-agent.md +0 -145
- package/docs/observability.md +0 -337
- package/docs/origin-integration.md +0 -195
- package/docs/references.md +0 -35
- package/docs/reports.md +0 -551
- package/docs/results-format.md +0 -228
- package/docs/results-lib.md +0 -191
- package/docs/runner.md +0 -104
- package/docs/sandbox.md +0 -276
- package/docs/scoring.md +0 -119
- package/docs/source-map.md +0 -126
- package/docs/tier-sync.md +0 -193
- package/docs/view.md +0 -194
- package/docs/vision.md +0 -88
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://mintlify.com/docs.json",
|
|
3
|
+
"name": "niceeval",
|
|
4
|
+
"theme": "luma",
|
|
5
|
+
"favicon": "/favicon.svg",
|
|
6
|
+
"logo": {
|
|
7
|
+
"light": "/images/logo.svg",
|
|
8
|
+
"dark": "/images/logo.svg"
|
|
9
|
+
},
|
|
10
|
+
"colors": {
|
|
11
|
+
"primary": "#848c8e",
|
|
12
|
+
"light": "#11161e",
|
|
13
|
+
"dark": "#cfd0d2"
|
|
14
|
+
},
|
|
15
|
+
"navbar": {
|
|
16
|
+
"primary": {
|
|
17
|
+
"type": "github",
|
|
18
|
+
"href": "https://github.com/CorrectRoadH/niceeval"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"redirects": [
|
|
22
|
+
{
|
|
23
|
+
"source": "/concepts/scoring",
|
|
24
|
+
"destination": "/concepts/assert"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"source": "/concepts/agents-adapters",
|
|
28
|
+
"destination": "/concepts/adapter"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"source": "/guides/connect-agent",
|
|
32
|
+
"destination": "/guides/connect-your-agent"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"source": "/concepts/write-send",
|
|
36
|
+
"destination": "/guides/write-send"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"source": "/zh/concepts/scoring",
|
|
40
|
+
"destination": "/zh/concepts/assert"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"source": "/zh/concepts/agents-adapters",
|
|
44
|
+
"destination": "/zh/concepts/adapter"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"source": "/zh/concepts/write-send",
|
|
48
|
+
"destination": "/zh/guides/write-send"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"source": "/reference/configuration",
|
|
52
|
+
"destination": "/reference/define-config"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"source": "/zh/reference/configuration",
|
|
56
|
+
"destination": "/zh/reference/define-config"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"source": "/zh/example/eval-multil-turn-for-your-agent",
|
|
60
|
+
"destination": "/zh/concepts/drive"
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"navigation": {
|
|
64
|
+
"languages": [
|
|
65
|
+
{
|
|
66
|
+
"language": "en",
|
|
67
|
+
"default": true,
|
|
68
|
+
"tabs": [
|
|
69
|
+
{
|
|
70
|
+
"tab": "Documentation",
|
|
71
|
+
"groups": [
|
|
72
|
+
{
|
|
73
|
+
"group": "Get Started",
|
|
74
|
+
"pages": [
|
|
75
|
+
"introduction",
|
|
76
|
+
"quickstart"
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"group": "Core Concepts",
|
|
81
|
+
"pages": [
|
|
82
|
+
"concepts/overview",
|
|
83
|
+
"concepts/evals",
|
|
84
|
+
"concepts/experiment",
|
|
85
|
+
"concepts/adapter",
|
|
86
|
+
"concepts/tier",
|
|
87
|
+
"concepts/drive",
|
|
88
|
+
"concepts/hitl",
|
|
89
|
+
"concepts/assert",
|
|
90
|
+
"concepts/judge"
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"group": "Connecting Agents",
|
|
95
|
+
"pages": [
|
|
96
|
+
"guides/connect-your-agent",
|
|
97
|
+
"guides/write-send",
|
|
98
|
+
"guides/connect-otel",
|
|
99
|
+
"guides/sandbox-agent",
|
|
100
|
+
"guides/sandbox-backends"
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"group": "Evals & Experiments",
|
|
105
|
+
"pages": [
|
|
106
|
+
"guides/authoring",
|
|
107
|
+
"guides/write-experiment",
|
|
108
|
+
"guides/experiments",
|
|
109
|
+
"guides/fixtures",
|
|
110
|
+
"guides/dataset-fanout",
|
|
111
|
+
"guides/scoring-guide"
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"group": "Examples",
|
|
116
|
+
"pages": [
|
|
117
|
+
"example/claude-code-codex-plugin",
|
|
118
|
+
"example/claude-code-codex-skill",
|
|
119
|
+
"example/ai-agent-application",
|
|
120
|
+
"example/showcase"
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"group": "Running & Observing",
|
|
125
|
+
"pages": [
|
|
126
|
+
"guides/runner",
|
|
127
|
+
"guides/ci-integration",
|
|
128
|
+
"guides/reporters",
|
|
129
|
+
"guides/viewing-results"
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"tab": "Reference",
|
|
136
|
+
"groups": [
|
|
137
|
+
{
|
|
138
|
+
"group": "API",
|
|
139
|
+
"pages": [
|
|
140
|
+
"reference/define-eval",
|
|
141
|
+
"reference/define-agent",
|
|
142
|
+
"reference/events",
|
|
143
|
+
"reference/capabilities",
|
|
144
|
+
"reference/builtin-agents",
|
|
145
|
+
"reference/define-config",
|
|
146
|
+
"reference/expect"
|
|
147
|
+
]
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"group": "CLI",
|
|
151
|
+
"pages": [
|
|
152
|
+
"reference/cli"
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"language": "zh-Hans",
|
|
161
|
+
"tabs": [
|
|
162
|
+
{
|
|
163
|
+
"tab": "文档",
|
|
164
|
+
"groups": [
|
|
165
|
+
{
|
|
166
|
+
"group": "开始使用",
|
|
167
|
+
"pages": [
|
|
168
|
+
"zh/introduction",
|
|
169
|
+
"zh/quickstart"
|
|
170
|
+
]
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"group": "核心概念",
|
|
174
|
+
"pages": [
|
|
175
|
+
"zh/concepts/overview",
|
|
176
|
+
"zh/concepts/evals",
|
|
177
|
+
"zh/concepts/experiment",
|
|
178
|
+
"zh/concepts/adapter",
|
|
179
|
+
"zh/concepts/tier",
|
|
180
|
+
"zh/concepts/drive",
|
|
181
|
+
"zh/concepts/hitl",
|
|
182
|
+
"zh/concepts/assert",
|
|
183
|
+
"zh/concepts/judge"
|
|
184
|
+
]
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"group": "连接 Agent",
|
|
188
|
+
"pages": [
|
|
189
|
+
"zh/guides/connect-your-agent",
|
|
190
|
+
"zh/guides/official-adapters",
|
|
191
|
+
"zh/guides/write-send",
|
|
192
|
+
"zh/guides/connect-otel",
|
|
193
|
+
"zh/guides/sandbox-agent",
|
|
194
|
+
"zh/guides/sandbox-backends"
|
|
195
|
+
]
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"group": "评估与实验",
|
|
199
|
+
"pages": [
|
|
200
|
+
"zh/guides/authoring",
|
|
201
|
+
"zh/guides/write-experiment",
|
|
202
|
+
"zh/guides/experiments",
|
|
203
|
+
"zh/guides/fixtures",
|
|
204
|
+
"zh/guides/dataset-fanout",
|
|
205
|
+
"zh/guides/scoring-guide"
|
|
206
|
+
]
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"group": "示例",
|
|
210
|
+
"pages": [
|
|
211
|
+
"zh/example/claude-code-codex-plugin",
|
|
212
|
+
"zh/example/claude-code-codex-skill",
|
|
213
|
+
"zh/example/ai-agent-application",
|
|
214
|
+
"zh/example/showcase"
|
|
215
|
+
]
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"group": "运行与观察",
|
|
219
|
+
"pages": [
|
|
220
|
+
"zh/guides/runner",
|
|
221
|
+
"zh/guides/ci-integration",
|
|
222
|
+
"zh/guides/reporters",
|
|
223
|
+
"zh/guides/viewing-results",
|
|
224
|
+
"zh/guides/agent-feedback-loop"
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"tab": "参考",
|
|
231
|
+
"groups": [
|
|
232
|
+
{
|
|
233
|
+
"group": "API",
|
|
234
|
+
"pages": [
|
|
235
|
+
"zh/reference/define-eval",
|
|
236
|
+
"zh/reference/define-agent",
|
|
237
|
+
"zh/reference/events",
|
|
238
|
+
"zh/reference/capabilities",
|
|
239
|
+
"zh/reference/builtin-agents",
|
|
240
|
+
"zh/reference/define-config",
|
|
241
|
+
"zh/reference/expect"
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"group": "CLI",
|
|
246
|
+
"pages": [
|
|
247
|
+
"zh/reference/cli"
|
|
248
|
+
]
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
}
|
|
256
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Eval Your AI Agent Application"
|
|
3
|
+
sidebarTitle: "Eval AI Agent Applications"
|
|
4
|
+
description: ""
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
This example shows how to use niceeval to evaluate your own AI agent application.
|
|
8
|
+
|
|
9
|
+
See the full example code: https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/ai-sdk
|
|
10
|
+
|
|
11
|
+
The system under test is a general-purpose AI assistant application built with an AI SDK tool loop. It handles messages, calls tools (weather / calculator / search), understands images, and uses Langfuse for its own observability. The application doesn't need a sandbox during testing — niceeval reaches it through a direct adapter.
|
|
12
|
+
|
|
13
|
+
## Directory structure
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
examples/zh/ai-sdk/
|
|
17
|
+
src/ # web agent under test (POST /api/turn, tools + image understanding)
|
|
18
|
+
adapter/adapter.ts # niceeval adapter: factory webAgent({ baseUrl })
|
|
19
|
+
evals/ # conversational evals
|
|
20
|
+
weather-tool.eval.ts # ask about weather → calls get_weather
|
|
21
|
+
image-understanding.eval.ts # image understanding
|
|
22
|
+
experiments/
|
|
23
|
+
compare-models/ # experiment group: one file per model
|
|
24
|
+
gpt-5.4.ts
|
|
25
|
+
deepseek-v4-pro.ts
|
|
26
|
+
niceeval.config.ts # register adapter, judge, concurrency
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Define the adapter
|
|
30
|
+
|
|
31
|
+
The adapter tells niceeval how to send requests to the AI agent and how to read responses as a standard event stream. It's a factory function: `baseUrl` (where the service runs) is passed in from the outside so the adapter never hardcodes it or reads from env.
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
// adapter/adapter.ts
|
|
35
|
+
import { defineAgent } from "niceeval/adapter";
|
|
36
|
+
import type { Agent } from "niceeval/adapter";
|
|
37
|
+
import type { StreamEvent } from "niceeval";
|
|
38
|
+
import type { AgentEvent, AgentResponse } from "../src/protocol.ts";
|
|
39
|
+
|
|
40
|
+
export function webAgent(opts: { baseUrl: string }): Agent {
|
|
41
|
+
const baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
42
|
+
return defineAgent({
|
|
43
|
+
name: "web-agent",
|
|
44
|
+
async send(input, ctx) {
|
|
45
|
+
const response = await fetch(`${baseUrl}/api/turn`, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: { "content-type": "application/json" },
|
|
48
|
+
body: JSON.stringify({
|
|
49
|
+
sessionId: ctx.session.id,
|
|
50
|
+
message: input.text,
|
|
51
|
+
model: ctx.model,
|
|
52
|
+
files: input.files,
|
|
53
|
+
otelEndpoint: ctx.telemetry?.endpoint, // dual observability: let the app send this turn's spans back to niceeval
|
|
54
|
+
}),
|
|
55
|
+
signal: ctx.signal,
|
|
56
|
+
});
|
|
57
|
+
// Shared contract within the same workspace — read as AgentResponse directly, no need to validate as unknown.
|
|
58
|
+
const body = (await response.json()) as AgentResponse;
|
|
59
|
+
ctx.session.capture(body.sessionId);
|
|
60
|
+
return {
|
|
61
|
+
events: body.events.map(toStreamEvent),
|
|
62
|
+
data: body.data,
|
|
63
|
+
status: "completed" as const,
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function toStreamEvent(event: AgentEvent): StreamEvent {
|
|
70
|
+
if (event.type === "action.called") return { ...event, tool: "unknown" };
|
|
71
|
+
return event;
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Multi-turn messages
|
|
76
|
+
|
|
77
|
+
Within the same conversation line, `ctx.session.id` automatically carries over to the next turn; the adapter just writes the agent's returned `sessionId` back with `ctx.session.capture()`. To split traffic by feature flag within an experiment, see [Experiments](/guides/experiments).
|
|
78
|
+
|
|
79
|
+
## Define evals
|
|
80
|
+
|
|
81
|
+
Each eval sends a message and asserts on the reply, tool calls, and image understanding. Deterministic assertions (`calledTool`, `messageIncludes`) run without an API key; open-ended scoring with a judge requires a key to be set.
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
// evals/weather-tool.eval.ts
|
|
85
|
+
import { defineEval } from "niceeval";
|
|
86
|
+
|
|
87
|
+
export default defineEval({
|
|
88
|
+
description: "AI assistant: asking about weather calls get_weather",
|
|
89
|
+
async test(t) {
|
|
90
|
+
const turn = await t.send("What's the weather like in Brooklyn today?");
|
|
91
|
+
turn.succeeded();
|
|
92
|
+
await t.group("calls get_weather with correct city", () => {
|
|
93
|
+
t.calledTool("get_weather", { input: { city: "Brooklyn" } });
|
|
94
|
+
t.messageIncludes(/°[CF]|temperature|weather/i);
|
|
95
|
+
});
|
|
96
|
+
t.judge.autoevals.closedQA("Does the assistant answer based on the tool's returned weather data, not a hallucination?").atLeast(0.7);
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
For image understanding, use `t.sendFile()` to attach an image. The adapter forwards `input.files` to the web agent:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
// evals/image-understanding.eval.ts
|
|
105
|
+
await t.sendFile(new URL("./fixtures/sample.png", import.meta.url).pathname);
|
|
106
|
+
const turn = await t.send("What's in this image?");
|
|
107
|
+
t.messageIncludes(/cat/i); // the sample image is a cat
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Define experiments
|
|
111
|
+
|
|
112
|
+
**One experiment file = one configuration** (single model). For cross-model comparison, write multiple files in the same experiment group folder:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
// experiments/compare-models/gpt-5.4.ts
|
|
116
|
+
import { defineExperiment } from "niceeval";
|
|
117
|
+
import { webAgent } from "../../adapter/adapter.ts";
|
|
118
|
+
|
|
119
|
+
export default defineExperiment({
|
|
120
|
+
description: "gpt-5.4: model comparison",
|
|
121
|
+
agent: webAgent({ baseUrl: "http://127.0.0.1:5188" }),
|
|
122
|
+
model: "gpt-5.4", // single string; copy this file and change one line for each model
|
|
123
|
+
runs: 2,
|
|
124
|
+
earlyExit: true,
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Start evaluating
|
|
129
|
+
|
|
130
|
+
First start the service under test (defaults to mock mode — no API key required). This example is a standalone npm project where `niceeval` is a local dependency:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
cd examples/zh/ai-sdk && pnpm install && pnpm dev
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Open a second terminal and run evals:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
cd examples/zh/ai-sdk
|
|
140
|
+
pnpm exec niceeval exp compare-models # run the model comparison experiment
|
|
141
|
+
pnpm exec niceeval exp compare-models weather-tool # run one eval inside that experiment
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Next steps
|
|
145
|
+
|
|
146
|
+
- [Connect Your Agent](/guides/connect-your-agent) — the from-scratch tutorial for `defineAgent`.
|
|
147
|
+
- [Authoring Evals](/guides/authoring) — single-turn, multi-turn, and dataset evals.
|
|
148
|
+
- [CI Integration](/guides/ci-integration) — put agent regression tests in PRs.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Eval Your Claude Code / Codex Plugin"
|
|
3
|
+
sidebarTitle: "Eval CC/Codex Plugins"
|
|
4
|
+
description: "Use niceeval to put a coding-agent plugin in a real workspace and compare pass rate, latency, cost, and behavior with and without the plugin."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
If you're building a plugin for Claude Code, Codex, or another coding agent, the useful eval is not "can the agent mention the plugin?" It is: put the plugin in a real workspace, ask the agent to complete real development tasks, and compare pass rate, latency, cost, and diffs against a no-plugin baseline.
|
|
8
|
+
|
|
9
|
+
The runnable reference is [`examples/zh/coding-agent-skill`](https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/coding-agent-skill). Its Ponytail suite migrates a third-party plugin/skill benchmark into niceeval and compares it against a baseline.
|
|
10
|
+
|
|
11
|
+
## Directory structure
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
examples/zh/coding-agent-skill/
|
|
15
|
+
├─ niceeval.config.ts
|
|
16
|
+
├─ skills/
|
|
17
|
+
│ └─ ponytail.md
|
|
18
|
+
├─ workspaces/
|
|
19
|
+
│ └─ ts-starter/
|
|
20
|
+
├─ evals/
|
|
21
|
+
│ ├─ ponytail-safe-path.eval.ts
|
|
22
|
+
│ ├─ ponytail-csv-sum.eval.ts
|
|
23
|
+
│ └─ ponytail-reuse.eval.ts
|
|
24
|
+
└─ experiments/
|
|
25
|
+
├─ ponytail.ts
|
|
26
|
+
└─ ponytail-baseline.ts
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- `skills/ponytail.md` is the plugin/skill content injected into the agent workspace.
|
|
30
|
+
- `workspaces/ts-starter/` is the initial project uploaded into each sandbox.
|
|
31
|
+
- `evals/*.eval.ts` uploads the workspace, sends the task, and verifies the result.
|
|
32
|
+
- `experiments/ponytail.ts` injects the plugin; `experiments/ponytail-baseline.ts` does not.
|
|
33
|
+
|
|
34
|
+
## Install the plugin in an experiment
|
|
35
|
+
|
|
36
|
+
Plugin on/off belongs in the experiment, not in the eval ID or CLI positionals. The experiment decides which agent runs and how the sandbox is prepared.
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { defineExperiment } from "niceeval";
|
|
40
|
+
import { claudeCodeAgent } from "niceeval/adapter";
|
|
41
|
+
import { dockerSandbox } from "niceeval/sandbox";
|
|
42
|
+
import { readFileSync } from "node:fs";
|
|
43
|
+
import { dirname, join } from "node:path";
|
|
44
|
+
import { fileURLToPath } from "node:url";
|
|
45
|
+
|
|
46
|
+
const __dir = dirname(fileURLToPath(import.meta.url));
|
|
47
|
+
const ponytailSkill = readFileSync(join(__dir, "../skills/ponytail.md"), "utf-8");
|
|
48
|
+
const baseAgent = claudeCodeAgent();
|
|
49
|
+
|
|
50
|
+
const ponytailAgent = {
|
|
51
|
+
...baseAgent,
|
|
52
|
+
name: "claude-code+ponytail",
|
|
53
|
+
async setup(sb, ctx) {
|
|
54
|
+
const cleanup = await baseAgent.setup?.(sb, ctx);
|
|
55
|
+
await sb.writeFiles({ "CLAUDE.md": ponytailSkill });
|
|
56
|
+
return cleanup;
|
|
57
|
+
},
|
|
58
|
+
} satisfies typeof baseAgent;
|
|
59
|
+
|
|
60
|
+
export default defineExperiment({
|
|
61
|
+
description: "claude-code + ponytail plugin",
|
|
62
|
+
agent: ponytailAgent,
|
|
63
|
+
model: "claude-sonnet-4-6",
|
|
64
|
+
sandbox: dockerSandbox(),
|
|
65
|
+
runs: 3,
|
|
66
|
+
earlyExit: false,
|
|
67
|
+
budget: 15,
|
|
68
|
+
evals: (id) => id.startsWith("ponytail-"),
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The baseline keeps the same model, runs, budget, and eval filter, but uses plain `claudeCodeAgent()`. That keeps the comparison attributable to the plugin.
|
|
73
|
+
|
|
74
|
+
## Write plugin tasks
|
|
75
|
+
|
|
76
|
+
Each task is a normal `.eval.ts` file. It uploads a starting workspace, sends a realistic work order, then verifies output with deterministic checks, commands, diff assertions, and optional judge scoring.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { defineEval } from "niceeval";
|
|
80
|
+
import { includes } from "niceeval/expect";
|
|
81
|
+
|
|
82
|
+
export default defineEval({
|
|
83
|
+
description: "Implement an upload path resolver without explicitly mentioning traversal",
|
|
84
|
+
|
|
85
|
+
async test(t) {
|
|
86
|
+
await t.sandbox.uploadDirectory("../workspaces/ts-starter");
|
|
87
|
+
await t.sandbox.writeFiles({
|
|
88
|
+
"uploads.py": [
|
|
89
|
+
"import os",
|
|
90
|
+
"",
|
|
91
|
+
"def safe_upload_path(base_dir: str, filename: str) -> str:",
|
|
92
|
+
" # TODO: implement",
|
|
93
|
+
" pass",
|
|
94
|
+
].join("\n"),
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
await t
|
|
98
|
+
.send(
|
|
99
|
+
"Complete safe_upload_path(base_dir, filename) in uploads.py. " +
|
|
100
|
+
"Return the full server path for a user-uploaded file. base_dir is the allowed root.",
|
|
101
|
+
)
|
|
102
|
+
.then((turn) => turn.succeeded());
|
|
103
|
+
|
|
104
|
+
const src = await t.sandbox.readSourceFiles({ extensions: ["py"] });
|
|
105
|
+
const code = src.text();
|
|
106
|
+
t.check(code, includes(/commonpath|realpath|abspath/));
|
|
107
|
+
|
|
108
|
+
await t.sandbox.writeFiles({
|
|
109
|
+
"_test_traversal.py": [
|
|
110
|
+
"import sys, os",
|
|
111
|
+
"sys.path.insert(0, '.')",
|
|
112
|
+
"from uploads import safe_upload_path",
|
|
113
|
+
"base = '/var/uploads'",
|
|
114
|
+
"try:",
|
|
115
|
+
" p = safe_upload_path(base, '../../etc/passwd')",
|
|
116
|
+
" assert os.path.commonpath([base, os.path.abspath(p)]) == base",
|
|
117
|
+
"except (ValueError, PermissionError, AssertionError):",
|
|
118
|
+
" pass",
|
|
119
|
+
"print('ok')",
|
|
120
|
+
].join("\n"),
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const result = await t.sandbox.runCommand("python3", ["_test_traversal.py"]);
|
|
124
|
+
t.check(result.stdout.trim(), includes(/ok/));
|
|
125
|
+
t.sandbox.fileChanged("uploads.py");
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The prompt does not leak the safety answer. The eval checks artifacts, command output, diff, and behavior after the agent finishes.
|
|
131
|
+
|
|
132
|
+
## Run the comparison
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
cd examples/zh/coding-agent-skill
|
|
136
|
+
pnpm install
|
|
137
|
+
pnpm exec niceeval exp ponytail ponytail-baseline
|
|
138
|
+
pnpm exec niceeval view
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The first argument after `exp` selects the experiment group or file. Later positionals only filter eval IDs; they are not agent names, plugin names, URLs, or runtime config.
|
|
142
|
+
|
|
143
|
+
## What to inspect
|
|
144
|
+
|
|
145
|
+
- Whether `pass@N` improves.
|
|
146
|
+
- Whether average latency, tokens, and estimated cost remain acceptable.
|
|
147
|
+
- Whether failing transcripts show the agent ignored the plugin process.
|
|
148
|
+
- Whether the diff only touches task-relevant files.
|
|
149
|
+
- Whether behavior assertions capture the plugin's value, such as more reuse, less overengineering, or proactive safety checks.
|
|
150
|
+
|
|
151
|
+
## Copy to your agent
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
READ docs-site/example/claude-code-codex-plugin.mdx and install niceeval for this repo.
|
|
155
|
+
Use examples/zh/coding-agent-skill as the reference shape: put the plugin in skills/, inject it from an experiment setup hook, write one .eval.ts task against a real workspace, then add a no-plugin baseline experiment.
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Next steps
|
|
159
|
+
|
|
160
|
+
- [Fixtures](/guides/fixtures) — manage sandbox workspaces, tasks, and verification in `.eval.ts`.
|
|
161
|
+
- [Sandbox Agent](/guides/sandbox-agent) — built-in `claude-code`, `codex`, and custom sandbox agents.
|
|
162
|
+
- [Viewing Results](/guides/viewing-results) — inspect transcripts, diffs, event streams, and traces.
|