niceeval 0.4.4 → 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 +36 -7
- package/src/context/types.ts +140 -0
- package/src/expect/index.ts +15 -8
- package/src/i18n/en.ts +19 -6
- package/src/i18n/zh-CN.ts +19 -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/reporters/artifacts.ts +11 -3
- package/src/runner/reporters/live.ts +45 -8
- package/src/runner/run.ts +71 -21
- package/src/runner/types.ts +45 -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,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "defineEval: declare, configure, and run NiceEval evals"
|
|
3
|
+
sidebarTitle: "defineEval"
|
|
4
|
+
description: "Reference for defineEval options, the test context t, Turn return values, sandbox helpers, and dataset array exports."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`defineEval` is the main entry point for authoring evals. Each eval file normally calls it once and default-exports the result.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { defineEval } from "niceeval";
|
|
11
|
+
|
|
12
|
+
export default defineEval({
|
|
13
|
+
description: "Brooklyn weather query",
|
|
14
|
+
async test(t) {
|
|
15
|
+
await t.send("What's the weather like in Brooklyn today?");
|
|
16
|
+
t.succeeded();
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
<Note>
|
|
22
|
+
Do not provide `id` or `name`. NiceEval derives the eval ID from the file path.
|
|
23
|
+
</Note>
|
|
24
|
+
|
|
25
|
+
## `defineEval` options
|
|
26
|
+
|
|
27
|
+
<ParamField body="description" type="string">
|
|
28
|
+
Human-readable description shown in console output and reports.
|
|
29
|
+
</ParamField>
|
|
30
|
+
|
|
31
|
+
<ParamField body="agent" type="string">
|
|
32
|
+
Agent name for this eval. Usually omitted so the experiment supplies the agent.
|
|
33
|
+
</ParamField>
|
|
34
|
+
|
|
35
|
+
<ParamField body="tags" type="string[]">
|
|
36
|
+
Tags for filtering or organizing evals.
|
|
37
|
+
</ParamField>
|
|
38
|
+
|
|
39
|
+
<ParamField body="judge" type="JudgeConfig">
|
|
40
|
+
Judge model override for this eval.
|
|
41
|
+
</ParamField>
|
|
42
|
+
|
|
43
|
+
<ParamField body="reporters" type="Reporter[]">
|
|
44
|
+
Eval-specific reporters. The instance only observes evals that reference it. If multiple evals share the same instance, their results land in the same destination. See [Reporters](../guides/reporters).
|
|
45
|
+
</ParamField>
|
|
46
|
+
|
|
47
|
+
<ParamField body="timeoutMs" type="number">
|
|
48
|
+
Timeout override.
|
|
49
|
+
</ParamField>
|
|
50
|
+
|
|
51
|
+
<ParamField body="metadata" type="Record<string, unknown>">
|
|
52
|
+
Extra metadata for reports or external tools.
|
|
53
|
+
</ParamField>
|
|
54
|
+
|
|
55
|
+
<ParamField body="test" type="(t: TestContext) => Promise<void>" required>
|
|
56
|
+
Eval body. Drive the agent and declare assertions here.
|
|
57
|
+
</ParamField>
|
|
58
|
+
|
|
59
|
+
## Test context: `t`
|
|
60
|
+
|
|
61
|
+
### Always available
|
|
62
|
+
|
|
63
|
+
<ParamField body="t.send(text)" type="(text: string, opts?) => Promise<Turn>">
|
|
64
|
+
Sends a message to the agent and returns the current turn.
|
|
65
|
+
</ParamField>
|
|
66
|
+
|
|
67
|
+
<ParamField body="t.sendFile(path, text?, opts?)" type="function">
|
|
68
|
+
Sends a file plus optional text.
|
|
69
|
+
</ParamField>
|
|
70
|
+
|
|
71
|
+
<ParamField body="t.check(value, assertion)" type="(value: unknown, assertion: Assertion) => void">
|
|
72
|
+
Records a value assertion. Failure does not immediately abort the test.
|
|
73
|
+
</ParamField>
|
|
74
|
+
|
|
75
|
+
<ParamField body="t.require(value, assertion)" type="(value: unknown, assertion: Assertion) => void">
|
|
76
|
+
Records a prerequisite assertion. Failure aborts the test immediately.
|
|
77
|
+
</ParamField>
|
|
78
|
+
|
|
79
|
+
<ParamField body="t.skip(reason)" type="(reason: string) => void">
|
|
80
|
+
Skips the eval.
|
|
81
|
+
</ParamField>
|
|
82
|
+
|
|
83
|
+
### Conversation
|
|
84
|
+
|
|
85
|
+
<ParamField body="t.reply" type="string">
|
|
86
|
+
Last assistant text message in the current session.
|
|
87
|
+
</ParamField>
|
|
88
|
+
|
|
89
|
+
<ParamField body="t.newSession()" type="() => TestContext">
|
|
90
|
+
Starts an independent session line.
|
|
91
|
+
</ParamField>
|
|
92
|
+
|
|
93
|
+
### Tool observability
|
|
94
|
+
|
|
95
|
+
<ParamField body="t.calledTool(name, opts?)" type="function">
|
|
96
|
+
Asserts that a tool was called.
|
|
97
|
+
</ParamField>
|
|
98
|
+
|
|
99
|
+
<ParamField body="t.notCalledTool(name, opts?)" type="function">
|
|
100
|
+
Asserts that a tool was not called. This is only trustworthy when the event stream is complete.
|
|
101
|
+
</ParamField>
|
|
102
|
+
|
|
103
|
+
<ParamField body="t.event(type, opts?)" type="function">
|
|
104
|
+
Low-level event stream assertion.
|
|
105
|
+
</ParamField>
|
|
106
|
+
|
|
107
|
+
### Workspace / sandbox
|
|
108
|
+
|
|
109
|
+
<ParamField body="t.sandbox.fileChanged(path)" type="function">
|
|
110
|
+
Asserts that a workspace file changed.
|
|
111
|
+
</ParamField>
|
|
112
|
+
|
|
113
|
+
<ParamField body="t.sandbox.runCommand(command, args?)" type="function">
|
|
114
|
+
Runs a verification command in the sandbox.
|
|
115
|
+
</ParamField>
|
|
116
|
+
|
|
117
|
+
## Judge assertions
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
t.judge.autoevals.factuality(expected, { on: t.reply }).atLeast(0.8);
|
|
121
|
+
t.judge.autoevals.closedQA(question, { on: t.reply }).atLeast(0.7);
|
|
122
|
+
t.judge.autoevals.closedQA(rubric, { on: t.reply }).atLeast(0.75);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## `Turn`
|
|
126
|
+
|
|
127
|
+
<ResponseField name="events" type="StreamEvent[]">
|
|
128
|
+
Standard event stream for this turn.
|
|
129
|
+
</ResponseField>
|
|
130
|
+
|
|
131
|
+
<ResponseField name="data" type="unknown | undefined">
|
|
132
|
+
Structured output, present only when declared by the send call.
|
|
133
|
+
</ResponseField>
|
|
134
|
+
|
|
135
|
+
<ResponseField name="status" type='"completed" | "failed" | "waiting"'>
|
|
136
|
+
Current turn status.
|
|
137
|
+
</ResponseField>
|
|
138
|
+
|
|
139
|
+
<ResponseField name="message" type="string">
|
|
140
|
+
Assistant text for this turn.
|
|
141
|
+
</ResponseField>
|
|
142
|
+
|
|
143
|
+
<ResponseField name="toolCalls" type="ToolCall[]">
|
|
144
|
+
Tool calls for this turn.
|
|
145
|
+
</ResponseField>
|
|
146
|
+
|
|
147
|
+
## Dataset export
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
export default rows.map((row) =>
|
|
151
|
+
defineEval({
|
|
152
|
+
description: row.task,
|
|
153
|
+
async test(t) {
|
|
154
|
+
await t.send(row.prompt);
|
|
155
|
+
},
|
|
156
|
+
}),
|
|
157
|
+
);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Array exports generate stable IDs such as `file/0000`, `file/0001`, and so on.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Standard event stream reference"
|
|
3
|
+
sidebarTitle: "Events"
|
|
4
|
+
description: "The nine StreamEvent variants: what each one means, when adapters emit it, and which assertions consume it. Producing this stream is the adapter's core job."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
An adapter `send` returns a `Turn`, and its `events: StreamEvent[]` is the **only data source for assertions**: `t.calledTool()`, `t.reply`, `toolOrder`, `noFailedActions`, and more all read from this stream. Once your adapter translates "what the agent did this turn" into this stream, the whole assertion surface becomes available.
|
|
8
|
+
|
|
9
|
+
## Turn: the return value of `send`
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
interface Turn {
|
|
13
|
+
events: StreamEvent[]; // events for this turn, in real order
|
|
14
|
+
data?: unknown; // structured output -> outputEquals / outputMatches
|
|
15
|
+
status: "completed" | "failed" | "waiting"; // waiting = paused for human input
|
|
16
|
+
usage?: { inputTokens: number; outputTokens: number }; // -> maxTokens / maxCost / cost reports
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`data` means "the structured product of this turn". Only fill it when the application answer itself is structured, such as extraction, classification, or form filling. `outputEquals` / `outputMatches` read from it. If the app only returns text, leave it unset. Do not copy raw response bodies or message text into `data`, and do not serialize structured output back into `events`. Include `usage` only when you have it. Do not invent numbers.
|
|
21
|
+
|
|
22
|
+
## Event table
|
|
23
|
+
|
|
24
|
+
| Event | Meaning | Consumed by |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `message` | the agent (or user) said something | `t.reply`, `messageIncludes`, judge inputs |
|
|
27
|
+
| `action.called` | a tool call started | `calledTool`, `toolOrder`, `maxToolCalls`, `notCalledTool` |
|
|
28
|
+
| `action.result` | the result of that call | `calledTool` status matching, `noFailedActions` |
|
|
29
|
+
| `subagent.called` | delegated to a subagent | `calledSubagent` |
|
|
30
|
+
| `subagent.completed` | the subagent returned | `calledSubagent` status, `noFailedActions` |
|
|
31
|
+
| `input.requested` | paused and waiting for human input | `t.parked()`, `t.requireInputRequest()` |
|
|
32
|
+
| `thinking` | reasoning text | `event("thinking")`, viewer display |
|
|
33
|
+
| `compaction` | context got compacted | `event("compaction")` |
|
|
34
|
+
| `error` | the turn hit an error | `event("error")`, viewer display |
|
|
35
|
+
|
|
36
|
+
Any event can also be checked with `event(type)`, `notEvent(type)`, `eventOrder(types)`, or `eventsSatisfy(label, predicate)`.
|
|
37
|
+
|
|
38
|
+
## Event details
|
|
39
|
+
|
|
40
|
+
### `message` - what was said
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
{ type: "message", role: "assistant" | "user", text: string }
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Emit one `message` with `role: "assistant"` for each chunk of assistant text. **Tool results are not assistant messages.** Do not wrap tool output as `message`, or `t.reply` will read the wrong thing. User `message` events are usually recorded by NiceEval automatically.
|
|
47
|
+
|
|
48
|
+
### `action.called` / `action.result` - which tool was used, and what happened
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
{ type: "action.called", callId: string, name: string, input: JsonValue }
|
|
52
|
+
{ type: "action.result", callId: string, output?: JsonValue,
|
|
53
|
+
status: "completed" | "failed" | "rejected" }
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- Pair each `action.called` with an `action.result` that has the same `callId`, so concurrent calls do not get mixed up. Use the explicit ID from your source when it exists.
|
|
57
|
+
- Fill `status` truthfully: actual tool execution failure is `"failed"`. Human denial is `"rejected"`.
|
|
58
|
+
- Keep `name` as the tool's original name.
|
|
59
|
+
|
|
60
|
+
### `subagent.called` / `subagent.completed` - which subagent was delegated to
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
{ type: "subagent.called", callId: string, name: string, remoteUrl?: string }
|
|
64
|
+
{ type: "subagent.completed", callId: string, output?: JsonValue,
|
|
65
|
+
status: "completed" | "failed" }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Emit this pair when the subject under test delegates work to a subagent and waits for it to return.
|
|
69
|
+
|
|
70
|
+
### `input.requested` - paused for human input
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
{ type: "input.requested", request: {
|
|
74
|
+
id?: string,
|
|
75
|
+
action?: string,
|
|
76
|
+
input?: JsonValue,
|
|
77
|
+
prompt?: string,
|
|
78
|
+
options?: { id: string, label?: string }[],
|
|
79
|
+
} }
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
When the agent pauses for a person, emit one event per pending question and return overall turn `status: "waiting"`. `t.requireInputRequest(filter)` matches this `request` structure field by field, so populate as many fields as you can. See the HITL part of [Connect Your Agent](/guides/connect-your-agent).
|
|
83
|
+
|
|
84
|
+
### `thinking` / `compaction` / `error`
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
{ type: "thinking", text: string }
|
|
88
|
+
{ type: "compaction", reason?: string }
|
|
89
|
+
{ type: "error", message: string }
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Emit them when your source gives them to you. Do not fabricate them. `compaction` mostly appears in coding-agent CLIs when context is compressed automatically.
|
|
93
|
+
|
|
94
|
+
## Three mapping rules
|
|
95
|
+
|
|
96
|
+
1. **Order is fact.** Keep events in real execution order. `toolOrder` and `eventOrder` depend on that sequence.
|
|
97
|
+
2. **Match `callId`s.** Every `called` event should have the corresponding `result` with the same ID.
|
|
98
|
+
3. **Be honest about completeness.** If you declare `toolObservability: true`, all tool calls must be in the stream. If you omit some of them, negative assertions can silently pass. If your manual mapping cannot be complete, [do not claim that capability](/reference/capabilities).
|
|
99
|
+
|
|
100
|
+
## A complete mapping example
|
|
101
|
+
|
|
102
|
+
When the agent response contains step records, the mapping is usually a small loop:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import type { StreamEvent } from "niceeval";
|
|
106
|
+
|
|
107
|
+
function toStreamEvents(body: MyBotResponse): StreamEvent[] {
|
|
108
|
+
const events: StreamEvent[] = [];
|
|
109
|
+
for (const step of body.steps) {
|
|
110
|
+
if (step.type === "tool_call") {
|
|
111
|
+
events.push({ type: "action.called", callId: step.id, name: step.tool, input: step.args });
|
|
112
|
+
events.push({
|
|
113
|
+
type: "action.result",
|
|
114
|
+
callId: step.id,
|
|
115
|
+
output: step.result,
|
|
116
|
+
status: step.error ? "failed" : "completed",
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (step.type === "text") {
|
|
120
|
+
events.push({ type: "message", role: "assistant", text: step.text });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return events;
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Related reading
|
|
128
|
+
|
|
129
|
+
- [Connect Your Agent](/guides/connect-your-agent) - The from-scratch integration tutorial.
|
|
130
|
+
- [Capabilities](/reference/capabilities) - What it means to claim "the event stream is complete".
|
|
131
|
+
- [Authoring Evals](/guides/authoring) - The assertions that consume this stream.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "niceeval/expect matchers and custom assertion reference"
|
|
3
|
+
sidebarTitle: "Assertion Matchers"
|
|
4
|
+
description: "Reference for niceeval/expect: includes, equals, matches, similarity, satisfies. Chain `.gate()` or `.atLeast(0.7)`, or build custom matchers with `makeAssertion`."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`niceeval/expect` provides a set of composable matchers for `t.check()` and `t.require()`. A matcher returns an `Assertion` with a default severity, either `gate` or `soft`.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { includes, equals, matches, similarity, satisfies } from "niceeval/expect";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## How matchers are used
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
t.check(t.reply, includes("confirmed"));
|
|
17
|
+
t.check(turn.data, equals({ intent: "refund" }));
|
|
18
|
+
t.require(turn.status, equals("completed"));
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
| Method | On failure | Best for |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `t.check` | record result, keep executing | most assertions |
|
|
24
|
+
| `t.require` | throw immediately, abort the test | preconditions where continuing makes no sense |
|
|
25
|
+
|
|
26
|
+
## Matchers
|
|
27
|
+
|
|
28
|
+
### `includes`
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
includes(substring: string | RegExp): Assertion
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Assert that a string contains the given substring, or matches a regex.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
t.check(t.reply, includes("Paris"));
|
|
38
|
+
t.check(t.reply, includes(/order #\d+/i));
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### `equals`
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
equals(expected: unknown): Assertion
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Assert deep structural equality, useful for JSON, arrays, and objects.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
t.check(turn.data, equals({ intent: "refund" }));
|
|
51
|
+
t.check(turn.data, equals(["a", "b", "c"]));
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### `matches`
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
matches(pattern: RegExp): Assertion
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Assert that a string matches a regex.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
t.check(t.reply, matches(/#[A-Z0-9]{8}/));
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### `similarity`
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
similarity(expected: string): Assertion
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Use this for semantic or textual similarity checks, usually together with a threshold.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
t.check(t.reply, similarity("The capital of France is Paris.").atLeast(0.8));
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### `satisfies`
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
satisfies(predicate: (value: unknown) => boolean): Assertion
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Check a value with a custom predicate.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
t.check(turn.data, satisfies((value) => Array.isArray(value)));
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Gate and soft
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
t.check(t.reply, includes("required").gate());
|
|
94
|
+
t.check(t.reply, includes("nice to have").atLeast(0.7));
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- `gate()`: failure makes the eval fail.
|
|
98
|
+
- `soft()`: contributes to scoring without necessarily failing the eval.
|
|
99
|
+
|
|
100
|
+
## Custom matchers
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { makeAssertion } from "niceeval/expect";
|
|
104
|
+
|
|
105
|
+
const validEmail = makeAssertion("valid email", (value) => {
|
|
106
|
+
return typeof value === "string" && value.includes("@") ? 1 : 0;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
t.check(t.reply, validEmail());
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Custom matchers should return a score between 0 and 1 and use a clear name.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
var script = document.createElement("script");
|
|
3
|
+
script.src = "https://api.goshipfast.com/tracker.js";
|
|
4
|
+
script.async = true;
|
|
5
|
+
script.setAttribute("data-project", "cmr24oe2n006qlj10lr9t38n8");
|
|
6
|
+
script.setAttribute("data-endpoint", "https://api.goshipfast.com");
|
|
7
|
+
document.head.appendChild(script);
|
|
8
|
+
})();
|