@tuned-tensor/cli 0.13.0-beta.0 → 0.13.0-beta.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 +1 -1
- package/dist/{chunk-HDGBDHOB.js → chunk-2VJ3VVZF.js} +383 -370
- package/dist/chunk-2VJ3VVZF.js.map +1 -0
- package/dist/index.js +395 -41
- package/dist/index.js.map +1 -1
- package/dist/local-runtime.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-HDGBDHOB.js.map +0 -1
|
@@ -1079,337 +1079,16 @@ var localRunnerConfigSchema = z.object({
|
|
|
1079
1079
|
})
|
|
1080
1080
|
}).strict();
|
|
1081
1081
|
|
|
1082
|
-
// src/local-runtime/local-project.ts
|
|
1083
|
-
import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
|
|
1084
|
-
import { readFile as readFile2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
1085
|
-
import { dirname as dirname2, isAbsolute as isAbsolute2, resolve as resolve3 } from "path";
|
|
1086
|
-
import { homedir } from "os";
|
|
1087
|
-
import { mkdir as mkdir2 } from "fs/promises";
|
|
1088
|
-
var DEFAULT_LOCAL_SPEC_PATH = "tunedtensor.json";
|
|
1089
|
-
function resolveLocalReference(value, baseDirectory) {
|
|
1090
|
-
if (typeof value !== "string" || !value || isAbsolute2(value) || /^[a-z][a-z0-9+.-]*:/i.test(value)) {
|
|
1091
|
-
return value;
|
|
1092
|
-
}
|
|
1093
|
-
if (value === "~") return homedir();
|
|
1094
|
-
if (value.startsWith("~/")) return resolve3(homedir(), value.slice(2));
|
|
1095
|
-
return resolve3(baseDirectory, value);
|
|
1096
|
-
}
|
|
1097
|
-
function resolveLocalRunInputPaths(raw, inputPath) {
|
|
1098
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return raw;
|
|
1099
|
-
const baseDirectory = dirname2(resolve3(inputPath));
|
|
1100
|
-
const value = structuredClone(raw);
|
|
1101
|
-
const dataset = value.dataset_prebuilt;
|
|
1102
|
-
if (dataset && typeof dataset === "object" && !Array.isArray(dataset)) {
|
|
1103
|
-
const fields = dataset;
|
|
1104
|
-
for (const key of ["training", "validation", "test"]) {
|
|
1105
|
-
if (fields[key] !== void 0) fields[key] = resolveLocalReference(fields[key], baseDirectory);
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
return value;
|
|
1109
|
-
}
|
|
1110
|
-
async function exists(path) {
|
|
1111
|
-
try {
|
|
1112
|
-
await stat2(path);
|
|
1113
|
-
return true;
|
|
1114
|
-
} catch {
|
|
1115
|
-
return false;
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
async function initLocalSpecFile(args) {
|
|
1119
|
-
if (!args.force && await exists(args.outputPath)) {
|
|
1120
|
-
throw new Error(`Refusing to overwrite existing file: ${args.outputPath}`);
|
|
1121
|
-
}
|
|
1122
|
-
const spec = localBehaviorSpecFileSchema.parse({
|
|
1123
|
-
id: randomUUID2(),
|
|
1124
|
-
name: args.name,
|
|
1125
|
-
description: "",
|
|
1126
|
-
system_prompt: "Describe the behavior this local model should learn.",
|
|
1127
|
-
guidelines: [
|
|
1128
|
-
"Return concise, task-specific answers."
|
|
1129
|
-
],
|
|
1130
|
-
constraints: [],
|
|
1131
|
-
base_model: args.baseModel,
|
|
1132
|
-
examples: [
|
|
1133
|
-
{
|
|
1134
|
-
input: "Replace this with representative training input.",
|
|
1135
|
-
output: "Replace this with the expected training output."
|
|
1136
|
-
},
|
|
1137
|
-
{
|
|
1138
|
-
input: "Replace this with a different validation input.",
|
|
1139
|
-
output: "Replace this with the expected validation output."
|
|
1140
|
-
}
|
|
1141
|
-
],
|
|
1142
|
-
hyperparameters: {
|
|
1143
|
-
n_epochs: 1
|
|
1144
|
-
}
|
|
1145
|
-
});
|
|
1146
|
-
await mkdir2(dirname2(args.outputPath), { recursive: true });
|
|
1147
|
-
await writeFile2(args.outputPath, `${JSON.stringify(spec, null, 2)}
|
|
1148
|
-
`, "utf8");
|
|
1149
|
-
return spec;
|
|
1150
|
-
}
|
|
1151
|
-
async function initLocalRunnerConfigFile(args) {
|
|
1152
|
-
if (!args.force && await exists(args.outputPath)) {
|
|
1153
|
-
throw new Error(`Refusing to overwrite existing file: ${args.outputPath}`);
|
|
1154
|
-
}
|
|
1155
|
-
const config = {
|
|
1156
|
-
artifactRoot: ".tt-local/artifacts",
|
|
1157
|
-
storeRoot: ".tt-local/store",
|
|
1158
|
-
evaluation: {
|
|
1159
|
-
inference: {
|
|
1160
|
-
device: "cuda"
|
|
1161
|
-
},
|
|
1162
|
-
scoring: {
|
|
1163
|
-
mode: "exact_match"
|
|
1164
|
-
},
|
|
1165
|
-
timeoutMs: 18e5
|
|
1166
|
-
}
|
|
1167
|
-
};
|
|
1168
|
-
await mkdir2(dirname2(args.outputPath), { recursive: true });
|
|
1169
|
-
await writeFile2(args.outputPath, `${JSON.stringify(config, null, 2)}
|
|
1170
|
-
`, "utf8");
|
|
1171
|
-
return config;
|
|
1172
|
-
}
|
|
1173
|
-
function generatedPlaceholderIssues(request) {
|
|
1174
|
-
const issues = [];
|
|
1175
|
-
if (/describe the behavior this local model should learn/i.test(request.spec_snapshot.system_prompt)) {
|
|
1176
|
-
issues.push("system_prompt still contains the generated placeholder");
|
|
1177
|
-
}
|
|
1178
|
-
request.spec_snapshot.examples.forEach((example, index) => {
|
|
1179
|
-
if (/replace this with/i.test(example.input) || /replace this with/i.test(example.output)) {
|
|
1180
|
-
issues.push(`examples[${index}] still contains generated placeholder text`);
|
|
1181
|
-
}
|
|
1182
|
-
});
|
|
1183
|
-
return issues;
|
|
1184
|
-
}
|
|
1185
|
-
function assertLocalRunInputReady(request) {
|
|
1186
|
-
const issues = generatedPlaceholderIssues(request);
|
|
1187
|
-
if (issues.length > 0) {
|
|
1188
|
-
throw new Error(`Edit the generated behavior spec before training: ${issues.join("; ")}.`);
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
function runRequestFromLocalSpec(spec, options = {}) {
|
|
1192
|
-
const {
|
|
1193
|
-
id,
|
|
1194
|
-
hyperparameters,
|
|
1195
|
-
dataset_prebuilt: datasetPrebuilt,
|
|
1196
|
-
...specSnapshot
|
|
1197
|
-
} = spec;
|
|
1198
|
-
const behaviorSpecId = id ?? deterministicBehaviorSpecId(specSnapshot);
|
|
1199
|
-
return fineTuneRunRequestSchema.parse({
|
|
1200
|
-
run_id: options.runId ?? randomUUID2(),
|
|
1201
|
-
user_id: "local-user",
|
|
1202
|
-
behavior_spec_id: behaviorSpecId,
|
|
1203
|
-
run_number: 1,
|
|
1204
|
-
spec_snapshot: specSnapshot,
|
|
1205
|
-
hyperparameters,
|
|
1206
|
-
dataset_prebuilt: datasetPrebuilt
|
|
1207
|
-
});
|
|
1208
|
-
}
|
|
1209
|
-
function deterministicBehaviorSpecId(spec) {
|
|
1210
|
-
const namespace = Buffer.from("9f783f01340457bea061942004259253", "hex");
|
|
1211
|
-
const digest = createHash2("sha1").update(namespace).update(JSON.stringify(spec)).digest().subarray(0, 16);
|
|
1212
|
-
digest[6] = digest[6] & 15 | 80;
|
|
1213
|
-
digest[8] = digest[8] & 63 | 128;
|
|
1214
|
-
const hex = digest.toString("hex");
|
|
1215
|
-
return [
|
|
1216
|
-
hex.slice(0, 8),
|
|
1217
|
-
hex.slice(8, 12),
|
|
1218
|
-
hex.slice(12, 16),
|
|
1219
|
-
hex.slice(16, 20),
|
|
1220
|
-
hex.slice(20)
|
|
1221
|
-
].join("-");
|
|
1222
|
-
}
|
|
1223
|
-
async function loadLocalRunInput(path, options = {}) {
|
|
1224
|
-
const raw = resolveLocalRunInputPaths(JSON.parse(await readFile2(path, "utf8")), path);
|
|
1225
|
-
const request = fineTuneRunRequestSchema.safeParse(raw);
|
|
1226
|
-
if (request.success) {
|
|
1227
|
-
return { kind: "request", path, request: request.data };
|
|
1228
|
-
}
|
|
1229
|
-
const spec = localBehaviorSpecFileSchema.parse(raw);
|
|
1230
|
-
return {
|
|
1231
|
-
kind: "spec",
|
|
1232
|
-
path,
|
|
1233
|
-
spec,
|
|
1234
|
-
request: runRequestFromLocalSpec(spec, options)
|
|
1235
|
-
};
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
|
-
// src/local-runtime/dataset.ts
|
|
1239
|
-
import { readFile as readFile3 } from "fs/promises";
|
|
1240
|
-
async function loadNormalizedChatJsonl(path) {
|
|
1241
|
-
const text = await readFile3(path, "utf8");
|
|
1242
|
-
const rows = [];
|
|
1243
|
-
const jsonLines = [];
|
|
1244
|
-
for (const [index, line] of text.split(/\r?\n/).entries()) {
|
|
1245
|
-
if (!line.trim()) continue;
|
|
1246
|
-
let value;
|
|
1247
|
-
try {
|
|
1248
|
-
value = JSON.parse(line);
|
|
1249
|
-
} catch (error) {
|
|
1250
|
-
throw new Error(`Invalid chat JSONL row ${index + 1}: malformed JSON`, { cause: error });
|
|
1251
|
-
}
|
|
1252
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1253
|
-
throw new Error(`Invalid chat JSONL row ${index + 1}: expected an object`);
|
|
1254
|
-
}
|
|
1255
|
-
const messages = value.messages;
|
|
1256
|
-
if (!Array.isArray(messages) || ![2, 3].includes(messages.length) || messages.some(
|
|
1257
|
-
(message) => !message || typeof message !== "object" || Array.isArray(message) || !["system", "user", "assistant"].includes(String(message.role)) || typeof message.content !== "string"
|
|
1258
|
-
)) {
|
|
1259
|
-
throw new Error(
|
|
1260
|
-
`Invalid chat JSONL row ${index + 1}: expected an optional system message, one user message, and one assistant answer`
|
|
1261
|
-
);
|
|
1262
|
-
}
|
|
1263
|
-
const row = { messages };
|
|
1264
|
-
const offset = row.messages.length === 3 ? 1 : 0;
|
|
1265
|
-
if (offset === 1 && row.messages[0]?.role !== "system" || row.messages[offset]?.role !== "user" || !row.messages[offset]?.content.trim() || row.messages[offset + 1]?.role !== "assistant" || !row.messages[offset + 1]?.content.trim()) {
|
|
1266
|
-
throw new Error(
|
|
1267
|
-
`Invalid chat JSONL row ${index + 1}: expected an optional system message, one non-empty user message, and one non-empty assistant answer`
|
|
1268
|
-
);
|
|
1269
|
-
}
|
|
1270
|
-
rows.push(row);
|
|
1271
|
-
jsonLines.push(JSON.stringify(row));
|
|
1272
|
-
}
|
|
1273
|
-
if (rows.length === 0) throw new Error(`Chat JSONL contains no examples: ${path}`);
|
|
1274
|
-
return {
|
|
1275
|
-
rows,
|
|
1276
|
-
jsonl: jsonLines.join("\n")
|
|
1277
|
-
};
|
|
1278
|
-
}
|
|
1279
|
-
async function normalizeChatJsonlForRelocation(path) {
|
|
1280
|
-
return (await loadNormalizedChatJsonl(path)).jsonl;
|
|
1281
|
-
}
|
|
1282
|
-
function buildSystemMessage(spec) {
|
|
1283
|
-
const parts = [];
|
|
1284
|
-
if (spec.system_prompt.trim()) parts.push(spec.system_prompt.trim());
|
|
1285
|
-
if (spec.guidelines.length > 0) {
|
|
1286
|
-
parts.push(`Guidelines:
|
|
1287
|
-
${spec.guidelines.map((guideline) => `- ${guideline}`).join("\n")}`);
|
|
1288
|
-
}
|
|
1289
|
-
if (spec.constraints.length > 0) {
|
|
1290
|
-
parts.push(`Constraints:
|
|
1291
|
-
${spec.constraints.map((constraint) => `- ${constraint}`).join("\n")}`);
|
|
1292
|
-
}
|
|
1293
|
-
return parts.join("\n\n") || "Follow the demonstrated behavior.";
|
|
1294
|
-
}
|
|
1295
|
-
function exampleToChatRow(spec, example) {
|
|
1296
|
-
const system = buildSystemMessage(spec);
|
|
1297
|
-
return {
|
|
1298
|
-
messages: [
|
|
1299
|
-
{ role: "system", content: system },
|
|
1300
|
-
{ role: "user", content: example.input },
|
|
1301
|
-
{ role: "assistant", content: example.output }
|
|
1302
|
-
]
|
|
1303
|
-
};
|
|
1304
|
-
}
|
|
1305
|
-
function compileSpecToJsonl(spec) {
|
|
1306
|
-
return spec.examples.map((example) => JSON.stringify(exampleToChatRow(spec, example))).join("\n");
|
|
1307
|
-
}
|
|
1308
|
-
function examplesFromSpec(spec) {
|
|
1309
|
-
return spec.examples;
|
|
1310
|
-
}
|
|
1311
|
-
async function examplesFromChatJsonl(path) {
|
|
1312
|
-
const normalized = await loadNormalizedChatJsonl(path);
|
|
1313
|
-
const examples = [];
|
|
1314
|
-
for (const [index, row] of normalized.rows.entries()) {
|
|
1315
|
-
const user = row.messages.at(-2);
|
|
1316
|
-
const assistant = row.messages.at(-1);
|
|
1317
|
-
examples.push({
|
|
1318
|
-
input: user.content,
|
|
1319
|
-
output: assistant.content
|
|
1320
|
-
});
|
|
1321
|
-
}
|
|
1322
|
-
return examples;
|
|
1323
|
-
}
|
|
1324
|
-
async function evaluationSuiteFromChatJsonl(path, configuredSystem) {
|
|
1325
|
-
const normalized = await loadNormalizedChatJsonl(path);
|
|
1326
|
-
const inputIdentities = /* @__PURE__ */ new Set();
|
|
1327
|
-
for (const row of normalized.rows) {
|
|
1328
|
-
const input = row.messages.at(-2).content;
|
|
1329
|
-
const identity = input.trim().replace(/\s+/g, " ").toLowerCase();
|
|
1330
|
-
if (inputIdentities.has(identity)) {
|
|
1331
|
-
throw new Error(
|
|
1332
|
-
"General regression data contains duplicate inputs; evaluation prompts must be unique."
|
|
1333
|
-
);
|
|
1334
|
-
}
|
|
1335
|
-
inputIdentities.add(identity);
|
|
1336
|
-
}
|
|
1337
|
-
const systems = new Set(
|
|
1338
|
-
normalized.rows.map((row) => row.messages.find((message) => message.role === "system")?.content).filter((value) => value !== void 0)
|
|
1339
|
-
);
|
|
1340
|
-
if (systems.size > 1) {
|
|
1341
|
-
throw new Error("General regression rows must use one consistent system message.");
|
|
1342
|
-
}
|
|
1343
|
-
const embeddedSystem = [...systems][0];
|
|
1344
|
-
if (configuredSystem !== void 0 && embeddedSystem !== void 0 && configuredSystem !== embeddedSystem) {
|
|
1345
|
-
throw new Error(
|
|
1346
|
-
"evaluation.generalRegression.systemPrompt must match the system message embedded in the dataset."
|
|
1347
|
-
);
|
|
1348
|
-
}
|
|
1349
|
-
return {
|
|
1350
|
-
examples: normalized.rows.map((row) => ({
|
|
1351
|
-
input: row.messages.at(-2).content,
|
|
1352
|
-
output: row.messages.at(-1).content
|
|
1353
|
-
})),
|
|
1354
|
-
system: configuredSystem ?? embeddedSystem ?? "You are a helpful assistant."
|
|
1355
|
-
};
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
// src/local-runtime/run-reporter.ts
|
|
1359
|
-
function reportInBackground(action) {
|
|
1360
|
-
try {
|
|
1361
|
-
void Promise.resolve(action()).catch(() => void 0);
|
|
1362
|
-
} catch {
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
function sanitizeLogLine(line) {
|
|
1366
|
-
return line.replace(/(Bearer\s+)[A-Za-z0-9._~+/=-]+/gi, "$1[redacted]").replace(/((?:api[_-]?key|token|secret|password)=)[^\s]+/gi, "$1[redacted]");
|
|
1367
|
-
}
|
|
1368
|
-
function forwardStreamLines(stream, onLine) {
|
|
1369
|
-
let buffered = "";
|
|
1370
|
-
stream.setEncoding("utf8");
|
|
1371
|
-
stream.on("data", (chunk) => {
|
|
1372
|
-
buffered += chunk;
|
|
1373
|
-
const lines = buffered.split(/\r\n|\n|\r/);
|
|
1374
|
-
buffered = lines.pop() ?? "";
|
|
1375
|
-
for (const line of lines) {
|
|
1376
|
-
if (line.trim()) onLine(sanitizeLogLine(line));
|
|
1377
|
-
}
|
|
1378
|
-
});
|
|
1379
|
-
stream.on("end", () => {
|
|
1380
|
-
if (buffered.trim()) onLine(sanitizeLogLine(buffered));
|
|
1381
|
-
});
|
|
1382
|
-
}
|
|
1383
|
-
|
|
1384
|
-
// src/local-runtime/package-root.ts
|
|
1385
|
-
import { existsSync } from "fs";
|
|
1386
|
-
import { dirname as dirname3, resolve as resolve4 } from "path";
|
|
1387
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1388
|
-
function localRuntimePackageRoot(moduleUrl) {
|
|
1389
|
-
const moduleDirectory = dirname3(fileURLToPath2(moduleUrl));
|
|
1390
|
-
const candidates = [
|
|
1391
|
-
dirname3(moduleDirectory),
|
|
1392
|
-
dirname3(dirname3(moduleDirectory))
|
|
1393
|
-
];
|
|
1394
|
-
const root = candidates.find(
|
|
1395
|
-
(candidate) => existsSync(resolve4(candidate, "package.json")) && existsSync(resolve4(candidate, "training/local-runner"))
|
|
1396
|
-
);
|
|
1397
|
-
if (!root) {
|
|
1398
|
-
throw new Error("Unable to locate the bundled Tuned Tensor local runtime assets.");
|
|
1399
|
-
}
|
|
1400
|
-
return root;
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
1082
|
// src/local-runtime/store.ts
|
|
1404
|
-
import { appendFile, copyFile as copyFile2, mkdir as
|
|
1405
|
-
import { homedir
|
|
1406
|
-
import { dirname as
|
|
1407
|
-
import { randomUUID as
|
|
1083
|
+
import { appendFile, copyFile as copyFile2, mkdir as mkdir2, readdir as readdir3, readFile as readFile2, rename as rename2, rm, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
1084
|
+
import { homedir } from "os";
|
|
1085
|
+
import { dirname as dirname2, join as join2, resolve as resolve3, sep as sep2 } from "path";
|
|
1086
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1408
1087
|
function isTerminalRunState(state) {
|
|
1409
1088
|
return state.status === "stage_completed" || state.status === "completed" || state.status === "failed" || state.status === "cancelled" && state.current_stage === "cancelled" && Boolean(state.completed_at);
|
|
1410
1089
|
}
|
|
1411
1090
|
function defaultLocalHome() {
|
|
1412
|
-
return
|
|
1091
|
+
return resolve3(process.env.TT_LOCAL_HOME ?? join2(homedir(), ".tuned-tensor-local"));
|
|
1413
1092
|
}
|
|
1414
1093
|
function localStorePaths(root) {
|
|
1415
1094
|
return {
|
|
@@ -1420,36 +1099,36 @@ function localStorePaths(root) {
|
|
|
1420
1099
|
datasetsDir: join2(root, "datasets")
|
|
1421
1100
|
};
|
|
1422
1101
|
}
|
|
1423
|
-
async function
|
|
1102
|
+
async function exists(path) {
|
|
1424
1103
|
try {
|
|
1425
|
-
await
|
|
1104
|
+
await stat2(path);
|
|
1426
1105
|
return true;
|
|
1427
1106
|
} catch {
|
|
1428
1107
|
return false;
|
|
1429
1108
|
}
|
|
1430
1109
|
}
|
|
1431
1110
|
async function writeJsonAtomic2(path, value) {
|
|
1432
|
-
await
|
|
1433
|
-
const tmp = `${path}.${process.pid}.${Date.now()}.${
|
|
1434
|
-
await
|
|
1111
|
+
await mkdir2(dirname2(path), { recursive: true });
|
|
1112
|
+
const tmp = `${path}.${process.pid}.${Date.now()}.${randomUUID2()}.tmp`;
|
|
1113
|
+
await writeFile2(tmp, `${JSON.stringify(value, null, 2)}
|
|
1435
1114
|
`, "utf8");
|
|
1436
1115
|
await rename2(tmp, path);
|
|
1437
1116
|
}
|
|
1438
1117
|
async function readJson2(path) {
|
|
1439
|
-
return JSON.parse(await
|
|
1118
|
+
return JSON.parse(await readFile2(path, "utf8"));
|
|
1440
1119
|
}
|
|
1441
1120
|
async function appendJsonl(path, value) {
|
|
1442
|
-
await
|
|
1121
|
+
await mkdir2(dirname2(path), { recursive: true });
|
|
1443
1122
|
await appendFile(path, `${JSON.stringify(value)}
|
|
1444
1123
|
`, "utf8");
|
|
1445
1124
|
}
|
|
1446
1125
|
async function readJsonl(path) {
|
|
1447
|
-
if (!await
|
|
1448
|
-
return (await
|
|
1126
|
+
if (!await exists(path)) return [];
|
|
1127
|
+
return (await readFile2(path, "utf8")).split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line));
|
|
1449
1128
|
}
|
|
1450
1129
|
async function copyIfExists(from, to) {
|
|
1451
|
-
if (!await
|
|
1452
|
-
await
|
|
1130
|
+
if (!await exists(from)) return;
|
|
1131
|
+
await mkdir2(dirname2(to), { recursive: true });
|
|
1453
1132
|
await copyFile2(from, to);
|
|
1454
1133
|
}
|
|
1455
1134
|
async function childDirectoryNames(path) {
|
|
@@ -1476,8 +1155,13 @@ function compareCreatedAt(left, right) {
|
|
|
1476
1155
|
function findByIdOrPrefix(records, id) {
|
|
1477
1156
|
return records.find((record) => record.id === id) ?? records.find((record) => record.id.startsWith(id));
|
|
1478
1157
|
}
|
|
1158
|
+
function isPathInside(root, candidate) {
|
|
1159
|
+
const resolvedRoot = resolve3(root);
|
|
1160
|
+
const resolvedCandidate = resolve3(candidate);
|
|
1161
|
+
return resolvedCandidate === resolvedRoot || resolvedCandidate.startsWith(`${resolvedRoot}${sep2}`);
|
|
1162
|
+
}
|
|
1479
1163
|
function createLocalStore(root = defaultLocalHome()) {
|
|
1480
|
-
const resolvedRoot =
|
|
1164
|
+
const resolvedRoot = resolve3(root);
|
|
1481
1165
|
const paths = localStorePaths(resolvedRoot);
|
|
1482
1166
|
const runDir = (id) => join2(paths.runsDir, id);
|
|
1483
1167
|
const runStatePath = (id) => join2(runDir(id), "state.json");
|
|
@@ -1490,10 +1174,10 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1490
1174
|
const modelPath = (id) => join2(paths.modelsDir, id, "model.json");
|
|
1491
1175
|
async function ensure() {
|
|
1492
1176
|
await Promise.all([
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1177
|
+
mkdir2(paths.specsDir, { recursive: true }),
|
|
1178
|
+
mkdir2(paths.runsDir, { recursive: true }),
|
|
1179
|
+
mkdir2(paths.modelsDir, { recursive: true }),
|
|
1180
|
+
mkdir2(paths.datasetsDir, { recursive: true })
|
|
1497
1181
|
]);
|
|
1498
1182
|
}
|
|
1499
1183
|
async function writeRunState(state) {
|
|
@@ -1502,11 +1186,11 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1502
1186
|
}
|
|
1503
1187
|
async function readSpecRecord(id) {
|
|
1504
1188
|
const path = specPath(id);
|
|
1505
|
-
if (!await
|
|
1189
|
+
if (!await exists(path)) return null;
|
|
1506
1190
|
const [spec, fileStats, directoryStats] = await Promise.all([
|
|
1507
1191
|
readJson2(path),
|
|
1508
|
-
|
|
1509
|
-
|
|
1192
|
+
stat2(path),
|
|
1193
|
+
stat2(specDir(id))
|
|
1510
1194
|
]);
|
|
1511
1195
|
const createdAt = directoryStats.birthtimeMs > 0 ? directoryStats.birthtime : directoryStats.ctime;
|
|
1512
1196
|
return {
|
|
@@ -1532,7 +1216,7 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1532
1216
|
const records = [];
|
|
1533
1217
|
for (const id of await childDirectoryNames(paths.runsDir)) {
|
|
1534
1218
|
const path = runStatePath(id);
|
|
1535
|
-
if (await
|
|
1219
|
+
if (await exists(path)) records.push(await readJson2(path));
|
|
1536
1220
|
}
|
|
1537
1221
|
return records.sort(compareUpdatedAt);
|
|
1538
1222
|
}
|
|
@@ -1541,13 +1225,13 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1541
1225
|
const records = [];
|
|
1542
1226
|
for (const id of await childDirectoryNames(paths.modelsDir)) {
|
|
1543
1227
|
const path = modelPath(id);
|
|
1544
|
-
if (await
|
|
1228
|
+
if (await exists(path)) records.push(await readJson2(path));
|
|
1545
1229
|
}
|
|
1546
1230
|
return records.sort(compareCreatedAt);
|
|
1547
1231
|
}
|
|
1548
1232
|
async function importSpecRecord(specId, spec) {
|
|
1549
1233
|
await ensure();
|
|
1550
|
-
await
|
|
1234
|
+
await mkdir2(specDir(specId), { recursive: true });
|
|
1551
1235
|
await writeJsonAtomic2(specPath(specId), spec);
|
|
1552
1236
|
const record = await readSpecRecord(specId);
|
|
1553
1237
|
if (!record) throw new Error(`Failed to persist spec: ${specId}`);
|
|
@@ -1555,7 +1239,7 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1555
1239
|
}
|
|
1556
1240
|
async function appendRunEvent(state, event) {
|
|
1557
1241
|
const row = {
|
|
1558
|
-
id:
|
|
1242
|
+
id: randomUUID2(),
|
|
1559
1243
|
run_id: state.id,
|
|
1560
1244
|
occurred_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1561
1245
|
...event
|
|
@@ -1605,7 +1289,7 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1605
1289
|
}
|
|
1606
1290
|
async function resolveRunId(id) {
|
|
1607
1291
|
await ensure();
|
|
1608
|
-
if (await
|
|
1292
|
+
if (await exists(runStatePath(id))) return id;
|
|
1609
1293
|
const record = findByIdOrPrefix(await listRunRecords(), id);
|
|
1610
1294
|
if (!record) throw new Error(`Run not found: ${id}`);
|
|
1611
1295
|
return record.id;
|
|
@@ -1617,7 +1301,7 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1617
1301
|
if (!args.training.model_artifact_uri || args.training.metrics?.dry_run === true) return null;
|
|
1618
1302
|
const previous = await getRun(args.request.run_id);
|
|
1619
1303
|
const modelId = `local-${args.request.run_id}`;
|
|
1620
|
-
const existingModel = await
|
|
1304
|
+
const existingModel = await exists(modelPath(modelId)) ? await readJson2(modelPath(modelId)) : void 0;
|
|
1621
1305
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1622
1306
|
const model = {
|
|
1623
1307
|
id: modelId,
|
|
@@ -1707,7 +1391,7 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1707
1391
|
},
|
|
1708
1392
|
async updateRun({ runId, status, stage, message, details }) {
|
|
1709
1393
|
const previous = await getRun(runId);
|
|
1710
|
-
if (status !== "cancelled" && await
|
|
1394
|
+
if (status !== "cancelled" && await exists(cancellationPath(previous.id))) {
|
|
1711
1395
|
return preserveCancellationRequestState(previous.id);
|
|
1712
1396
|
}
|
|
1713
1397
|
const active = status !== "stage_completed" && status !== "completed" && status !== "failed" && status !== "cancelled";
|
|
@@ -1722,7 +1406,7 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1722
1406
|
updated_at: now
|
|
1723
1407
|
};
|
|
1724
1408
|
await writeRunState(state);
|
|
1725
|
-
if (status !== "cancelled" && await
|
|
1409
|
+
if (status !== "cancelled" && await exists(cancellationPath(previous.id))) {
|
|
1726
1410
|
return preserveCancellationRequestState(previous.id);
|
|
1727
1411
|
}
|
|
1728
1412
|
await appendRunEvent(state, {
|
|
@@ -1734,7 +1418,7 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1734
1418
|
return state;
|
|
1735
1419
|
},
|
|
1736
1420
|
async completeRun(report, artifactDir, reportPath) {
|
|
1737
|
-
if (await
|
|
1421
|
+
if (await exists(cancellationPath(report.run_id))) {
|
|
1738
1422
|
return preserveCancellationRequestState(report.run_id);
|
|
1739
1423
|
}
|
|
1740
1424
|
const request = await readJson2(runRequestPath(report.run_id));
|
|
@@ -1761,7 +1445,7 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1761
1445
|
updated_at: completedAt
|
|
1762
1446
|
};
|
|
1763
1447
|
await writeRunState(state);
|
|
1764
|
-
if (await
|
|
1448
|
+
if (await exists(cancellationPath(report.run_id))) {
|
|
1765
1449
|
return preserveCancellationRequestState(report.run_id);
|
|
1766
1450
|
}
|
|
1767
1451
|
await copyIfExists(reportPath, runReportPath(report.run_id));
|
|
@@ -1793,7 +1477,7 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1793
1477
|
async failRun(runId, error) {
|
|
1794
1478
|
const previous = await getRun(runId);
|
|
1795
1479
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1796
|
-
if (await
|
|
1480
|
+
if (await exists(cancellationPath(previous.id))) {
|
|
1797
1481
|
return preserveCancellationRequestState(previous.id);
|
|
1798
1482
|
}
|
|
1799
1483
|
const state = {
|
|
@@ -1806,7 +1490,7 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1806
1490
|
updated_at: now
|
|
1807
1491
|
};
|
|
1808
1492
|
await writeRunState(state);
|
|
1809
|
-
if (await
|
|
1493
|
+
if (await exists(cancellationPath(previous.id))) {
|
|
1810
1494
|
return preserveCancellationRequestState(previous.id);
|
|
1811
1495
|
}
|
|
1812
1496
|
await appendRunEvent(state, { stage: "failed", status: "failed", message: error });
|
|
@@ -1817,7 +1501,7 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1817
1501
|
if (isTerminalRunState(state) || state.status === "cancelled" && state.current_stage === "cancel_requested") {
|
|
1818
1502
|
return;
|
|
1819
1503
|
}
|
|
1820
|
-
await
|
|
1504
|
+
await writeFile2(cancellationPath(state.id), `${(/* @__PURE__ */ new Date()).toISOString()}
|
|
1821
1505
|
`, "utf8");
|
|
1822
1506
|
const latest = await getRun(state.id);
|
|
1823
1507
|
if (isTerminalRunState(latest)) {
|
|
@@ -1841,7 +1525,7 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1841
1525
|
},
|
|
1842
1526
|
async isCancellationRequested(runId) {
|
|
1843
1527
|
const state = await getRun(runId);
|
|
1844
|
-
return state.status === "cancelled" || await
|
|
1528
|
+
return state.status === "cancelled" || await exists(cancellationPath(state.id));
|
|
1845
1529
|
},
|
|
1846
1530
|
async listRuns() {
|
|
1847
1531
|
return listRunRecords();
|
|
@@ -1853,11 +1537,19 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1853
1537
|
},
|
|
1854
1538
|
async getRunReport(id) {
|
|
1855
1539
|
const state = await getRun(id);
|
|
1856
|
-
|
|
1857
|
-
|
|
1540
|
+
const candidates = [];
|
|
1541
|
+
if (state.report_path) {
|
|
1542
|
+
const reportPath = resolve3(state.report_path);
|
|
1543
|
+
const allowedRoots = [resolvedRoot];
|
|
1544
|
+
if (state.artifact_dir) allowedRoots.push(resolve3(state.artifact_dir));
|
|
1545
|
+
if (allowedRoots.some((allowed) => isPathInside(allowed, reportPath))) {
|
|
1546
|
+
candidates.push(reportPath);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
candidates.push(runReportPath(state.id));
|
|
1550
|
+
for (const path of candidates) {
|
|
1551
|
+
if (await exists(path)) return readJson2(path);
|
|
1858
1552
|
}
|
|
1859
|
-
const copiedReportPath = runReportPath(state.id);
|
|
1860
|
-
if (await exists2(copiedReportPath)) return readJson2(copiedReportPath);
|
|
1861
1553
|
throw new Error(`Run has no report yet: ${id}`);
|
|
1862
1554
|
},
|
|
1863
1555
|
async listModels() {
|
|
@@ -1871,11 +1563,332 @@ function createLocalStore(root = defaultLocalHome()) {
|
|
|
1871
1563
|
};
|
|
1872
1564
|
}
|
|
1873
1565
|
|
|
1566
|
+
// src/local-runtime/local-project.ts
|
|
1567
|
+
import { createHash as createHash2, randomUUID as randomUUID3 } from "crypto";
|
|
1568
|
+
import { readFile as readFile3, stat as stat3, writeFile as writeFile3 } from "fs/promises";
|
|
1569
|
+
import { dirname as dirname3, isAbsolute as isAbsolute2, resolve as resolve4 } from "path";
|
|
1570
|
+
import { homedir as homedir2 } from "os";
|
|
1571
|
+
import { mkdir as mkdir3 } from "fs/promises";
|
|
1572
|
+
var DEFAULT_LOCAL_SPEC_PATH = "tunedtensor.json";
|
|
1573
|
+
function resolveLocalReference(value, baseDirectory) {
|
|
1574
|
+
if (typeof value !== "string" || !value || isAbsolute2(value) || /^[a-z][a-z0-9+.-]*:/i.test(value)) {
|
|
1575
|
+
return value;
|
|
1576
|
+
}
|
|
1577
|
+
if (value === "~") return homedir2();
|
|
1578
|
+
if (value.startsWith("~/")) return resolve4(homedir2(), value.slice(2));
|
|
1579
|
+
return resolve4(baseDirectory, value);
|
|
1580
|
+
}
|
|
1581
|
+
function resolveLocalRunInputPaths(raw, inputPath) {
|
|
1582
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return raw;
|
|
1583
|
+
const baseDirectory = dirname3(resolve4(inputPath));
|
|
1584
|
+
const value = structuredClone(raw);
|
|
1585
|
+
const dataset = value.dataset_prebuilt;
|
|
1586
|
+
if (dataset && typeof dataset === "object" && !Array.isArray(dataset)) {
|
|
1587
|
+
const fields = dataset;
|
|
1588
|
+
for (const key of ["training", "validation", "test"]) {
|
|
1589
|
+
if (fields[key] !== void 0) fields[key] = resolveLocalReference(fields[key], baseDirectory);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
return value;
|
|
1593
|
+
}
|
|
1594
|
+
async function exists2(path) {
|
|
1595
|
+
try {
|
|
1596
|
+
await stat3(path);
|
|
1597
|
+
return true;
|
|
1598
|
+
} catch {
|
|
1599
|
+
return false;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
async function initLocalSpecFile(args) {
|
|
1603
|
+
if (!args.force && await exists2(args.outputPath)) {
|
|
1604
|
+
throw new Error(`Refusing to overwrite existing file: ${args.outputPath}`);
|
|
1605
|
+
}
|
|
1606
|
+
const spec = localBehaviorSpecFileSchema.parse({
|
|
1607
|
+
id: randomUUID3(),
|
|
1608
|
+
name: args.name,
|
|
1609
|
+
description: "",
|
|
1610
|
+
system_prompt: "Describe the behavior this local model should learn.",
|
|
1611
|
+
guidelines: [
|
|
1612
|
+
"Return concise, task-specific answers."
|
|
1613
|
+
],
|
|
1614
|
+
constraints: [],
|
|
1615
|
+
base_model: args.baseModel,
|
|
1616
|
+
examples: [
|
|
1617
|
+
{
|
|
1618
|
+
input: "Replace this with representative training input.",
|
|
1619
|
+
output: "Replace this with the expected training output."
|
|
1620
|
+
},
|
|
1621
|
+
{
|
|
1622
|
+
input: "Replace this with a different validation input.",
|
|
1623
|
+
output: "Replace this with the expected validation output."
|
|
1624
|
+
}
|
|
1625
|
+
],
|
|
1626
|
+
hyperparameters: {
|
|
1627
|
+
n_epochs: 1
|
|
1628
|
+
}
|
|
1629
|
+
});
|
|
1630
|
+
await mkdir3(dirname3(args.outputPath), { recursive: true });
|
|
1631
|
+
await writeFile3(args.outputPath, `${JSON.stringify(spec, null, 2)}
|
|
1632
|
+
`, "utf8");
|
|
1633
|
+
return spec;
|
|
1634
|
+
}
|
|
1635
|
+
async function initLocalRunnerConfigFile(args) {
|
|
1636
|
+
if (!args.force && await exists2(args.outputPath)) {
|
|
1637
|
+
throw new Error(`Refusing to overwrite existing file: ${args.outputPath}`);
|
|
1638
|
+
}
|
|
1639
|
+
const config = {
|
|
1640
|
+
artifactRoot: ".tt-local/artifacts",
|
|
1641
|
+
storeRoot: ".tt-local/store",
|
|
1642
|
+
evaluation: {
|
|
1643
|
+
inference: {
|
|
1644
|
+
device: "cuda"
|
|
1645
|
+
},
|
|
1646
|
+
scoring: {
|
|
1647
|
+
mode: "exact_match"
|
|
1648
|
+
},
|
|
1649
|
+
timeoutMs: 18e5
|
|
1650
|
+
}
|
|
1651
|
+
};
|
|
1652
|
+
await mkdir3(dirname3(args.outputPath), { recursive: true });
|
|
1653
|
+
await writeFile3(args.outputPath, `${JSON.stringify(config, null, 2)}
|
|
1654
|
+
`, "utf8");
|
|
1655
|
+
return config;
|
|
1656
|
+
}
|
|
1657
|
+
function generatedPlaceholderIssues(request) {
|
|
1658
|
+
const issues = [];
|
|
1659
|
+
if (/describe the behavior this local model should learn/i.test(request.spec_snapshot.system_prompt)) {
|
|
1660
|
+
issues.push("system_prompt still contains the generated placeholder");
|
|
1661
|
+
}
|
|
1662
|
+
request.spec_snapshot.examples.forEach((example, index) => {
|
|
1663
|
+
if (/replace this with/i.test(example.input) || /replace this with/i.test(example.output)) {
|
|
1664
|
+
issues.push(`examples[${index}] still contains generated placeholder text`);
|
|
1665
|
+
}
|
|
1666
|
+
});
|
|
1667
|
+
return issues;
|
|
1668
|
+
}
|
|
1669
|
+
function assertLocalRunInputReady(request) {
|
|
1670
|
+
const issues = generatedPlaceholderIssues(request);
|
|
1671
|
+
if (issues.length > 0) {
|
|
1672
|
+
throw new Error(`Edit the generated behavior spec before training: ${issues.join("; ")}.`);
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
function runRequestFromLocalSpec(spec, options = {}) {
|
|
1676
|
+
const {
|
|
1677
|
+
id,
|
|
1678
|
+
hyperparameters,
|
|
1679
|
+
dataset_prebuilt: datasetPrebuilt,
|
|
1680
|
+
...specSnapshot
|
|
1681
|
+
} = spec;
|
|
1682
|
+
const behaviorSpecId = id ?? deterministicBehaviorSpecId(specSnapshot);
|
|
1683
|
+
return fineTuneRunRequestSchema.parse({
|
|
1684
|
+
run_id: options.runId ?? randomUUID3(),
|
|
1685
|
+
user_id: "local-user",
|
|
1686
|
+
behavior_spec_id: behaviorSpecId,
|
|
1687
|
+
run_number: 1,
|
|
1688
|
+
spec_snapshot: specSnapshot,
|
|
1689
|
+
hyperparameters,
|
|
1690
|
+
dataset_prebuilt: datasetPrebuilt
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
function deterministicBehaviorSpecId(spec) {
|
|
1694
|
+
const namespace = Buffer.from("9f783f01340457bea061942004259253", "hex");
|
|
1695
|
+
const digest = createHash2("sha1").update(namespace).update(JSON.stringify(spec)).digest().subarray(0, 16);
|
|
1696
|
+
digest[6] = digest[6] & 15 | 80;
|
|
1697
|
+
digest[8] = digest[8] & 63 | 128;
|
|
1698
|
+
const hex = digest.toString("hex");
|
|
1699
|
+
return [
|
|
1700
|
+
hex.slice(0, 8),
|
|
1701
|
+
hex.slice(8, 12),
|
|
1702
|
+
hex.slice(12, 16),
|
|
1703
|
+
hex.slice(16, 20),
|
|
1704
|
+
hex.slice(20)
|
|
1705
|
+
].join("-");
|
|
1706
|
+
}
|
|
1707
|
+
async function loadLocalRunInput(path, options = {}) {
|
|
1708
|
+
const raw = resolveLocalRunInputPaths(JSON.parse(await readFile3(path, "utf8")), path);
|
|
1709
|
+
const request = fineTuneRunRequestSchema.safeParse(raw);
|
|
1710
|
+
if (request.success) {
|
|
1711
|
+
return { kind: "request", path, request: request.data };
|
|
1712
|
+
}
|
|
1713
|
+
const spec = localBehaviorSpecFileSchema.parse(raw);
|
|
1714
|
+
return {
|
|
1715
|
+
kind: "spec",
|
|
1716
|
+
path,
|
|
1717
|
+
spec,
|
|
1718
|
+
request: runRequestFromLocalSpec(spec, options)
|
|
1719
|
+
};
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
// src/local-runtime/dataset.ts
|
|
1723
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
1724
|
+
async function loadNormalizedChatJsonl(path) {
|
|
1725
|
+
const text = await readFile4(path, "utf8");
|
|
1726
|
+
const rows = [];
|
|
1727
|
+
const jsonLines = [];
|
|
1728
|
+
for (const [index, line] of text.split(/\r?\n/).entries()) {
|
|
1729
|
+
if (!line.trim()) continue;
|
|
1730
|
+
let value;
|
|
1731
|
+
try {
|
|
1732
|
+
value = JSON.parse(line);
|
|
1733
|
+
} catch (error) {
|
|
1734
|
+
throw new Error(`Invalid chat JSONL row ${index + 1}: malformed JSON`, { cause: error });
|
|
1735
|
+
}
|
|
1736
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1737
|
+
throw new Error(`Invalid chat JSONL row ${index + 1}: expected an object`);
|
|
1738
|
+
}
|
|
1739
|
+
const messages = value.messages;
|
|
1740
|
+
if (!Array.isArray(messages) || ![2, 3].includes(messages.length) || messages.some(
|
|
1741
|
+
(message) => !message || typeof message !== "object" || Array.isArray(message) || !["system", "user", "assistant"].includes(String(message.role)) || typeof message.content !== "string"
|
|
1742
|
+
)) {
|
|
1743
|
+
throw new Error(
|
|
1744
|
+
`Invalid chat JSONL row ${index + 1}: expected an optional system message, one user message, and one assistant answer`
|
|
1745
|
+
);
|
|
1746
|
+
}
|
|
1747
|
+
const row = { messages };
|
|
1748
|
+
const offset = row.messages.length === 3 ? 1 : 0;
|
|
1749
|
+
if (offset === 1 && row.messages[0]?.role !== "system" || row.messages[offset]?.role !== "user" || !row.messages[offset]?.content.trim() || row.messages[offset + 1]?.role !== "assistant" || !row.messages[offset + 1]?.content.trim()) {
|
|
1750
|
+
throw new Error(
|
|
1751
|
+
`Invalid chat JSONL row ${index + 1}: expected an optional system message, one non-empty user message, and one non-empty assistant answer`
|
|
1752
|
+
);
|
|
1753
|
+
}
|
|
1754
|
+
rows.push(row);
|
|
1755
|
+
jsonLines.push(JSON.stringify(row));
|
|
1756
|
+
}
|
|
1757
|
+
if (rows.length === 0) throw new Error(`Chat JSONL contains no examples: ${path}`);
|
|
1758
|
+
return {
|
|
1759
|
+
rows,
|
|
1760
|
+
jsonl: jsonLines.join("\n")
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
async function normalizeChatJsonlForRelocation(path) {
|
|
1764
|
+
return (await loadNormalizedChatJsonl(path)).jsonl;
|
|
1765
|
+
}
|
|
1766
|
+
function buildSystemMessage(spec) {
|
|
1767
|
+
const parts = [];
|
|
1768
|
+
if (spec.system_prompt.trim()) parts.push(spec.system_prompt.trim());
|
|
1769
|
+
if (spec.guidelines.length > 0) {
|
|
1770
|
+
parts.push(`Guidelines:
|
|
1771
|
+
${spec.guidelines.map((guideline) => `- ${guideline}`).join("\n")}`);
|
|
1772
|
+
}
|
|
1773
|
+
if (spec.constraints.length > 0) {
|
|
1774
|
+
parts.push(`Constraints:
|
|
1775
|
+
${spec.constraints.map((constraint) => `- ${constraint}`).join("\n")}`);
|
|
1776
|
+
}
|
|
1777
|
+
return parts.join("\n\n") || "Follow the demonstrated behavior.";
|
|
1778
|
+
}
|
|
1779
|
+
function exampleToChatRow(spec, example) {
|
|
1780
|
+
const system = buildSystemMessage(spec);
|
|
1781
|
+
return {
|
|
1782
|
+
messages: [
|
|
1783
|
+
{ role: "system", content: system },
|
|
1784
|
+
{ role: "user", content: example.input },
|
|
1785
|
+
{ role: "assistant", content: example.output }
|
|
1786
|
+
]
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
function compileSpecToJsonl(spec) {
|
|
1790
|
+
return spec.examples.map((example) => JSON.stringify(exampleToChatRow(spec, example))).join("\n");
|
|
1791
|
+
}
|
|
1792
|
+
function examplesFromSpec(spec) {
|
|
1793
|
+
return spec.examples;
|
|
1794
|
+
}
|
|
1795
|
+
async function examplesFromChatJsonl(path) {
|
|
1796
|
+
const normalized = await loadNormalizedChatJsonl(path);
|
|
1797
|
+
const examples = [];
|
|
1798
|
+
for (const [index, row] of normalized.rows.entries()) {
|
|
1799
|
+
const user = row.messages.at(-2);
|
|
1800
|
+
const assistant = row.messages.at(-1);
|
|
1801
|
+
examples.push({
|
|
1802
|
+
input: user.content,
|
|
1803
|
+
output: assistant.content
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
return examples;
|
|
1807
|
+
}
|
|
1808
|
+
async function evaluationSuiteFromChatJsonl(path, configuredSystem) {
|
|
1809
|
+
const normalized = await loadNormalizedChatJsonl(path);
|
|
1810
|
+
const inputIdentities = /* @__PURE__ */ new Set();
|
|
1811
|
+
for (const row of normalized.rows) {
|
|
1812
|
+
const input = row.messages.at(-2).content;
|
|
1813
|
+
const identity = input.trim().replace(/\s+/g, " ").toLowerCase();
|
|
1814
|
+
if (inputIdentities.has(identity)) {
|
|
1815
|
+
throw new Error(
|
|
1816
|
+
"General regression data contains duplicate inputs; evaluation prompts must be unique."
|
|
1817
|
+
);
|
|
1818
|
+
}
|
|
1819
|
+
inputIdentities.add(identity);
|
|
1820
|
+
}
|
|
1821
|
+
const systems = new Set(
|
|
1822
|
+
normalized.rows.map((row) => row.messages.find((message) => message.role === "system")?.content).filter((value) => value !== void 0)
|
|
1823
|
+
);
|
|
1824
|
+
if (systems.size > 1) {
|
|
1825
|
+
throw new Error("General regression rows must use one consistent system message.");
|
|
1826
|
+
}
|
|
1827
|
+
const embeddedSystem = [...systems][0];
|
|
1828
|
+
if (configuredSystem !== void 0 && embeddedSystem !== void 0 && configuredSystem !== embeddedSystem) {
|
|
1829
|
+
throw new Error(
|
|
1830
|
+
"evaluation.generalRegression.systemPrompt must match the system message embedded in the dataset."
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
return {
|
|
1834
|
+
examples: normalized.rows.map((row) => ({
|
|
1835
|
+
input: row.messages.at(-2).content,
|
|
1836
|
+
output: row.messages.at(-1).content
|
|
1837
|
+
})),
|
|
1838
|
+
system: configuredSystem ?? embeddedSystem ?? "You are a helpful assistant."
|
|
1839
|
+
};
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
// src/local-runtime/run-reporter.ts
|
|
1843
|
+
function reportInBackground(action) {
|
|
1844
|
+
try {
|
|
1845
|
+
void Promise.resolve(action()).catch(() => void 0);
|
|
1846
|
+
} catch {
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
function sanitizeLogLine(line) {
|
|
1850
|
+
return line.replace(/(Bearer\s+)[A-Za-z0-9._~+/=-]+/gi, "$1[redacted]").replace(/((?:api[_-]?key|token|secret|password)=)[^\s]+/gi, "$1[redacted]");
|
|
1851
|
+
}
|
|
1852
|
+
function forwardStreamLines(stream, onLine) {
|
|
1853
|
+
let buffered = "";
|
|
1854
|
+
stream.setEncoding("utf8");
|
|
1855
|
+
stream.on("data", (chunk) => {
|
|
1856
|
+
buffered += chunk;
|
|
1857
|
+
const lines = buffered.split(/\r\n|\n|\r/);
|
|
1858
|
+
buffered = lines.pop() ?? "";
|
|
1859
|
+
for (const line of lines) {
|
|
1860
|
+
if (line.trim()) onLine(sanitizeLogLine(line));
|
|
1861
|
+
}
|
|
1862
|
+
});
|
|
1863
|
+
stream.on("end", () => {
|
|
1864
|
+
if (buffered.trim()) onLine(sanitizeLogLine(buffered));
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
// src/local-runtime/package-root.ts
|
|
1869
|
+
import { existsSync } from "fs";
|
|
1870
|
+
import { dirname as dirname4, resolve as resolve5 } from "path";
|
|
1871
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1872
|
+
function localRuntimePackageRoot(moduleUrl) {
|
|
1873
|
+
const moduleDirectory = dirname4(fileURLToPath2(moduleUrl));
|
|
1874
|
+
const candidates = [
|
|
1875
|
+
dirname4(moduleDirectory),
|
|
1876
|
+
dirname4(dirname4(moduleDirectory))
|
|
1877
|
+
];
|
|
1878
|
+
const root = candidates.find(
|
|
1879
|
+
(candidate) => existsSync(resolve5(candidate, "package.json")) && existsSync(resolve5(candidate, "training/local-runner"))
|
|
1880
|
+
);
|
|
1881
|
+
if (!root) {
|
|
1882
|
+
throw new Error("Unable to locate the bundled Tuned Tensor local runtime assets.");
|
|
1883
|
+
}
|
|
1884
|
+
return root;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1874
1887
|
// src/local-runtime/prefetch.ts
|
|
1875
1888
|
import { createHash as createHash4 } from "crypto";
|
|
1876
1889
|
import { createReadStream as createReadStream2 } from "fs";
|
|
1877
1890
|
import { lstat as lstat3, mkdir as mkdir5, readFile as readFile5, readdir as readdir4, realpath as realpath2, stat as stat4 } from "fs/promises";
|
|
1878
|
-
import { isAbsolute as isAbsolute3, join as join5, relative as relative2, resolve as resolve8, sep as
|
|
1891
|
+
import { isAbsolute as isAbsolute3, join as join5, relative as relative2, resolve as resolve8, sep as sep3 } from "path";
|
|
1879
1892
|
|
|
1880
1893
|
// src/local-runtime/process-runner.ts
|
|
1881
1894
|
import { createHash as createHash3 } from "crypto";
|
|
@@ -2221,7 +2234,7 @@ async function certifiedFileDigest(path, expected) {
|
|
|
2221
2234
|
}
|
|
2222
2235
|
function isStrictPhysicalDescendant(parent, child) {
|
|
2223
2236
|
const candidate = relative2(parent, child);
|
|
2224
|
-
return candidate !== "" && candidate !== ".." && !candidate.startsWith(`..${
|
|
2237
|
+
return candidate !== "" && candidate !== ".." && !candidate.startsWith(`..${sep3}`) && !isAbsolute3(candidate);
|
|
2225
2238
|
}
|
|
2226
2239
|
async function verifySnapshotCacheLocation(path, modelId, revision, modelCache) {
|
|
2227
2240
|
const repository = `models--${modelId.replaceAll("/", "--")}`;
|
|
@@ -4753,6 +4766,10 @@ export {
|
|
|
4753
4766
|
trainingReportSchema,
|
|
4754
4767
|
runReportSchema,
|
|
4755
4768
|
localRunnerConfigSchema,
|
|
4769
|
+
isTerminalRunState,
|
|
4770
|
+
defaultLocalHome,
|
|
4771
|
+
localStorePaths,
|
|
4772
|
+
createLocalStore,
|
|
4756
4773
|
DEFAULT_LOCAL_SPEC_PATH,
|
|
4757
4774
|
resolveLocalRunInputPaths,
|
|
4758
4775
|
initLocalSpecFile,
|
|
@@ -4774,10 +4791,6 @@ export {
|
|
|
4774
4791
|
localRuntimePackageRoot,
|
|
4775
4792
|
buildBundledPythonCommand,
|
|
4776
4793
|
withBundledPythonEnvironment,
|
|
4777
|
-
isTerminalRunState,
|
|
4778
|
-
defaultLocalHome,
|
|
4779
|
-
localStorePaths,
|
|
4780
|
-
createLocalStore,
|
|
4781
4794
|
minimalMachineLearningEnvironment,
|
|
4782
4795
|
withHuggingFaceCacheEnvironment,
|
|
4783
4796
|
withOfflineHuggingFaceCacheEnvironment,
|
|
@@ -4797,4 +4810,4 @@ export {
|
|
|
4797
4810
|
runLocalPipeline,
|
|
4798
4811
|
runLocalFineTune
|
|
4799
4812
|
};
|
|
4800
|
-
//# sourceMappingURL=chunk-
|
|
4813
|
+
//# sourceMappingURL=chunk-2VJ3VVZF.js.map
|