niceeval 0.4.4 → 0.4.6

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 (177) hide show
  1. package/README.md +21 -12
  2. package/README.zh.md +8 -9
  3. package/docs-site/.mintignore +13 -0
  4. package/docs-site/AGENTS.md +46 -0
  5. package/docs-site/concepts/adapter.mdx +287 -0
  6. package/docs-site/concepts/assert.mdx +243 -0
  7. package/docs-site/concepts/drive.mdx +118 -0
  8. package/docs-site/concepts/evals.mdx +108 -0
  9. package/docs-site/concepts/experiment.mdx +37 -0
  10. package/docs-site/concepts/hitl.mdx +83 -0
  11. package/docs-site/concepts/judge.mdx +129 -0
  12. package/docs-site/concepts/overview.mdx +98 -0
  13. package/docs-site/concepts/tier.mdx +42 -0
  14. package/docs-site/docs-ref/00-index.md +23 -0
  15. package/docs-site/docs-ref/01-page-types.md +43 -0
  16. package/docs-site/docs-ref/03-style-rules.md +45 -0
  17. package/docs-site/docs-ref/04-code-examples.md +37 -0
  18. package/docs-site/docs-ref/05-dx-failure-paths.md +45 -0
  19. package/docs-site/docs-ref/06-checklists.md +53 -0
  20. package/docs-site/docs.json +256 -0
  21. package/docs-site/example/ai-agent-application.mdx +148 -0
  22. package/docs-site/example/claude-code-codex-plugin.mdx +162 -0
  23. package/docs-site/example/claude-code-codex-skill.mdx +147 -0
  24. package/docs-site/example/showcase.mdx +39 -0
  25. package/docs-site/example/tier1-ai-sdk-v7.mdx +136 -0
  26. package/docs-site/example/tier1-claude-sdk.mdx +119 -0
  27. package/docs-site/example/tier1-codex-sdk.mdx +111 -0
  28. package/docs-site/example/tier1-langgraph.mdx +119 -0
  29. package/docs-site/example/tier1-pi-sdk.mdx +119 -0
  30. package/docs-site/favicon.svg +5 -0
  31. package/docs-site/github-diff.css +135 -0
  32. package/docs-site/github-diff.js +11 -0
  33. package/docs-site/guides/authoring.mdx +129 -0
  34. package/docs-site/guides/ci-integration.mdx +97 -0
  35. package/docs-site/guides/connect-otel.mdx +209 -0
  36. package/docs-site/guides/connect-your-agent.mdx +221 -0
  37. package/docs-site/guides/dataset-fanout.mdx +98 -0
  38. package/docs-site/guides/experiments.mdx +71 -0
  39. package/docs-site/guides/fixtures.mdx +147 -0
  40. package/docs-site/guides/reporters.mdx +113 -0
  41. package/docs-site/guides/runner.mdx +79 -0
  42. package/docs-site/guides/sandbox-agent.mdx +138 -0
  43. package/docs-site/guides/sandbox-backends.mdx +64 -0
  44. package/docs-site/guides/scoring-guide.mdx +92 -0
  45. package/docs-site/guides/viewing-results.mdx +195 -0
  46. package/docs-site/guides/write-experiment.mdx +81 -0
  47. package/docs-site/guides/write-send.mdx +347 -0
  48. package/docs-site/images/adapter-tiers-zh.svg +60 -0
  49. package/docs-site/images/agent-turn-roundtrip-en.svg +62 -0
  50. package/docs-site/images/agent-turn-roundtrip-zh.svg +77 -0
  51. package/docs-site/images/hitl-handshake-zh.svg +89 -0
  52. package/docs-site/images/logo.svg +6 -0
  53. package/docs-site/index.mdx +181 -0
  54. package/docs-site/introduction.mdx +141 -0
  55. package/docs-site/quickstart.mdx +136 -0
  56. package/docs-site/reference/builtin-agents.mdx +161 -0
  57. package/docs-site/reference/capabilities.mdx +76 -0
  58. package/docs-site/reference/cli.mdx +120 -0
  59. package/docs-site/reference/define-agent.mdx +168 -0
  60. package/docs-site/reference/define-config.mdx +41 -0
  61. package/docs-site/reference/define-eval.mdx +160 -0
  62. package/docs-site/reference/events.mdx +131 -0
  63. package/docs-site/reference/expect.mdx +112 -0
  64. package/docs-site/tracker.js +8 -0
  65. package/docs-site/zh/concepts/adapter.mdx +286 -0
  66. package/docs-site/zh/concepts/assert.mdx +243 -0
  67. package/docs-site/zh/concepts/drive.mdx +118 -0
  68. package/docs-site/zh/concepts/evals.mdx +124 -0
  69. package/docs-site/zh/concepts/experiment.mdx +37 -0
  70. package/docs-site/zh/concepts/hitl.mdx +83 -0
  71. package/docs-site/zh/concepts/judge.mdx +130 -0
  72. package/docs-site/zh/concepts/overview.mdx +109 -0
  73. package/docs-site/zh/concepts/tier.mdx +44 -0
  74. package/docs-site/zh/example/ai-agent-application.mdx +152 -0
  75. package/docs-site/zh/example/claude-code-codex-plugin.mdx +163 -0
  76. package/docs-site/zh/example/claude-code-codex-skill.mdx +147 -0
  77. package/docs-site/zh/example/showcase.mdx +39 -0
  78. package/docs-site/zh/example/tier1-ai-sdk-v7.mdx +140 -0
  79. package/docs-site/zh/example/tier1-claude-sdk.mdx +122 -0
  80. package/docs-site/zh/example/tier1-codex-sdk.mdx +117 -0
  81. package/docs-site/zh/example/tier1-langgraph.mdx +123 -0
  82. package/docs-site/zh/example/tier1-pi-sdk.mdx +122 -0
  83. package/docs-site/zh/guides/agent-feedback-loop.mdx +79 -0
  84. package/docs-site/zh/guides/authoring.mdx +129 -0
  85. package/docs-site/zh/guides/ci-integration.mdx +97 -0
  86. package/docs-site/zh/guides/connect-otel.mdx +208 -0
  87. package/docs-site/zh/guides/connect-your-agent.mdx +226 -0
  88. package/docs-site/zh/guides/dataset-fanout.mdx +83 -0
  89. package/docs-site/zh/guides/experiments.mdx +72 -0
  90. package/docs-site/zh/guides/fixtures.mdx +147 -0
  91. package/docs-site/zh/guides/official-adapters.mdx +132 -0
  92. package/docs-site/zh/guides/reporters.mdx +113 -0
  93. package/docs-site/zh/guides/runner.mdx +82 -0
  94. package/docs-site/zh/guides/sandbox-agent.mdx +139 -0
  95. package/docs-site/zh/guides/sandbox-backends.mdx +75 -0
  96. package/docs-site/zh/guides/scoring-guide.mdx +92 -0
  97. package/docs-site/zh/guides/viewing-results.mdx +195 -0
  98. package/docs-site/zh/guides/write-experiment.mdx +101 -0
  99. package/docs-site/zh/guides/write-send.mdx +353 -0
  100. package/docs-site/zh/index.mdx +180 -0
  101. package/docs-site/zh/introduction.mdx +140 -0
  102. package/docs-site/zh/quickstart.mdx +137 -0
  103. package/docs-site/zh/reference/builtin-agents.mdx +364 -0
  104. package/docs-site/zh/reference/capabilities.mdx +76 -0
  105. package/docs-site/zh/reference/cli.mdx +140 -0
  106. package/docs-site/zh/reference/define-agent.mdx +461 -0
  107. package/docs-site/zh/reference/define-config.mdx +107 -0
  108. package/docs-site/zh/reference/define-eval.mdx +674 -0
  109. package/docs-site/zh/reference/events.mdx +252 -0
  110. package/docs-site/zh/reference/expect.mdx +208 -0
  111. package/package.json +3 -2
  112. package/src/agents/bub.ts +15 -5
  113. package/src/agents/claude-code.ts +8 -5
  114. package/src/agents/codex.ts +9 -5
  115. package/src/agents/sdk-streams.test.ts +4 -4
  116. package/src/agents/sdk-streams.ts +14 -9
  117. package/src/agents/types.ts +40 -1
  118. package/src/agents/ui-message-stream.ts +1 -0
  119. package/src/cli.ts +36 -7
  120. package/src/context/types.ts +140 -0
  121. package/src/expect/index.ts +15 -8
  122. package/src/i18n/en.ts +19 -6
  123. package/src/i18n/zh-CN.ts +19 -6
  124. package/src/o11y/parsers/bub.test.ts +71 -0
  125. package/src/o11y/parsers/bub.ts +5 -0
  126. package/src/o11y/types.ts +27 -2
  127. package/src/runner/reporters/artifacts.ts +11 -3
  128. package/src/runner/reporters/live.ts +45 -8
  129. package/src/runner/run.ts +71 -21
  130. package/src/runner/types.ts +45 -2
  131. package/src/sandbox/types.ts +18 -0
  132. package/src/scoring/types.ts +5 -0
  133. package/src/shared/types.ts +3 -0
  134. package/src/util.test.ts +26 -1
  135. package/src/util.ts +16 -0
  136. package/src/view/app/App.tsx +2 -2
  137. package/src/view/app/components/AttemptModal.tsx +2 -0
  138. package/src/view/app/components/CopyControls.tsx +87 -28
  139. package/src/view/app/i18n.ts +3 -3
  140. package/src/view/client-dist/app.css +1 -1
  141. package/src/view/client-dist/app.js +18 -18
  142. package/docs/README.md +0 -120
  143. package/docs/adapters/README.md +0 -60
  144. package/docs/adapters/authoring.md +0 -179
  145. package/docs/adapters/coding-agent-skills-plugins.md +0 -324
  146. package/docs/adapters/collection.md +0 -128
  147. package/docs/adapters/contract.md +0 -264
  148. package/docs/adapters/reference/agent-eval.md +0 -215
  149. package/docs/adapters/reference/agent-loop-apis.md +0 -69
  150. package/docs/adapters/reference/claude-code-otel-telemetry.md +0 -100
  151. package/docs/adapters/reference/eve-protocol.md +0 -127
  152. package/docs/adapters/reference/otel-genai.md +0 -107
  153. package/docs/adapters/reference/otel-instrumentation.md +0 -65
  154. package/docs/adapters/targets.md +0 -99
  155. package/docs/architecture.md +0 -140
  156. package/docs/assertions.md +0 -387
  157. package/docs/capabilities-by-construction.md +0 -48
  158. package/docs/cli.md +0 -173
  159. package/docs/concepts.md +0 -106
  160. package/docs/e2e-ci.md +0 -332
  161. package/docs/eval-authoring.md +0 -319
  162. package/docs/experiments.md +0 -157
  163. package/docs/getting-started.md +0 -224
  164. package/docs/multi-agent.md +0 -145
  165. package/docs/observability.md +0 -337
  166. package/docs/origin-integration.md +0 -195
  167. package/docs/references.md +0 -35
  168. package/docs/reports.md +0 -551
  169. package/docs/results-format.md +0 -228
  170. package/docs/results-lib.md +0 -191
  171. package/docs/runner.md +0 -104
  172. package/docs/sandbox.md +0 -276
  173. package/docs/scoring.md +0 -119
  174. package/docs/source-map.md +0 -126
  175. package/docs/tier-sync.md +0 -193
  176. package/docs/view.md +0 -194
  177. 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
+ })();