@mastra/evals 1.10.2-alpha.0 → 1.10.2-alpha.1
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/dist/{checks-DGTgg-nW.cjs → checks-CGRgwpDb.cjs} +20 -9
- package/dist/checks-CGRgwpDb.cjs.map +1 -0
- package/dist/{checks-64AonnEK.js → checks-DX9-p5w0.js} +21 -10
- package/dist/checks-DX9-p5w0.js.map +1 -0
- package/dist/checks.cjs +1 -1
- package/dist/checks.js +1 -1
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/scorers/code/checks/index.d.ts +5 -2
- package/dist/scorers/code/checks/index.d.ts.map +1 -1
- package/dist/scorers/prebuilt/index.cjs +1 -1
- package/dist/scorers/prebuilt/index.js +1 -1
- package/dist/scorers/utils.cjs +91 -16
- package/dist/scorers/utils.cjs.map +1 -1
- package/dist/scorers/utils.d.ts +72 -10
- package/dist/scorers/utils.d.ts.map +1 -1
- package/dist/scorers/utils.js +91 -17
- package/dist/scorers/utils.js.map +1 -1
- package/package.json +4 -4
- package/dist/checks-64AonnEK.js.map +0 -1
- package/dist/checks-DGTgg-nW.cjs.map +0 -1
|
@@ -323,8 +323,11 @@ function usedNoTools() {
|
|
|
323
323
|
});
|
|
324
324
|
}
|
|
325
325
|
/**
|
|
326
|
-
* Scores 1 if none of the tool invocations resulted in an error
|
|
327
|
-
*
|
|
326
|
+
* Scores 1 if none of the tool invocations resulted in an error.
|
|
327
|
+
*
|
|
328
|
+
* Treats every failure representation a native run can persist as an error: a
|
|
329
|
+
* thrown call (`state: 'output-error'`), an incomplete call (`state: 'call'`), a
|
|
330
|
+
* result the executor flagged with `isError`, and a result carrying an `error` field.
|
|
328
331
|
*
|
|
329
332
|
* @example
|
|
330
333
|
* ```ts
|
|
@@ -340,7 +343,7 @@ function noToolErrors() {
|
|
|
340
343
|
type: "agent"
|
|
341
344
|
}).preprocess(async ({ run }) => {
|
|
342
345
|
const invocations = extractRawInvocations(run.output);
|
|
343
|
-
const errorCount = invocations.filter(
|
|
346
|
+
const errorCount = invocations.filter(isErrorInvocation).length;
|
|
344
347
|
return {
|
|
345
348
|
errorCount,
|
|
346
349
|
totalCalls: invocations.length,
|
|
@@ -350,13 +353,21 @@ function noToolErrors() {
|
|
|
350
353
|
return results.preprocessStepResult?.passed ? 1 : 0;
|
|
351
354
|
});
|
|
352
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* True when an invocation represents a tool failure rather than a success.
|
|
358
|
+
*
|
|
359
|
+
* A natively thrown tool call is persisted as `state: 'output-error'` with
|
|
360
|
+
* `errorText`, so keying only on `state: 'call'` or `result.error` lets it pass.
|
|
361
|
+
* `isError` is set alongside `state: 'result'` when the executor reported a failure
|
|
362
|
+
* even though the result carries no `error` field; core's `extractTrajectory`
|
|
363
|
+
* likewise defines success as `state === 'result' && isError !== true`.
|
|
364
|
+
*/
|
|
365
|
+
function isErrorInvocation(inv) {
|
|
366
|
+
return inv.state === "call" || inv.state === "output-error" || inv.isError === true || Boolean(inv.result?.error);
|
|
367
|
+
}
|
|
353
368
|
function extractRawInvocations(output) {
|
|
354
369
|
const invocations = [];
|
|
355
|
-
for (const message of output)
|
|
356
|
-
const legacy = message?.content?.toolInvocations;
|
|
357
|
-
const fromParts = legacy ? void 0 : (message?.content)?.parts?.filter((p) => p.type === "tool-invocation").map((p) => p.toolInvocation);
|
|
358
|
-
for (const inv of legacy ?? fromParts ?? []) if (inv) invocations.push(inv);
|
|
359
|
-
}
|
|
370
|
+
for (const message of output) for (const inv of require_scorers_utils.mergeToolInvocations(message)) if (inv) invocations.push(inv);
|
|
360
371
|
return invocations;
|
|
361
372
|
}
|
|
362
373
|
/**
|
|
@@ -476,4 +487,4 @@ Object.defineProperty(exports, "usedNoTools", {
|
|
|
476
487
|
}
|
|
477
488
|
});
|
|
478
489
|
|
|
479
|
-
//# sourceMappingURL=checks-
|
|
490
|
+
//# sourceMappingURL=checks-CGRgwpDb.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checks-CGRgwpDb.cjs","names":["getTextContentFromMastraDBMessage","stringSimilarity","extractToolCalls","mergeToolInvocations"],"sources":["../src/scorers/code/checks/index.ts"],"sourcesContent":["import { createScorer } from '@mastra/core/evals';\nimport stringSimilarity from 'string-similarity';\nimport { extractToolCalls, getTextContentFromMastraDBMessage, mergeToolInvocations } 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.\n *\n * Treats every failure representation a native run can persist as an error: a\n * thrown call (`state: 'output-error'`), an incomplete call (`state: 'call'`), a\n * result the executor flagged with `isError`, and a result carrying an `error` field.\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(isErrorInvocation).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\n/**\n * True when an invocation represents a tool failure rather than a success.\n *\n * A natively thrown tool call is persisted as `state: 'output-error'` with\n * `errorText`, so keying only on `state: 'call'` or `result.error` lets it pass.\n * `isError` is set alongside `state: 'result'` when the executor reported a failure\n * even though the result carries no `error` field; core's `extractTrajectory`\n * likewise defines success as `state === 'result' && isError !== true`.\n */\nfunction isErrorInvocation(inv: any): boolean {\n return inv.state === 'call' || inv.state === 'output-error' || inv.isError === true || Boolean(inv.result?.error);\n}\n\nfunction extractRawInvocations(output: Parameters<typeof extractToolCalls>[0]) {\n const invocations: any[] = [];\n for (const message of output) {\n // Merge both storage forms so a call present only in `content.parts` — which is\n // where thrown calls live — is never hidden by a legacy `toolInvocations` array.\n for (const inv of mergeToolInvocations(message)) {\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":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { extractToolCalls, getTextContentFromMastraDBMessage } from "./scorers/utils.js";
|
|
1
|
+
import { extractToolCalls, getTextContentFromMastraDBMessage, mergeToolInvocations } from "./scorers/utils.js";
|
|
2
2
|
import { createScorer } from "@mastra/core/evals";
|
|
3
3
|
import stringSimilarity from "string-similarity";
|
|
4
4
|
//#region src/scorers/code/checks/index.ts
|
|
@@ -300,8 +300,11 @@ function usedNoTools() {
|
|
|
300
300
|
});
|
|
301
301
|
}
|
|
302
302
|
/**
|
|
303
|
-
* Scores 1 if none of the tool invocations resulted in an error
|
|
304
|
-
*
|
|
303
|
+
* Scores 1 if none of the tool invocations resulted in an error.
|
|
304
|
+
*
|
|
305
|
+
* Treats every failure representation a native run can persist as an error: a
|
|
306
|
+
* thrown call (`state: 'output-error'`), an incomplete call (`state: 'call'`), a
|
|
307
|
+
* result the executor flagged with `isError`, and a result carrying an `error` field.
|
|
305
308
|
*
|
|
306
309
|
* @example
|
|
307
310
|
* ```ts
|
|
@@ -317,7 +320,7 @@ function noToolErrors() {
|
|
|
317
320
|
type: "agent"
|
|
318
321
|
}).preprocess(async ({ run }) => {
|
|
319
322
|
const invocations = extractRawInvocations(run.output);
|
|
320
|
-
const errorCount = invocations.filter(
|
|
323
|
+
const errorCount = invocations.filter(isErrorInvocation).length;
|
|
321
324
|
return {
|
|
322
325
|
errorCount,
|
|
323
326
|
totalCalls: invocations.length,
|
|
@@ -327,13 +330,21 @@ function noToolErrors() {
|
|
|
327
330
|
return results.preprocessStepResult?.passed ? 1 : 0;
|
|
328
331
|
});
|
|
329
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* True when an invocation represents a tool failure rather than a success.
|
|
335
|
+
*
|
|
336
|
+
* A natively thrown tool call is persisted as `state: 'output-error'` with
|
|
337
|
+
* `errorText`, so keying only on `state: 'call'` or `result.error` lets it pass.
|
|
338
|
+
* `isError` is set alongside `state: 'result'` when the executor reported a failure
|
|
339
|
+
* even though the result carries no `error` field; core's `extractTrajectory`
|
|
340
|
+
* likewise defines success as `state === 'result' && isError !== true`.
|
|
341
|
+
*/
|
|
342
|
+
function isErrorInvocation(inv) {
|
|
343
|
+
return inv.state === "call" || inv.state === "output-error" || inv.isError === true || Boolean(inv.result?.error);
|
|
344
|
+
}
|
|
330
345
|
function extractRawInvocations(output) {
|
|
331
346
|
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
|
-
}
|
|
347
|
+
for (const message of output) for (const inv of mergeToolInvocations(message)) if (inv) invocations.push(inv);
|
|
337
348
|
return invocations;
|
|
338
349
|
}
|
|
339
350
|
/**
|
|
@@ -376,4 +387,4 @@ const checks = {
|
|
|
376
387
|
//#endregion
|
|
377
388
|
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
389
|
|
|
379
|
-
//# sourceMappingURL=checks-
|
|
390
|
+
//# sourceMappingURL=checks-DX9-p5w0.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checks-DX9-p5w0.js","names":[],"sources":["../src/scorers/code/checks/index.ts"],"sourcesContent":["import { createScorer } from '@mastra/core/evals';\nimport stringSimilarity from 'string-similarity';\nimport { extractToolCalls, getTextContentFromMastraDBMessage, mergeToolInvocations } 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.\n *\n * Treats every failure representation a native run can persist as an error: a\n * thrown call (`state: 'output-error'`), an incomplete call (`state: 'call'`), a\n * result the executor flagged with `isError`, and a result carrying an `error` field.\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(isErrorInvocation).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\n/**\n * True when an invocation represents a tool failure rather than a success.\n *\n * A natively thrown tool call is persisted as `state: 'output-error'` with\n * `errorText`, so keying only on `state: 'call'` or `result.error` lets it pass.\n * `isError` is set alongside `state: 'result'` when the executor reported a failure\n * even though the result carries no `error` field; core's `extractTrajectory`\n * likewise defines success as `state === 'result' && isError !== true`.\n */\nfunction isErrorInvocation(inv: any): boolean {\n return inv.state === 'call' || inv.state === 'output-error' || inv.isError === true || Boolean(inv.result?.error);\n}\n\nfunction extractRawInvocations(output: Parameters<typeof extractToolCalls>[0]) {\n const invocations: any[] = [];\n for (const message of output) {\n // Merge both storage forms so a call present only in `content.parts` — which is\n // where thrown calls live — is never hidden by a legacy `toolInvocations` array.\n for (const inv of mergeToolInvocations(message)) {\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;;;;;;;;;;;;;;AAeA,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,OAAO,iBAAiB,CAAC,CAAC;EACzD,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;;;;;;;;;;AAaA,SAAS,kBAAkB,KAAmB;CAC5C,OAAO,IAAI,UAAU,UAAU,IAAI,UAAU,kBAAkB,IAAI,YAAY,QAAQ,QAAQ,IAAI,QAAQ,KAAK;AAClH;AAEA,SAAS,sBAAsB,QAAgD;CAC7E,MAAM,cAAqB,CAAC;CAC5B,KAAK,MAAM,WAAW,QAGpB,KAAK,MAAM,OAAO,qBAAqB,OAAO,GAC5C,IAAI,KAAK,YAAY,KAAK,GAAG;CAGjC,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,MAAa,SAAS;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
|
package/dist/checks.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_checks = require("./checks-
|
|
2
|
+
const require_checks = require("./checks-CGRgwpDb.cjs");
|
|
3
3
|
exports.calledTool = require_checks.calledTool;
|
|
4
4
|
exports.checks = require_checks.checks;
|
|
5
5
|
exports.didNotCall = require_checks.didNotCall;
|
package/dist/checks.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as excludes, c as maxToolCalls, d as toolOrder, f as usedNoTools, i as equals, l as noToolErrors, n as checks, o as includes, r as didNotCall, s as matches, t as calledTool, u as similarity } from "./checks-
|
|
1
|
+
import { a as excludes, c as maxToolCalls, d as toolOrder, f as usedNoTools, i as equals, l as noToolErrors, n as checks, o as includes, r as didNotCall, s as matches, t as calledTool, u as similarity } from "./checks-DX9-p5w0.js";
|
|
2
2
|
export { calledTool, checks, didNotCall, equals, excludes, includes, matches, maxToolCalls, noToolErrors, similarity, toolOrder, usedNoTools };
|
package/dist/docs/SKILL.md
CHANGED
|
@@ -160,8 +160,11 @@ export declare function usedNoTools(): import("@mastra/core/evals").MastraScorer
|
|
|
160
160
|
passed: boolean;
|
|
161
161
|
}> & Record<"generateScoreStepResult", number>>;
|
|
162
162
|
/**
|
|
163
|
-
* Scores 1 if none of the tool invocations resulted in an error
|
|
164
|
-
*
|
|
163
|
+
* Scores 1 if none of the tool invocations resulted in an error.
|
|
164
|
+
*
|
|
165
|
+
* Treats every failure representation a native run can persist as an error: a
|
|
166
|
+
* thrown call (`state: 'output-error'`), an incomplete call (`state: 'call'`), a
|
|
167
|
+
* result the executor flagged with `isError`, and a result carrying an `error` field.
|
|
165
168
|
*
|
|
166
169
|
* @example
|
|
167
170
|
* ```ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/scorers/code/checks/index.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,6CAA6C;IAC7C,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;;;;gDAuBvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;;;;gDAuBvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;;;;gDAuBrE;AAED,MAAM,WAAW,cAAc;IAC7B,uGAAuG;IACvG,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB;;;;gDAoBpE;AAED,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB;;;;;gDA0B3E;AAID,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB;;;;;gDAgB3E;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM;;;;gDAe1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,aAAa,EAAE,MAAM,EAAE;;;;gDAsBhD;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM;;;;gDAcvC;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW;;;gDAc1B;AAED
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/scorers/code/checks/index.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,6CAA6C;IAC7C,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;;;;gDAuBvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;;;;gDAuBvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;;;;gDAuBrE;AAED,MAAM,WAAW,cAAc;IAC7B,uGAAuG;IACvG,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB;;;;gDAoBpE;AAED,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB;;;;;gDA0B3E;AAID,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB;;;;;gDAgB3E;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM;;;;gDAe1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,aAAa,EAAE,MAAM,EAAE;;;;gDAsBhD;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM;;;;gDAcvC;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW;;;gDAc1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY;;;;gDAe3B;AA+BD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;CAYlB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_checks = require("../../checks-
|
|
2
|
+
const require_checks = require("../../checks-CGRgwpDb.cjs");
|
|
3
3
|
const require_scorers_utils = require("../utils.cjs");
|
|
4
4
|
let _mastra_core_evals = require("@mastra/core/evals");
|
|
5
5
|
let compromise = require("compromise");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { analyzeToolFailures, checkTrajectoryBlacklist, checkTrajectoryEfficiency, compareTrajectories, extractAgentResponseMessages, extractToolCalls, getAssistantMessageFromRunOutput, getCombinedSystemPrompt, getConversationHistoryFromRunInput, getTextContentFromMastraDBMessage, getUserMessageFromRunInput, isScorerRunInputForAgent, isScorerRunOutputForAgent, roundToTwoDecimals } from "../utils.js";
|
|
2
|
-
import { a as excludes, c as maxToolCalls, d as toolOrder, f as usedNoTools, i as equals, l as noToolErrors, n as checks, o as includes, r as didNotCall, s as matches, t as calledTool, u as similarity } from "../../checks-
|
|
2
|
+
import { a as excludes, c as maxToolCalls, d as toolOrder, f as usedNoTools, i as equals, l as noToolErrors, n as checks, o as includes, r as didNotCall, s as matches, t as calledTool, u as similarity } from "../../checks-DX9-p5w0.js";
|
|
3
3
|
import { createScorer } from "@mastra/core/evals";
|
|
4
4
|
import nlp from "compromise";
|
|
5
5
|
import keyword_extractor from "keyword-extractor";
|
package/dist/scorers/utils.cjs
CHANGED
|
@@ -352,8 +352,10 @@ const getReasoningFromRunOutput = (output) => {
|
|
|
352
352
|
* @param options.toolCallId - Unique identifier for the tool call
|
|
353
353
|
* @param options.toolName - Name of the tool being called
|
|
354
354
|
* @param options.args - Arguments passed to the tool
|
|
355
|
-
* @param options.result - Result returned by the tool
|
|
355
|
+
* @param options.result - Result returned by the tool (absent for a thrown call)
|
|
356
356
|
* @param options.state - State of the invocation (default: 'result')
|
|
357
|
+
* @param options.errorText - Error text recorded when a tool threw (`state: 'output-error'`)
|
|
358
|
+
* @param options.isError - Set alongside `state: 'result'` when the executor reported a failure
|
|
357
359
|
* @returns A tool invocation object
|
|
358
360
|
*
|
|
359
361
|
* @example
|
|
@@ -364,15 +366,26 @@ const getReasoningFromRunOutput = (output) => {
|
|
|
364
366
|
* args: { location: 'London' },
|
|
365
367
|
* result: { temperature: 20, condition: 'sunny' },
|
|
366
368
|
* });
|
|
369
|
+
*
|
|
370
|
+
* // A tool that threw
|
|
371
|
+
* const thrown = createToolInvocation({
|
|
372
|
+
* toolCallId: 'call-456',
|
|
373
|
+
* toolName: 'saveTool',
|
|
374
|
+
* args: { value: 'x' },
|
|
375
|
+
* state: 'output-error',
|
|
376
|
+
* errorText: 'Save failed',
|
|
377
|
+
* });
|
|
367
378
|
* ```
|
|
368
379
|
*/
|
|
369
|
-
const createToolInvocation = ({ toolCallId, toolName, args, result, state = "result" }) => {
|
|
380
|
+
const createToolInvocation = ({ toolCallId, toolName, args, result, state = "result", errorText, isError }) => {
|
|
370
381
|
return {
|
|
371
382
|
toolCallId,
|
|
372
383
|
toolName,
|
|
373
384
|
args,
|
|
374
385
|
result,
|
|
375
|
-
state
|
|
386
|
+
state,
|
|
387
|
+
...errorText !== void 0 && { errorText },
|
|
388
|
+
...isError !== void 0 && { isError }
|
|
376
389
|
};
|
|
377
390
|
};
|
|
378
391
|
/**
|
|
@@ -406,15 +419,34 @@ const createToolInvocation = ({ toolCallId, toolName, args, result, state = "res
|
|
|
406
419
|
* state: 'result',
|
|
407
420
|
* }],
|
|
408
421
|
* });
|
|
422
|
+
*
|
|
423
|
+
* // With native V2 parts — the only form that can carry a thrown call
|
|
424
|
+
* const messageWithThrownTool = createTestMessage({
|
|
425
|
+
* content: 'That failed.',
|
|
426
|
+
* role: 'assistant',
|
|
427
|
+
* parts: [
|
|
428
|
+
* { type: 'text', text: 'That failed.' },
|
|
429
|
+
* {
|
|
430
|
+
* type: 'tool-invocation',
|
|
431
|
+
* toolInvocation: createToolInvocation({
|
|
432
|
+
* toolCallId: 'call-2',
|
|
433
|
+
* toolName: 'saveTool',
|
|
434
|
+
* args: { value: 'x' },
|
|
435
|
+
* state: 'output-error',
|
|
436
|
+
* errorText: 'Save failed',
|
|
437
|
+
* }),
|
|
438
|
+
* },
|
|
439
|
+
* ],
|
|
440
|
+
* });
|
|
409
441
|
* ```
|
|
410
442
|
*/
|
|
411
|
-
function createTestMessage({ content, role, id = "test-message", toolInvocations = [] }) {
|
|
443
|
+
function createTestMessage({ content, role, id = "test-message", toolInvocations = [], parts }) {
|
|
412
444
|
return {
|
|
413
445
|
id,
|
|
414
446
|
role,
|
|
415
447
|
content: {
|
|
416
448
|
format: 2,
|
|
417
|
-
parts: [{
|
|
449
|
+
parts: parts ?? [{
|
|
418
450
|
type: "text",
|
|
419
451
|
text: content
|
|
420
452
|
}],
|
|
@@ -503,10 +535,56 @@ const createTrajectoryTestRun = ({ inputMessages = [], trajectory, rememberedMes
|
|
|
503
535
|
};
|
|
504
536
|
};
|
|
505
537
|
/**
|
|
538
|
+
* Merges the two places a message can store tool invocations into one list.
|
|
539
|
+
*
|
|
540
|
+
* A native message may carry `content.parts` tool-invocation entries, the legacy
|
|
541
|
+
* `content.toolInvocations` array, or both. Neither form is a superset of the
|
|
542
|
+
* other: thrown calls are recorded in parts as `state: 'output-error'` and can be
|
|
543
|
+
* missing from the legacy array, while older persisted messages may only carry the
|
|
544
|
+
* legacy array. Reading one form exclusively therefore hides real calls.
|
|
545
|
+
*
|
|
546
|
+
* Parts win when the same `toolCallId` appears in both, since they hold the real
|
|
547
|
+
* terminal state. Legacy-only calls are retained before their next shared anchor so
|
|
548
|
+
* compatible call order survives instead of being appended.
|
|
549
|
+
*
|
|
550
|
+
* Mirrors `extractTrajectory` in `@mastra/core` (`packages/core/src/evals/types.ts`)
|
|
551
|
+
* so tool-use checks and trajectory scorers agree on what a run actually called.
|
|
552
|
+
* Keep the two in step.
|
|
553
|
+
*
|
|
554
|
+
* @param message - A single message from the scorer run output
|
|
555
|
+
* @returns The merged tool invocations for that message
|
|
556
|
+
*/
|
|
557
|
+
function mergeToolInvocations(message) {
|
|
558
|
+
const legacy = message?.content?.toolInvocations;
|
|
559
|
+
const fromParts = message?.content?.parts?.filter((p) => p.type === "tool-invocation").map((p) => p.toolInvocation).filter(Boolean) ?? [];
|
|
560
|
+
const partCallIds = new Set(fromParts.map((invocation) => invocation.toolCallId).filter(Boolean));
|
|
561
|
+
const legacyInvocations = legacy ?? [];
|
|
562
|
+
const legacyPositions = new Map(legacyInvocations.map((invocation, index) => [invocation?.toolCallId, index]));
|
|
563
|
+
const toolInvocations = [];
|
|
564
|
+
let legacyIndex = 0;
|
|
565
|
+
for (const invocation of fromParts) {
|
|
566
|
+
const sharedIndex = invocation.toolCallId ? legacyPositions.get(invocation.toolCallId) : void 0;
|
|
567
|
+
if (sharedIndex !== void 0 && sharedIndex >= legacyIndex) {
|
|
568
|
+
for (; legacyIndex < sharedIndex; legacyIndex++) {
|
|
569
|
+
const previous = legacyInvocations[legacyIndex];
|
|
570
|
+
if (previous && !partCallIds.has(previous.toolCallId)) toolInvocations.push(previous);
|
|
571
|
+
}
|
|
572
|
+
legacyIndex++;
|
|
573
|
+
}
|
|
574
|
+
toolInvocations.push(invocation);
|
|
575
|
+
}
|
|
576
|
+
for (; legacyIndex < legacyInvocations.length; legacyIndex++) {
|
|
577
|
+
const invocation = legacyInvocations[legacyIndex];
|
|
578
|
+
if (invocation && !partCallIds.has(invocation.toolCallId)) toolInvocations.push(invocation);
|
|
579
|
+
}
|
|
580
|
+
return toolInvocations;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
506
583
|
* Extracts all tool calls from a scorer run output.
|
|
507
584
|
*
|
|
508
|
-
* Iterates through all messages and their tool invocations to collect
|
|
509
|
-
*
|
|
585
|
+
* Iterates through all messages and their tool invocations to collect information
|
|
586
|
+
* about tools that were called. A call counts regardless of outcome, so the states
|
|
587
|
+
* `'result'`, `'call'`, and `'output-error'` (a tool that threw) are all included.
|
|
510
588
|
*
|
|
511
589
|
* @param output - The scorer run output (array of MastraDBMessage)
|
|
512
590
|
* @returns An object containing tool names and detailed tool call info
|
|
@@ -528,13 +606,11 @@ function extractToolCalls(output) {
|
|
|
528
606
|
const toolCallInfos = [];
|
|
529
607
|
for (let messageIndex = 0; messageIndex < output.length; messageIndex++) {
|
|
530
608
|
const message = output[messageIndex];
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
const toolInvocations = legacy ?? fromParts;
|
|
534
|
-
if (!toolInvocations?.length) continue;
|
|
609
|
+
const toolInvocations = mergeToolInvocations(message);
|
|
610
|
+
if (!toolInvocations.length) continue;
|
|
535
611
|
for (let invocationIndex = 0; invocationIndex < toolInvocations.length; invocationIndex++) {
|
|
536
612
|
const invocation = toolInvocations[invocationIndex];
|
|
537
|
-
if (invocation && invocation.toolName && (invocation.state === "result" || invocation.state === "call")) {
|
|
613
|
+
if (invocation && invocation.toolName && (invocation.state === "result" || invocation.state === "call" || invocation.state === "output-error")) {
|
|
538
614
|
toolCalls.push(invocation.toolName);
|
|
539
615
|
toolCallInfos.push({
|
|
540
616
|
toolName: invocation.toolName,
|
|
@@ -616,10 +692,8 @@ const extractAgentResponseMessages = (runOutput) => {
|
|
|
616
692
|
function extractToolResults(output) {
|
|
617
693
|
const results = [];
|
|
618
694
|
for (const message of output) {
|
|
619
|
-
const
|
|
620
|
-
|
|
621
|
-
const toolInvocations = legacy ?? fromParts;
|
|
622
|
-
if (!toolInvocations?.length) continue;
|
|
695
|
+
const toolInvocations = mergeToolInvocations(message);
|
|
696
|
+
if (!toolInvocations.length) continue;
|
|
623
697
|
for (const invocation of toolInvocations) if (invocation.state === "result" && invocation.result !== void 0) results.push({
|
|
624
698
|
toolName: invocation.toolName,
|
|
625
699
|
toolCallId: invocation.toolCallId || "",
|
|
@@ -1030,6 +1104,7 @@ exports.getUserMessageFromRunInput = getUserMessageFromRunInput;
|
|
|
1030
1104
|
exports.isCloserTo = isCloserTo;
|
|
1031
1105
|
exports.isScorerRunInputForAgent = isScorerRunInputForAgent;
|
|
1032
1106
|
exports.isScorerRunOutputForAgent = isScorerRunOutputForAgent;
|
|
1107
|
+
exports.mergeToolInvocations = mergeToolInvocations;
|
|
1033
1108
|
exports.roundToTwoDecimals = roundToTwoDecimals;
|
|
1034
1109
|
|
|
1035
1110
|
//# sourceMappingURL=utils.cjs.map
|