@hviana/sema 0.5.8 → 0.6.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/AGENTS.md +43 -4
- package/DATASETS.md +160 -0
- package/README.md +12 -0
- package/dist/example/train_base/cache.d.ts +35 -0
- package/dist/example/train_base/cache.js +211 -0
- package/dist/example/train_base/config.d.ts +21 -0
- package/dist/example/train_base/config.js +94 -0
- package/dist/example/train_base/corpora/aya.d.ts +19 -0
- package/dist/example/train_base/corpora/aya.js +76 -0
- package/dist/example/train_base/corpora/converted-parquet.d.ts +14 -0
- package/dist/example/train_base/corpora/converted-parquet.js +44 -0
- package/dist/example/train_base/corpora/genknow.d.ts +14 -0
- package/dist/example/train_base/corpora/genknow.js +83 -0
- package/dist/example/train_base/corpora/index.d.ts +29 -0
- package/dist/example/train_base/corpora/index.js +81 -0
- package/dist/example/train_base/corpora/massive.d.ts +7 -0
- package/dist/example/train_base/corpora/massive.js +98 -0
- package/dist/example/train_base/corpora/oasst2.d.ts +52 -0
- package/dist/example/train_base/corpora/oasst2.js +120 -0
- package/dist/example/train_base/corpora/smolsent.d.ts +23 -0
- package/dist/example/train_base/corpora/smolsent.js +156 -0
- package/dist/example/train_base/corpora/soda.d.ts +12 -0
- package/dist/example/train_base/corpora/soda.js +113 -0
- package/dist/example/train_base/corpora/taskmaster.d.ts +15 -0
- package/dist/example/train_base/corpora/taskmaster.js +144 -0
- package/dist/example/train_base/corpora/wiki2.d.ts +23 -0
- package/dist/example/train_base/corpora/wiki2.js +132 -0
- package/dist/example/train_base/corpus.d.ts +88 -0
- package/dist/example/train_base/corpus.js +65 -0
- package/dist/example/train_base/discovery.d.ts +48 -0
- package/dist/example/train_base/discovery.js +143 -0
- package/dist/example/train_base/http.d.ts +82 -0
- package/dist/example/train_base/http.js +219 -0
- package/dist/example/train_base/items.d.ts +46 -0
- package/dist/example/train_base/items.js +98 -0
- package/dist/example/train_base/main.d.ts +4 -0
- package/dist/example/train_base/main.js +207 -0
- package/dist/example/train_base/progress.d.ts +34 -0
- package/dist/example/train_base/progress.js +114 -0
- package/dist/example/train_base/readers.d.ts +125 -0
- package/dist/example/train_base/readers.js +391 -0
- package/dist/example/train_base/runtime.d.ts +115 -0
- package/dist/example/train_base/runtime.js +637 -0
- package/dist/example/train_base/stage.d.ts +3 -0
- package/dist/example/train_base/stage.js +246 -0
- package/dist/example/train_base/ui.d.ts +88 -0
- package/dist/example/train_base/ui.js +272 -0
- package/dist/src/geometry.d.ts +20 -0
- package/dist/src/geometry.js +22 -0
- package/dist/src/mind/attention.d.ts +6 -0
- package/dist/src/mind/attention.js +44 -4
- package/dist/src/mind/learning.js +134 -50
- package/dist/src/mind/mechanisms/cast.js +45 -1
- package/dist/src/mind/mind.d.ts +7 -2
- package/dist/src/mind/mind.js +15 -3
- package/dist/src/mind/reasoning.js +59 -5
- package/dist/src/mind/recognition.js +29 -3
- package/dist/src/mind/traverse.d.ts +16 -0
- package/dist/src/mind/traverse.js +18 -0
- package/dist/src/store-sqlite.d.ts +4 -0
- package/dist/src/store-sqlite.js +47 -0
- package/dist/src/store.d.ts +7 -0
- package/example/train_base/cache.ts +251 -0
- package/example/train_base/config.ts +128 -0
- package/example/train_base/corpora/aya.ts +106 -0
- package/example/train_base/corpora/converted-parquet.ts +64 -0
- package/example/train_base/corpora/genknow.ts +114 -0
- package/example/train_base/corpora/index.ts +88 -0
- package/example/train_base/corpora/massive.ts +111 -0
- package/example/train_base/corpora/oasst2.ts +163 -0
- package/example/train_base/corpora/smolsent.ts +203 -0
- package/example/train_base/corpora/soda.ts +130 -0
- package/example/train_base/corpora/taskmaster.ts +217 -0
- package/example/train_base/corpora/wiki2.ts +190 -0
- package/example/train_base/corpus.ts +150 -0
- package/example/train_base/discovery.ts +203 -0
- package/example/train_base/http.ts +284 -0
- package/example/train_base/items.ts +118 -0
- package/example/train_base/main.ts +240 -0
- package/example/train_base/progress.ts +149 -0
- package/example/train_base/readers.ts +505 -0
- package/example/train_base/runtime.ts +894 -0
- package/example/train_base/stage.ts +276 -0
- package/example/train_base/ui.ts +333 -0
- package/jsr.json +1 -1
- package/package.json +2 -4
- package/src/geometry.ts +23 -0
- package/src/mind/attention.ts +54 -1
- package/src/mind/learning.ts +137 -43
- package/src/mind/mechanisms/cast.ts +48 -1
- package/src/mind/mind.ts +13 -2
- package/src/mind/reasoning.ts +64 -5
- package/src/mind/recognition.ts +29 -3
- package/src/mind/traverse.ts +19 -0
- package/src/store-sqlite.ts +53 -0
- package/src/store.ts +28 -0
- package/test/13-conversation.test.mjs +1 -1
- package/test/29-counterfactual.test.mjs +43 -6
- package/test/77-company-saturation.test.mjs +302 -0
- package/test/78-atom-hub-recognition-cliff.test.mjs +135 -0
- package/test/84-composed-answer-honesty.test.mjs +137 -0
- package/test/85-answered-directly.test.mjs +126 -0
- package/test/86-cast-voices-committed.test.mjs +164 -0
- package/test/87-codominant-commitment.test.mjs +250 -0
- package/test/88-dependency-footprint.test.mjs +99 -0
- package/dist/example/train_base.d.ts +0 -93
- package/dist/example/train_base.js +0 -2269
- package/example/train_base.ts +0 -2735
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// train_base/corpora/aya.ts — CohereLabs/aya_dataset prompt→completion pairs
|
|
2
|
+
//
|
|
3
|
+
// Knobs, the row adapter, and the stage descriptor for ONE corpus, together
|
|
4
|
+
// with the evidence that fixed each default. A corpus file owns everything
|
|
5
|
+
// source-specific; the contract it fills is ../corpus.ts and the loop that runs
|
|
6
|
+
// it is ../stage.ts.
|
|
7
|
+
import { env } from "../config.js";
|
|
8
|
+
import { refineItems } from "../items.js";
|
|
9
|
+
import { parquet } from "../readers.js";
|
|
10
|
+
import { singleUnit } from "../corpus.js";
|
|
11
|
+
// ── CohereLabs/aya_dataset (the second training stage, after SmolSent) ──
|
|
12
|
+
// The Aya Dataset is ~204k HUMAN-annotated prompt→completion pairs across 70+
|
|
13
|
+
// languages, each a clean (inputs → targets) fact in a named language. It ships
|
|
14
|
+
// ONLY as Snappy-compressed Parquet (no JSONL/CSV). We DOWNLOAD the one train
|
|
15
|
+
// Parquet file and read it row-group by row-group with `hyparquet` (a pure-JS,
|
|
16
|
+
// dependency-free Parquet reader) + `hyparquet-compressors` (Snappy) over a
|
|
17
|
+
// web-standard Blob byte source — no whole-file-in-memory load. AYA=0 disables
|
|
18
|
+
// the stage; AYA_URL overrides the Parquet source.
|
|
19
|
+
const AYA = env("AYA", "1") !== "0";
|
|
20
|
+
const AYA_URL = env("AYA_URL", "https://huggingface.co/datasets/CohereLabs/aya_dataset/resolve/main/data/train-00000-of-00001.parquet");
|
|
21
|
+
// A single Aya field this many chars or longer is skipped: inputs/targets range
|
|
22
|
+
// up to ~3.3M chars, and a multi-MB "pair" is documentation/dump noise, not a
|
|
23
|
+
// cognitive example.
|
|
24
|
+
const MAX_AYA_FIELD_CHARS = Math.max(10_000, Math.floor(Number(env("MAX_AYA_FIELD_KB", "256")) * 1000) || 256_000);
|
|
25
|
+
/** Normalize a raw datasets-server row object into an AyaRow, or null when it
|
|
26
|
+
* lacks a usable prompt/answer or a field is implausibly large (a dump, not a
|
|
27
|
+
* cognitive example). Trims surrounding whitespace; keeps inner text verbatim
|
|
28
|
+
* (human prose, possibly multi-paragraph). */
|
|
29
|
+
export function toAyaRow(row, maxChars = MAX_AYA_FIELD_CHARS) {
|
|
30
|
+
if (!row || typeof row !== "object")
|
|
31
|
+
return null;
|
|
32
|
+
const r = row;
|
|
33
|
+
const inputs = typeof r.inputs === "string" ? r.inputs.trim() : "";
|
|
34
|
+
const targets = typeof r.targets === "string" ? r.targets.trim() : "";
|
|
35
|
+
if (!inputs || !targets)
|
|
36
|
+
return null;
|
|
37
|
+
if (inputs.length > maxChars || targets.length > maxChars)
|
|
38
|
+
return null;
|
|
39
|
+
const language = typeof r.language === "string" ? r.language.trim() : "";
|
|
40
|
+
return { inputs, targets, language };
|
|
41
|
+
}
|
|
42
|
+
/** Translate ONE Aya row into SEMA training items. A row is a single human
|
|
43
|
+
* (question → answer) exchange — exactly one FACT, the (inputs → targets) edge.
|
|
44
|
+
* No standalone-answer experience and no one-exchange "cumulative" walk: a lone
|
|
45
|
+
* Q→A is not multi-turn, and both would only replicate the same edge. */
|
|
46
|
+
export function ayaRowToItems(row) {
|
|
47
|
+
const { inputs, targets } = row;
|
|
48
|
+
return refineItems([{ context: inputs, continuation: targets }]);
|
|
49
|
+
}
|
|
50
|
+
export const aya = {
|
|
51
|
+
id: "aya",
|
|
52
|
+
label: "Aya Dataset",
|
|
53
|
+
kind: "multilingual chat",
|
|
54
|
+
enabled: AYA,
|
|
55
|
+
// The three columns toAyaRow reads, out of six. Kept for the same reason as
|
|
56
|
+
// the other Parquet stages — the read states what the adapter uses — though
|
|
57
|
+
// here it is nearly free rather than a saving: measured on the train file,
|
|
58
|
+
// 238 MB uncompressed across all six and 233 MB for these three (98.2%). The
|
|
59
|
+
// dropped columns are ids and annotation metadata, so there is little to
|
|
60
|
+
// drop.
|
|
61
|
+
read: parquet({ columns: ["inputs", "targets", "language"] }),
|
|
62
|
+
toItems: (row) => {
|
|
63
|
+
const r = toAyaRow(row);
|
|
64
|
+
return r ? ayaRowToItems(r) : null;
|
|
65
|
+
},
|
|
66
|
+
discover: singleUnit({
|
|
67
|
+
// Resume id "aya::dataset" — the string this store already records.
|
|
68
|
+
key: "dataset",
|
|
69
|
+
label: "Aya Dataset",
|
|
70
|
+
display: "Aya Dataset",
|
|
71
|
+
url: AYA_URL,
|
|
72
|
+
dest: "aya_train.parquet",
|
|
73
|
+
localMatch: [/aya.*\.parquet$/i, /\.parquet$/i],
|
|
74
|
+
localWhat: "Aya *.parquet",
|
|
75
|
+
}),
|
|
76
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Unit } from "../corpus.js";
|
|
2
|
+
import type { TrainCtx } from "../runtime.js";
|
|
3
|
+
/** The work-list of a corpus read from Hugging Face's auto-converted
|
|
4
|
+
* `refs/convert/parquet` branch. Shared by 2Wiki, SODA and MASSIVE: they
|
|
5
|
+
* differ in their dataset, their budget and their adapter — nothing else. */
|
|
6
|
+
export declare function convertedParquetUnits(opts: {
|
|
7
|
+
id: string;
|
|
8
|
+
label: string;
|
|
9
|
+
dataset: string;
|
|
10
|
+
config: string;
|
|
11
|
+
splits: string[];
|
|
12
|
+
/** Subdirectory of LOCAL_PATH holding pre-downloaded shards. */
|
|
13
|
+
localSub: string;
|
|
14
|
+
}): (ctx: TrainCtx) => Promise<Unit[] | null>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// train_base/corpora/converted-parquet.ts — the work-list shape three corpora
|
|
2
|
+
// share.
|
|
3
|
+
//
|
|
4
|
+
// Read from Hugging Face's auto-converted `refs/convert/parquet` branch, not
|
|
5
|
+
// from main: a dataset's own Parquet may be written as ONE giant row-group
|
|
6
|
+
// (SODA's is 1,191,582 rows) and a column chunk is per-group, so any read of it
|
|
7
|
+
// materialises the whole file. The converted branch uses uniform 10,000-row
|
|
8
|
+
// groups.
|
|
9
|
+
import { LOCAL_PATH } from "../config.js";
|
|
10
|
+
import { hfConvertedParquet, localFiles } from "../discovery.js";
|
|
11
|
+
import { localDir } from "../corpus.js";
|
|
12
|
+
import { DIM, R, YEL } from "../ui.js";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
/** The work-list of a corpus read from Hugging Face's auto-converted
|
|
15
|
+
* `refs/convert/parquet` branch. Shared by 2Wiki, SODA and MASSIVE: they
|
|
16
|
+
* differ in their dataset, their budget and their adapter — nothing else. */
|
|
17
|
+
export function convertedParquetUnits(opts) {
|
|
18
|
+
return async (ctx) => {
|
|
19
|
+
if (LOCAL_PATH) {
|
|
20
|
+
const dir = localDir(opts.localSub);
|
|
21
|
+
const names = localFiles(dir, /\.parquet$/i);
|
|
22
|
+
if (names.length === 0) {
|
|
23
|
+
ctx.progress.log(` ${DIM}· no ${opts.label} *.parquet in ${dir} — skipping${R}`);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return names.map((n) => ({
|
|
27
|
+
key: n.path,
|
|
28
|
+
name: n.path,
|
|
29
|
+
display: `${opts.label} ${n.path}`,
|
|
30
|
+
local: join(dir, n.path),
|
|
31
|
+
bytes: n.size,
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
const paths = await hfConvertedParquet(opts.dataset, opts.config, opts.splits, opts.label, ctx.http, (m) => ctx.progress.log(` ${YEL}⚠${R} ${m}`));
|
|
35
|
+
return paths.map(({ path, size }) => ({
|
|
36
|
+
key: path,
|
|
37
|
+
name: path,
|
|
38
|
+
display: `${opts.label} ${path}`,
|
|
39
|
+
url: `https://huggingface.co/datasets/${opts.dataset}` +
|
|
40
|
+
`/resolve/refs%2Fconvert%2Fparquet/${path}`,
|
|
41
|
+
bytes: size,
|
|
42
|
+
}));
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type TrainingItem } from "../items.js";
|
|
2
|
+
import { type Corpus } from "../corpus.js";
|
|
3
|
+
/** One normalized General-Knowledge row. */
|
|
4
|
+
export interface GenKnowRow {
|
|
5
|
+
question: string;
|
|
6
|
+
answer: string;
|
|
7
|
+
}
|
|
8
|
+
/** Normalize a raw datasets-server row into a GenKnowRow, or null when it lacks
|
|
9
|
+
* a usable question/answer or a side is implausibly large (corruption). */
|
|
10
|
+
export declare function toGenKnowRow(row: unknown, maxChars?: number): GenKnowRow | null;
|
|
11
|
+
/** Translate ONE General-Knowledge row into SEMA items: exactly one
|
|
12
|
+
* (question → answer) FACT. refineItems drops a degenerate question === answer. */
|
|
13
|
+
export declare function genKnowRowToItems(row: GenKnowRow): TrainingItem[];
|
|
14
|
+
export declare const genknow: Corpus;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// train_base/corpora/genknow.ts — MuskumPillerum/General-Knowledge Q&A
|
|
2
|
+
//
|
|
3
|
+
// Knobs, the row adapter, and the stage descriptor for ONE corpus, together
|
|
4
|
+
// with the evidence that fixed each default. A corpus file owns everything
|
|
5
|
+
// source-specific; the contract it fills is ../corpus.ts and the loop that runs
|
|
6
|
+
// it is ../stage.ts.
|
|
7
|
+
import { env } from "../config.js";
|
|
8
|
+
import { refineItems } from "../items.js";
|
|
9
|
+
import { jsonArray } from "../readers.js";
|
|
10
|
+
import { singleUnit } from "../corpus.js";
|
|
11
|
+
// ── MuskumPillerum/General-Knowledge (the fourth training stage, after oasst2) ──
|
|
12
|
+
// A ~37.6k-row general-knowledge Q&A set: each row is a single {Question, Answer}
|
|
13
|
+
// pair. A row is a pure RELATION (question → answer), so it becomes exactly ONE
|
|
14
|
+
// FACT, identical in shape to the Aya stage. It ships as a single JSON array
|
|
15
|
+
// file (output.json); we DOWNLOAD it and stream the array. GENKNOW_URL overrides
|
|
16
|
+
// the source.
|
|
17
|
+
//
|
|
18
|
+
// DISABLED BY DEFAULT ON LICENCE GROUNDS (2026-08-13). The HF repo carries NO
|
|
19
|
+
// licence tag and no licence in its card — an earlier header in this file
|
|
20
|
+
// claimed MIT without support — and its own dataset card states it "contains a
|
|
21
|
+
// subset of the alpaca dataset". Alpaca is CC BY-NC 4.0: NonCommercial, which
|
|
22
|
+
// conflicts with Sema's commercial licence. Because a Sema store retains its
|
|
23
|
+
// training text VERBATIM, an unlicensed corpus inside it makes the whole
|
|
24
|
+
// artifact undistributable. See DATASETS.md §3.2. GENKNOW=1 re-enables the
|
|
25
|
+
// stage for local, non-distributed experiments only.
|
|
26
|
+
const GENKNOW = env("GENKNOW", "0") !== "0";
|
|
27
|
+
const GENKNOW_URL = env("GENKNOW_URL", "https://huggingface.co/datasets/MuskumPillerum/General-Knowledge/resolve/main/output.json");
|
|
28
|
+
// A Question/Answer longer than this is skipped (answers run to a few hundred
|
|
29
|
+
// chars; this only guards against a corrupt/runaway field).
|
|
30
|
+
const MAX_GENKNOW_CHARS = Math.max(4_000, Math.floor(Number(env("MAX_GENKNOW_KB", "64")) * 1000) || 64_000);
|
|
31
|
+
/** Turn a source value into clean prose: decode the literal "\n"/"\t"/"\r"
|
|
32
|
+
* two-character escapes the source JSON left in the text, collapse the runs of
|
|
33
|
+
* whitespace that creates, and trim. */
|
|
34
|
+
function unescapePlain(s) {
|
|
35
|
+
return s
|
|
36
|
+
.replace(/\\r\\n|\\n|\\r/g, "\n")
|
|
37
|
+
.replace(/\\t/g, " ")
|
|
38
|
+
.replace(/[ \t]+/g, " ")
|
|
39
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
40
|
+
.trim();
|
|
41
|
+
}
|
|
42
|
+
/** Normalize a raw datasets-server row into a GenKnowRow, or null when it lacks
|
|
43
|
+
* a usable question/answer or a side is implausibly large (corruption). */
|
|
44
|
+
export function toGenKnowRow(row, maxChars = MAX_GENKNOW_CHARS) {
|
|
45
|
+
if (!row || typeof row !== "object")
|
|
46
|
+
return null;
|
|
47
|
+
const r = row;
|
|
48
|
+
const question = typeof r.Question === "string"
|
|
49
|
+
? unescapePlain(r.Question)
|
|
50
|
+
: "";
|
|
51
|
+
const answer = typeof r.Answer === "string" ? unescapePlain(r.Answer) : "";
|
|
52
|
+
if (!question || !answer)
|
|
53
|
+
return null;
|
|
54
|
+
if (question.length > maxChars || answer.length > maxChars)
|
|
55
|
+
return null;
|
|
56
|
+
return { question, answer };
|
|
57
|
+
}
|
|
58
|
+
/** Translate ONE General-Knowledge row into SEMA items: exactly one
|
|
59
|
+
* (question → answer) FACT. refineItems drops a degenerate question === answer. */
|
|
60
|
+
export function genKnowRowToItems(row) {
|
|
61
|
+
return refineItems([{ context: row.question, continuation: row.answer }]);
|
|
62
|
+
}
|
|
63
|
+
export const genknow = {
|
|
64
|
+
id: "genknow",
|
|
65
|
+
label: "General-Knowledge",
|
|
66
|
+
kind: "Q&A facts",
|
|
67
|
+
enabled: GENKNOW,
|
|
68
|
+
read: jsonArray(),
|
|
69
|
+
toItems: (row) => {
|
|
70
|
+
const r = toGenKnowRow(row);
|
|
71
|
+
return r ? genKnowRowToItems(r) : null;
|
|
72
|
+
},
|
|
73
|
+
discover: singleUnit({
|
|
74
|
+
// Resume id "genknow::qa" — the string this store already records.
|
|
75
|
+
key: "qa",
|
|
76
|
+
label: "General-Knowledge",
|
|
77
|
+
display: "General-Knowledge",
|
|
78
|
+
url: GENKNOW_URL,
|
|
79
|
+
dest: "general_knowledge.json",
|
|
80
|
+
localMatch: [/general.*knowledge.*\.json$/i, /output\.json$/i],
|
|
81
|
+
localWhat: "General-Knowledge *.json",
|
|
82
|
+
}),
|
|
83
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Corpus } from "../corpus.js";
|
|
2
|
+
export declare const CURRICULUM: Corpus[];
|
|
3
|
+
/** The corpora this RUN will train, for the panel header — derived, so it can
|
|
4
|
+
* never go stale the way the hand-written string it replaces had. */
|
|
5
|
+
export declare const enabledLabels: () => string;
|
|
6
|
+
/** The corpora a STORE contains: everything this run will train PLUS everything
|
|
7
|
+
* an earlier run already did, in curriculum order.
|
|
8
|
+
*
|
|
9
|
+
* Not the same question as `enabledLabels`, and conflating them wrote a false
|
|
10
|
+
* statement into every store that was ever resumed with a different set of
|
|
11
|
+
* stages enabled. Observed on a real store: `train.dataset` read
|
|
12
|
+
* "SmolSent+Aya+oasst2" while the tally recorded 37,623 General-Knowledge
|
|
13
|
+
* deposits sitting in it. That is not cosmetic — a Sema store retains its
|
|
14
|
+
* training text VERBATIM, so `train.dataset` is the record of whose licence
|
|
15
|
+
* terms travel with the artifact, and General-Knowledge is precisely the
|
|
16
|
+
* corpus DATASETS.md §3.2 disables on NonCommercial grounds.
|
|
17
|
+
*
|
|
18
|
+
* `trainedIds` are the corpus ids an earlier run deposited under (the keys of
|
|
19
|
+
* the per-corpus tally). An id no longer in the curriculum cannot be named and
|
|
20
|
+
* is dropped — the tally still carries it, which is where that evidence lives. */
|
|
21
|
+
export declare const storedLabels: (trainedIds: Iterable<string>) => string;
|
|
22
|
+
export * from "./smolsent.js";
|
|
23
|
+
export * from "./aya.js";
|
|
24
|
+
export * from "./oasst2.js";
|
|
25
|
+
export * from "./taskmaster.js";
|
|
26
|
+
export * from "./wiki2.js";
|
|
27
|
+
export * from "./soda.js";
|
|
28
|
+
export * from "./massive.js";
|
|
29
|
+
export * from "./genknow.js";
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// train_base/corpora/index.ts — THE CURRICULUM.
|
|
2
|
+
//
|
|
3
|
+
// The order is the curriculum, and it is load-bearing: each stage runs only
|
|
4
|
+
// after the previous one finishes, and every stage records itself in the same
|
|
5
|
+
// completed-set, so a single store resumes the whole sequence.
|
|
6
|
+
//
|
|
7
|
+
// 1. SmolSent sentence-level TRANSLATION pairs across 100+ low-resource
|
|
8
|
+
// languages. Each pair is "two names for one meaning" → a
|
|
9
|
+
// foreign→English translation FACT, so every language's
|
|
10
|
+
// rendering of a meaning converges on ONE English node (cf.
|
|
11
|
+
// test/05-concepts.test.mjs).
|
|
12
|
+
// 2. Aya ~204k human prompt→completion pairs, 70+ languages → one
|
|
13
|
+
// (question → answer) FACT each.
|
|
14
|
+
// 3. oasst2 MULTI-TURN human↔assistant conversation trees → the
|
|
15
|
+
// accumulated-context walk (single-turn trees are skipped).
|
|
16
|
+
// 4. Taskmaster task-oriented DIALOGUE, the best-scoring corpora on the
|
|
17
|
+
// fold-unit recurrence benchmark that predicts halo health.
|
|
18
|
+
// 5. 2Wiki the `evidences` TRIPLES — the one stage aimed at
|
|
19
|
+
// COMPOSITION. Its Wikipedia passages and its composed
|
|
20
|
+
// questions are deliberately NOT read.
|
|
21
|
+
// 6. SODA social/commonsense DIALOGUE, budgeted.
|
|
22
|
+
// 7. MASSIVE short intent utterances → ONE bare experience each.
|
|
23
|
+
// DISABLED BY DEFAULT — edge-less content was measured to
|
|
24
|
+
// manufacture answers where the store should stay silent.
|
|
25
|
+
// 8. GenKnow ~37.6k {Question, Answer} pairs → one FACT each. DISABLED
|
|
26
|
+
// BY DEFAULT on licence grounds; see DATASETS.md §3.2.
|
|
27
|
+
import { smolsent } from "./smolsent.js";
|
|
28
|
+
import { aya } from "./aya.js";
|
|
29
|
+
import { oasst2 } from "./oasst2.js";
|
|
30
|
+
import { taskmaster } from "./taskmaster.js";
|
|
31
|
+
import { wiki2 } from "./wiki2.js";
|
|
32
|
+
import { soda } from "./soda.js";
|
|
33
|
+
import { massive } from "./massive.js";
|
|
34
|
+
import { genknow } from "./genknow.js";
|
|
35
|
+
export const CURRICULUM = [
|
|
36
|
+
smolsent,
|
|
37
|
+
aya,
|
|
38
|
+
oasst2,
|
|
39
|
+
taskmaster,
|
|
40
|
+
wiki2,
|
|
41
|
+
soda,
|
|
42
|
+
massive,
|
|
43
|
+
genknow,
|
|
44
|
+
];
|
|
45
|
+
/** The corpora this RUN will train, for the panel header — derived, so it can
|
|
46
|
+
* never go stale the way the hand-written string it replaces had. */
|
|
47
|
+
export const enabledLabels = () => CURRICULUM.filter((c) => c.enabled).map((c) => c.label).join("+");
|
|
48
|
+
/** The corpora a STORE contains: everything this run will train PLUS everything
|
|
49
|
+
* an earlier run already did, in curriculum order.
|
|
50
|
+
*
|
|
51
|
+
* Not the same question as `enabledLabels`, and conflating them wrote a false
|
|
52
|
+
* statement into every store that was ever resumed with a different set of
|
|
53
|
+
* stages enabled. Observed on a real store: `train.dataset` read
|
|
54
|
+
* "SmolSent+Aya+oasst2" while the tally recorded 37,623 General-Knowledge
|
|
55
|
+
* deposits sitting in it. That is not cosmetic — a Sema store retains its
|
|
56
|
+
* training text VERBATIM, so `train.dataset` is the record of whose licence
|
|
57
|
+
* terms travel with the artifact, and General-Knowledge is precisely the
|
|
58
|
+
* corpus DATASETS.md §3.2 disables on NonCommercial grounds.
|
|
59
|
+
*
|
|
60
|
+
* `trainedIds` are the corpus ids an earlier run deposited under (the keys of
|
|
61
|
+
* the per-corpus tally). An id no longer in the curriculum cannot be named and
|
|
62
|
+
* is dropped — the tally still carries it, which is where that evidence lives. */
|
|
63
|
+
export const storedLabels = (trainedIds) => {
|
|
64
|
+
const trained = new Set(trainedIds);
|
|
65
|
+
return CURRICULUM
|
|
66
|
+
.filter((c) => c.enabled || trained.has(c.id))
|
|
67
|
+
.map((c) => c.label)
|
|
68
|
+
.join("+");
|
|
69
|
+
};
|
|
70
|
+
// One re-export per corpus, carrying the descriptor AND its adapters. The
|
|
71
|
+
// explicit `export { aya, genknow, … }` list that used to sit here named the
|
|
72
|
+
// eight descriptors a second time; the star exports below already provide them,
|
|
73
|
+
// and a hand-kept list of everything is exactly the thing that goes stale.
|
|
74
|
+
export * from "./smolsent.js";
|
|
75
|
+
export * from "./aya.js";
|
|
76
|
+
export * from "./oasst2.js";
|
|
77
|
+
export * from "./taskmaster.js";
|
|
78
|
+
export * from "./wiki2.js";
|
|
79
|
+
export * from "./soda.js";
|
|
80
|
+
export * from "./massive.js";
|
|
81
|
+
export * from "./genknow.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type TrainingItem } from "../items.js";
|
|
2
|
+
import type { Corpus } from "../corpus.js";
|
|
3
|
+
/** Translate ONE MASSIVE row into SEMA items: its bare utterance, as an
|
|
4
|
+
* experience. `annot_utt` (slot-annotated) is deliberately not used — its
|
|
5
|
+
* "[date : ...]" markup is not prose. Returns [] for an unusable row. */
|
|
6
|
+
export declare function massiveRowToItems(row: unknown, maxChars?: number): TrainingItem[];
|
|
7
|
+
export declare const massive: Corpus;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// train_base/corpora/massive.ts — AmazonScience/massive short intents
|
|
2
|
+
//
|
|
3
|
+
// Knobs, the row adapter, and the stage descriptor for ONE corpus, together
|
|
4
|
+
// with the evidence that fixed each default. A corpus file owns everything
|
|
5
|
+
// source-specific; the contract it fills is ../corpus.ts and the loop that runs
|
|
6
|
+
// it is ../stage.ts.
|
|
7
|
+
import { env } from "../config.js";
|
|
8
|
+
import { refineItems } from "../items.js";
|
|
9
|
+
import { parquet } from "../readers.js";
|
|
10
|
+
import { convertedParquetUnits } from "./converted-parquet.js";
|
|
11
|
+
// MASSIVE deposits BARE UTTERANCES — an experience, not an episode — and that
|
|
12
|
+
// is the only shape its data supports. Two richer shapes were considered and
|
|
13
|
+
// rejected on evidence:
|
|
14
|
+
// • Same-intent pairs as paraphrases. 49.1% of consecutive rows share
|
|
15
|
+
// (locale, intent), but they are NOT meaning-equivalent: intent 48 in mn-MN
|
|
16
|
+
// runs "wake me at nine on the fifth" next to "set an alarm two hours from
|
|
17
|
+
// now". Depositing that pair as an episode teaches a continuation that does
|
|
18
|
+
// not exist.
|
|
19
|
+
// • Same-id rows across locales. Those ARE translations of one another —
|
|
20
|
+
// which is exactly SmolSent's relation, and SmolSent scores worst of every
|
|
21
|
+
// corpus measured on fold-unit recurrence (23.2%) because cross-lingual
|
|
22
|
+
// pairs share no units.
|
|
23
|
+
// So the stage contributes recurring fold units and lexical coverage (65.1%
|
|
24
|
+
// recurring unit mass, median 29 B) and nothing relational. `annot_utt` carries
|
|
25
|
+
// slot markup ("[date : tavdahad] ...") and is never read.
|
|
26
|
+
// DISABLED BY DEFAULT, on evidence gathered after the stage was written. A bare
|
|
27
|
+
// experience deposits content with NO EDGE, and that cuts both ways. Measured on
|
|
28
|
+
// a three-pair dialogue store with and without six MASSIVE-style utterances:
|
|
29
|
+
//
|
|
30
|
+
// "set an alarm" without: "Sure, what size would you like?" (wrong)
|
|
31
|
+
// with: "set an alarm for seven" (better)
|
|
32
|
+
// "play music" without: "" (correct silence)
|
|
33
|
+
// with: "Yes, sweetened or unsweetened?" (wrong)
|
|
34
|
+
//
|
|
35
|
+
// So it displaces some wrong answers and manufactures others, INCLUDING turning
|
|
36
|
+
// a correct silence into a wrong answer — and honest silence is a stated
|
|
37
|
+
// property of this engine (AGENTS §2.13). On the mixed-curriculum store the
|
|
38
|
+
// same shape produced the fragment "nus" for "wake me up at nine am".
|
|
39
|
+
//
|
|
40
|
+
// That evidence is four probes on toy stores and is NOT conclusive; it is,
|
|
41
|
+
// however, the only evidence there is, and it points the wrong way. The stage
|
|
42
|
+
// stays implemented and one env var away. Turn it on (MASSIVE=1) once there is
|
|
43
|
+
// a real measurement showing the recurring fold units it contributes (72.3% of
|
|
44
|
+
// deposited unit mass) buy more than the spurious answers cost.
|
|
45
|
+
const MASSIVE = env("MASSIVE", "0") !== "0";
|
|
46
|
+
const MASSIVE_DATASET = env("MASSIVE_DATASET", "AmazonScience/massive");
|
|
47
|
+
// "all" is the config covering every locale in one set of shards.
|
|
48
|
+
const MASSIVE_CONFIG = env("MASSIVE_CONFIG", "all");
|
|
49
|
+
const MASSIVE_SPLITS = env("MASSIVE_SPLITS", "train")
|
|
50
|
+
.split(",").map((s) => s.trim()).filter(Boolean);
|
|
51
|
+
// 0 = every row (587,214 in `all`/train, ~17 MB of content).
|
|
52
|
+
const MASSIVE_MAX_ROWS = Math.max(0, Math.floor(Number(env("MASSIVE_MAX_ROWS", "0"))) || 0);
|
|
53
|
+
const MAX_MASSIVE_UTT_CHARS = Math.max(100, Math.floor(Number(env("MAX_MASSIVE_UTT_KB", "2")) * 1000) || 2_000);
|
|
54
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
55
|
+
// §6e⁗ MASSIVE parsing — one short utterance → ONE SEMA experience
|
|
56
|
+
//
|
|
57
|
+
// See the constants note for why this deposits a bare experience and not a
|
|
58
|
+
// relation: the two relational shapes this corpus appears to offer are both
|
|
59
|
+
// false (same-intent rows are not paraphrases; same-id rows across locales are
|
|
60
|
+
// translations, SmolSent's worst-scoring relation).
|
|
61
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
62
|
+
/** Translate ONE MASSIVE row into SEMA items: its bare utterance, as an
|
|
63
|
+
* experience. `annot_utt` (slot-annotated) is deliberately not used — its
|
|
64
|
+
* "[date : ...]" markup is not prose. Returns [] for an unusable row. */
|
|
65
|
+
export function massiveRowToItems(row, maxChars = MAX_MASSIVE_UTT_CHARS) {
|
|
66
|
+
if (!row || typeof row !== "object")
|
|
67
|
+
return [];
|
|
68
|
+
const utt = row.utt;
|
|
69
|
+
const text = typeof utt === "string" ? utt.trim() : "";
|
|
70
|
+
if (!text || text.length > maxChars)
|
|
71
|
+
return [];
|
|
72
|
+
return refineItems([text]);
|
|
73
|
+
}
|
|
74
|
+
export const massive = {
|
|
75
|
+
id: "massive",
|
|
76
|
+
label: "MASSIVE",
|
|
77
|
+
kind: "short intents",
|
|
78
|
+
enabled: MASSIVE,
|
|
79
|
+
maxRows: MASSIVE_MAX_ROWS,
|
|
80
|
+
// One of ten columns — `annot_utt`, whose slot markup the note above rejects,
|
|
81
|
+
// is not decoded either. Measured on the converted train shard: 92 MB
|
|
82
|
+
// uncompressed across all ten, 36 MB for `utt` (38.7%).
|
|
83
|
+
read: parquet({ columns: ["utt"] }),
|
|
84
|
+
toItems: (row) => {
|
|
85
|
+
const items = massiveRowToItems(row);
|
|
86
|
+
return items.length ? items : null;
|
|
87
|
+
},
|
|
88
|
+
unitNoun: "shard(s)",
|
|
89
|
+
log: { rows: "row(s)" },
|
|
90
|
+
discover: convertedParquetUnits({
|
|
91
|
+
id: "massive",
|
|
92
|
+
label: "MASSIVE",
|
|
93
|
+
dataset: MASSIVE_DATASET,
|
|
94
|
+
config: MASSIVE_CONFIG,
|
|
95
|
+
splits: MASSIVE_SPLITS,
|
|
96
|
+
localSub: "massive",
|
|
97
|
+
}),
|
|
98
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type TrainingItem } from "../items.js";
|
|
2
|
+
import { type Corpus } from "../corpus.js";
|
|
3
|
+
/** A single oasst2 message node (the fields we use; the tree nests via replies). */
|
|
4
|
+
interface OasstNode {
|
|
5
|
+
role?: string;
|
|
6
|
+
text?: string;
|
|
7
|
+
rank?: number | null;
|
|
8
|
+
deleted?: boolean;
|
|
9
|
+
replies?: OasstNode[];
|
|
10
|
+
}
|
|
11
|
+
/** One conversational turn extracted from a tree. */
|
|
12
|
+
export interface OasstTurn {
|
|
13
|
+
role: string;
|
|
14
|
+
text: string;
|
|
15
|
+
}
|
|
16
|
+
/** Collapse a conversation tree to ONE linear path: at each node, descend into
|
|
17
|
+
* its best-ranked, non-deleted reply (rank 0 preferred; unranked sorts last).
|
|
18
|
+
* Returns the ordered turns (already strictly alternating in this corpus). */
|
|
19
|
+
export declare function bestOasstPath(root: OasstNode): OasstTurn[];
|
|
20
|
+
/** Translate ONE multi-turn oasst2 conversation into SEMA training items.
|
|
21
|
+
*
|
|
22
|
+
* This is the ONE stage where cumulative continuous context is truly necessary:
|
|
23
|
+
* the data is a real multi-turn dialogue, and what must be learned is how each
|
|
24
|
+
* turn follows from the WHOLE conversation so far — not from the previous turn
|
|
25
|
+
* alone. The conversation is emitted ONLY as the accumulated walk; standalone
|
|
26
|
+
* turn experiences and local adjacent-pair facts are NOT emitted (they are
|
|
27
|
+
* subsumed by it and would merely replicate the content).
|
|
28
|
+
*
|
|
29
|
+
* The walk is the pattern proven in test/13-conversation.test.mjs
|
|
30
|
+
* ("teachConversation"): each turn is the continuation of all prior turns,
|
|
31
|
+
* with BARE turn text — NO "User:/Assistant:" labels. The SHAPE is identical
|
|
32
|
+
* (cumulative context → next turn); the join string is not, and does not need
|
|
33
|
+
* to be — that file joins with nothing and this corpus joins with "\n" (see
|
|
34
|
+
* `accumulate`). Saying "byte-for-byte", as this comment used to, invites the
|
|
35
|
+
* reading that the two must agree on a separator. They must not agree,
|
|
36
|
+
* because there is nothing to agree about: turn boundaries are offsets, and
|
|
37
|
+
* the join string is just corpus text. Roles already
|
|
38
|
+
* alternate by position in an oasst2 best-path (the root is a prompter), so a
|
|
39
|
+
* label adds nothing the position does not, while a clean continuation matches
|
|
40
|
+
* the test's recall (predictNext queries bare prior turns) and lets a turn share
|
|
41
|
+
* its gist with the same text elsewhere (e.g. an Aya question stored bare).
|
|
42
|
+
*
|
|
43
|
+
* Returns [] for a conversation below the multi-turn threshold, so callers can
|
|
44
|
+
* simply skip empties. */
|
|
45
|
+
export declare function oasstConversationToItems(turns: OasstTurn[], minTurns?: number): TrainingItem[];
|
|
46
|
+
/** The row adapter: ONE line of the tree dump → its deposits. Returns null for
|
|
47
|
+
* a tree with no prompt and for every single-turn tree — the latter is the
|
|
48
|
+
* stage's design, not a defect, which is why the reader counts it `unusable`
|
|
49
|
+
* rather than `skipped`. */
|
|
50
|
+
export declare function oasstTreeToItems(row: unknown): TrainingItem[] | null;
|
|
51
|
+
export declare const oasst2: Corpus;
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// train_base/corpora/oasst2.ts — OpenAssistant/oasst2 conversation trees
|
|
2
|
+
//
|
|
3
|
+
// Knobs, the row adapter, and the stage descriptor for ONE corpus, together
|
|
4
|
+
// with the evidence that fixed each default. A corpus file owns everything
|
|
5
|
+
// source-specific; the contract it fills is ../corpus.ts and the loop that runs
|
|
6
|
+
// it is ../stage.ts.
|
|
7
|
+
import { env } from "../config.js";
|
|
8
|
+
import { accumulate, refineItems } from "../items.js";
|
|
9
|
+
import { lines } from "../readers.js";
|
|
10
|
+
import { singleUnit } from "../corpus.js";
|
|
11
|
+
// ── OpenAssistant/oasst2 (the fourth training stage, after Aya) ──
|
|
12
|
+
// oasst2 is a corpus of human↔assistant conversation TREES. Its richest, most
|
|
13
|
+
// stream-friendly artifact is "<date>_oasst2_ready.trees.jsonl.gz": one JSON
|
|
14
|
+
// conversation tree PER LINE, gzip-compressed (a web standard — Decompression
|
|
15
|
+
// Stream("gzip")). Each tree is {message_tree_id, prompt:{role,text,replies:[…]}}
|
|
16
|
+
// where `replies` nests recursively and a prompt can have several ranked
|
|
17
|
+
// assistant replies (rank 0 = best). We follow the best-ranked, non-deleted
|
|
18
|
+
// reply at each step to get ONE linear, strictly-alternating conversation per
|
|
19
|
+
// tree, then keep only the MULTI-TURN ones (≥ OASST_MIN_TURNS messages, i.e. at
|
|
20
|
+
// least two full user→assistant exchanges) — single Q→A trees are skipped, by
|
|
21
|
+
// design. OASST=0 disables the stage; OASST_URL overrides the source.
|
|
22
|
+
const OASST = env("OASST", "1") !== "0";
|
|
23
|
+
const OASST_URL = env("OASST_URL", "https://huggingface.co/datasets/OpenAssistant/oasst2/resolve/main/2023-11-05_oasst2_ready.trees.jsonl.gz");
|
|
24
|
+
// Multi-turn threshold: a conversation must have at least this many turns to be
|
|
25
|
+
// trained (4 = user→assistant→user→assistant, the smallest real multi-turn).
|
|
26
|
+
const OASST_MIN_TURNS = Math.max(2, Math.floor(Number(env("OASST_MIN_TURNS", "4"))) || 4);
|
|
27
|
+
// Skip a tree whose decoded JSON line exceeds this (a pathological record); the
|
|
28
|
+
// real maximum is far smaller, so this only guards against corruption.
|
|
29
|
+
const MAX_OASST_LINE_CHARS = Math.max(100_000, Math.floor(Number(env("MAX_OASST_LINE_MB", "8")) * 1_000_000) || 8_000_000);
|
|
30
|
+
/** Collapse a conversation tree to ONE linear path: at each node, descend into
|
|
31
|
+
* its best-ranked, non-deleted reply (rank 0 preferred; unranked sorts last).
|
|
32
|
+
* Returns the ordered turns (already strictly alternating in this corpus). */
|
|
33
|
+
export function bestOasstPath(root) {
|
|
34
|
+
const turns = [];
|
|
35
|
+
let node = root;
|
|
36
|
+
while (node) {
|
|
37
|
+
const text = typeof node.text === "string" ? node.text.trim() : "";
|
|
38
|
+
if (text)
|
|
39
|
+
turns.push({ role: String(node.role ?? "?"), text });
|
|
40
|
+
const live = (node.replies ?? []).filter((r) => r && !r.deleted && typeof r.text === "string" && r.text.trim() !== "");
|
|
41
|
+
if (live.length === 0)
|
|
42
|
+
break;
|
|
43
|
+
live.sort((a, b) => (a.rank ?? Number.MAX_SAFE_INTEGER) - (b.rank ?? Number.MAX_SAFE_INTEGER));
|
|
44
|
+
node = live[0];
|
|
45
|
+
}
|
|
46
|
+
return turns;
|
|
47
|
+
}
|
|
48
|
+
/** Translate ONE multi-turn oasst2 conversation into SEMA training items.
|
|
49
|
+
*
|
|
50
|
+
* This is the ONE stage where cumulative continuous context is truly necessary:
|
|
51
|
+
* the data is a real multi-turn dialogue, and what must be learned is how each
|
|
52
|
+
* turn follows from the WHOLE conversation so far — not from the previous turn
|
|
53
|
+
* alone. The conversation is emitted ONLY as the accumulated walk; standalone
|
|
54
|
+
* turn experiences and local adjacent-pair facts are NOT emitted (they are
|
|
55
|
+
* subsumed by it and would merely replicate the content).
|
|
56
|
+
*
|
|
57
|
+
* The walk is the pattern proven in test/13-conversation.test.mjs
|
|
58
|
+
* ("teachConversation"): each turn is the continuation of all prior turns,
|
|
59
|
+
* with BARE turn text — NO "User:/Assistant:" labels. The SHAPE is identical
|
|
60
|
+
* (cumulative context → next turn); the join string is not, and does not need
|
|
61
|
+
* to be — that file joins with nothing and this corpus joins with "\n" (see
|
|
62
|
+
* `accumulate`). Saying "byte-for-byte", as this comment used to, invites the
|
|
63
|
+
* reading that the two must agree on a separator. They must not agree,
|
|
64
|
+
* because there is nothing to agree about: turn boundaries are offsets, and
|
|
65
|
+
* the join string is just corpus text. Roles already
|
|
66
|
+
* alternate by position in an oasst2 best-path (the root is a prompter), so a
|
|
67
|
+
* label adds nothing the position does not, while a clean continuation matches
|
|
68
|
+
* the test's recall (predictNext queries bare prior turns) and lets a turn share
|
|
69
|
+
* its gist with the same text elsewhere (e.g. an Aya question stored bare).
|
|
70
|
+
*
|
|
71
|
+
* Returns [] for a conversation below the multi-turn threshold, so callers can
|
|
72
|
+
* simply skip empties. */
|
|
73
|
+
export function oasstConversationToItems(turns, minTurns = OASST_MIN_TURNS) {
|
|
74
|
+
if (turns.length < minTurns)
|
|
75
|
+
return []; // not multi-turn — skip
|
|
76
|
+
return refineItems(accumulate(turns.map((t) => t.text)));
|
|
77
|
+
}
|
|
78
|
+
/** The row adapter: ONE line of the tree dump → its deposits. Returns null for
|
|
79
|
+
* a tree with no prompt and for every single-turn tree — the latter is the
|
|
80
|
+
* stage's design, not a defect, which is why the reader counts it `unusable`
|
|
81
|
+
* rather than `skipped`. */
|
|
82
|
+
export function oasstTreeToItems(row) {
|
|
83
|
+
if (!row || typeof row !== "object")
|
|
84
|
+
return null;
|
|
85
|
+
const tree = row;
|
|
86
|
+
if (!tree.prompt)
|
|
87
|
+
return null;
|
|
88
|
+
const items = oasstConversationToItems(bestOasstPath(tree.prompt));
|
|
89
|
+
return items.length ? items : null;
|
|
90
|
+
}
|
|
91
|
+
export const oasst2 = {
|
|
92
|
+
id: "oasst2",
|
|
93
|
+
label: "oasst2",
|
|
94
|
+
kind: "multi-turn chat",
|
|
95
|
+
enabled: OASST,
|
|
96
|
+
read: lines({ gzip: true, maxLineChars: MAX_OASST_LINE_CHARS }),
|
|
97
|
+
toItems: oasstTreeToItems,
|
|
98
|
+
// The one corpus that KEEPS a cached file after a complete read: a copy left
|
|
99
|
+
// behind by a previous interrupted run is not this stage's to reclaim.
|
|
100
|
+
keepCached: true,
|
|
101
|
+
log: {
|
|
102
|
+
deposits: "examples",
|
|
103
|
+
// A tree that yields items is exactly a tree that cleared OASST_MIN_TURNS.
|
|
104
|
+
rows: "conversation(s)",
|
|
105
|
+
// The single-turn trees this stage drops BY DESIGN must not be reported as
|
|
106
|
+
// damage — only genuinely malformed lines are.
|
|
107
|
+
malformedOnly: true,
|
|
108
|
+
},
|
|
109
|
+
discover: singleUnit({
|
|
110
|
+
// Resume id "oasst2::trees" — the string this store already records.
|
|
111
|
+
key: "trees",
|
|
112
|
+
label: "oasst2",
|
|
113
|
+
display: "oasst2 (multi-turn)",
|
|
114
|
+
url: OASST_URL,
|
|
115
|
+
dest: "oasst2_ready.trees.jsonl.gz",
|
|
116
|
+
acquireLabel: "oasst2 trees",
|
|
117
|
+
localMatch: [/oasst.*trees.*\.jsonl\.gz$/i, /oasst.*\.jsonl\.gz$/i],
|
|
118
|
+
localWhat: "oasst2 *trees*.jsonl.gz",
|
|
119
|
+
}),
|
|
120
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type TrainingItem } from "../items.js";
|
|
2
|
+
import type { Corpus } from "../corpus.js";
|
|
3
|
+
/** One normalized SmolSent row. */
|
|
4
|
+
export interface SmolSentRow {
|
|
5
|
+
src: string;
|
|
6
|
+
trg: string;
|
|
7
|
+
sl: string;
|
|
8
|
+
tl: string;
|
|
9
|
+
}
|
|
10
|
+
/** Normalize a raw datasets-server row into a SmolSentRow, or null when it lacks
|
|
11
|
+
* both sides or a side is implausibly large (a dump, not a sentence). */
|
|
12
|
+
export declare function toSmolSentRow(row: unknown, maxChars?: number): SmolSentRow | null;
|
|
13
|
+
/** Translate ONE SmolSent pair into SEMA facts. The two sentences are one
|
|
14
|
+
* meaning in two languages, but the two BINDINGS are not equally sound —
|
|
15
|
+
* SmolSent's English side is a shared pool translated into every language, so
|
|
16
|
+
* `trg -> src` gives one English context a different answer in every language
|
|
17
|
+
* file. See SMOLSENT_DIRECTIONS. refineItems drops the degenerate case where
|
|
18
|
+
* src === trg. */
|
|
19
|
+
export declare function smolSentRowToItems(row: SmolSentRow, dirs?: {
|
|
20
|
+
src2trg: boolean;
|
|
21
|
+
trg2src: boolean;
|
|
22
|
+
}): TrainingItem[];
|
|
23
|
+
export declare const smolsent: Corpus;
|