@tuned-tensor/cli 0.21.0 → 0.22.1
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 +97 -5
- package/dist/{chunk-PVLX7LJI.js → chunk-RPWOCVIL.js} +1320 -229
- package/dist/chunk-RPWOCVIL.js.map +1 -0
- package/dist/index.js +527 -55
- package/dist/index.js.map +1 -1
- package/dist/local-runtime.js +107 -44
- package/dist/local-runtime.js.map +1 -1
- package/docs/local-runtime/architecture.md +38 -0
- package/docs/local-runtime/aws-gpu.md +2 -0
- package/docs/spec-workflow.md +7 -0
- package/package.json +1 -1
- package/training/adapter/src/hub_download.py +384 -0
- package/training/adapter/src/prefetch.py +20 -31
- package/training/adapter/src/prefetch_dataset.py +116 -0
- package/training/adapter/src/serve.py +5 -1
- package/dist/chunk-PVLX7LJI.js.map +0 -1
package/dist/local-runtime.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
DEFAULT_LOCAL_SPEC_PATH,
|
|
4
|
+
DatasetNotDownloadedError,
|
|
4
5
|
assertArtifactManifest,
|
|
5
6
|
assertFoundationSpecReady,
|
|
6
7
|
assertLocalRunInputReady,
|
|
7
8
|
assertUsableModelArtifact,
|
|
8
9
|
assessHardware,
|
|
10
|
+
auditRun,
|
|
9
11
|
baseModelRevisionSchema,
|
|
10
12
|
behaviorSpecExampleSchema,
|
|
11
13
|
behaviorSpecSchema,
|
|
@@ -18,14 +20,19 @@ import {
|
|
|
18
20
|
comparisonReportSchema,
|
|
19
21
|
compileSpecToJsonl,
|
|
20
22
|
createLocalStore,
|
|
23
|
+
createRunConsoleReporter,
|
|
24
|
+
datasetColumnsSchema,
|
|
21
25
|
datasetFormatSchema,
|
|
26
|
+
datasetInputIdentity,
|
|
22
27
|
datasetPrebuiltSchema,
|
|
28
|
+
datasetSourceSchema,
|
|
23
29
|
decisionHyperparametersSchema,
|
|
24
30
|
decisionLabels,
|
|
25
31
|
decisionPlaceholderIssues,
|
|
26
32
|
decisionQuestionSchema,
|
|
27
33
|
defaultBaseModelRevision,
|
|
28
34
|
defaultLocalHome,
|
|
35
|
+
ensureDatasetCached,
|
|
29
36
|
evalExampleResultSchema,
|
|
30
37
|
evalReportSchema,
|
|
31
38
|
evalSplitSchema,
|
|
@@ -42,10 +49,14 @@ import {
|
|
|
42
49
|
foundationPlaceholderIssues,
|
|
43
50
|
generatedPlaceholderIssues,
|
|
44
51
|
hardenExistingLocalStore,
|
|
52
|
+
huggingFaceDataset,
|
|
53
|
+
huggingFaceDatasetSourceSchema,
|
|
54
|
+
huggingFaceRepoIdSchema,
|
|
45
55
|
initLocalRunnerConfigFile,
|
|
46
56
|
initLocalSpecFile,
|
|
47
57
|
isDecisionSpecFile,
|
|
48
58
|
isFoundationSpecFile,
|
|
59
|
+
isRepoRelativePath,
|
|
49
60
|
isTerminalRunState,
|
|
50
61
|
jsonFieldMetricsSchema,
|
|
51
62
|
loadJsonFile,
|
|
@@ -66,6 +77,7 @@ import {
|
|
|
66
77
|
parseLocalRunnerConfig,
|
|
67
78
|
pipelineForRunInput,
|
|
68
79
|
prefetchBaseModel,
|
|
80
|
+
prefetchHuggingFaceDataset,
|
|
69
81
|
projectRuntimeSchema,
|
|
70
82
|
pythonEnvironmentPath,
|
|
71
83
|
reportInBackground,
|
|
@@ -77,8 +89,10 @@ import {
|
|
|
77
89
|
runGpuProcess,
|
|
78
90
|
runLocalFineTune,
|
|
79
91
|
runLocalPipeline,
|
|
92
|
+
runProvenanceSchema,
|
|
80
93
|
runReportSchema,
|
|
81
94
|
runRequestFromLocalSpec,
|
|
95
|
+
safeName,
|
|
82
96
|
sanitizeLogLine,
|
|
83
97
|
specHash,
|
|
84
98
|
specSnapshotSchema,
|
|
@@ -94,13 +108,13 @@ import {
|
|
|
94
108
|
withHuggingFaceCacheEnvironment,
|
|
95
109
|
withOfflineHuggingFaceCacheEnvironment,
|
|
96
110
|
writePrivateJsonAtomic
|
|
97
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-RPWOCVIL.js";
|
|
98
112
|
|
|
99
113
|
// src/local-runtime/index.ts
|
|
100
114
|
import { readFileSync as readFileSync3, realpathSync } from "fs";
|
|
101
115
|
import { createHash as createHash2 } from "crypto";
|
|
102
116
|
import { readFile as readFile2, stat } from "fs/promises";
|
|
103
|
-
import { basename, dirname, join as join5, resolve as resolve3 } from "path";
|
|
117
|
+
import { basename, dirname, join as join5, relative, resolve as resolve3 } from "path";
|
|
104
118
|
import { cwd } from "process";
|
|
105
119
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
106
120
|
|
|
@@ -932,8 +946,9 @@ Commands:
|
|
|
932
946
|
validate [tunedtensor.json] [--config local-runner.json]
|
|
933
947
|
run [tunedtensor.json] [--config local-runner.json] [--dry-run] [--verbose] [--quiet]
|
|
934
948
|
serve <model-id|active|base|foundation> [--config local-runner.json] [--host 127.0.0.1] [--port 8000]
|
|
935
|
-
runs list|get|events|report|compare [args] [--config local-runner.json]
|
|
949
|
+
runs list|get|events|report|compare|audit [args] [--config local-runner.json]
|
|
936
950
|
models list|get|verify|prefetch|verify-base|active|activate|rollback|serve [args] [--config local-runner.json]
|
|
951
|
+
datasets prefetch|verify [tunedtensor.json]
|
|
937
952
|
|
|
938
953
|
Global options:
|
|
939
954
|
-h, --help Show help
|
|
@@ -1037,6 +1052,7 @@ var COMMAND_GROUPS = {
|
|
|
1037
1052
|
get: { usage: "tt runs get <run-id> [--config path]", description: "Get a local run.", options: [CONFIG_OPTION], minPositionals: 1, maxPositionals: 1, missingPositionalsMessage: "runs get requires <run-id>" },
|
|
1038
1053
|
events: { usage: "tt runs events <run-id> [--config path]", description: "List run events.", options: [CONFIG_OPTION], minPositionals: 1, maxPositionals: 1, missingPositionalsMessage: "runs events requires <run-id>" },
|
|
1039
1054
|
report: { usage: "tt runs report <run-id> [--config path]", description: "Show the baseline-vs-tuned report, including deltas and regressions.", options: [CONFIG_OPTION], minPositionals: 1, maxPositionals: 1, missingPositionalsMessage: "runs report requires <run-id>" },
|
|
1055
|
+
audit: { usage: "tt runs audit <run-id> [--config path]", description: "Verify the run's event chain and report digest, and show its timeline and provenance.", options: [CONFIG_OPTION], minPositionals: 1, maxPositionals: 1, missingPositionalsMessage: "runs audit requires <run-id>" },
|
|
1040
1056
|
compare: { usage: "tt runs compare <run-id-a> <run-id-b> [--config path]", description: "Compare two run reports.", options: [CONFIG_OPTION], minPositionals: 2, maxPositionals: 2, missingPositionalsMessage: "runs compare requires <run-id-a> <run-id-b>" }
|
|
1041
1057
|
}
|
|
1042
1058
|
},
|
|
@@ -1095,6 +1111,24 @@ var COMMAND_GROUPS = {
|
|
|
1095
1111
|
missingPositionalsMessage: "models serve requires <model-id>"
|
|
1096
1112
|
}
|
|
1097
1113
|
}
|
|
1114
|
+
},
|
|
1115
|
+
datasets: {
|
|
1116
|
+
description: "Download or verify the Hugging Face dataset a behavior spec trains on.",
|
|
1117
|
+
defaultSubcommand: "prefetch",
|
|
1118
|
+
subcommands: {
|
|
1119
|
+
prefetch: {
|
|
1120
|
+
usage: "tt datasets prefetch [tunedtensor.json] [options]",
|
|
1121
|
+
description: "Download dataset_prebuilt.huggingface files into the local Hugging Face cache. Resumes after interruption.",
|
|
1122
|
+
options: [CONFIG_OPTION, VERBOSE_OPTION, QUIET_OPTION],
|
|
1123
|
+
maxPositionals: 1
|
|
1124
|
+
},
|
|
1125
|
+
verify: {
|
|
1126
|
+
usage: "tt datasets verify [tunedtensor.json] [options]",
|
|
1127
|
+
description: "Verify the cached dataset files and checksums without network access.",
|
|
1128
|
+
options: [CONFIG_OPTION, QUIET_OPTION],
|
|
1129
|
+
maxPositionals: 1
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1098
1132
|
}
|
|
1099
1133
|
};
|
|
1100
1134
|
function hasHelpFlag(argv) {
|
|
@@ -1255,38 +1289,9 @@ async function loadCliBehaviorSpec(inputPath, runId) {
|
|
|
1255
1289
|
function printJson(value) {
|
|
1256
1290
|
console.log(JSON.stringify(value, null, 2));
|
|
1257
1291
|
}
|
|
1258
|
-
function shortValue(value) {
|
|
1259
|
-
if (value === void 0 || value === null) return null;
|
|
1260
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1261
|
-
return String(value);
|
|
1262
|
-
}
|
|
1263
|
-
if (Array.isArray(value)) return `[${value.length} items]`;
|
|
1264
|
-
return null;
|
|
1265
|
-
}
|
|
1266
|
-
function formatEvent(event) {
|
|
1267
|
-
const detailText = Object.entries(event.details ?? {}).filter(([key]) => key !== "metrics").map(([key, value]) => {
|
|
1268
|
-
const formatted = key === "command" && Array.isArray(value) ? value.join(" ") : shortValue(value);
|
|
1269
|
-
return formatted ? `${key}=${formatted}` : null;
|
|
1270
|
-
}).filter((value) => Boolean(value)).slice(0, 5).join(" ");
|
|
1271
|
-
return sanitizeLogLine(`[tt] ${event.stage}: ${event.message}${detailText ? ` (${detailText})` : ""}`);
|
|
1272
|
-
}
|
|
1273
1292
|
function createConsoleReporter(options) {
|
|
1274
1293
|
if (options.quiet) return void 0;
|
|
1275
|
-
|
|
1276
|
-
return {
|
|
1277
|
-
verbose: options.verbose,
|
|
1278
|
-
onEvent(event) {
|
|
1279
|
-
process.stderr.write(`${formatEvent(event)}
|
|
1280
|
-
`);
|
|
1281
|
-
},
|
|
1282
|
-
onLog(log) {
|
|
1283
|
-
const line = sanitizeLogLine(`[tt] ${log.stage}${log.stream ? ` ${log.stream}` : ""}: ${log.message}`);
|
|
1284
|
-
if (line === lastLogLine) return;
|
|
1285
|
-
lastLogLine = line;
|
|
1286
|
-
process.stderr.write(`${line}
|
|
1287
|
-
`);
|
|
1288
|
-
}
|
|
1289
|
-
};
|
|
1294
|
+
return createRunConsoleReporter({ verbose: options.verbose });
|
|
1290
1295
|
}
|
|
1291
1296
|
async function verifyStoredModel(model, config) {
|
|
1292
1297
|
const manifestPath = join5(model.artifact_dir, "artifact-manifest.json");
|
|
@@ -1805,10 +1810,32 @@ ${validation.errors.join("\n")}`);
|
|
|
1805
1810
|
const input = loaded;
|
|
1806
1811
|
assertLocalRunInputReady(input.request);
|
|
1807
1812
|
const configSelection = await configSelectionFromArgv(argv, inputPath);
|
|
1808
|
-
const
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1813
|
+
const remoteDataset = huggingFaceDataset(input.request);
|
|
1814
|
+
let validated;
|
|
1815
|
+
try {
|
|
1816
|
+
validated = await validateLocalFineTuneInput({
|
|
1817
|
+
request: input.request,
|
|
1818
|
+
config: configSelection.config
|
|
1819
|
+
});
|
|
1820
|
+
} catch (error) {
|
|
1821
|
+
if (!(error instanceof DatasetNotDownloadedError) || !remoteDataset) throw error;
|
|
1822
|
+
const config2 = localRunnerConfigSchema.parse(configSelection.config);
|
|
1823
|
+
printJson({
|
|
1824
|
+
ok: true,
|
|
1825
|
+
input_path: input.path,
|
|
1826
|
+
config_path: configSelection.path ?? null,
|
|
1827
|
+
behavior_spec_id: input.request.behavior_spec_id,
|
|
1828
|
+
base_model: input.request.spec_snapshot.base_model,
|
|
1829
|
+
dataset_format: remoteDataset.format,
|
|
1830
|
+
dataset_status: "not_downloaded",
|
|
1831
|
+
dataset_huggingface: remoteDataset.huggingface,
|
|
1832
|
+
next_step: `tt datasets prefetch ${relative(cwd(), input.path) || input.path}`,
|
|
1833
|
+
artifact_root: config2.artifactRoot,
|
|
1834
|
+
store_root: config2.storeRoot,
|
|
1835
|
+
dry_run: config2.dryRun
|
|
1836
|
+
});
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1812
1839
|
const request = validated.request;
|
|
1813
1840
|
const config = validated.config;
|
|
1814
1841
|
printJson({
|
|
@@ -1818,6 +1845,7 @@ ${validation.errors.join("\n")}`);
|
|
|
1818
1845
|
behavior_spec_id: request.behavior_spec_id,
|
|
1819
1846
|
base_model: request.spec_snapshot.base_model,
|
|
1820
1847
|
dataset_format: request.dataset_prebuilt?.format ?? null,
|
|
1848
|
+
...request.dataset_source ? { dataset_status: "cached", dataset_source: request.dataset_source } : {},
|
|
1821
1849
|
artifact_root: config.artifactRoot,
|
|
1822
1850
|
store_root: config.storeRoot,
|
|
1823
1851
|
dry_run: config.dryRun
|
|
@@ -1834,15 +1862,16 @@ ${validation.errors.join("\n")}`);
|
|
|
1834
1862
|
dryRun: hasFlag(argv, "--dry-run") ? true : configInput.dryRun
|
|
1835
1863
|
});
|
|
1836
1864
|
assertLocalRunInputReady(input.request);
|
|
1837
|
-
const validated = await validateLocalFineTuneInput({
|
|
1838
|
-
request: input.request,
|
|
1839
|
-
config
|
|
1840
|
-
});
|
|
1841
|
-
let request = validated.request;
|
|
1842
1865
|
const reporter = createConsoleReporter({
|
|
1843
1866
|
verbose: hasFlag(argv, "--verbose"),
|
|
1844
1867
|
quiet: hasFlag(argv, "--quiet")
|
|
1845
1868
|
});
|
|
1869
|
+
const ensured = await ensureDatasetCached({ request: input.request, config, reporter });
|
|
1870
|
+
const validated = await validateLocalFineTuneInput({
|
|
1871
|
+
request: ensured.request,
|
|
1872
|
+
config
|
|
1873
|
+
});
|
|
1874
|
+
let request = validated.request;
|
|
1846
1875
|
if (!config.dryRun && !config.paths.baseModel && !request.hyperparameters.base_model_revision) {
|
|
1847
1876
|
const prefetch = await prefetchBaseModel({
|
|
1848
1877
|
request,
|
|
@@ -1860,12 +1889,13 @@ ${validation.errors.join("\n")}`);
|
|
|
1860
1889
|
}
|
|
1861
1890
|
});
|
|
1862
1891
|
}
|
|
1892
|
+
const specFile = /^\..+\.tt-local-/.test(basename(input.path)) ? void 0 : { path: input.path, sha256: specHash(await readFile2(input.path, "utf8")) };
|
|
1863
1893
|
if (input.spec.pipeline) {
|
|
1864
|
-
const result2 = await runLocalPipeline({ request, config, reporter, pipeline: pipelineForRunInput(input), projectSpec: input.spec });
|
|
1894
|
+
const result2 = await runLocalPipeline({ request, config, reporter, pipeline: pipelineForRunInput(input), projectSpec: input.spec, specFile });
|
|
1865
1895
|
printJson(result2);
|
|
1866
1896
|
return;
|
|
1867
1897
|
}
|
|
1868
|
-
const result = await runLocalFineTune({ request, config, reporter });
|
|
1898
|
+
const result = await runLocalFineTune({ request, config, reporter, specFile });
|
|
1869
1899
|
printJson({
|
|
1870
1900
|
status: result.report.status,
|
|
1871
1901
|
run_id: result.report.run_id,
|
|
@@ -1913,6 +1943,14 @@ ${validation.errors.join("\n")}`);
|
|
|
1913
1943
|
if (!id) throw new Error("runs report requires <run-id>");
|
|
1914
1944
|
return printJson(await store.getRunReport(id));
|
|
1915
1945
|
}
|
|
1946
|
+
if (subcommand === "audit") {
|
|
1947
|
+
const id = cli.positionals[0];
|
|
1948
|
+
if (!id) throw new Error("runs audit requires <run-id>");
|
|
1949
|
+
const audit = await auditRun(store, id);
|
|
1950
|
+
printJson(audit);
|
|
1951
|
+
if (audit.verdict === "tampered") process.exitCode = 2;
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1916
1954
|
if (subcommand === "compare") {
|
|
1917
1955
|
const idA = cli.positionals[0];
|
|
1918
1956
|
const idB = cli.positionals[1];
|
|
@@ -1925,6 +1963,23 @@ ${validation.errors.join("\n")}`);
|
|
|
1925
1963
|
}
|
|
1926
1964
|
throw new Error(`Unknown runs command: ${subcommand}`);
|
|
1927
1965
|
}
|
|
1966
|
+
if (command === "datasets") {
|
|
1967
|
+
const subcommand = cli.subcommand;
|
|
1968
|
+
const inputPath = resolve3(cli.positionals[0] ?? DEFAULT_LOCAL_SPEC_PATH);
|
|
1969
|
+
const config = await configFromArgv(argv, inputPath);
|
|
1970
|
+
const input = await loadCliBehaviorSpec(inputPath);
|
|
1971
|
+
if (subcommand !== "prefetch" && subcommand !== "verify") throw new Error(`Unknown datasets command: ${subcommand}`);
|
|
1972
|
+
const report = await prefetchHuggingFaceDataset({
|
|
1973
|
+
request: input.request,
|
|
1974
|
+
config,
|
|
1975
|
+
localOnly: subcommand === "verify",
|
|
1976
|
+
reporter: createConsoleReporter({
|
|
1977
|
+
verbose: hasFlag(argv, "--verbose"),
|
|
1978
|
+
quiet: hasFlag(argv, "--quiet")
|
|
1979
|
+
})
|
|
1980
|
+
});
|
|
1981
|
+
return printJson({ ...report, input_path: input.path });
|
|
1982
|
+
}
|
|
1928
1983
|
if (command === "models") {
|
|
1929
1984
|
const subcommand = cli.subcommand;
|
|
1930
1985
|
const modelInputPath = subcommand === "prefetch" || subcommand === "verify-base" ? resolve3(cli.positionals[0] ?? DEFAULT_LOCAL_SPEC_PATH) : void 0;
|
|
@@ -2040,8 +2095,11 @@ export {
|
|
|
2040
2095
|
comparisonReportSchema,
|
|
2041
2096
|
compileSpecToJsonl,
|
|
2042
2097
|
createLocalStore,
|
|
2098
|
+
datasetColumnsSchema,
|
|
2043
2099
|
datasetFormatSchema,
|
|
2100
|
+
datasetInputIdentity,
|
|
2044
2101
|
datasetPrebuiltSchema,
|
|
2102
|
+
datasetSourceSchema,
|
|
2045
2103
|
decisionHyperparametersSchema,
|
|
2046
2104
|
decisionLabels,
|
|
2047
2105
|
decisionPlaceholderIssues,
|
|
@@ -2065,10 +2123,13 @@ export {
|
|
|
2065
2123
|
getActiveModel,
|
|
2066
2124
|
getLocalRunnerInfo,
|
|
2067
2125
|
hardenExistingLocalStore,
|
|
2126
|
+
huggingFaceDatasetSourceSchema,
|
|
2127
|
+
huggingFaceRepoIdSchema,
|
|
2068
2128
|
initLocalRunnerConfigFile,
|
|
2069
2129
|
initLocalSpecFile,
|
|
2070
2130
|
isDecisionSpecFile,
|
|
2071
2131
|
isFoundationSpecFile,
|
|
2132
|
+
isRepoRelativePath,
|
|
2072
2133
|
isTerminalRunState,
|
|
2073
2134
|
jsonFieldMetricsSchema,
|
|
2074
2135
|
loadJsonFile,
|
|
@@ -2092,8 +2153,10 @@ export {
|
|
|
2092
2153
|
rollbackActiveModel,
|
|
2093
2154
|
runLocalFineTune,
|
|
2094
2155
|
runLocalPipeline,
|
|
2156
|
+
runProvenanceSchema,
|
|
2095
2157
|
runReportSchema,
|
|
2096
2158
|
runRequestFromLocalSpec,
|
|
2159
|
+
safeName,
|
|
2097
2160
|
sanitizeLogLine,
|
|
2098
2161
|
serveLocalModel,
|
|
2099
2162
|
specHash,
|