@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
@@ -1,626 +0,0 @@
1
- import { RequestContext } from '@mastra/core/request-context';
2
- export { extractTrajectory } from '@mastra/core/evals';
3
-
4
- // src/scorers/utils.ts
5
- function getTextContentFromMastraDBMessage(message) {
6
- const content = message.content;
7
- if (typeof content === "string") {
8
- return content;
9
- }
10
- if (Array.isArray(content)) {
11
- const textParts = content.filter((p) => p.type === "text");
12
- return textParts.length > 0 ? textParts[textParts.length - 1]?.text || "" : "";
13
- }
14
- if (typeof content?.content === "string" && content.content !== "") {
15
- return content.content;
16
- }
17
- if (typeof content?.text === "string" && content.text !== "") {
18
- return content.text;
19
- }
20
- if (content?.parts && Array.isArray(content.parts)) {
21
- const textParts = content.parts.filter((p) => p.type === "text");
22
- return textParts.length > 0 ? textParts[textParts.length - 1]?.text || "" : "";
23
- }
24
- return "";
25
- }
26
- var isRecord = (value) => {
27
- return typeof value === "object" && value !== null;
28
- };
29
- var getTextFromValue = (value) => {
30
- if (typeof value === "string") return value === "" ? void 0 : value;
31
- if (Array.isArray(value)) {
32
- const textParts = value.filter((part) => isRecord(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text);
33
- return textParts.length > 0 ? textParts[textParts.length - 1] : void 0;
34
- }
35
- if (!isRecord(value)) return void 0;
36
- const fromParts = Array.isArray(value.parts) ? getTextFromValue(value.parts) : void 0;
37
- return getTextFromValue(value.content) ?? (typeof value.text === "string" && value.text !== "" ? value.text : void 0) ?? (typeof value.body === "string" && value.body !== "" ? value.body : void 0) ?? fromParts;
38
- };
39
- var isScorerRunInputForAgent = (input) => {
40
- return isRecord(input) && Array.isArray(input.inputMessages) && Array.isArray(input.rememberedMessages) && Array.isArray(input.systemMessages) && isRecord(input.taggedSystemMessages);
41
- };
42
- var isMastraDBMessageLike = (message) => {
43
- return isRecord(message) && typeof message.id === "string" && typeof message.role === "string" && "content" in message && "createdAt" in message;
44
- };
45
- var isScorerRunOutputForAgent = (output) => {
46
- return Array.isArray(output) && output.every(isMastraDBMessageLike);
47
- };
48
- var getEffectiveMessageRole = (message) => {
49
- if (message.role !== "signal") return typeof message.role === "string" ? message.role : void 0;
50
- const signalMeta = isRecord(message.content) && isRecord(message.content.metadata) ? message.content.metadata.signal : void 0;
51
- const tagName = isRecord(signalMeta) && typeof signalMeta.tagName === "string" ? signalMeta.tagName : void 0;
52
- const signalType = isRecord(signalMeta) && typeof signalMeta.type === "string" ? signalMeta.type : void 0;
53
- const topLevelType = typeof message.type === "string" ? message.type : void 0;
54
- return tagName ?? signalType ?? topLevelType;
55
- };
56
- var getTextFromMessages = (messages, role) => {
57
- if (!Array.isArray(messages)) return void 0;
58
- const message = messages.find((message2) => isRecord(message2) && getEffectiveMessageRole(message2) === role);
59
- return message ? getTextFromValue(message) : void 0;
60
- };
61
- var roundToTwoDecimals = (num) => {
62
- return Math.round((num + Number.EPSILON) * 100) / 100;
63
- };
64
- function isCloserTo(value, target1, target2) {
65
- return Math.abs(value - target1) < Math.abs(value - target2);
66
- }
67
- var createTestRun = (input, output, additionalContext, requestContext) => {
68
- return {
69
- input: [{ role: "user", content: input }],
70
- output: { role: "assistant", text: output },
71
- additionalContext: additionalContext ?? {},
72
- requestContext: requestContext ?? {}
73
- };
74
- };
75
- var getUserMessageFromRunInput = (input) => {
76
- if (typeof input === "string") return input;
77
- if (!isRecord(input)) return void 0;
78
- return getTextFromMessages(input.inputMessages, "user") ?? getTextFromMessages(input.messages, "user") ?? (typeof input.prompt === "string" ? input.prompt : void 0) ?? (typeof input.text === "string" ? input.text : void 0) ?? getTextFromValue(input.content) ?? getTextFromValue(input.input) ?? getTextFromValue(input.user);
79
- };
80
- var getSystemMessagesFromRunInput = (input) => {
81
- const systemMessages = [];
82
- if (!isRecord(input)) return systemMessages;
83
- if (Array.isArray(input.systemMessages)) {
84
- systemMessages.push(
85
- ...input.systemMessages.map((msg) => {
86
- if (typeof msg.content === "string") {
87
- return msg.content;
88
- } else if (Array.isArray(msg.content)) {
89
- return msg.content.filter((part) => part.type === "text").map((part) => part.text || "").join(" ");
90
- }
91
- return "";
92
- }).filter((content) => content)
93
- );
94
- }
95
- const addSystemMessages = (messages) => {
96
- if (!Array.isArray(messages)) return;
97
- systemMessages.push(
98
- ...messages.filter((message) => isRecord(message) && message.role === "system").map((message) => getTextFromValue(message)).filter((content) => Boolean(content))
99
- );
100
- };
101
- addSystemMessages(input.inputMessages);
102
- addSystemMessages(input.messages);
103
- if (isRecord(input.taggedSystemMessages)) {
104
- Object.values(input.taggedSystemMessages).forEach((messages) => {
105
- if (!Array.isArray(messages)) return;
106
- messages.forEach((msg) => {
107
- const content = getTextFromValue(msg);
108
- if (content) {
109
- systemMessages.push(content);
110
- }
111
- });
112
- });
113
- }
114
- return systemMessages;
115
- };
116
- var getCombinedSystemPrompt = (input) => {
117
- const systemMessages = getSystemMessagesFromRunInput(input);
118
- return systemMessages.join("\n\n");
119
- };
120
- var getAssistantMessageFromRunOutput = (output) => {
121
- if (typeof output === "string") return output;
122
- if (Array.isArray(output)) return getTextFromMessages(output, "assistant");
123
- if (!isRecord(output)) return void 0;
124
- const isAssistantOutput = output.role === void 0 || output.role === "assistant";
125
- if (isAssistantOutput && typeof output.text === "string") return output.text;
126
- if (isAssistantOutput && typeof output.content === "string") return output.content;
127
- if (isAssistantOutput && (isRecord(output.content) || Array.isArray(output.content))) {
128
- return getTextContentFromMastraDBMessage(output) || getTextContentFromMastraDBMessage(output.content) || void 0;
129
- }
130
- if (output.role === "assistant") return getTextContentFromMastraDBMessage(output) || void 0;
131
- return void 0;
132
- };
133
- var getReasoningFromRunOutput = (output) => {
134
- if (!output) return void 0;
135
- const message = output.find(({ role }) => role === "assistant");
136
- if (!message) return void 0;
137
- if (message.content.reasoning) {
138
- return message.content.reasoning;
139
- }
140
- const reasoningParts = message.content.parts?.filter((p) => p.type === "reasoning");
141
- if (reasoningParts && reasoningParts.length > 0) {
142
- const reasoningTexts = reasoningParts.map((p) => {
143
- if (p.details && Array.isArray(p.details)) {
144
- return p.details.filter((d) => d.type === "text").map((d) => d.text).join("");
145
- }
146
- return p.reasoning || "";
147
- }).filter(Boolean);
148
- return reasoningTexts.length > 0 ? reasoningTexts.join("\n") : void 0;
149
- }
150
- return void 0;
151
- };
152
- var createToolInvocation = ({
153
- toolCallId,
154
- toolName,
155
- args,
156
- result,
157
- state = "result"
158
- }) => {
159
- return {
160
- toolCallId,
161
- toolName,
162
- args,
163
- result,
164
- state
165
- };
166
- };
167
- function createTestMessage({
168
- content,
169
- role,
170
- id = "test-message",
171
- toolInvocations = []
172
- }) {
173
- return {
174
- id,
175
- role,
176
- content: {
177
- format: 2,
178
- parts: [{ type: "text", text: content }],
179
- content,
180
- ...toolInvocations.length > 0 && {
181
- toolInvocations: toolInvocations.map((ti) => ({
182
- toolCallId: ti.toolCallId,
183
- toolName: ti.toolName,
184
- args: ti.args,
185
- result: ti.result,
186
- state: ti.state
187
- }))
188
- }
189
- },
190
- createdAt: /* @__PURE__ */ new Date()
191
- };
192
- }
193
- var createAgentTestRun = ({
194
- inputMessages = [],
195
- output,
196
- rememberedMessages = [],
197
- systemMessages = [],
198
- taggedSystemMessages = {},
199
- requestContext = new RequestContext(),
200
- runId = crypto.randomUUID()
201
- }) => {
202
- return {
203
- input: {
204
- inputMessages,
205
- rememberedMessages,
206
- systemMessages,
207
- taggedSystemMessages
208
- },
209
- output,
210
- requestContext,
211
- runId
212
- };
213
- };
214
- var createTrajectoryTestRun = ({
215
- inputMessages = [],
216
- trajectory,
217
- rememberedMessages = [],
218
- systemMessages = [],
219
- taggedSystemMessages = {},
220
- requestContext = new RequestContext(),
221
- runId = crypto.randomUUID(),
222
- expectedTrajectory
223
- }) => {
224
- return {
225
- input: {
226
- inputMessages,
227
- rememberedMessages,
228
- systemMessages,
229
- taggedSystemMessages
230
- },
231
- output: trajectory,
232
- expectedTrajectory,
233
- requestContext,
234
- runId
235
- };
236
- };
237
- function extractToolCalls(output) {
238
- const toolCalls = [];
239
- const toolCallInfos = [];
240
- for (let messageIndex = 0; messageIndex < output.length; messageIndex++) {
241
- const message = output[messageIndex];
242
- const legacy = message?.content?.toolInvocations;
243
- const fromParts = legacy ? void 0 : message?.content?.parts?.filter((p) => p.type === "tool-invocation").map((p) => p.toolInvocation);
244
- const toolInvocations = legacy ?? fromParts;
245
- if (!toolInvocations?.length) continue;
246
- for (let invocationIndex = 0; invocationIndex < toolInvocations.length; invocationIndex++) {
247
- const invocation = toolInvocations[invocationIndex];
248
- if (invocation && invocation.toolName && (invocation.state === "result" || invocation.state === "call")) {
249
- toolCalls.push(invocation.toolName);
250
- toolCallInfos.push({
251
- toolName: invocation.toolName,
252
- toolCallId: invocation.toolCallId || `${messageIndex}-${invocationIndex}`,
253
- messageIndex,
254
- invocationIndex
255
- });
256
- }
257
- }
258
- }
259
- return { tools: toolCalls, toolCallInfos };
260
- }
261
- var extractInputMessages = (runInput) => {
262
- return runInput?.inputMessages?.map((msg) => getTextContentFromMastraDBMessage(msg)) || [];
263
- };
264
- var extractAgentResponseMessages = (runOutput) => {
265
- return runOutput.filter((msg) => msg.role === "assistant").map((msg) => getTextContentFromMastraDBMessage(msg));
266
- };
267
- function extractToolResults(output) {
268
- const results = [];
269
- for (const message of output) {
270
- const legacy = message?.content?.toolInvocations;
271
- const fromParts = legacy ? void 0 : message?.content?.parts?.filter((p) => p.type === "tool-invocation").map((p) => p.toolInvocation);
272
- const toolInvocations = legacy ?? fromParts;
273
- if (!toolInvocations?.length) continue;
274
- for (const invocation of toolInvocations) {
275
- if (invocation.state === "result" && invocation.result !== void 0) {
276
- results.push({
277
- toolName: invocation.toolName,
278
- toolCallId: invocation.toolCallId || "",
279
- args: invocation.args || {},
280
- result: invocation.result
281
- });
282
- }
283
- }
284
- }
285
- return results;
286
- }
287
- function compareTrajectories(actual, expected, options = {}) {
288
- const { allowRepeatedSteps = true, ordering = "relaxed" } = options;
289
- const normalizedExpected = {
290
- steps: expected.steps
291
- };
292
- if (normalizedExpected.steps.length === 0) {
293
- return {
294
- score: actual.steps.length === 0 ? 1 : 0,
295
- matchedSteps: 0,
296
- totalExpectedSteps: 0,
297
- totalActualSteps: actual.steps.length,
298
- missingSteps: [],
299
- extraSteps: actual.steps.map((s) => s.name),
300
- outOfOrderSteps: [],
301
- repeatedSteps: []
302
- };
303
- }
304
- const actualNames = actual.steps.map((s) => s.name);
305
- const nameCounts = /* @__PURE__ */ new Map();
306
- for (const name of actualNames) {
307
- nameCounts.set(name, (nameCounts.get(name) || 0) + 1);
308
- }
309
- const repeatedSteps = [...nameCounts.entries()].filter(([_, count]) => count > 1).map(([name]) => name);
310
- if (ordering === "strict") {
311
- return compareStrictOrder(actual, normalizedExpected, { allowRepeatedSteps, repeatedSteps });
312
- }
313
- if (ordering === "unordered") {
314
- return compareUnorderedPresence(actual, normalizedExpected, { allowRepeatedSteps, repeatedSteps });
315
- }
316
- return compareRelaxedOrder(actual, normalizedExpected, { allowRepeatedSteps, repeatedSteps });
317
- }
318
- function compareStrictOrder(actual, expected, opts) {
319
- const actualNames = actual.steps.map((s) => s.name);
320
- const expectedNames = expected.steps.map((s) => s.name);
321
- let matchedSteps = 0;
322
- const outOfOrderSteps = [];
323
- const matchedExpectedIndices = /* @__PURE__ */ new Set();
324
- const maxLen = Math.max(actualNames.length, expectedNames.length);
325
- for (let i = 0; i < maxLen; i++) {
326
- const actualName = actualNames[i];
327
- const expectedName = expectedNames[i];
328
- if (actualName === expectedName) {
329
- if (actual.steps[i] && expected.steps[i]) {
330
- if (expectedStepMatches(actual.steps[i], expected.steps[i])) {
331
- matchedSteps++;
332
- matchedExpectedIndices.add(i);
333
- }
334
- } else {
335
- matchedSteps++;
336
- matchedExpectedIndices.add(i);
337
- }
338
- } else if (actualName && expectedNames.includes(actualName)) {
339
- outOfOrderSteps.push(actualName);
340
- }
341
- }
342
- const missingSteps = expectedNames.filter((_, i) => !matchedExpectedIndices.has(i));
343
- const extraSteps = actualNames.filter((name) => !expectedNames.includes(name));
344
- let score = matchedSteps / expected.steps.length;
345
- if (actualNames.length > expectedNames.length) {
346
- const extraPenalty = (actualNames.length - expectedNames.length) / expectedNames.length;
347
- score = Math.max(0, score - extraPenalty * 0.5);
348
- }
349
- if (!opts.allowRepeatedSteps && opts.repeatedSteps.length > 0) {
350
- score = Math.max(0, score - opts.repeatedSteps.length * 0.1);
351
- }
352
- return {
353
- score: roundToTwoDecimals(Math.max(0, Math.min(1, score))),
354
- matchedSteps,
355
- totalExpectedSteps: expected.steps.length,
356
- totalActualSteps: actual.steps.length,
357
- missingSteps,
358
- extraSteps,
359
- outOfOrderSteps,
360
- repeatedSteps: opts.repeatedSteps
361
- };
362
- }
363
- function compareRelaxedOrder(actual, expected, opts) {
364
- const actualNames = actual.steps.map((s) => s.name);
365
- const expectedNames = expected.steps.map((s) => s.name);
366
- let matchedSteps = 0;
367
- let lastMatchedIndex = -1;
368
- const outOfOrderSteps = [];
369
- const matchedExpectedIndices = /* @__PURE__ */ new Set();
370
- for (let i = 0; i < expectedNames.length; i++) {
371
- const expectedName = expectedNames[i];
372
- let found = false;
373
- for (let j = lastMatchedIndex + 1; j < actualNames.length; j++) {
374
- if (actualNames[j] === expectedName) {
375
- if (actual.steps[j] && expected.steps[i]) {
376
- if (expectedStepMatches(actual.steps[j], expected.steps[i])) {
377
- matchedSteps++;
378
- lastMatchedIndex = j;
379
- matchedExpectedIndices.add(i);
380
- found = true;
381
- break;
382
- }
383
- } else {
384
- matchedSteps++;
385
- lastMatchedIndex = j;
386
- matchedExpectedIndices.add(i);
387
- found = true;
388
- break;
389
- }
390
- }
391
- }
392
- if (!found) {
393
- if (actualNames.includes(expectedName)) {
394
- outOfOrderSteps.push(expectedName);
395
- }
396
- }
397
- }
398
- const missingSteps = expectedNames.filter((_, i) => !matchedExpectedIndices.has(i));
399
- const expectedSet = new Set(expectedNames);
400
- const extraSteps = actualNames.filter((name) => !expectedSet.has(name));
401
- let score = matchedSteps / expected.steps.length;
402
- if (!opts.allowRepeatedSteps && opts.repeatedSteps.length > 0) {
403
- score = Math.max(0, score - opts.repeatedSteps.length * 0.1);
404
- }
405
- return {
406
- score: roundToTwoDecimals(Math.max(0, Math.min(1, score))),
407
- matchedSteps,
408
- totalExpectedSteps: expected.steps.length,
409
- totalActualSteps: actual.steps.length,
410
- missingSteps,
411
- extraSteps,
412
- outOfOrderSteps,
413
- repeatedSteps: opts.repeatedSteps
414
- };
415
- }
416
- var COMPARABLE_FIELDS_BY_TYPE = {
417
- tool_call: ["toolArgs", "toolResult", "success"],
418
- mcp_tool_call: ["toolArgs", "toolResult", "mcpServer", "success"],
419
- model_generation: ["modelId", "promptTokens", "completionTokens", "finishReason"],
420
- agent_run: ["agentId"],
421
- workflow_step: ["stepId", "status", "output"],
422
- workflow_run: ["workflowId", "status"],
423
- workflow_conditional: ["conditionCount", "selectedSteps"],
424
- workflow_parallel: ["branchCount", "parallelSteps"],
425
- workflow_loop: ["loopType", "totalIterations"],
426
- workflow_sleep: ["sleepDurationMs", "sleepType"],
427
- workflow_wait_event: ["eventName", "eventReceived"],
428
- processor_run: ["processorId"]
429
- };
430
- function expectedStepMatches(actual, expected) {
431
- if (actual.name !== expected.name) return false;
432
- if (expected.stepType && actual.stepType !== expected.stepType) return false;
433
- if (expected.stepType) {
434
- const fields = COMPARABLE_FIELDS_BY_TYPE[expected.stepType] ?? [];
435
- for (const field of fields) {
436
- const expectedVal = expected[field];
437
- if (expectedVal === void 0) continue;
438
- const actualVal = actual[field];
439
- if (actualVal === void 0) return false;
440
- try {
441
- if (JSON.stringify(actualVal) !== JSON.stringify(expectedVal)) return false;
442
- } catch {
443
- return false;
444
- }
445
- }
446
- }
447
- return true;
448
- }
449
- function compareUnorderedPresence(actual, expected, opts) {
450
- const actualNames = actual.steps.map((s) => s.name);
451
- const expectedNames = expected.steps.map((s) => s.name);
452
- let matchedSteps = 0;
453
- const matchedExpectedIndices = /* @__PURE__ */ new Set();
454
- const usedIndices = /* @__PURE__ */ new Set();
455
- for (let i = 0; i < expected.steps.length; i++) {
456
- const expectedStep = expected.steps[i];
457
- for (let j = 0; j < actual.steps.length; j++) {
458
- if (!usedIndices.has(j) && expectedStepMatches(actual.steps[j], expectedStep)) {
459
- matchedSteps++;
460
- matchedExpectedIndices.add(i);
461
- usedIndices.add(j);
462
- break;
463
- }
464
- }
465
- }
466
- const missingSteps = expectedNames.filter((_, i) => !matchedExpectedIndices.has(i));
467
- const expectedSet = new Set(expectedNames);
468
- const extraSteps = actualNames.filter((name) => !expectedSet.has(name));
469
- let score = matchedSteps / expected.steps.length;
470
- if (!opts.allowRepeatedSteps && opts.repeatedSteps.length > 0) {
471
- score = Math.max(0, score - opts.repeatedSteps.length * 0.1);
472
- }
473
- return {
474
- score: roundToTwoDecimals(Math.max(0, Math.min(1, score))),
475
- matchedSteps,
476
- totalExpectedSteps: expected.steps.length,
477
- totalActualSteps: actual.steps.length,
478
- missingSteps,
479
- extraSteps,
480
- outOfOrderSteps: [],
481
- // ordering not checked in unordered mode
482
- repeatedSteps: opts.repeatedSteps
483
- };
484
- }
485
- function checkTrajectoryEfficiency(trajectory, options = {}) {
486
- const { maxSteps, maxTotalTokens, maxTotalDurationMs, noRedundantCalls = true } = options;
487
- const totalSteps = trajectory.steps.length;
488
- let totalTokens = 0;
489
- for (const step of trajectory.steps) {
490
- if (step.stepType === "model_generation") {
491
- totalTokens += (step.promptTokens ?? 0) + (step.completionTokens ?? 0);
492
- }
493
- }
494
- const totalDurationMs = trajectory.totalDurationMs ?? trajectory.steps.reduce((sum, s) => sum + (s.durationMs ?? 0), 0);
495
- const redundantCalls = [];
496
- if (noRedundantCalls) {
497
- for (let i = 1; i < trajectory.steps.length; i++) {
498
- const prev = trajectory.steps[i - 1];
499
- const curr = trajectory.steps[i];
500
- if (prev.name === curr.name && prev.stepType === curr.stepType && (prev.stepType === "tool_call" || prev.stepType === "mcp_tool_call")) {
501
- const prevArgs = prev.toolArgs;
502
- const currArgs = curr.toolArgs;
503
- try {
504
- if (JSON.stringify(prevArgs) === JSON.stringify(currArgs)) {
505
- redundantCalls.push({ name: curr.name, index: i });
506
- }
507
- } catch {
508
- }
509
- }
510
- }
511
- }
512
- const overStepBudget = maxSteps !== void 0 && totalSteps > maxSteps;
513
- const overTokenBudget = maxTotalTokens !== void 0 && totalTokens > maxTotalTokens;
514
- const overDurationBudget = maxTotalDurationMs !== void 0 && totalDurationMs > maxTotalDurationMs;
515
- const dimensions = [];
516
- if (maxSteps !== void 0) {
517
- dimensions.push(overStepBudget ? Math.max(0, 1 - (totalSteps - maxSteps) / maxSteps) : 1);
518
- }
519
- if (maxTotalTokens !== void 0) {
520
- dimensions.push(overTokenBudget ? Math.max(0, 1 - (totalTokens - maxTotalTokens) / maxTotalTokens) : 1);
521
- }
522
- if (maxTotalDurationMs !== void 0) {
523
- dimensions.push(
524
- overDurationBudget ? Math.max(0, 1 - (totalDurationMs - maxTotalDurationMs) / maxTotalDurationMs) : 1
525
- );
526
- }
527
- if (noRedundantCalls) {
528
- dimensions.push(redundantCalls.length === 0 ? 1 : Math.max(0, 1 - redundantCalls.length * 0.2));
529
- }
530
- const score = dimensions.length > 0 ? dimensions.reduce((a, b) => a + b, 0) / dimensions.length : 1;
531
- return {
532
- score: roundToTwoDecimals(Math.max(0, Math.min(1, score))),
533
- totalSteps,
534
- overStepBudget,
535
- totalTokens,
536
- overTokenBudget,
537
- totalDurationMs,
538
- overDurationBudget,
539
- redundantCalls
540
- };
541
- }
542
- function checkTrajectoryBlacklist(trajectory, options = {}) {
543
- const { blacklistedTools = [], blacklistedSequences = [] } = options;
544
- const violatedTools = [];
545
- const violatedSequences = [];
546
- const stepNames = trajectory.steps.map((s) => s.name);
547
- for (const forbidden of blacklistedTools) {
548
- if (stepNames.includes(forbidden)) {
549
- violatedTools.push(forbidden);
550
- }
551
- }
552
- for (const sequence of blacklistedSequences) {
553
- if (sequence.length === 0) continue;
554
- for (let i = 0; i <= stepNames.length - sequence.length; i++) {
555
- let match = true;
556
- for (let j = 0; j < sequence.length; j++) {
557
- if (stepNames[i + j] !== sequence[j]) {
558
- match = false;
559
- break;
560
- }
561
- }
562
- if (match) {
563
- violatedSequences.push(sequence);
564
- break;
565
- }
566
- }
567
- }
568
- const hasViolations = violatedTools.length > 0 || violatedSequences.length > 0;
569
- return {
570
- score: hasViolations ? 0 : 1,
571
- violatedTools,
572
- violatedSequences
573
- };
574
- }
575
- function analyzeToolFailures(trajectory, options = {}) {
576
- const { maxRetriesPerTool = 2 } = options;
577
- const patterns = [];
578
- let totalRetries = 0;
579
- const toolCallSteps = trajectory.steps.filter((s) => s.stepType === "tool_call" || s.stepType === "mcp_tool_call");
580
- if (toolCallSteps.length === 0) {
581
- return { score: 1, patterns: [], totalRetries: 0, excessiveRetryTools: [] };
582
- }
583
- let i = 0;
584
- while (i < toolCallSteps.length) {
585
- const currentTool = toolCallSteps[i];
586
- let retryCount = 0;
587
- let j = i + 1;
588
- while (j < toolCallSteps.length && toolCallSteps[j].name === currentTool.name) {
589
- const prevStep = toolCallSteps[j - 1];
590
- if (prevStep.success === false) {
591
- retryCount++;
592
- }
593
- j++;
594
- }
595
- if (retryCount > 0) {
596
- const nextDifferentTool = j < toolCallSteps.length ? toolCallSteps[j] : void 0;
597
- const lastRetry = toolCallSteps[j - 1];
598
- const lastSuccess = lastRetry.success !== false;
599
- patterns.push({
600
- toolName: currentTool.name,
601
- retryCount,
602
- fellBackToAlternative: nextDifferentTool !== void 0 && !lastSuccess,
603
- alternativeTool: nextDifferentTool !== void 0 && !lastSuccess ? nextDifferentTool.name : void 0,
604
- eventuallySucceeded: lastSuccess
605
- });
606
- totalRetries += retryCount;
607
- }
608
- i = j;
609
- }
610
- const excessiveRetryTools = patterns.filter((p) => p.retryCount > maxRetriesPerTool).map((p) => p.toolName);
611
- let score = 1;
612
- if (toolCallSteps.length > 0) {
613
- const excessRetries = patterns.reduce((sum, p) => sum + Math.max(0, p.retryCount - maxRetriesPerTool), 0);
614
- score = Math.max(0, 1 - excessRetries * 0.2);
615
- }
616
- return {
617
- score: roundToTwoDecimals(Math.max(0, Math.min(1, score))),
618
- patterns,
619
- totalRetries,
620
- excessiveRetryTools
621
- };
622
- }
623
-
624
- export { analyzeToolFailures, checkTrajectoryBlacklist, checkTrajectoryEfficiency, compareTrajectories, createAgentTestRun, createTestMessage, createTestRun, createToolInvocation, createTrajectoryTestRun, extractAgentResponseMessages, extractInputMessages, extractToolCalls, extractToolResults, getAssistantMessageFromRunOutput, getCombinedSystemPrompt, getReasoningFromRunOutput, getSystemMessagesFromRunInput, getTextContentFromMastraDBMessage, getUserMessageFromRunInput, isCloserTo, isScorerRunInputForAgent, isScorerRunOutputForAgent, roundToTwoDecimals };
625
- //# sourceMappingURL=chunk-UJ4WCQ3F.js.map
626
- //# sourceMappingURL=chunk-UJ4WCQ3F.js.map