jev-recipes 0.9.6 → 0.9.7
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.
|
@@ -142,9 +142,9 @@ export declare function compare(baseline: EvaluationRun, candidate: EvaluationRu
|
|
|
142
142
|
}[];
|
|
143
143
|
thresholdEvaluation: string;
|
|
144
144
|
thresholds: {
|
|
145
|
+
readyAccuracy: number | null;
|
|
145
146
|
minConfidence: number;
|
|
146
147
|
deferRate: number | null;
|
|
147
|
-
readyAccuracy: number | null;
|
|
148
148
|
readyCases: number;
|
|
149
149
|
reviewCases: number;
|
|
150
150
|
failedCases: number;
|
|
@@ -225,9 +225,9 @@ export declare function compare(baseline: EvaluationRun, candidate: EvaluationRu
|
|
|
225
225
|
}[];
|
|
226
226
|
thresholdEvaluation: string;
|
|
227
227
|
thresholds: {
|
|
228
|
+
readyAccuracy: number | null;
|
|
228
229
|
minConfidence: number;
|
|
229
230
|
deferRate: number | null;
|
|
230
|
-
readyAccuracy: number | null;
|
|
231
231
|
readyCases: number;
|
|
232
232
|
reviewCases: number;
|
|
233
233
|
failedCases: number;
|
|
@@ -328,9 +328,9 @@ export declare function compare(baseline: EvaluationRun, candidate: EvaluationRu
|
|
|
328
328
|
}[];
|
|
329
329
|
thresholdEvaluation: string;
|
|
330
330
|
thresholds: {
|
|
331
|
+
readyAccuracy: number | null;
|
|
331
332
|
minConfidence: number;
|
|
332
333
|
deferRate: number | null;
|
|
333
|
-
readyAccuracy: number | null;
|
|
334
334
|
readyCases: number;
|
|
335
335
|
reviewCases: number;
|
|
336
336
|
failedCases: number;
|
|
@@ -411,9 +411,9 @@ export declare function compare(baseline: EvaluationRun, candidate: EvaluationRu
|
|
|
411
411
|
}[];
|
|
412
412
|
thresholdEvaluation: string;
|
|
413
413
|
thresholds: {
|
|
414
|
+
readyAccuracy: number | null;
|
|
414
415
|
minConfidence: number;
|
|
415
416
|
deferRate: number | null;
|
|
416
|
-
readyAccuracy: number | null;
|
|
417
417
|
readyCases: number;
|
|
418
418
|
reviewCases: number;
|
|
419
419
|
failedCases: number;
|
|
@@ -29,9 +29,9 @@ export declare function buildReport(id: string, rows: EvaluationRow[], confidenc
|
|
|
29
29
|
}[];
|
|
30
30
|
thresholdEvaluation: string;
|
|
31
31
|
thresholds: {
|
|
32
|
+
readyAccuracy: number | null;
|
|
32
33
|
minConfidence: number;
|
|
33
34
|
deferRate: number | null;
|
|
34
|
-
readyAccuracy: number | null;
|
|
35
35
|
readyCases: number;
|
|
36
36
|
reviewCases: number;
|
|
37
37
|
failedCases: number;
|
|
@@ -112,9 +112,9 @@ export declare function buildReport(id: string, rows: EvaluationRow[], confidenc
|
|
|
112
112
|
}[];
|
|
113
113
|
thresholdEvaluation: string;
|
|
114
114
|
thresholds: {
|
|
115
|
+
readyAccuracy: number | null;
|
|
115
116
|
minConfidence: number;
|
|
116
117
|
deferRate: number | null;
|
|
117
|
-
readyAccuracy: number | null;
|
|
118
118
|
readyCases: number;
|
|
119
119
|
reviewCases: number;
|
|
120
120
|
failedCases: number;
|
|
@@ -1,26 +1,34 @@
|
|
|
1
1
|
import { isRecord, roundedTo } from './decisions.js';
|
|
2
2
|
import { matchesExpected } from './comparison.js';
|
|
3
|
+
import { resultMetadataSchema } from '../src/schema.js';
|
|
3
4
|
export function buildReport(id, rows, confidenceThresholds, price, evidence) {
|
|
4
5
|
const completed = rows.filter((row) => row.error === undefined);
|
|
5
6
|
const ready = completed.filter((row) => row.ready);
|
|
6
|
-
const
|
|
7
|
+
const thresholdEvaluations = confidenceThresholds.map((minConfidence) => {
|
|
7
8
|
const decisions = completed
|
|
8
9
|
.flatMap((row) => row.decisions)
|
|
9
10
|
.filter((decision) => decision.minConfidence === minConfidence);
|
|
10
11
|
const accepted = decisions.filter((decision) => decision.ready);
|
|
12
|
+
const correctReadyCases = accepted.filter((decision) => decision.correct).length;
|
|
11
13
|
return {
|
|
12
14
|
minConfidence,
|
|
13
15
|
deferRate: completed.length
|
|
14
16
|
? roundedTo(3, (completed.length - accepted.length) / completed.length)
|
|
15
17
|
: null,
|
|
16
|
-
readyAccuracy:
|
|
18
|
+
readyAccuracy: accepted.length ? correctReadyCases / accepted.length : null,
|
|
17
19
|
readyCases: accepted.length,
|
|
18
20
|
reviewCases: completed.length - accepted.length,
|
|
19
21
|
failedCases: rows.length - completed.length,
|
|
20
|
-
readyAccuracyInterval95: wilsonInterval(
|
|
22
|
+
readyAccuracyInterval95: wilsonInterval(correctReadyCases, accepted.length),
|
|
21
23
|
};
|
|
22
24
|
});
|
|
23
|
-
const
|
|
25
|
+
const suggestedMinConfidence = thresholdEvaluations.find((entry) => entry.readyAccuracy !== null && entry.readyAccuracy >= 0.95)?.minConfidence ?? null;
|
|
26
|
+
const thresholds = thresholdEvaluations.map((threshold) => ({
|
|
27
|
+
...threshold,
|
|
28
|
+
readyAccuracy: threshold.readyAccuracy === null ? null : roundedTo(3, threshold.readyAccuracy),
|
|
29
|
+
}));
|
|
30
|
+
const usage = summarizeUsage(rows);
|
|
31
|
+
const cost = estimateKnownCost(usage, price);
|
|
24
32
|
const models = [...new Set(rows.flatMap((row) => (row.model ? [row.model] : [])))].sort();
|
|
25
33
|
return {
|
|
26
34
|
...(evidence ? { evidence } : {}),
|
|
@@ -60,21 +68,10 @@ export function buildReport(id, rows, confidenceThresholds, price, evidence) {
|
|
|
60
68
|
? 'recipe-replay'
|
|
61
69
|
: 'not-applicable',
|
|
62
70
|
thresholds,
|
|
63
|
-
suggestedMinConfidence
|
|
64
|
-
?.minConfidence ?? null,
|
|
71
|
+
suggestedMinConfidence,
|
|
65
72
|
latencyMs: latencyOf(rows.map((row) => row.durationMs)),
|
|
66
73
|
usage,
|
|
67
|
-
cost
|
|
68
|
-
usage.models.every((model) => model === price.model) &&
|
|
69
|
-
usage.unknownResponses === 0 &&
|
|
70
|
-
usage.failedRequests === 0
|
|
71
|
-
? {
|
|
72
|
-
...price,
|
|
73
|
-
estimated: roundedTo(8, (usage.input_tokens * price.inputPerMillion +
|
|
74
|
-
usage.output_tokens * price.outputPerMillion) /
|
|
75
|
-
1_000_000),
|
|
76
|
-
}
|
|
77
|
-
: null,
|
|
74
|
+
cost,
|
|
78
75
|
confusion: confusionOf(rows),
|
|
79
76
|
failures: rows
|
|
80
77
|
.filter((row) => !row.correct)
|
|
@@ -126,7 +123,7 @@ function latencyOf(values) {
|
|
|
126
123
|
totalCaseTime: roundedTo(2, values.reduce((sum, value) => sum + value, 0)),
|
|
127
124
|
};
|
|
128
125
|
}
|
|
129
|
-
function
|
|
126
|
+
function summarizeUsage(rows) {
|
|
130
127
|
let input_tokens = 0, output_tokens = 0, unknownResponses = 0, failedRequests = 0;
|
|
131
128
|
const models = new Set();
|
|
132
129
|
const exchanges = rows.flatMap((row) => row.exchanges);
|
|
@@ -135,18 +132,17 @@ function usageOf(rows) {
|
|
|
135
132
|
failedRequests++;
|
|
136
133
|
continue;
|
|
137
134
|
}
|
|
138
|
-
const response = exchange.response;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (!
|
|
142
|
-
!isRecord(response.usage) ||
|
|
143
|
-
typeof response.usage.input_tokens !== 'number' ||
|
|
144
|
-
typeof response.usage.output_tokens !== 'number') {
|
|
135
|
+
const response = isRecord(exchange.response) ? exchange.response : {};
|
|
136
|
+
const usage = resultMetadataSchema.shape.usage.safeParse(response.usage);
|
|
137
|
+
const model = resultMetadataSchema.shape.model.safeParse(response.model);
|
|
138
|
+
if (!usage.success || !model.success)
|
|
145
139
|
unknownResponses++;
|
|
140
|
+
if (model.success)
|
|
141
|
+
models.add(model.data);
|
|
142
|
+
if (!usage.success)
|
|
146
143
|
continue;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
output_tokens += response.usage.output_tokens;
|
|
144
|
+
input_tokens += usage.data.input_tokens;
|
|
145
|
+
output_tokens += usage.data.output_tokens;
|
|
150
146
|
}
|
|
151
147
|
return {
|
|
152
148
|
requests: exchanges.length,
|
|
@@ -157,6 +153,18 @@ function usageOf(rows) {
|
|
|
157
153
|
models: [...models].sort(),
|
|
158
154
|
};
|
|
159
155
|
}
|
|
156
|
+
function estimateKnownCost(usage, price) {
|
|
157
|
+
if (!price ||
|
|
158
|
+
usage.unknownResponses > 0 ||
|
|
159
|
+
usage.failedRequests > 0 ||
|
|
160
|
+
usage.models.some((model) => model !== price.model))
|
|
161
|
+
return null;
|
|
162
|
+
return {
|
|
163
|
+
...price,
|
|
164
|
+
estimated: roundedTo(8, (usage.input_tokens * price.inputPerMillion + usage.output_tokens * price.outputPerMillion) /
|
|
165
|
+
1_000_000),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
160
168
|
function confusionOf(rows) {
|
|
161
169
|
const byExpected = new Map();
|
|
162
170
|
for (const row of rows) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jev-recipes",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.7",
|
|
4
4
|
"description": "248 small Jev decisions for JavaScript and TypeScript: route, rerank, gate, grade, compare, and label text for agents, RAG, support, code review, and music. Each returns a typed result with explicit uncertainty. Plug into Vercel AI SDK or LangChain agents, import one recipe, or run the CLI with JSON from any language.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|