@cogitator-ai/evals 0.9.0 → 0.10.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.
- package/README.md +195 -47
- package/dist/datasets/csv-loader.d.ts +5 -0
- package/dist/datasets/csv-loader.d.ts.map +1 -1
- package/dist/datasets/csv-loader.js +18 -0
- package/dist/datasets/csv-loader.js.map +1 -1
- package/dist/eval-builder.d.ts +3 -0
- package/dist/eval-builder.d.ts.map +1 -1
- package/dist/eval-builder.js +7 -0
- package/dist/eval-builder.js.map +1 -1
- package/dist/eval-comparison.d.ts +5 -0
- package/dist/eval-comparison.d.ts.map +1 -1
- package/dist/eval-comparison.js +20 -4
- package/dist/eval-comparison.js.map +1 -1
- package/dist/eval-suite.d.ts +48 -5
- package/dist/eval-suite.d.ts.map +1 -1
- package/dist/eval-suite.js +219 -57
- package/dist/eval-suite.js.map +1 -1
- package/dist/index.d.ts +13 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/matchers.d.ts +68 -0
- package/dist/matchers.d.ts.map +1 -0
- package/dist/matchers.js +112 -0
- package/dist/matchers.js.map +1 -0
- package/dist/metrics/custom.d.ts +19 -7
- package/dist/metrics/custom.d.ts.map +1 -1
- package/dist/metrics/custom.js +5 -0
- package/dist/metrics/custom.js.map +1 -1
- package/dist/metrics/index.d.ts +8 -4
- package/dist/metrics/index.d.ts.map +1 -1
- package/dist/metrics/index.js +4 -2
- package/dist/metrics/index.js.map +1 -1
- package/dist/metrics/llm-judge.d.ts +20 -1
- package/dist/metrics/llm-judge.d.ts.map +1 -1
- package/dist/metrics/llm-judge.js +64 -10
- package/dist/metrics/llm-judge.js.map +1 -1
- package/dist/metrics/matching.d.ts +28 -0
- package/dist/metrics/matching.d.ts.map +1 -0
- package/dist/metrics/matching.js +124 -0
- package/dist/metrics/matching.js.map +1 -0
- package/dist/metrics/retrieval.d.ts +21 -0
- package/dist/metrics/retrieval.d.ts.map +1 -0
- package/dist/metrics/retrieval.js +108 -0
- package/dist/metrics/retrieval.js.map +1 -0
- package/dist/metrics/statistical.d.ts +28 -0
- package/dist/metrics/statistical.d.ts.map +1 -1
- package/dist/metrics/statistical.js +61 -0
- package/dist/metrics/statistical.js.map +1 -1
- package/dist/metrics/tool-calls.d.ts +43 -0
- package/dist/metrics/tool-calls.d.ts.map +1 -0
- package/dist/metrics/tool-calls.js +106 -0
- package/dist/metrics/tool-calls.js.map +1 -0
- package/dist/metrics/types.d.ts +47 -5
- package/dist/metrics/types.d.ts.map +1 -1
- package/dist/metrics/types.js.map +1 -1
- package/dist/reporters/console.d.ts.map +1 -1
- package/dist/reporters/console.js +6 -2
- package/dist/reporters/console.js.map +1 -1
- package/dist/reporters/format.d.ts +6 -0
- package/dist/reporters/format.d.ts.map +1 -1
- package/dist/reporters/format.js +4 -0
- package/dist/reporters/format.js.map +1 -1
- package/dist/reporters/github.d.ts.map +1 -1
- package/dist/reporters/github.js +3 -2
- package/dist/reporters/github.js.map +1 -1
- package/dist/reporters/index.d.ts +34 -21
- package/dist/reporters/index.d.ts.map +1 -1
- package/dist/reporters/index.js.map +1 -1
- package/dist/schema.d.ts +14 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +13 -0
- package/dist/schema.js.map +1 -1
- package/package.json +8 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const VERSION: string;
|
|
2
2
|
export { EvalSuite, isLLMMetric } from './eval-suite.js';
|
|
3
|
-
export type { EvalTarget, EvalTargetContext, EvalProgress, EvalRunOptions, EvalSuiteOptions, EvalSuiteResult, EvalSuiteStats, } from './eval-suite.js';
|
|
3
|
+
export type { EvalTarget, EvalTargetContext, EvalTurn, RetrievalToolResult, EvalProgress, EvalRunOptions, EvalSuiteOptions, EvalSuiteResult, EvalSuiteStats, } from './eval-suite.js';
|
|
4
4
|
export { EvalComparison } from './eval-comparison.js';
|
|
5
5
|
export type { EvalComparisonOptions, EvalComparisonRunOptions, MetricComparison, ComparisonResult, } from './eval-comparison.js';
|
|
6
6
|
export { EvalBuilder } from './eval-builder.js';
|
|
@@ -8,25 +8,30 @@ export { Dataset } from './datasets/index.js';
|
|
|
8
8
|
export { loadJsonl } from './datasets/index.js';
|
|
9
9
|
export { loadCsv } from './datasets/index.js';
|
|
10
10
|
export { exactMatch, contains, containsAll, containsAny, similarity, regex, jsonSchema, } from './metrics/deterministic.js';
|
|
11
|
-
export { faithfulness, relevance, coherence, helpfulness, llmMetric, bindJudgeContext, } from './metrics/llm-judge.js';
|
|
12
|
-
export type { LLMMetricFn, JudgeContext } from './metrics/llm-judge.js';
|
|
13
|
-
export { latency, cost, tokenUsage } from './metrics/statistical.js';
|
|
11
|
+
export { faithfulness, relevance, coherence, helpfulness, llmMetric, contextRelevance, bindJudgeContext, } from './metrics/llm-judge.js';
|
|
12
|
+
export type { LLMMetricFn, JudgeContext, JudgeMessage } from './metrics/llm-judge.js';
|
|
13
|
+
export { latency, cost, tokenUsage, passAtK, passAtKEstimate, isPassAtKMetric, } from './metrics/statistical.js';
|
|
14
|
+
export type { PassAtKOptions, PassAtKMetricFn } from './metrics/statistical.js';
|
|
15
|
+
export { toolCalls, trajectory, toolCallMatches, trajectoryScore } from './metrics/tool-calls.js';
|
|
16
|
+
export type { ToolCallsOptions, TrajectoryOptions, ToolArgumentsMatch, ToolCallsScore, TrajectoryOrder, } from './metrics/tool-calls.js';
|
|
17
|
+
export { retrievalRecall, retrievalPrecision, retrievalMRR, ragSearchPassages, } from './metrics/retrieval.js';
|
|
18
|
+
export { passageMatches } from './metrics/matching.js';
|
|
14
19
|
export { metric } from './metrics/custom.js';
|
|
15
|
-
export type { MetricFn, MetricScore, MetricUsage, MetricOptions, EvalCaseResult, StatisticalMetricFn, StatisticalScore, } from './metrics/types.js';
|
|
16
|
-
export type { CustomMetricConfig } from './metrics/custom.js';
|
|
20
|
+
export type { MetricFn, MetricScore, MetricUsage, MetricOptions, EvalCaseResult, ScoredCaseResult, EvalToolCall, EvalToolResult, EvalTurnResult, Passage, StatisticalMetricFn, StatisticalScore, } from './metrics/types.js';
|
|
21
|
+
export type { CustomMetricConfig, CustomMetricData } from './metrics/custom.js';
|
|
17
22
|
export { threshold } from './assertions/index.js';
|
|
18
23
|
export { noRegression } from './assertions/index.js';
|
|
19
24
|
export { assertion } from './assertions/index.js';
|
|
20
25
|
export { maxErrorRate } from './assertions/index.js';
|
|
21
26
|
export type { AssertionFn, AssertionResult, AggregatedMetric, EvalStats } from './assertions/index.js';
|
|
22
27
|
export { report } from './reporters/index.js';
|
|
23
|
-
export type { ReporterType, ReporterOptions } from './reporters/index.js';
|
|
28
|
+
export type { ReporterType, ReporterOptions, ReportedCase } from './reporters/index.js';
|
|
24
29
|
export { pairedTTest } from './stats/t-test.js';
|
|
25
30
|
export type { TTestResult } from './stats/t-test.js';
|
|
26
31
|
export { mcnemarsTest } from './stats/mcnemar.js';
|
|
27
32
|
export type { McNemarResult } from './stats/mcnemar.js';
|
|
28
33
|
export { mean, median, stdDev, percentile, aggregate } from './stats/percentiles.js';
|
|
29
|
-
export type { EvalCase, EvalSuiteConfig, JudgeConfig, JudgeConfigInput, JudgeCache, JudgeCogitator, EvalComparisonConfig, } from './schema.js';
|
|
34
|
+
export type { EvalCase, ExpectedToolCall, EvalSuiteConfig, JudgeConfig, JudgeConfigInput, JudgeCache, JudgeCogitator, EvalComparisonConfig, } from './schema.js';
|
|
30
35
|
export { createRunEvalTool, evalTools } from './tools.js';
|
|
31
36
|
export type { EvalTool } from './tools.js';
|
|
32
37
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,OAAO,EAAE,MAA4B,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACtD,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,YAAY,EACV,qBAAqB,EACrB,wBAAwB,EACxB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,OAAO,EACL,UAAU,EACV,QAAQ,EACR,WAAW,EACX,WAAW,EACX,UAAU,EACV,KAAK,EACL,UAAU,GACX,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,EACX,SAAS,EACT,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -8,8 +8,11 @@ export { Dataset } from './datasets/index.js';
|
|
|
8
8
|
export { loadJsonl } from './datasets/index.js';
|
|
9
9
|
export { loadCsv } from './datasets/index.js';
|
|
10
10
|
export { exactMatch, contains, containsAll, containsAny, similarity, regex, jsonSchema, } from './metrics/deterministic.js';
|
|
11
|
-
export { faithfulness, relevance, coherence, helpfulness, llmMetric, bindJudgeContext, } from './metrics/llm-judge.js';
|
|
12
|
-
export { latency, cost, tokenUsage } from './metrics/statistical.js';
|
|
11
|
+
export { faithfulness, relevance, coherence, helpfulness, llmMetric, contextRelevance, bindJudgeContext, } from './metrics/llm-judge.js';
|
|
12
|
+
export { latency, cost, tokenUsage, passAtK, passAtKEstimate, isPassAtKMetric, } from './metrics/statistical.js';
|
|
13
|
+
export { toolCalls, trajectory, toolCallMatches, trajectoryScore } from './metrics/tool-calls.js';
|
|
14
|
+
export { retrievalRecall, retrievalPrecision, retrievalMRR, ragSearchPassages, } from './metrics/retrieval.js';
|
|
15
|
+
export { passageMatches } from './metrics/matching.js';
|
|
13
16
|
export { metric } from './metrics/custom.js';
|
|
14
17
|
export { threshold } from './assertions/index.js';
|
|
15
18
|
export { noRegression } from './assertions/index.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAwB,CAAC;AAE7F,MAAM,CAAC,MAAM,OAAO,GAAW,WAAW,CAAC,OAAO,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAwB,CAAC;AAE7F,MAAM,CAAC,MAAM,OAAO,GAAW,WAAW,CAAC,OAAO,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAYtD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAOnD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,OAAO,EACL,UAAU,EACV,QAAQ,EACR,WAAW,EACX,WAAW,EACX,UAAU,EACV,KAAK,EACL,UAAU,GACX,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,OAAO,EACP,IAAI,EACJ,UAAU,EACV,OAAO,EACP,eAAe,EACf,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAQ/F,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAiB1C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAalF,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { TrajectoryOrder } from './metrics/tool-calls.js';
|
|
2
|
+
/** The matchers `evalMatchers` adds to Vitest's `expect`, typed for Vitest 5 */
|
|
3
|
+
export interface EvalMatchers<R = unknown> {
|
|
4
|
+
/**
|
|
5
|
+
* The case result called the tool `name`, over any of its turns, with arguments holding `args`
|
|
6
|
+
* when given (other arguments may be there too)
|
|
7
|
+
*/
|
|
8
|
+
toHaveCalledTool(name: string, args?: Record<string, unknown>): R;
|
|
9
|
+
/**
|
|
10
|
+
* The case result called the tools in `names`. `order: 'exact'` (default): those calls and
|
|
11
|
+
* no others, in this order. `'in-order'`: in this order, other calls may come between.
|
|
12
|
+
* `'any-order'`: each of them, in any order, other calls allowed
|
|
13
|
+
*/
|
|
14
|
+
toFollowTrajectory(names: readonly string[], options?: {
|
|
15
|
+
order?: TrajectoryOrder;
|
|
16
|
+
}): R;
|
|
17
|
+
/**
|
|
18
|
+
* The case result retrieved a passage with this id or this text, or whose text contains this
|
|
19
|
+
* one or is contained in it when the contained text has at least three words
|
|
20
|
+
*/
|
|
21
|
+
toHaveRetrieved(idOrText: string): R;
|
|
22
|
+
/**
|
|
23
|
+
* A case result scored at least `min` on the metric, or a suite result's mean of the metric
|
|
24
|
+
* is at least `min`
|
|
25
|
+
*/
|
|
26
|
+
toScoreAtLeast(metricName: string, min: number): R;
|
|
27
|
+
}
|
|
28
|
+
declare module 'vitest' {
|
|
29
|
+
interface Assertion<R extends void | Promise<void> = void, T = unknown> extends EvalMatchers<R> {
|
|
30
|
+
}
|
|
31
|
+
interface AsymmetricMatchersContaining extends EvalMatchers {
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** The part of Vitest's matcher context the eval matchers use */
|
|
35
|
+
interface MatcherContext {
|
|
36
|
+
isNot: boolean;
|
|
37
|
+
}
|
|
38
|
+
interface MatcherResult {
|
|
39
|
+
pass: boolean;
|
|
40
|
+
message: () => string;
|
|
41
|
+
actual?: unknown;
|
|
42
|
+
expected?: unknown;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Vitest matchers for eval results. Register them once, in a test file or a setup file:
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* import { expect } from 'vitest';
|
|
50
|
+
* import { evalMatchers } from '@cogitator-ai/evals/matchers';
|
|
51
|
+
*
|
|
52
|
+
* expect.extend(evalMatchers);
|
|
53
|
+
*
|
|
54
|
+
* const { results } = await suite.run();
|
|
55
|
+
* expect(results[0]).toHaveCalledTool('get_weather', { city: 'Paris' });
|
|
56
|
+
* expect(results[0]).toFollowTrajectory(['search', 'answer'], { order: 'in-order' });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare const evalMatchers: {
|
|
60
|
+
toHaveCalledTool(this: MatcherContext, received: unknown, name: string, args?: Record<string, unknown>): MatcherResult;
|
|
61
|
+
toFollowTrajectory(this: MatcherContext, received: unknown, names: readonly string[], options?: {
|
|
62
|
+
order?: TrajectoryOrder;
|
|
63
|
+
}): MatcherResult;
|
|
64
|
+
toHaveRetrieved(this: MatcherContext, received: unknown, idOrText: string): MatcherResult;
|
|
65
|
+
toScoreAtLeast(this: MatcherContext, received: unknown, metricName: string, min: number): MatcherResult;
|
|
66
|
+
};
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=matchers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.d.ts","sourceRoot":"","sources":["../src/matchers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAS5D,gFAAgF;AAChF,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC;;;OAGG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAClE;;;;OAIG;IACH,kBAAkB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,eAAe,CAAA;KAAE,GAAG,CAAC,CAAC;IACvF;;;OAGG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;IACrC;;;OAGG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC;CACpD;AAED,OAAO,QAAQ,QAAQ,CAAC;IAEtB,UAAU,SAAS,CAAC,CAAC,SAAS,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,OAAO,CAAE,SAAQ,YAAY,CAAC,CAAC,CAAC;KAAG;IAElG,UAAU,4BAA6B,SAAQ,YAAY;KAAG;CAC/D;AAED,iEAAiE;AACjE,UAAU,cAAc;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA4BD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,YAAY;2BAEf,cAAc,YACV,OAAO,QACX,MAAM,SACL,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,aAAa;6BAgBR,cAAc,YACV,OAAO,SACV,SAAS,MAAM,EAAE,YACf;QAAE,KAAK,CAAC,EAAE,eAAe,CAAA;KAAE,GACnC,aAAa;0BAmBM,cAAc,YAAY,OAAO,YAAY,MAAM,GAAG,aAAa;yBAejF,cAAc,YACV,OAAO,cACL,MAAM,OACb,MAAM,GACV,aAAa;CAUjB,CAAC"}
|
package/dist/matchers.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { trajectoryScore } from './metrics/tool-calls.js';
|
|
2
|
+
import { isSubset, longestCommonSubsequence, multisetOverlap, passageMatches, } from './metrics/matching.js';
|
|
3
|
+
function isRecord(value) {
|
|
4
|
+
return typeof value === 'object' && value !== null;
|
|
5
|
+
}
|
|
6
|
+
function caseResultOf(received, matcher) {
|
|
7
|
+
if (isRecord(received) && isRecord(received.case) && typeof received.output === 'string') {
|
|
8
|
+
return received;
|
|
9
|
+
}
|
|
10
|
+
throw new TypeError(`${matcher} expects a case result, one of suite.run()'s results`);
|
|
11
|
+
}
|
|
12
|
+
function callText(name, args) {
|
|
13
|
+
return args === undefined ? name : `${name}(${JSON.stringify(args)})`;
|
|
14
|
+
}
|
|
15
|
+
function callsText(result) {
|
|
16
|
+
const calls = result.toolCalls ?? [];
|
|
17
|
+
return calls.length === 0
|
|
18
|
+
? 'no tool calls'
|
|
19
|
+
: calls.map((c) => callText(c.name, c.arguments)).join(', ');
|
|
20
|
+
}
|
|
21
|
+
function negation(context) {
|
|
22
|
+
return context.isNot ? 'not ' : '';
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Vitest matchers for eval results. Register them once, in a test file or a setup file:
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { expect } from 'vitest';
|
|
30
|
+
* import { evalMatchers } from '@cogitator-ai/evals/matchers';
|
|
31
|
+
*
|
|
32
|
+
* expect.extend(evalMatchers);
|
|
33
|
+
*
|
|
34
|
+
* const { results } = await suite.run();
|
|
35
|
+
* expect(results[0]).toHaveCalledTool('get_weather', { city: 'Paris' });
|
|
36
|
+
* expect(results[0]).toFollowTrajectory(['search', 'answer'], { order: 'in-order' });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export const evalMatchers = {
|
|
40
|
+
toHaveCalledTool(received, name, args) {
|
|
41
|
+
const result = caseResultOf(received, 'toHaveCalledTool');
|
|
42
|
+
const calls = result.toolCalls ?? [];
|
|
43
|
+
const pass = calls.some((call) => call.name === name && (args === undefined || isSubset(args, call.arguments)));
|
|
44
|
+
return {
|
|
45
|
+
pass,
|
|
46
|
+
message: () => `expected the case ${negation(this)}to call ${callText(name, args)}, it made ${callsText(result)}`,
|
|
47
|
+
actual: calls.map((c) => ({ name: c.name, arguments: c.arguments })),
|
|
48
|
+
expected: { name, ...(args !== undefined && { arguments: args }) },
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
toFollowTrajectory(received, names, options = {}) {
|
|
52
|
+
const result = caseResultOf(received, 'toFollowTrajectory');
|
|
53
|
+
const order = options.order ?? 'exact';
|
|
54
|
+
const actual = (result.toolCalls ?? []).map((c) => c.name);
|
|
55
|
+
const pass = order === 'exact'
|
|
56
|
+
? trajectoryScore(names, actual, 'exact') === 1
|
|
57
|
+
: order === 'in-order'
|
|
58
|
+
? longestCommonSubsequence(names, actual) === names.length
|
|
59
|
+
: multisetOverlap(names, actual) === names.length;
|
|
60
|
+
return {
|
|
61
|
+
pass,
|
|
62
|
+
message: () => `expected the tool calls ${negation(this)}to follow [${names.join(', ')}] (${order}), they were [${actual.join(', ')}]`,
|
|
63
|
+
actual,
|
|
64
|
+
expected: [...names],
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
toHaveRetrieved(received, idOrText) {
|
|
68
|
+
const result = caseResultOf(received, 'toHaveRetrieved');
|
|
69
|
+
const retrieved = result.retrieved ?? [];
|
|
70
|
+
const pass = retrieved.some((p) => passageMatches(p, idOrText));
|
|
71
|
+
const shown = retrieved.map((p) => p.id ?? JSON.stringify(p.content.slice(0, 60)));
|
|
72
|
+
return {
|
|
73
|
+
pass,
|
|
74
|
+
message: () => `expected the case ${negation(this)}to retrieve ${JSON.stringify(idOrText)}, it retrieved ${retrieved.length === 0 ? 'nothing' : `${retrieved.length} passage(s): ${shown.join(', ')}`}`,
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
toScoreAtLeast(received, metricName, min) {
|
|
78
|
+
const { score, of } = metricScoreOf(received, metricName);
|
|
79
|
+
const pass = score >= min;
|
|
80
|
+
return {
|
|
81
|
+
pass,
|
|
82
|
+
message: () => `expected ${of} ${negation(this)}to be at least ${min}, it is ${score}`,
|
|
83
|
+
actual: score,
|
|
84
|
+
expected: min,
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
/** The score a matcher compares: a case result's score of the metric, or a suite's mean of it */
|
|
89
|
+
function metricScoreOf(received, metricName) {
|
|
90
|
+
if (isRecord(received) && isRecord(received.aggregated)) {
|
|
91
|
+
const aggregated = received.aggregated;
|
|
92
|
+
const metric = aggregated[metricName];
|
|
93
|
+
if (!metric) {
|
|
94
|
+
throw new Error(`toScoreAtLeast: the suite has no metric '${metricName}', it has ${namesText(Object.keys(aggregated))}`);
|
|
95
|
+
}
|
|
96
|
+
return { score: metric.mean, of: `the mean of ${metricName}` };
|
|
97
|
+
}
|
|
98
|
+
const result = caseResultOf(received, 'toScoreAtLeast');
|
|
99
|
+
const scores = result.scores ?? [];
|
|
100
|
+
const found = scores.find((s) => s.name === metricName);
|
|
101
|
+
if (!found) {
|
|
102
|
+
throw new Error(`toScoreAtLeast: the case has no score for '${metricName}', it has ${namesText(scores.map((s) => s.name))}`);
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
score: found.score,
|
|
106
|
+
of: `the ${metricName} score of the case${found.details ? ` (${found.details})` : ''}`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function namesText(names) {
|
|
110
|
+
return names.length === 0 ? 'none' : names.map((n) => `'${n}'`).join(', ');
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=matchers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.js","sourceRoot":"","sources":["../src/matchers.ts"],"names":[],"mappings":"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"}
|
package/dist/metrics/custom.d.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import type { MetricFn } from './types.js';
|
|
1
|
+
import type { MetricFn, EvalCaseResult, EvalToolCall, EvalToolResult, EvalTurnResult, Passage } from './types.js';
|
|
2
2
|
export interface CustomMetricConfig {
|
|
3
3
|
name: string;
|
|
4
|
-
evaluate: (data: {
|
|
5
|
-
input: string;
|
|
6
|
-
output: string;
|
|
7
|
-
expected?: string;
|
|
8
|
-
context?: Record<string, unknown>;
|
|
9
|
-
}) => Promise<{
|
|
4
|
+
evaluate: (data: CustomMetricData) => Promise<{
|
|
10
5
|
score: number;
|
|
11
6
|
details?: string;
|
|
12
7
|
}> | {
|
|
@@ -14,6 +9,23 @@ export interface CustomMetricConfig {
|
|
|
14
9
|
details?: string;
|
|
15
10
|
};
|
|
16
11
|
}
|
|
12
|
+
/** What a custom metric's `evaluate` gets about a case */
|
|
13
|
+
export interface CustomMetricData {
|
|
14
|
+
input: string;
|
|
15
|
+
output: string;
|
|
16
|
+
expected?: string;
|
|
17
|
+
context?: Record<string, unknown>;
|
|
18
|
+
/** The tool calls of the run, over every turn */
|
|
19
|
+
toolCalls?: readonly EvalToolCall[];
|
|
20
|
+
/** What the tool calls returned, over every turn */
|
|
21
|
+
toolResults?: readonly EvalToolResult[];
|
|
22
|
+
/** The passages the run retrieved */
|
|
23
|
+
retrieved?: readonly Passage[];
|
|
24
|
+
/** Each turn of a multi-turn case */
|
|
25
|
+
turns?: readonly EvalTurnResult[];
|
|
26
|
+
/** The whole case result, the case itself included */
|
|
27
|
+
result: EvalCaseResult;
|
|
28
|
+
}
|
|
17
29
|
/**
|
|
18
30
|
* A metric from an `evaluate` function. Its score is clamped to 0 - 1. When `evaluate` throws or
|
|
19
31
|
* returns a score that is not a finite number (such as NaN from a division by zero), the metric
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/metrics/custom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/metrics/custom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,cAAc,EACd,cAAc,EACd,OAAO,EACR,MAAM,SAAS,CAAC;AAGjB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,CACR,IAAI,EAAE,gBAAgB,KACnB,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACzF;AAED,0DAA0D;AAC1D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,iDAAiD;IACjD,SAAS,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACpC,oDAAoD;IACpD,WAAW,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IACxC,qCAAqC;IACrC,SAAS,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC/B,qCAAqC;IACrC,KAAK,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAClC,sDAAsD;IACtD,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,QAAQ,CA2C3D"}
|
package/dist/metrics/custom.js
CHANGED
|
@@ -12,6 +12,11 @@ export function metric(config) {
|
|
|
12
12
|
output: result.output,
|
|
13
13
|
expected: result.case.expected,
|
|
14
14
|
context: result.case.context,
|
|
15
|
+
toolCalls: result.toolCalls,
|
|
16
|
+
toolResults: result.toolResults,
|
|
17
|
+
retrieved: result.retrieved,
|
|
18
|
+
turns: result.turns,
|
|
19
|
+
result,
|
|
15
20
|
});
|
|
16
21
|
const invalid = nonFiniteScoreError(score);
|
|
17
22
|
if (invalid) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom.js","sourceRoot":"","sources":["../../src/metrics/custom.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"custom.js","sourceRoot":"","sources":["../../src/metrics/custom.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AA2B9C;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAC,MAA0B;IAC/C,MAAM,EAAE,GAAG,CAAC,KAAK,EAAE,MAAsB,EAAE,EAAE;QAC3C,IAAI,CAAC;YACH,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC;gBAC/C,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK;gBACxB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ;gBAC9B,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO;gBAC5B,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,MAAM;aACP,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC3C,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO;oBACL,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,KAAK,EAAE,CAAC;oBACR,OAAO,EAAE,mBAAmB,OAAO,EAAE;oBACrC,KAAK,EAAE,OAAO;iBACf,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;gBACtC,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,CAAC;aAC1C,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO;gBACL,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,mBAAmB,OAAO,EAAE;gBACrC,KAAK,EAAE,OAAO;aACf,CAAC;QACJ,CAAC;IACH,CAAC,CAAa,CAAC;IAEf,EAAE,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAC5B,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
package/dist/metrics/index.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
export type { MetricScore, MetricUsage, MetricOptions, EvalCaseResult, MetricFn, StatisticalMetricFn, StatisticalScore, } from './types.js';
|
|
1
|
+
export type { MetricScore, MetricUsage, MetricOptions, EvalCaseResult, MetricFn, StatisticalMetricFn, StatisticalScore, ScoredCaseResult, EvalToolCall, EvalToolResult, EvalTurnResult, Passage, } from './types.js';
|
|
2
2
|
export { exactMatch, contains, containsAll, containsAny, similarity, regex, jsonSchema, } from './deterministic.js';
|
|
3
3
|
export { metric } from './custom.js';
|
|
4
|
-
export type { CustomMetricConfig } from './custom.js';
|
|
5
|
-
export { latency, cost, tokenUsage } from './statistical.js';
|
|
6
|
-
export {
|
|
4
|
+
export type { CustomMetricConfig, CustomMetricData } from './custom.js';
|
|
5
|
+
export { latency, cost, tokenUsage, passAtK, passAtKEstimate, isPassAtKMetric, } from './statistical.js';
|
|
6
|
+
export type { PassAtKOptions, PassAtKMetricFn } from './statistical.js';
|
|
7
|
+
export { toolCalls, trajectory, toolCallMatches, trajectoryScore } from './tool-calls.js';
|
|
8
|
+
export type { ToolCallsOptions, TrajectoryOptions, ToolArgumentsMatch, ToolCallsScore, TrajectoryOrder, } from './tool-calls.js';
|
|
9
|
+
export { retrievalRecall, retrievalPrecision, retrievalMRR, ragSearchPassages } from './retrieval.js';
|
|
10
|
+
export { faithfulness, relevance, coherence, helpfulness, contextRelevance, llmMetric, bindJudgeContext, } from './llm-judge.js';
|
|
7
11
|
export type { JudgeContext, LLMMetricFn } from './llm-judge.js';
|
|
8
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,EACd,QAAQ,EACR,mBAAmB,EACnB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,EACd,QAAQ,EACR,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,cAAc,EACd,OAAO,GACR,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,UAAU,EACV,QAAQ,EACR,WAAW,EACX,WAAW,EACX,UAAU,EACV,KAAK,EACL,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACrE,OAAO,EACL,OAAO,EACP,IAAI,EACJ,UAAU,EACV,OAAO,EACP,eAAe,EACf,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACvF,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnG,OAAO,EACL,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,SAAS,EACT,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/metrics/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { exactMatch, contains, containsAll, containsAny, similarity, regex, jsonSchema, } from './deterministic.js';
|
|
2
2
|
export { metric } from './custom.js';
|
|
3
|
-
export { latency, cost, tokenUsage } from './statistical.js';
|
|
4
|
-
export {
|
|
3
|
+
export { latency, cost, tokenUsage, passAtK, passAtKEstimate, isPassAtKMetric, } from './statistical.js';
|
|
4
|
+
export { toolCalls, trajectory, toolCallMatches, trajectoryScore } from './tool-calls.js';
|
|
5
|
+
export { retrievalRecall, retrievalPrecision, retrievalMRR, ragSearchPassages } from './retrieval.js';
|
|
6
|
+
export { faithfulness, relevance, coherence, helpfulness, contextRelevance, llmMetric, bindJudgeContext, } from './llm-judge.js';
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,UAAU,EACV,QAAQ,EACR,WAAW,EACX,WAAW,EACX,UAAU,EACV,KAAK,EACL,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,OAAO,EACL,OAAO,EACP,IAAI,EACJ,UAAU,EACV,OAAO,EACP,eAAe,EACf,eAAe,GAChB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAQvF,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnG,OAAO,EACL,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,SAAS,EACT,gBAAgB,GACjB,MAAM,aAAa,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { JudgeCogitator, JudgeConfig } from '../schema.js';
|
|
2
|
-
import type { MetricFn, MetricOptions, MetricUsage } from './types.js';
|
|
2
|
+
import type { MetricFn, EvalCaseResult, MetricOptions, MetricUsage } from './types.js';
|
|
3
3
|
export interface JudgeContext {
|
|
4
4
|
cogitator: {
|
|
5
5
|
run: (opts: {
|
|
@@ -11,10 +11,18 @@ export interface JudgeContext {
|
|
|
11
11
|
};
|
|
12
12
|
judgeConfig: JudgeConfig;
|
|
13
13
|
}
|
|
14
|
+
/** What the judge is asked about a case, or why the case is not judged and scores 0 */
|
|
15
|
+
export type JudgeMessage = {
|
|
16
|
+
message: string;
|
|
17
|
+
} | {
|
|
18
|
+
skip: string;
|
|
19
|
+
};
|
|
14
20
|
export interface LLMMetricFn extends MetricFn {
|
|
15
21
|
readonly requiresJudge: true;
|
|
16
22
|
readonly __judgeSystemPrompt: string;
|
|
17
23
|
readonly __judgeName: string;
|
|
24
|
+
/** Builds what the judge reads about a case. Default: input, context, expected and response */
|
|
25
|
+
readonly __judgeMessage?: (result: EvalCaseResult) => JudgeMessage;
|
|
18
26
|
}
|
|
19
27
|
/**
|
|
20
28
|
* A judge context that runs the judge as a Cogitator agent on `judgeConfig.model`,
|
|
@@ -22,7 +30,18 @@ export interface LLMMetricFn extends MetricFn {
|
|
|
22
30
|
*/
|
|
23
31
|
export declare function judgeContextFor(cogitator: JudgeCogitator, judgeConfig: JudgeConfig): JudgeContext;
|
|
24
32
|
export declare function bindJudgeContext(metric: LLMMetricFn, context: JudgeContext): MetricFn;
|
|
33
|
+
/**
|
|
34
|
+
* How faithful the response is to the input and the evidence: the passages the run retrieved
|
|
35
|
+
* when the case has any, its `context` otherwise.
|
|
36
|
+
*/
|
|
25
37
|
export declare function faithfulness(opts?: MetricOptions): LLMMetricFn;
|
|
38
|
+
/**
|
|
39
|
+
* Whether the passages the run retrieved are relevant to the input, judged on the input (the
|
|
40
|
+
* conversation for a multi-turn case) and the passages alone (the case's `context` when nothing
|
|
41
|
+
* was retrieved). A case with neither scores 0
|
|
42
|
+
* without a judge call.
|
|
43
|
+
*/
|
|
44
|
+
export declare function contextRelevance(opts?: MetricOptions): LLMMetricFn;
|
|
26
45
|
export declare function relevance(opts?: MetricOptions): LLMMetricFn;
|
|
27
46
|
export declare function coherence(opts?: MetricOptions): LLMMetricFn;
|
|
28
47
|
export declare function helpfulness(opts?: MetricOptions): LLMMetricFn;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm-judge.d.ts","sourceRoot":"","sources":["../../src/metrics/llm-judge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,cAAc,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"llm-judge.d.ts","sourceRoot":"","sources":["../../src/metrics/llm-judge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,cAAc,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EAEd,aAAa,EACb,WAAW,EAEZ,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE;QACT,GAAG,EAAE,CAAC,IAAI,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,WAAW,CAAA;SAAE,CAAC,CAAC;KACpF,CAAC;IACF,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,uFAAuF;AACvF,MAAM,MAAM,YAAY,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAElE,MAAM,WAAW,WAAY,SAAQ,QAAQ;IAC3C,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC;IAC7B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,+FAA+F;IAC/F,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,YAAY,CAAC;CACpE;AAsFD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,GAAG,YAAY,CAyDjG;AAgJD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,GAAG,QAAQ,CA8CrF;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,WAAW,CAM9D;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,WAAW,CAUlE;AAED,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,WAAW,CAK3D;AAED,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,WAAW,CAK3D;AAED,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,WAAW,CAK7D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,CAK7E"}
|
|
@@ -195,7 +195,7 @@ function limiter(limit) {
|
|
|
195
195
|
}
|
|
196
196
|
};
|
|
197
197
|
}
|
|
198
|
-
function createJudgeMetric(name, systemPrompt) {
|
|
198
|
+
function createJudgeMetric(name, systemPrompt, message) {
|
|
199
199
|
const fn = (async (_result) => {
|
|
200
200
|
return { name, score: 0, details: 'unbound judge metric — call bindJudgeContext first' };
|
|
201
201
|
});
|
|
@@ -203,6 +203,8 @@ function createJudgeMetric(name, systemPrompt) {
|
|
|
203
203
|
Object.defineProperty(fn, 'requiresJudge', { value: true, writable: false });
|
|
204
204
|
Object.defineProperty(fn, '__judgeSystemPrompt', { value: systemPrompt, writable: false });
|
|
205
205
|
Object.defineProperty(fn, '__judgeName', { value: name, writable: false });
|
|
206
|
+
if (message)
|
|
207
|
+
Object.defineProperty(fn, '__judgeMessage', { value: message, writable: false });
|
|
206
208
|
return fn;
|
|
207
209
|
}
|
|
208
210
|
function contextText(context) {
|
|
@@ -210,23 +212,57 @@ function contextText(context) {
|
|
|
210
212
|
.map(([key, value]) => `${key}: ${typeof value === 'string' ? value : JSON.stringify(value, null, 2)}`)
|
|
211
213
|
.join('\n');
|
|
212
214
|
}
|
|
215
|
+
function passagesText(passages) {
|
|
216
|
+
return passages
|
|
217
|
+
.map((p, i) => `[${i + 1}]${p.source ? ` (${p.source})` : ''} ${p.content}`)
|
|
218
|
+
.join('\n');
|
|
219
|
+
}
|
|
213
220
|
/**
|
|
214
|
-
*
|
|
215
|
-
*
|
|
221
|
+
* The evidence of a case: its retrieved passages when it has any and `preferRetrieved` is set,
|
|
222
|
+
* else its context, else nothing
|
|
216
223
|
*/
|
|
217
|
-
function
|
|
218
|
-
|
|
224
|
+
function evidenceBlock(result, preferRetrieved) {
|
|
225
|
+
if (preferRetrieved && result.retrieved && result.retrieved.length > 0) {
|
|
226
|
+
return `Retrieved passages:\n${passagesText(result.retrieved)}`;
|
|
227
|
+
}
|
|
219
228
|
const context = result.case.context;
|
|
220
|
-
|
|
221
|
-
|
|
229
|
+
return context && Object.keys(context).length > 0
|
|
230
|
+
? `Context:\n${contextText(context)}`
|
|
231
|
+
: undefined;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* What the response answers. A single-turn case: its input. A multi-turn case: the conversation
|
|
235
|
+
* before the last user message, each turn's input and answer, then that last message marked as
|
|
236
|
+
* the one the response replies to.
|
|
237
|
+
*/
|
|
238
|
+
function inputBlock(result) {
|
|
239
|
+
const inputs = [result.case.input, ...(result.case.turns ?? [])];
|
|
240
|
+
if (inputs.length === 1)
|
|
241
|
+
return `Input: ${result.case.input}`;
|
|
242
|
+
const earlier = inputs
|
|
243
|
+
.slice(0, -1)
|
|
244
|
+
.map((input, i) => `User: ${input}\nAssistant: ${result.turns?.[i]?.output ?? ''}`);
|
|
245
|
+
return `Conversation so far:\n${earlier.join('\n')}\nInput (the last user message, which the response answers): ${inputs[inputs.length - 1]}`;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* What the judge reads: the input (the conversation for a multi-turn case), the case's evidence when it has some (its context, or the
|
|
249
|
+
* retrieved passages for metrics that prefer them), the expected answer and the response.
|
|
250
|
+
*/
|
|
251
|
+
function buildUserMessage(result, preferRetrieved = false) {
|
|
252
|
+
const expected = result.case.expected || 'N/A';
|
|
253
|
+
const evidence = evidenceBlock(result, preferRetrieved);
|
|
254
|
+
const evidenceText = evidence === undefined ? '' : `\n${evidence}`;
|
|
255
|
+
return `${inputBlock(result)}${evidenceText}\nExpected: ${expected}\nResponse: ${result.output}`;
|
|
222
256
|
}
|
|
223
257
|
export function bindJudgeContext(metric, context) {
|
|
224
258
|
const name = metric.__judgeName;
|
|
225
259
|
const systemPrompt = metric.__judgeSystemPrompt;
|
|
226
260
|
const bound = (async (result) => {
|
|
227
261
|
try {
|
|
228
|
-
const
|
|
229
|
-
|
|
262
|
+
const message = metric.__judgeMessage?.(result) ?? { message: buildUserMessage(result) };
|
|
263
|
+
if ('skip' in message)
|
|
264
|
+
return { name, score: 0, details: message.skip };
|
|
265
|
+
const prompt = `${systemPrompt}\n\n${message.message}`;
|
|
230
266
|
const runResult = await context.cogitator.run({ input: prompt });
|
|
231
267
|
const usage = usageOf(runResult.usage);
|
|
232
268
|
const parsed = parseJudgeOutput(runResult.output);
|
|
@@ -260,8 +296,26 @@ export function bindJudgeContext(metric, context) {
|
|
|
260
296
|
Object.defineProperty(bound, 'metricName', { value: name, writable: false });
|
|
261
297
|
return bound;
|
|
262
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* How faithful the response is to the input and the evidence: the passages the run retrieved
|
|
301
|
+
* when the case has any, its `context` otherwise.
|
|
302
|
+
*/
|
|
263
303
|
export function faithfulness(opts) {
|
|
264
|
-
return createJudgeMetric(opts?.name ?? 'faithfulness', 'You are evaluating the faithfulness of an AI assistant\'s response.\n\nGiven the input, the context when there
|
|
304
|
+
return createJudgeMetric(opts?.name ?? 'faithfulness', 'You are evaluating the faithfulness of an AI assistant\'s response.\n\nGiven the input, the context or retrieved passages when there are some, and the response, rate how faithful the response is to the facts and information in the input and the context. Claims that neither supports count against it.\n\nScore from 0.0 (completely unfaithful) to 1.0 (perfectly faithful).\n\nRespond with JSON: {"score": <number>, "reasoning": "<explanation>"}', (result) => ({ message: buildUserMessage(result, true) }));
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Whether the passages the run retrieved are relevant to the input, judged on the input (the
|
|
308
|
+
* conversation for a multi-turn case) and the passages alone (the case's `context` when nothing
|
|
309
|
+
* was retrieved). A case with neither scores 0
|
|
310
|
+
* without a judge call.
|
|
311
|
+
*/
|
|
312
|
+
export function contextRelevance(opts) {
|
|
313
|
+
return createJudgeMetric(opts?.name ?? 'contextRelevance', 'You are evaluating the context an AI assistant retrieved to answer a request.\n\nGiven the input and the retrieved passages (or context), rate how relevant they are to the input: whether they hold the information needed to answer it, with little that is off topic.\n\nScore from 0.0 (completely irrelevant) to 1.0 (perfectly relevant).\n\nRespond with JSON: {"score": <number>, "reasoning": "<explanation>"}', (result) => {
|
|
314
|
+
const evidence = evidenceBlock(result, true);
|
|
315
|
+
if (evidence === undefined)
|
|
316
|
+
return { skip: 'no retrieved passages or context to judge' };
|
|
317
|
+
return { message: `${inputBlock(result)}\n${evidence}` };
|
|
318
|
+
});
|
|
265
319
|
}
|
|
266
320
|
export function relevance(opts) {
|
|
267
321
|
return createJudgeMetric(opts?.name ?? 'relevance', 'You are evaluating the relevance of an AI assistant\'s response.\n\nGiven the input and the response, rate how relevant the response is to the question asked.\n\nScore from 0.0 (completely irrelevant) to 1.0 (perfectly relevant).\n\nRespond with JSON: {"score": <number>, "reasoning": "<explanation>"}');
|