@hmharness/evolution 0.14.12 → 0.14.14
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/judge.d.ts +4 -0
- package/dist/judge.js +1 -1
- package/dist/reward-model.d.ts +25 -0
- package/dist/reward-model.js +45 -0
- package/package.json +1 -1
package/dist/judge.d.ts
CHANGED
|
@@ -43,6 +43,10 @@ export declare function runJudgeBatch(opts: {
|
|
|
43
43
|
provider: ProviderConfig;
|
|
44
44
|
modelTag?: string;
|
|
45
45
|
log?: (line: string) => void;
|
|
46
|
+
/** re-judge sessions that carry a HUMAN label too - the 2026-09-21
|
|
47
|
+
* direction: those stars were blind guesses, not ground truth; the
|
|
48
|
+
* judge re-grades them and the judge label takes precedence. */
|
|
49
|
+
includeHumanLabeled?: boolean;
|
|
46
50
|
}): Promise<{
|
|
47
51
|
labeled: number;
|
|
48
52
|
skipped: number;
|
package/dist/judge.js
CHANGED
|
@@ -107,7 +107,7 @@ export async function runJudgeBatch(opts) {
|
|
|
107
107
|
const modelTag = opts.modelTag ?? provider.model;
|
|
108
108
|
const human = await readLabels(home);
|
|
109
109
|
const judged = await readJudgeLabels(home);
|
|
110
|
-
const done = new Set([...human.map((l) => l.session), ...judged.map((l) => l.session)]);
|
|
110
|
+
const done = new Set([...(opts.includeHumanLabeled ? [] : human.map((l) => l.session)), ...judged.map((l) => l.session)]);
|
|
111
111
|
let insights = [];
|
|
112
112
|
try {
|
|
113
113
|
const text = await readFile(join(home, 'insights', 'insights.jsonl'), 'utf8');
|
package/dist/reward-model.d.ts
CHANGED
|
@@ -64,3 +64,28 @@ export declare function exportDpoPairs(labels: HumanLabel[], insights: InsightLi
|
|
|
64
64
|
crossBucketPrefix?: number;
|
|
65
65
|
sources?: Map<string, 'human' | 'judge'>;
|
|
66
66
|
}): DpoPair[];
|
|
67
|
+
/** Deterministic ~80/20 train/eval split by pair identity. Pure. */
|
|
68
|
+
export declare function splitDpoPairs(pairs: DpoPair[], salt?: string): {
|
|
69
|
+
train: DpoPair[];
|
|
70
|
+
eval: DpoPair[];
|
|
71
|
+
};
|
|
72
|
+
/** Leakage/quality audit before training consumes the pairs: empty sides,
|
|
73
|
+
* exact duplicates, and eval pairs whose prompt ALSO appears in train
|
|
74
|
+
* (prompt leakage inflates offline metrics). Pure. */
|
|
75
|
+
export declare function auditDpoPairs(train: DpoPair[], evalP: DpoPair[]): {
|
|
76
|
+
emptyPrompt: number;
|
|
77
|
+
emptyAnswer: number;
|
|
78
|
+
duplicatePairs: number;
|
|
79
|
+
evalPromptsLeakedIntoTrain: number;
|
|
80
|
+
};
|
|
81
|
+
/** The versioned manifest written beside the exported pairs file - the
|
|
82
|
+
* dataset's birth certificate: counts by source, split sizes, audit. */
|
|
83
|
+
export interface DpoManifest {
|
|
84
|
+
version: string;
|
|
85
|
+
pairsTotal: number;
|
|
86
|
+
bySource: Record<string, number>;
|
|
87
|
+
train: number;
|
|
88
|
+
eval: number;
|
|
89
|
+
audit: ReturnType<typeof auditDpoPairs>;
|
|
90
|
+
exportedAt: string;
|
|
91
|
+
}
|
package/dist/reward-model.js
CHANGED
|
@@ -191,3 +191,48 @@ export function exportDpoPairs(labels, insights, taskOf, answerOf, opts = {}) {
|
|
|
191
191
|
}
|
|
192
192
|
return pairs;
|
|
193
193
|
}
|
|
194
|
+
/* ---------------- DPO dataset form (J1 follow-up) ---------------- */
|
|
195
|
+
/** Deterministic zero-dep FNV-1a - the split must not reshuffle between
|
|
196
|
+
* runs: a pair that was in eval yesterday must stay in eval today. */
|
|
197
|
+
function fnv1a(str) {
|
|
198
|
+
let h = 0x811c9dc5;
|
|
199
|
+
for (let i = 0; i < str.length; i++) {
|
|
200
|
+
h ^= str.charCodeAt(i);
|
|
201
|
+
h = (h + (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24)) >>> 0;
|
|
202
|
+
}
|
|
203
|
+
return h >>> 0;
|
|
204
|
+
}
|
|
205
|
+
/** Deterministic ~80/20 train/eval split by pair identity. Pure. */
|
|
206
|
+
export function splitDpoPairs(pairs, salt = 'dpo') {
|
|
207
|
+
const train = [];
|
|
208
|
+
const evalP = [];
|
|
209
|
+
for (const p of pairs) {
|
|
210
|
+
(fnv1a(salt + '|' + p.prompt + '|' + p.chosenSession + '|' + p.rejectedSession) % 5 === 0 ? evalP : train).push(p);
|
|
211
|
+
}
|
|
212
|
+
return { train, eval: evalP };
|
|
213
|
+
}
|
|
214
|
+
/** Leakage/quality audit before training consumes the pairs: empty sides,
|
|
215
|
+
* exact duplicates, and eval pairs whose prompt ALSO appears in train
|
|
216
|
+
* (prompt leakage inflates offline metrics). Pure. */
|
|
217
|
+
export function auditDpoPairs(train, evalP) {
|
|
218
|
+
let emptyPrompt = 0, emptyAnswer = 0;
|
|
219
|
+
const seen = new Set();
|
|
220
|
+
let duplicatePairs = 0;
|
|
221
|
+
for (const p of [...train, ...evalP]) {
|
|
222
|
+
if (!p.prompt.trim())
|
|
223
|
+
emptyPrompt++;
|
|
224
|
+
if (!p.chosen.trim() || !p.rejected.trim())
|
|
225
|
+
emptyAnswer++;
|
|
226
|
+
const key = p.prompt + '\u0000' + p.chosen + '\u0000' + p.rejected;
|
|
227
|
+
if (seen.has(key))
|
|
228
|
+
duplicatePairs++;
|
|
229
|
+
else
|
|
230
|
+
seen.add(key);
|
|
231
|
+
}
|
|
232
|
+
const trainPrompts = new Set(train.map((p) => p.prompt));
|
|
233
|
+
let evalPromptsLeakedIntoTrain = 0;
|
|
234
|
+
for (const p of evalP)
|
|
235
|
+
if (trainPrompts.has(p.prompt))
|
|
236
|
+
evalPromptsLeakedIntoTrain++;
|
|
237
|
+
return { emptyPrompt, emptyAnswer, duplicatePairs, evalPromptsLeakedIntoTrain };
|
|
238
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hmharness/evolution",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.14",
|
|
4
4
|
"description": "hmharness evolution subsystem: persistent memory, insight capture, skill library, and the bench that gives evolution its fitness signal. First-class kernel citizen, not a plugin.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|