@mastra/evals 1.6.0 → 1.7.0

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 (62) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/dist/checks-64AonnEK.js +379 -0
  3. package/dist/checks-64AonnEK.js.map +1 -0
  4. package/dist/checks-DGTgg-nW.cjs +479 -0
  5. package/dist/checks-DGTgg-nW.cjs.map +1 -0
  6. package/dist/checks.cjs +14 -56
  7. package/dist/checks.js +2 -3
  8. package/dist/docs/SKILL.md +2 -1
  9. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  10. package/dist/docs/references/docs-evals-built-in-scorers.md +4 -4
  11. package/dist/docs/references/docs-evals-overview.md +6 -4
  12. package/dist/docs/references/docs-evals-quick-checks.md +2 -2
  13. package/dist/docs/references/reference-evals-answer-relevancy.md +5 -5
  14. package/dist/docs/references/reference-evals-answer-similarity.md +1 -1
  15. package/dist/docs/references/reference-evals-bias.md +4 -4
  16. package/dist/docs/references/reference-evals-checks.md +3 -3
  17. package/dist/docs/references/reference-evals-completeness.md +5 -5
  18. package/dist/docs/references/reference-evals-content-similarity.md +5 -5
  19. package/dist/docs/references/reference-evals-context-precision.md +5 -5
  20. package/dist/docs/references/reference-evals-context-recall.md +11 -11
  21. package/dist/docs/references/reference-evals-context-relevance.md +15 -15
  22. package/dist/docs/references/reference-evals-faithfulness.md +4 -4
  23. package/dist/docs/references/reference-evals-hallucination.md +11 -11
  24. package/dist/docs/references/reference-evals-keyword-coverage.md +6 -6
  25. package/dist/docs/references/reference-evals-noise-sensitivity.md +15 -15
  26. package/dist/docs/references/reference-evals-prompt-alignment.md +20 -20
  27. package/dist/docs/references/reference-evals-rubric.md +2 -2
  28. package/dist/docs/references/reference-evals-scorer-utils.md +4 -4
  29. package/dist/docs/references/reference-evals-summarization.md +203 -0
  30. package/dist/docs/references/reference-evals-textual-difference.md +4 -4
  31. package/dist/docs/references/reference-evals-tool-call-accuracy.md +4 -4
  32. package/dist/docs/references/reference-evals-toxicity.md +5 -5
  33. package/dist/docs/references/reference-evals-trajectory-accuracy.md +10 -10
  34. package/dist/index.cjs +12 -2
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.js +13 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/scorers/llm/index.d.ts +1 -0
  39. package/dist/scorers/llm/index.d.ts.map +1 -1
  40. package/dist/scorers/llm/summarization/index.d.ts +55 -0
  41. package/dist/scorers/llm/summarization/index.d.ts.map +1 -0
  42. package/dist/scorers/llm/summarization/prompts.d.ts +48 -0
  43. package/dist/scorers/llm/summarization/prompts.d.ts.map +1 -0
  44. package/dist/scorers/prebuilt/index.cjs +2753 -2848
  45. package/dist/scorers/prebuilt/index.cjs.map +1 -1
  46. package/dist/scorers/prebuilt/index.js +2735 -2791
  47. package/dist/scorers/prebuilt/index.js.map +1 -1
  48. package/dist/scorers/utils.cjs +966 -101
  49. package/dist/scorers/utils.cjs.map +1 -1
  50. package/dist/scorers/utils.js +939 -2
  51. package/dist/scorers/utils.js.map +1 -1
  52. package/package.json +11 -10
  53. package/dist/checks.cjs.map +0 -1
  54. package/dist/checks.js.map +0 -1
  55. package/dist/chunk-GGHVFNVI.cjs +0 -233
  56. package/dist/chunk-GGHVFNVI.cjs.map +0 -1
  57. package/dist/chunk-IZLA36WC.cjs +0 -654
  58. package/dist/chunk-IZLA36WC.cjs.map +0 -1
  59. package/dist/chunk-UJ4WCQ3F.js +0 -626
  60. package/dist/chunk-UJ4WCQ3F.js.map +0 -1
  61. package/dist/chunk-WEADJCUA.js +0 -216
  62. package/dist/chunk-WEADJCUA.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # @mastra/evals
2
2
 
3
+ ## 1.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added a `summarization` scorer to `@mastra/evals`. It grades a summary on two axes and returns the lower score, so a summary cannot pass by being faithful but empty, or thorough but wrong. ([#20293](https://github.com/mastra-ai/mastra/pull/20293))
8
+
9
+ **Alignment** checks that every claim in the summary is supported by the source text. **Coverage** draws closed-ended questions from the source and answers them using the summary alone, in a separate call that never receives the source, so a missing fact cannot be answered from the source instead. The final score is `min(alignment, coverage) × scale`, and the reason names the axis that produced it.
10
+
11
+ The source text defaults to the user message of the run input. Pass `source` or `sourceExtractor` when the text being summarized comes from somewhere else, such as a tool result. `maxQuestions` bounds the coverage questions so cost does not grow with document length.
12
+
13
+ ```ts
14
+ import { createSummarizationScorer } from '@mastra/evals/scorers/prebuilt';
15
+
16
+ const scorer = createSummarizationScorer({
17
+ model: 'openai/gpt-5.5',
18
+ options: { maxQuestions: 10 },
19
+ });
20
+
21
+ const result = await scorer.run(run);
22
+ result.score;
23
+ ```
24
+
25
+ This restores the summarization metric that was removed with the legacy evals system, rebuilt on the scorers pipeline.
26
+
27
+ ### Patch Changes
28
+
29
+ - Updated dependencies [[`4844167`](https://github.com/mastra-ai/mastra/commit/4844167cff2d5ec5004e94edd34970833040fa3f), [`c5e56ff`](https://github.com/mastra-ai/mastra/commit/c5e56ff3bcabdf062708f2d48744fec304df6792), [`594f7b2`](https://github.com/mastra-ai/mastra/commit/594f7b28f5263fb9982fd50d95c471fb971ea984), [`7f4e26d`](https://github.com/mastra-ai/mastra/commit/7f4e26dd57bd9b23c278ea21235ab823a3810a6c), [`311f943`](https://github.com/mastra-ai/mastra/commit/311f943bee60e8fdf5c84499ea50e884276c936c), [`322daa6`](https://github.com/mastra-ai/mastra/commit/322daa6d90552909204044790d850958f6745fed), [`db4e6ff`](https://github.com/mastra-ai/mastra/commit/db4e6ff744503112eb64deeaf6c2b54bf26a54c7), [`5faf93f`](https://github.com/mastra-ai/mastra/commit/5faf93f03e19daea394b9e2a923f2e4f833407f2), [`82201f7`](https://github.com/mastra-ai/mastra/commit/82201f75fae8e050a8de2df08b74875ee74c6b83), [`cadaa13`](https://github.com/mastra-ai/mastra/commit/cadaa1372e1077c8e85eb64c5499ba8803caa323), [`0c89896`](https://github.com/mastra-ai/mastra/commit/0c8989673fb7d106837098398131e570c6023b68), [`6d19a65`](https://github.com/mastra-ai/mastra/commit/6d19a6517f5da3911023d446b7e2d5dad8adb1cb), [`23b4238`](https://github.com/mastra-ai/mastra/commit/23b423844ad0bcf2a502a68dd62866d6160f9f6d), [`80ad891`](https://github.com/mastra-ai/mastra/commit/80ad891f8cd10379aa5b5af7510c763783b2ab56), [`fb18da5`](https://github.com/mastra-ai/mastra/commit/fb18da56fc35689ae370621a8f10b5b0d8606e20), [`fb18da5`](https://github.com/mastra-ai/mastra/commit/fb18da56fc35689ae370621a8f10b5b0d8606e20), [`e320a76`](https://github.com/mastra-ai/mastra/commit/e320a763feaf65c6be3cebecf746defcbde161b3), [`03b4918`](https://github.com/mastra-ai/mastra/commit/03b4918c80d188ce375334c393e131c6e94bd7eb), [`14ef73a`](https://github.com/mastra-ai/mastra/commit/14ef73a4bbd73e7808414816eb0628ce1d80b5d7), [`b582f7f`](https://github.com/mastra-ai/mastra/commit/b582f7fa2f9c1f87d19efc63d344fbe5dda2608c), [`0a6598b`](https://github.com/mastra-ai/mastra/commit/0a6598bde80bde008986ad6616bed9632b9294cb), [`06000d7`](https://github.com/mastra-ai/mastra/commit/06000d73712911572e913b8a83339270296d0a22), [`1d677d5`](https://github.com/mastra-ai/mastra/commit/1d677d5f99d7db403f7828585e8c25f299f72628), [`9e1dad8`](https://github.com/mastra-ai/mastra/commit/9e1dad8f7b1cab2bb7ade90e5b7561f24577b88a), [`2f43145`](https://github.com/mastra-ai/mastra/commit/2f4314504c03cbba280414ac81ba3197448ee6b0), [`4e35a56`](https://github.com/mastra-ai/mastra/commit/4e35a56cdf8d74a5ff6d5eda01f2c1deaf6cc7be), [`d94b8e1`](https://github.com/mastra-ai/mastra/commit/d94b8e1cee67416d518a8c30099040061bef6a1c), [`93e28ec`](https://github.com/mastra-ai/mastra/commit/93e28ecce9031c02397e0ae8406593e5c7a95883), [`729dab4`](https://github.com/mastra-ai/mastra/commit/729dab408faccfaef0cbb048e5a4338f9172847e), [`484003d`](https://github.com/mastra-ai/mastra/commit/484003d33ff59330c86b19863e4a38732d7e4155), [`3de0188`](https://github.com/mastra-ai/mastra/commit/3de0188bfaf9a9c09c95fe322b53838cf52c70b6), [`34d34d8`](https://github.com/mastra-ai/mastra/commit/34d34d8c811df512fef4dd5459f79b7821be1866), [`b582f7f`](https://github.com/mastra-ai/mastra/commit/b582f7fa2f9c1f87d19efc63d344fbe5dda2608c), [`933d291`](https://github.com/mastra-ai/mastra/commit/933d291146b789c19442ad206f94da3e4be90c64), [`a1cb98d`](https://github.com/mastra-ai/mastra/commit/a1cb98d11990b560b98482292a1f34aa1a2d9092), [`598ad82`](https://github.com/mastra-ai/mastra/commit/598ad82d41c41389a686338a1d0e50b7400e1938), [`1fd6aad`](https://github.com/mastra-ai/mastra/commit/1fd6aad1ea4a9d32f65efa832307c35e981a4c0a)]:
30
+ - @mastra/core@1.56.0
31
+
32
+ ## 1.7.0-alpha.0
33
+
34
+ ### Minor Changes
35
+
36
+ - Added a `summarization` scorer to `@mastra/evals`. It grades a summary on two axes and returns the lower score, so a summary cannot pass by being faithful but empty, or thorough but wrong. ([#20293](https://github.com/mastra-ai/mastra/pull/20293))
37
+
38
+ **Alignment** checks that every claim in the summary is supported by the source text. **Coverage** draws closed-ended questions from the source and answers them using the summary alone, in a separate call that never receives the source, so a missing fact cannot be answered from the source instead. The final score is `min(alignment, coverage) × scale`, and the reason names the axis that produced it.
39
+
40
+ The source text defaults to the user message of the run input. Pass `source` or `sourceExtractor` when the text being summarized comes from somewhere else, such as a tool result. `maxQuestions` bounds the coverage questions so cost does not grow with document length.
41
+
42
+ ```ts
43
+ import { createSummarizationScorer } from '@mastra/evals/scorers/prebuilt';
44
+
45
+ const scorer = createSummarizationScorer({
46
+ model: 'openai/gpt-5.5',
47
+ options: { maxQuestions: 10 },
48
+ });
49
+
50
+ const result = await scorer.run(run);
51
+ result.score;
52
+ ```
53
+
54
+ This restores the summarization metric that was removed with the legacy evals system, rebuilt on the scorers pipeline.
55
+
56
+ ### Patch Changes
57
+
58
+ - Updated dependencies [[`594f7b2`](https://github.com/mastra-ai/mastra/commit/594f7b28f5263fb9982fd50d95c471fb971ea984), [`311f943`](https://github.com/mastra-ai/mastra/commit/311f943bee60e8fdf5c84499ea50e884276c936c), [`0c89896`](https://github.com/mastra-ai/mastra/commit/0c8989673fb7d106837098398131e570c6023b68), [`23b4238`](https://github.com/mastra-ai/mastra/commit/23b423844ad0bcf2a502a68dd62866d6160f9f6d), [`e320a76`](https://github.com/mastra-ai/mastra/commit/e320a763feaf65c6be3cebecf746defcbde161b3), [`03b4918`](https://github.com/mastra-ai/mastra/commit/03b4918c80d188ce375334c393e131c6e94bd7eb), [`14ef73a`](https://github.com/mastra-ai/mastra/commit/14ef73a4bbd73e7808414816eb0628ce1d80b5d7), [`1d677d5`](https://github.com/mastra-ai/mastra/commit/1d677d5f99d7db403f7828585e8c25f299f72628), [`93e28ec`](https://github.com/mastra-ai/mastra/commit/93e28ecce9031c02397e0ae8406593e5c7a95883), [`729dab4`](https://github.com/mastra-ai/mastra/commit/729dab408faccfaef0cbb048e5a4338f9172847e), [`484003d`](https://github.com/mastra-ai/mastra/commit/484003d33ff59330c86b19863e4a38732d7e4155), [`933d291`](https://github.com/mastra-ai/mastra/commit/933d291146b789c19442ad206f94da3e4be90c64)]:
59
+ - @mastra/core@1.56.0-alpha.3
60
+
3
61
  ## 1.6.0
4
62
 
5
63
  ### Minor Changes
@@ -0,0 +1,379 @@
1
+ import { extractToolCalls, getTextContentFromMastraDBMessage } from "./scorers/utils.js";
2
+ import { createScorer } from "@mastra/core/evals";
3
+ import stringSimilarity from "string-similarity";
4
+ //#region src/scorers/code/checks/index.ts
5
+ /**
6
+ * Scores 1 if the agent's output text contains the expected substring, 0 otherwise.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { checks } from '@mastra/evals';
11
+ * const scorer = checks.includes('sunny');
12
+ * ```
13
+ */
14
+ function includes(expected, options = {}) {
15
+ const { ignoreCase = true } = options;
16
+ return createScorer({
17
+ id: "check-includes",
18
+ name: "Includes Check",
19
+ description: `Checks if output includes "${expected}"`,
20
+ type: "agent"
21
+ }).preprocess(async ({ run }) => {
22
+ let output = run.output.filter((m) => m.role === "assistant").map((m) => getTextContentFromMastraDBMessage(m)).join(" ");
23
+ let target = expected;
24
+ if (ignoreCase) {
25
+ output = output.toLowerCase();
26
+ target = target.toLowerCase();
27
+ }
28
+ return {
29
+ output,
30
+ target,
31
+ found: output.includes(target)
32
+ };
33
+ }).generateScore(({ results }) => {
34
+ return results.preprocessStepResult?.found ? 1 : 0;
35
+ });
36
+ }
37
+ /**
38
+ * Scores 1 if the agent's output text does NOT contain the substring, 0 otherwise.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * import { checks } from '@mastra/evals';
43
+ * const scorer = checks.excludes('error');
44
+ * ```
45
+ */
46
+ function excludes(unwanted, options = {}) {
47
+ const { ignoreCase = true } = options;
48
+ return createScorer({
49
+ id: "check-excludes",
50
+ name: "Excludes Check",
51
+ description: `Checks that output does not include "${unwanted}"`,
52
+ type: "agent"
53
+ }).preprocess(async ({ run }) => {
54
+ let output = run.output.filter((m) => m.role === "assistant").map((m) => getTextContentFromMastraDBMessage(m)).join(" ");
55
+ let target = unwanted;
56
+ if (ignoreCase) {
57
+ output = output.toLowerCase();
58
+ target = target.toLowerCase();
59
+ }
60
+ return {
61
+ output,
62
+ target,
63
+ excluded: !output.includes(target)
64
+ };
65
+ }).generateScore(({ results }) => {
66
+ return results.preprocessStepResult?.excluded ? 1 : 0;
67
+ });
68
+ }
69
+ /**
70
+ * Scores 1 if the output text exactly equals the expected string (after optional normalization).
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * import { checks } from '@mastra/evals';
75
+ * const scorer = checks.equals('Hello, world!');
76
+ * ```
77
+ */
78
+ function equals(expected, options = {}) {
79
+ const { ignoreCase = true } = options;
80
+ return createScorer({
81
+ id: "check-equals",
82
+ name: "Equals Check",
83
+ description: `Checks if output equals "${expected}"`,
84
+ type: "agent"
85
+ }).preprocess(async ({ run }) => {
86
+ let output = run.output.filter((m) => m.role === "assistant").map((m) => getTextContentFromMastraDBMessage(m)).join("");
87
+ let target = expected;
88
+ if (ignoreCase) {
89
+ output = output.toLowerCase();
90
+ target = target.toLowerCase();
91
+ }
92
+ return {
93
+ output,
94
+ target,
95
+ isEqual: output === target
96
+ };
97
+ }).generateScore(({ results }) => {
98
+ return results.preprocessStepResult?.isEqual ? 1 : 0;
99
+ });
100
+ }
101
+ /**
102
+ * Scores 1 if the output matches the given regular expression, 0 otherwise.
103
+ *
104
+ * @example
105
+ * ```ts
106
+ * import { checks } from '@mastra/evals';
107
+ * const scorer = checks.matches(/\d{1,3}°[FC]/);
108
+ * ```
109
+ */
110
+ function matches(pattern, options = {}) {
111
+ const { exact = false } = options;
112
+ return createScorer({
113
+ id: "check-matches",
114
+ name: "Matches Check",
115
+ description: `Checks if output matches pattern ${pattern}`,
116
+ type: "agent"
117
+ }).preprocess(async ({ run }) => {
118
+ const output = run.output.filter((m) => m.role === "assistant").map((m) => getTextContentFromMastraDBMessage(m)).join("");
119
+ const matched = (exact ? new RegExp(`^${pattern.source}$`, pattern.flags) : pattern).test(output);
120
+ return {
121
+ output,
122
+ pattern: pattern.toString(),
123
+ matched
124
+ };
125
+ }).generateScore(({ results }) => {
126
+ return results.preprocessStepResult?.matched ? 1 : 0;
127
+ });
128
+ }
129
+ /**
130
+ * Returns the string similarity score (0-1) between the output and an expected string.
131
+ * Useful for fuzzy matching when exact equality is too strict.
132
+ *
133
+ * @example
134
+ * ```ts
135
+ * import { checks } from '@mastra/evals';
136
+ * const scorer = checks.similarity('Sunny, 72°F');
137
+ * ```
138
+ */
139
+ function similarity(expected, options = {}) {
140
+ const { ignoreCase = true, threshold } = options;
141
+ return createScorer({
142
+ id: "check-similarity",
143
+ name: "Similarity Check",
144
+ description: `Checks string similarity to "${expected}"`,
145
+ type: "agent"
146
+ }).preprocess(async ({ run }) => {
147
+ let output = run.output.filter((m) => m.role === "assistant").map((m) => getTextContentFromMastraDBMessage(m)).join(" ");
148
+ let target = expected;
149
+ if (ignoreCase) {
150
+ output = output.toLowerCase();
151
+ target = target.toLowerCase();
152
+ }
153
+ const score = stringSimilarity.compareTwoStrings(output, target);
154
+ return {
155
+ output,
156
+ target,
157
+ score,
158
+ threshold
159
+ };
160
+ }).generateScore(({ results }) => {
161
+ const score = results.preprocessStepResult?.score ?? 0;
162
+ const t = results.preprocessStepResult?.threshold;
163
+ return t !== void 0 ? score >= t ? 1 : 0 : score;
164
+ });
165
+ }
166
+ /**
167
+ * Scores 1 if the agent called the specified tool (at least `times` times).
168
+ *
169
+ * @example
170
+ * ```ts
171
+ * import { checks } from '@mastra/evals';
172
+ * const scorer = checks.calledTool('get_weather');
173
+ * const twice = checks.calledTool('search', { times: 2 });
174
+ * ```
175
+ */
176
+ function calledTool(toolName, options = {}) {
177
+ const { times = 1 } = options;
178
+ return createScorer({
179
+ id: "check-called-tool",
180
+ name: "Called Tool Check",
181
+ description: `Checks that "${toolName}" was called${times > 1 ? ` at least ${times} times` : ""}`,
182
+ type: "agent"
183
+ }).preprocess(async ({ run }) => {
184
+ const { tools } = extractToolCalls(run.output);
185
+ const count = tools.filter((t) => t === toolName).length;
186
+ return {
187
+ toolName,
188
+ expectedTimes: times,
189
+ actualCount: count,
190
+ passed: count >= times
191
+ };
192
+ }).generateScore(({ results }) => {
193
+ return results.preprocessStepResult?.passed ? 1 : 0;
194
+ });
195
+ }
196
+ /**
197
+ * Scores 1 if the agent did NOT call the specified tool.
198
+ *
199
+ * @example
200
+ * ```ts
201
+ * import { checks } from '@mastra/evals';
202
+ * const scorer = checks.didNotCall('delete_user');
203
+ * ```
204
+ */
205
+ function didNotCall(toolName) {
206
+ return createScorer({
207
+ id: "check-did-not-call",
208
+ name: "Did Not Call Check",
209
+ description: `Checks that "${toolName}" was NOT called`,
210
+ type: "agent"
211
+ }).preprocess(async ({ run }) => {
212
+ const { tools } = extractToolCalls(run.output);
213
+ const count = tools.filter((t) => t === toolName).length;
214
+ return {
215
+ toolName,
216
+ count,
217
+ passed: count === 0
218
+ };
219
+ }).generateScore(({ results }) => {
220
+ return results.preprocessStepResult?.passed ? 1 : 0;
221
+ });
222
+ }
223
+ /**
224
+ * Scores 1 if the tools were called in the specified order (relaxed: allows other calls in between).
225
+ *
226
+ * @example
227
+ * ```ts
228
+ * import { checks } from '@mastra/evals';
229
+ * const scorer = checks.toolOrder(['search', 'summarize', 'respond']);
230
+ * ```
231
+ */
232
+ function toolOrder(expectedOrder) {
233
+ return createScorer({
234
+ id: "check-tool-order",
235
+ name: "Tool Order Check",
236
+ description: `Checks tool call order: [${expectedOrder.join(" → ")}]`,
237
+ type: "agent"
238
+ }).preprocess(async ({ run }) => {
239
+ const { tools } = extractToolCalls(run.output);
240
+ let orderIndex = 0;
241
+ for (const tool of tools) if (orderIndex < expectedOrder.length && tool === expectedOrder[orderIndex]) orderIndex++;
242
+ return {
243
+ actualTools: tools,
244
+ expectedOrder,
245
+ passed: orderIndex === expectedOrder.length
246
+ };
247
+ }).generateScore(({ results }) => {
248
+ return results.preprocessStepResult?.passed ? 1 : 0;
249
+ });
250
+ }
251
+ /**
252
+ * Scores 1 if the agent used no more than `max` tool calls.
253
+ *
254
+ * @example
255
+ * ```ts
256
+ * import { checks } from '@mastra/evals';
257
+ * const scorer = checks.maxToolCalls(5);
258
+ * ```
259
+ */
260
+ function maxToolCalls(max) {
261
+ return createScorer({
262
+ id: "check-max-tool-calls",
263
+ name: "Max Tool Calls Check",
264
+ description: `Checks that no more than ${max} tool calls were made`,
265
+ type: "agent"
266
+ }).preprocess(async ({ run }) => {
267
+ const { tools } = extractToolCalls(run.output);
268
+ return {
269
+ count: tools.length,
270
+ max,
271
+ passed: tools.length <= max
272
+ };
273
+ }).generateScore(({ results }) => {
274
+ return results.preprocessStepResult?.passed ? 1 : 0;
275
+ });
276
+ }
277
+ /**
278
+ * Scores 1 if the agent made no tool calls at all.
279
+ *
280
+ * @example
281
+ * ```ts
282
+ * import { checks } from '@mastra/evals';
283
+ * const scorer = checks.usedNoTools();
284
+ * ```
285
+ */
286
+ function usedNoTools() {
287
+ return createScorer({
288
+ id: "check-used-no-tools",
289
+ name: "Used No Tools Check",
290
+ description: "Checks that no tools were called",
291
+ type: "agent"
292
+ }).preprocess(async ({ run }) => {
293
+ const { tools } = extractToolCalls(run.output);
294
+ return {
295
+ count: tools.length,
296
+ passed: tools.length === 0
297
+ };
298
+ }).generateScore(({ results }) => {
299
+ return results.preprocessStepResult?.passed ? 1 : 0;
300
+ });
301
+ }
302
+ /**
303
+ * Scores 1 if none of the tool invocations resulted in an error state.
304
+ * Checks for tool invocations with state other than 'result' (i.e., missing results).
305
+ *
306
+ * @example
307
+ * ```ts
308
+ * import { checks } from '@mastra/evals';
309
+ * const scorer = checks.noToolErrors();
310
+ * ```
311
+ */
312
+ function noToolErrors() {
313
+ return createScorer({
314
+ id: "check-no-tool-errors",
315
+ name: "No Tool Errors Check",
316
+ description: "Checks that no tool calls resulted in errors",
317
+ type: "agent"
318
+ }).preprocess(async ({ run }) => {
319
+ const invocations = extractRawInvocations(run.output);
320
+ const errorCount = invocations.filter((inv) => inv.state === "call" || inv.result && inv.result.error).length;
321
+ return {
322
+ errorCount,
323
+ totalCalls: invocations.length,
324
+ passed: errorCount === 0
325
+ };
326
+ }).generateScore(({ results }) => {
327
+ return results.preprocessStepResult?.passed ? 1 : 0;
328
+ });
329
+ }
330
+ function extractRawInvocations(output) {
331
+ const invocations = [];
332
+ for (const message of output) {
333
+ const legacy = message?.content?.toolInvocations;
334
+ const fromParts = legacy ? void 0 : (message?.content)?.parts?.filter((p) => p.type === "tool-invocation").map((p) => p.toolInvocation);
335
+ for (const inv of legacy ?? fromParts ?? []) if (inv) invocations.push(inv);
336
+ }
337
+ return invocations;
338
+ }
339
+ /**
340
+ * Quick Checks — composable micro-scorers for common assertions.
341
+ *
342
+ * These are zero-LLM, zero-ceremony scorers that plug into the existing
343
+ * `scorers: [...]` array anywhere scorers are used. Internally they are
344
+ * standard `createScorer()` instances with the same observability, storage,
345
+ * and pipeline integration as any other scorer.
346
+ *
347
+ * @example
348
+ * ```ts
349
+ * import { checks } from '@mastra/evals';
350
+ *
351
+ * await runEvals({
352
+ * data: [...],
353
+ * target: myAgent,
354
+ * scorers: [
355
+ * checks.includes('sunny'),
356
+ * checks.calledTool('get_weather'),
357
+ * checks.toolOrder(['search', 'summarize']),
358
+ * checks.noToolErrors(),
359
+ * ],
360
+ * });
361
+ * ```
362
+ */
363
+ const checks = {
364
+ includes,
365
+ excludes,
366
+ equals,
367
+ matches,
368
+ similarity,
369
+ calledTool,
370
+ didNotCall,
371
+ toolOrder,
372
+ maxToolCalls,
373
+ usedNoTools,
374
+ noToolErrors
375
+ };
376
+ //#endregion
377
+ export { excludes as a, maxToolCalls as c, toolOrder as d, usedNoTools as f, equals as i, noToolErrors as l, checks as n, includes as o, didNotCall as r, matches as s, calledTool as t, similarity as u };
378
+
379
+ //# sourceMappingURL=checks-64AonnEK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks-64AonnEK.js","names":[],"sources":["../src/scorers/code/checks/index.ts"],"sourcesContent":["import { createScorer } from '@mastra/core/evals';\nimport stringSimilarity from 'string-similarity';\nimport { extractToolCalls, getTextContentFromMastraDBMessage } from '../../utils';\n\n// ─── Output Text Checks ───────────────────────────────────────────────────────\n\nexport interface IncludesOptions {\n /** Case-insensitive match (default: true) */\n ignoreCase?: boolean;\n}\n\n/**\n * Scores 1 if the agent's output text contains the expected substring, 0 otherwise.\n *\n * @example\n * ```ts\n * import { checks } from '@mastra/evals';\n * const scorer = checks.includes('sunny');\n * ```\n */\nexport function includes(expected: string, options: IncludesOptions = {}) {\n const { ignoreCase = true } = options;\n return createScorer({\n id: 'check-includes',\n name: 'Includes Check',\n description: `Checks if output includes \"${expected}\"`,\n type: 'agent',\n })\n .preprocess(async ({ run }) => {\n let output = run.output\n .filter(m => m.role === 'assistant')\n .map(m => getTextContentFromMastraDBMessage(m))\n .join(' ');\n let target = expected;\n if (ignoreCase) {\n output = output.toLowerCase();\n target = target.toLowerCase();\n }\n return { output, target, found: output.includes(target) };\n })\n .generateScore(({ results }) => {\n return results.preprocessStepResult?.found ? 1 : 0;\n });\n}\n\n/**\n * Scores 1 if the agent's output text does NOT contain the substring, 0 otherwise.\n *\n * @example\n * ```ts\n * import { checks } from '@mastra/evals';\n * const scorer = checks.excludes('error');\n * ```\n */\nexport function excludes(unwanted: string, options: IncludesOptions = {}) {\n const { ignoreCase = true } = options;\n return createScorer({\n id: 'check-excludes',\n name: 'Excludes Check',\n description: `Checks that output does not include \"${unwanted}\"`,\n type: 'agent',\n })\n .preprocess(async ({ run }) => {\n let output = run.output\n .filter(m => m.role === 'assistant')\n .map(m => getTextContentFromMastraDBMessage(m))\n .join(' ');\n let target = unwanted;\n if (ignoreCase) {\n output = output.toLowerCase();\n target = target.toLowerCase();\n }\n return { output, target, excluded: !output.includes(target) };\n })\n .generateScore(({ results }) => {\n return results.preprocessStepResult?.excluded ? 1 : 0;\n });\n}\n\n/**\n * Scores 1 if the output text exactly equals the expected string (after optional normalization).\n *\n * @example\n * ```ts\n * import { checks } from '@mastra/evals';\n * const scorer = checks.equals('Hello, world!');\n * ```\n */\nexport function equals(expected: string, options: IncludesOptions = {}) {\n const { ignoreCase = true } = options;\n return createScorer({\n id: 'check-equals',\n name: 'Equals Check',\n description: `Checks if output equals \"${expected}\"`,\n type: 'agent',\n })\n .preprocess(async ({ run }) => {\n let output = run.output\n .filter(m => m.role === 'assistant')\n .map(m => getTextContentFromMastraDBMessage(m))\n .join('');\n let target = expected;\n if (ignoreCase) {\n output = output.toLowerCase();\n target = target.toLowerCase();\n }\n return { output, target, isEqual: output === target };\n })\n .generateScore(({ results }) => {\n return results.preprocessStepResult?.isEqual ? 1 : 0;\n });\n}\n\nexport interface MatchesOptions {\n /** If true, the output must match the pattern exactly (anchored). Default: false (substring match). */\n exact?: boolean;\n}\n\n/**\n * Scores 1 if the output matches the given regular expression, 0 otherwise.\n *\n * @example\n * ```ts\n * import { checks } from '@mastra/evals';\n * const scorer = checks.matches(/\\d{1,3}°[FC]/);\n * ```\n */\nexport function matches(pattern: RegExp, options: MatchesOptions = {}) {\n const { exact = false } = options;\n return createScorer({\n id: 'check-matches',\n name: 'Matches Check',\n description: `Checks if output matches pattern ${pattern}`,\n type: 'agent',\n })\n .preprocess(async ({ run }) => {\n const output = run.output\n .filter(m => m.role === 'assistant')\n .map(m => getTextContentFromMastraDBMessage(m))\n .join('');\n const regex = exact ? new RegExp(`^${pattern.source}$`, pattern.flags) : pattern;\n const matched = regex.test(output);\n return { output, pattern: pattern.toString(), matched };\n })\n .generateScore(({ results }) => {\n return results.preprocessStepResult?.matched ? 1 : 0;\n });\n}\n\nexport interface SimilarityOptions {\n /** Minimum similarity threshold (0-1) to score 1. Default: 0.7 */\n threshold?: number;\n /** Case-insensitive comparison (default: true) */\n ignoreCase?: boolean;\n}\n\n/**\n * Returns the string similarity score (0-1) between the output and an expected string.\n * Useful for fuzzy matching when exact equality is too strict.\n *\n * @example\n * ```ts\n * import { checks } from '@mastra/evals';\n * const scorer = checks.similarity('Sunny, 72°F');\n * ```\n */\nexport function similarity(expected: string, options: SimilarityOptions = {}) {\n const { ignoreCase = true, threshold } = options;\n return createScorer({\n id: 'check-similarity',\n name: 'Similarity Check',\n description: `Checks string similarity to \"${expected}\"`,\n type: 'agent',\n })\n .preprocess(async ({ run }) => {\n let output = run.output\n .filter(m => m.role === 'assistant')\n .map(m => getTextContentFromMastraDBMessage(m))\n .join(' ');\n let target = expected;\n if (ignoreCase) {\n output = output.toLowerCase();\n target = target.toLowerCase();\n }\n const score = stringSimilarity.compareTwoStrings(output, target);\n return { output, target, score, threshold };\n })\n .generateScore(({ results }) => {\n const score = results.preprocessStepResult?.score ?? 0;\n const t = results.preprocessStepResult?.threshold;\n return t !== undefined ? (score >= t ? 1 : 0) : score;\n });\n}\n\n// ─── Tool Call Checks ─────────────────────────────────────────────────────────\n\nexport interface CalledToolOptions {\n /** Minimum number of times the tool must be called. Default: 1 */\n times?: number;\n}\n\n/**\n * Scores 1 if the agent called the specified tool (at least `times` times).\n *\n * @example\n * ```ts\n * import { checks } from '@mastra/evals';\n * const scorer = checks.calledTool('get_weather');\n * const twice = checks.calledTool('search', { times: 2 });\n * ```\n */\nexport function calledTool(toolName: string, options: CalledToolOptions = {}) {\n const { times = 1 } = options;\n return createScorer({\n id: 'check-called-tool',\n name: 'Called Tool Check',\n description: `Checks that \"${toolName}\" was called${times > 1 ? ` at least ${times} times` : ''}`,\n type: 'agent',\n })\n .preprocess(async ({ run }) => {\n const { tools } = extractToolCalls(run.output);\n const count = tools.filter(t => t === toolName).length;\n return { toolName, expectedTimes: times, actualCount: count, passed: count >= times };\n })\n .generateScore(({ results }) => {\n return results.preprocessStepResult?.passed ? 1 : 0;\n });\n}\n\n/**\n * Scores 1 if the agent did NOT call the specified tool.\n *\n * @example\n * ```ts\n * import { checks } from '@mastra/evals';\n * const scorer = checks.didNotCall('delete_user');\n * ```\n */\nexport function didNotCall(toolName: string) {\n return createScorer({\n id: 'check-did-not-call',\n name: 'Did Not Call Check',\n description: `Checks that \"${toolName}\" was NOT called`,\n type: 'agent',\n })\n .preprocess(async ({ run }) => {\n const { tools } = extractToolCalls(run.output);\n const count = tools.filter(t => t === toolName).length;\n return { toolName, count, passed: count === 0 };\n })\n .generateScore(({ results }) => {\n return results.preprocessStepResult?.passed ? 1 : 0;\n });\n}\n\n/**\n * Scores 1 if the tools were called in the specified order (relaxed: allows other calls in between).\n *\n * @example\n * ```ts\n * import { checks } from '@mastra/evals';\n * const scorer = checks.toolOrder(['search', 'summarize', 'respond']);\n * ```\n */\nexport function toolOrder(expectedOrder: string[]) {\n return createScorer({\n id: 'check-tool-order',\n name: 'Tool Order Check',\n description: `Checks tool call order: [${expectedOrder.join(' → ')}]`,\n type: 'agent',\n })\n .preprocess(async ({ run }) => {\n const { tools } = extractToolCalls(run.output);\n // Check that expectedOrder appears as a subsequence of tools\n let orderIndex = 0;\n for (const tool of tools) {\n if (orderIndex < expectedOrder.length && tool === expectedOrder[orderIndex]) {\n orderIndex++;\n }\n }\n const passed = orderIndex === expectedOrder.length;\n return { actualTools: tools, expectedOrder, passed };\n })\n .generateScore(({ results }) => {\n return results.preprocessStepResult?.passed ? 1 : 0;\n });\n}\n\n/**\n * Scores 1 if the agent used no more than `max` tool calls.\n *\n * @example\n * ```ts\n * import { checks } from '@mastra/evals';\n * const scorer = checks.maxToolCalls(5);\n * ```\n */\nexport function maxToolCalls(max: number) {\n return createScorer({\n id: 'check-max-tool-calls',\n name: 'Max Tool Calls Check',\n description: `Checks that no more than ${max} tool calls were made`,\n type: 'agent',\n })\n .preprocess(async ({ run }) => {\n const { tools } = extractToolCalls(run.output);\n return { count: tools.length, max, passed: tools.length <= max };\n })\n .generateScore(({ results }) => {\n return results.preprocessStepResult?.passed ? 1 : 0;\n });\n}\n\n/**\n * Scores 1 if the agent made no tool calls at all.\n *\n * @example\n * ```ts\n * import { checks } from '@mastra/evals';\n * const scorer = checks.usedNoTools();\n * ```\n */\nexport function usedNoTools() {\n return createScorer({\n id: 'check-used-no-tools',\n name: 'Used No Tools Check',\n description: 'Checks that no tools were called',\n type: 'agent',\n })\n .preprocess(async ({ run }) => {\n const { tools } = extractToolCalls(run.output);\n return { count: tools.length, passed: tools.length === 0 };\n })\n .generateScore(({ results }) => {\n return results.preprocessStepResult?.passed ? 1 : 0;\n });\n}\n\n/**\n * Scores 1 if none of the tool invocations resulted in an error state.\n * Checks for tool invocations with state other than 'result' (i.e., missing results).\n *\n * @example\n * ```ts\n * import { checks } from '@mastra/evals';\n * const scorer = checks.noToolErrors();\n * ```\n */\nexport function noToolErrors() {\n return createScorer({\n id: 'check-no-tool-errors',\n name: 'No Tool Errors Check',\n description: 'Checks that no tool calls resulted in errors',\n type: 'agent',\n })\n .preprocess(async ({ run }) => {\n const invocations = extractRawInvocations(run.output);\n const errorCount = invocations.filter(inv => inv.state === 'call' || (inv.result && inv.result.error)).length;\n return { errorCount, totalCalls: invocations.length, passed: errorCount === 0 };\n })\n .generateScore(({ results }) => {\n return results.preprocessStepResult?.passed ? 1 : 0;\n });\n}\n\n// ─── Internal helpers ──────────────────────────────────────────────────────────\n\nfunction extractRawInvocations(output: Parameters<typeof extractToolCalls>[0]) {\n const invocations: any[] = [];\n for (const message of output) {\n const legacy = message?.content?.toolInvocations;\n const fromParts = legacy\n ? undefined\n : (message?.content as any)?.parts\n ?.filter((p: any) => p.type === 'tool-invocation')\n .map((p: any) => p.toolInvocation);\n for (const inv of legacy ?? fromParts ?? []) {\n if (inv) invocations.push(inv);\n }\n }\n return invocations;\n}\n\n// ─── Convenience namespace ────────────────────────────────────────────────────\n\n/**\n * Quick Checks — composable micro-scorers for common assertions.\n *\n * These are zero-LLM, zero-ceremony scorers that plug into the existing\n * `scorers: [...]` array anywhere scorers are used. Internally they are\n * standard `createScorer()` instances with the same observability, storage,\n * and pipeline integration as any other scorer.\n *\n * @example\n * ```ts\n * import { checks } from '@mastra/evals';\n *\n * await runEvals({\n * data: [...],\n * target: myAgent,\n * scorers: [\n * checks.includes('sunny'),\n * checks.calledTool('get_weather'),\n * checks.toolOrder(['search', 'summarize']),\n * checks.noToolErrors(),\n * ],\n * });\n * ```\n */\nexport const checks = {\n includes,\n excludes,\n equals,\n matches,\n similarity,\n calledTool,\n didNotCall,\n toolOrder,\n maxToolCalls,\n usedNoTools,\n noToolErrors,\n};\n"],"mappings":";;;;;;;;;;;;;AAoBA,SAAgB,SAAS,UAAkB,UAA2B,CAAC,GAAG;CACxE,MAAM,EAAE,aAAa,SAAS;CAC9B,OAAO,aAAa;EAClB,IAAI;EACJ,MAAM;EACN,aAAa,8BAA8B,SAAS;EACpD,MAAM;CACR,CAAC,CAAC,CACC,WAAW,OAAO,EAAE,UAAU;EAC7B,IAAI,SAAS,IAAI,OACd,QAAO,MAAK,EAAE,SAAS,WAAW,CAAC,CACnC,KAAI,MAAK,kCAAkC,CAAC,CAAC,CAAC,CAC9C,KAAK,GAAG;EACX,IAAI,SAAS;EACb,IAAI,YAAY;GACd,SAAS,OAAO,YAAY;GAC5B,SAAS,OAAO,YAAY;EAC9B;EACA,OAAO;GAAE;GAAQ;GAAQ,OAAO,OAAO,SAAS,MAAM;EAAE;CAC1D,CAAC,CAAC,CACD,eAAe,EAAE,cAAc;EAC9B,OAAO,QAAQ,sBAAsB,QAAQ,IAAI;CACnD,CAAC;AACL;;;;;;;;;;AAWA,SAAgB,SAAS,UAAkB,UAA2B,CAAC,GAAG;CACxE,MAAM,EAAE,aAAa,SAAS;CAC9B,OAAO,aAAa;EAClB,IAAI;EACJ,MAAM;EACN,aAAa,wCAAwC,SAAS;EAC9D,MAAM;CACR,CAAC,CAAC,CACC,WAAW,OAAO,EAAE,UAAU;EAC7B,IAAI,SAAS,IAAI,OACd,QAAO,MAAK,EAAE,SAAS,WAAW,CAAC,CACnC,KAAI,MAAK,kCAAkC,CAAC,CAAC,CAAC,CAC9C,KAAK,GAAG;EACX,IAAI,SAAS;EACb,IAAI,YAAY;GACd,SAAS,OAAO,YAAY;GAC5B,SAAS,OAAO,YAAY;EAC9B;EACA,OAAO;GAAE;GAAQ;GAAQ,UAAU,CAAC,OAAO,SAAS,MAAM;EAAE;CAC9D,CAAC,CAAC,CACD,eAAe,EAAE,cAAc;EAC9B,OAAO,QAAQ,sBAAsB,WAAW,IAAI;CACtD,CAAC;AACL;;;;;;;;;;AAWA,SAAgB,OAAO,UAAkB,UAA2B,CAAC,GAAG;CACtE,MAAM,EAAE,aAAa,SAAS;CAC9B,OAAO,aAAa;EAClB,IAAI;EACJ,MAAM;EACN,aAAa,4BAA4B,SAAS;EAClD,MAAM;CACR,CAAC,CAAC,CACC,WAAW,OAAO,EAAE,UAAU;EAC7B,IAAI,SAAS,IAAI,OACd,QAAO,MAAK,EAAE,SAAS,WAAW,CAAC,CACnC,KAAI,MAAK,kCAAkC,CAAC,CAAC,CAAC,CAC9C,KAAK,EAAE;EACV,IAAI,SAAS;EACb,IAAI,YAAY;GACd,SAAS,OAAO,YAAY;GAC5B,SAAS,OAAO,YAAY;EAC9B;EACA,OAAO;GAAE;GAAQ;GAAQ,SAAS,WAAW;EAAO;CACtD,CAAC,CAAC,CACD,eAAe,EAAE,cAAc;EAC9B,OAAO,QAAQ,sBAAsB,UAAU,IAAI;CACrD,CAAC;AACL;;;;;;;;;;AAgBA,SAAgB,QAAQ,SAAiB,UAA0B,CAAC,GAAG;CACrE,MAAM,EAAE,QAAQ,UAAU;CAC1B,OAAO,aAAa;EAClB,IAAI;EACJ,MAAM;EACN,aAAa,oCAAoC;EACjD,MAAM;CACR,CAAC,CAAC,CACC,WAAW,OAAO,EAAE,UAAU;EAC7B,MAAM,SAAS,IAAI,OAChB,QAAO,MAAK,EAAE,SAAS,WAAW,CAAC,CACnC,KAAI,MAAK,kCAAkC,CAAC,CAAC,CAAC,CAC9C,KAAK,EAAE;EAEV,MAAM,WADQ,QAAQ,IAAI,OAAO,IAAI,QAAQ,OAAO,IAAI,QAAQ,KAAK,IAAI,QAAA,CACnD,KAAK,MAAM;EACjC,OAAO;GAAE;GAAQ,SAAS,QAAQ,SAAS;GAAG;EAAQ;CACxD,CAAC,CAAC,CACD,eAAe,EAAE,cAAc;EAC9B,OAAO,QAAQ,sBAAsB,UAAU,IAAI;CACrD,CAAC;AACL;;;;;;;;;;;AAmBA,SAAgB,WAAW,UAAkB,UAA6B,CAAC,GAAG;CAC5E,MAAM,EAAE,aAAa,MAAM,cAAc;CACzC,OAAO,aAAa;EAClB,IAAI;EACJ,MAAM;EACN,aAAa,gCAAgC,SAAS;EACtD,MAAM;CACR,CAAC,CAAC,CACC,WAAW,OAAO,EAAE,UAAU;EAC7B,IAAI,SAAS,IAAI,OACd,QAAO,MAAK,EAAE,SAAS,WAAW,CAAC,CACnC,KAAI,MAAK,kCAAkC,CAAC,CAAC,CAAC,CAC9C,KAAK,GAAG;EACX,IAAI,SAAS;EACb,IAAI,YAAY;GACd,SAAS,OAAO,YAAY;GAC5B,SAAS,OAAO,YAAY;EAC9B;EACA,MAAM,QAAQ,iBAAiB,kBAAkB,QAAQ,MAAM;EAC/D,OAAO;GAAE;GAAQ;GAAQ;GAAO;EAAU;CAC5C,CAAC,CAAC,CACD,eAAe,EAAE,cAAc;EAC9B,MAAM,QAAQ,QAAQ,sBAAsB,SAAS;EACrD,MAAM,IAAI,QAAQ,sBAAsB;EACxC,OAAO,MAAM,KAAA,IAAa,SAAS,IAAI,IAAI,IAAK;CAClD,CAAC;AACL;;;;;;;;;;;AAmBA,SAAgB,WAAW,UAAkB,UAA6B,CAAC,GAAG;CAC5E,MAAM,EAAE,QAAQ,MAAM;CACtB,OAAO,aAAa;EAClB,IAAI;EACJ,MAAM;EACN,aAAa,gBAAgB,SAAS,cAAc,QAAQ,IAAI,aAAa,MAAM,UAAU;EAC7F,MAAM;CACR,CAAC,CAAC,CACC,WAAW,OAAO,EAAE,UAAU;EAC7B,MAAM,EAAE,UAAU,iBAAiB,IAAI,MAAM;EAC7C,MAAM,QAAQ,MAAM,QAAO,MAAK,MAAM,QAAQ,CAAC,CAAC;EAChD,OAAO;GAAE;GAAU,eAAe;GAAO,aAAa;GAAO,QAAQ,SAAS;EAAM;CACtF,CAAC,CAAC,CACD,eAAe,EAAE,cAAc;EAC9B,OAAO,QAAQ,sBAAsB,SAAS,IAAI;CACpD,CAAC;AACL;;;;;;;;;;AAWA,SAAgB,WAAW,UAAkB;CAC3C,OAAO,aAAa;EAClB,IAAI;EACJ,MAAM;EACN,aAAa,gBAAgB,SAAS;EACtC,MAAM;CACR,CAAC,CAAC,CACC,WAAW,OAAO,EAAE,UAAU;EAC7B,MAAM,EAAE,UAAU,iBAAiB,IAAI,MAAM;EAC7C,MAAM,QAAQ,MAAM,QAAO,MAAK,MAAM,QAAQ,CAAC,CAAC;EAChD,OAAO;GAAE;GAAU;GAAO,QAAQ,UAAU;EAAE;CAChD,CAAC,CAAC,CACD,eAAe,EAAE,cAAc;EAC9B,OAAO,QAAQ,sBAAsB,SAAS,IAAI;CACpD,CAAC;AACL;;;;;;;;;;AAWA,SAAgB,UAAU,eAAyB;CACjD,OAAO,aAAa;EAClB,IAAI;EACJ,MAAM;EACN,aAAa,4BAA4B,cAAc,KAAK,KAAK,EAAE;EACnE,MAAM;CACR,CAAC,CAAC,CACC,WAAW,OAAO,EAAE,UAAU;EAC7B,MAAM,EAAE,UAAU,iBAAiB,IAAI,MAAM;EAE7C,IAAI,aAAa;EACjB,KAAK,MAAM,QAAQ,OACjB,IAAI,aAAa,cAAc,UAAU,SAAS,cAAc,aAC9D;EAIJ,OAAO;GAAE,aAAa;GAAO;GAAe,QAD7B,eAAe,cAAc;EACO;CACrD,CAAC,CAAC,CACD,eAAe,EAAE,cAAc;EAC9B,OAAO,QAAQ,sBAAsB,SAAS,IAAI;CACpD,CAAC;AACL;;;;;;;;;;AAWA,SAAgB,aAAa,KAAa;CACxC,OAAO,aAAa;EAClB,IAAI;EACJ,MAAM;EACN,aAAa,4BAA4B,IAAI;EAC7C,MAAM;CACR,CAAC,CAAC,CACC,WAAW,OAAO,EAAE,UAAU;EAC7B,MAAM,EAAE,UAAU,iBAAiB,IAAI,MAAM;EAC7C,OAAO;GAAE,OAAO,MAAM;GAAQ;GAAK,QAAQ,MAAM,UAAU;EAAI;CACjE,CAAC,CAAC,CACD,eAAe,EAAE,cAAc;EAC9B,OAAO,QAAQ,sBAAsB,SAAS,IAAI;CACpD,CAAC;AACL;;;;;;;;;;AAWA,SAAgB,cAAc;CAC5B,OAAO,aAAa;EAClB,IAAI;EACJ,MAAM;EACN,aAAa;EACb,MAAM;CACR,CAAC,CAAC,CACC,WAAW,OAAO,EAAE,UAAU;EAC7B,MAAM,EAAE,UAAU,iBAAiB,IAAI,MAAM;EAC7C,OAAO;GAAE,OAAO,MAAM;GAAQ,QAAQ,MAAM,WAAW;EAAE;CAC3D,CAAC,CAAC,CACD,eAAe,EAAE,cAAc;EAC9B,OAAO,QAAQ,sBAAsB,SAAS,IAAI;CACpD,CAAC;AACL;;;;;;;;;;;AAYA,SAAgB,eAAe;CAC7B,OAAO,aAAa;EAClB,IAAI;EACJ,MAAM;EACN,aAAa;EACb,MAAM;CACR,CAAC,CAAC,CACC,WAAW,OAAO,EAAE,UAAU;EAC7B,MAAM,cAAc,sBAAsB,IAAI,MAAM;EACpD,MAAM,aAAa,YAAY,QAAO,QAAO,IAAI,UAAU,UAAW,IAAI,UAAU,IAAI,OAAO,KAAM,CAAC,CAAC;EACvG,OAAO;GAAE;GAAY,YAAY,YAAY;GAAQ,QAAQ,eAAe;EAAE;CAChF,CAAC,CAAC,CACD,eAAe,EAAE,cAAc;EAC9B,OAAO,QAAQ,sBAAsB,SAAS,IAAI;CACpD,CAAC;AACL;AAIA,SAAS,sBAAsB,QAAgD;CAC7E,MAAM,cAAqB,CAAC;CAC5B,KAAK,MAAM,WAAW,QAAQ;EAC5B,MAAM,SAAS,SAAS,SAAS;EACjC,MAAM,YAAY,SACd,KAAA,KACC,SAAS,QAAA,EAAiB,OACvB,QAAQ,MAAW,EAAE,SAAS,iBAAiB,CAAC,CACjD,KAAK,MAAW,EAAE,cAAc;EACvC,KAAK,MAAM,OAAO,UAAU,aAAa,CAAC,GACxC,IAAI,KAAK,YAAY,KAAK,GAAG;CAEjC;CACA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,MAAa,SAAS;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}