@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.
@@ -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 mkdir3, readdir as readdir3, readFile as readFile4, rename as rename2, rm, stat as stat3, writeFile as writeFile3 } from "fs/promises";
1405
- import { homedir as homedir2 } from "os";
1406
- import { dirname as dirname4, join as join2, resolve as resolve5 } from "path";
1407
- import { randomUUID as randomUUID3 } from "crypto";
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 resolve5(process.env.TT_LOCAL_HOME ?? join2(homedir2(), ".tuned-tensor-local"));
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 exists2(path) {
1102
+ async function exists(path) {
1424
1103
  try {
1425
- await stat3(path);
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 mkdir3(dirname4(path), { recursive: true });
1433
- const tmp = `${path}.${process.pid}.${Date.now()}.${randomUUID3()}.tmp`;
1434
- await writeFile3(tmp, `${JSON.stringify(value, null, 2)}
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 readFile4(path, "utf8"));
1118
+ return JSON.parse(await readFile2(path, "utf8"));
1440
1119
  }
1441
1120
  async function appendJsonl(path, value) {
1442
- await mkdir3(dirname4(path), { recursive: true });
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 exists2(path)) return [];
1448
- return (await readFile4(path, "utf8")).split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line));
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 exists2(from)) return;
1452
- await mkdir3(dirname4(to), { recursive: true });
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 = resolve5(root);
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
- mkdir3(paths.specsDir, { recursive: true }),
1494
- mkdir3(paths.runsDir, { recursive: true }),
1495
- mkdir3(paths.modelsDir, { recursive: true }),
1496
- mkdir3(paths.datasetsDir, { recursive: true })
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 exists2(path)) return null;
1189
+ if (!await exists(path)) return null;
1506
1190
  const [spec, fileStats, directoryStats] = await Promise.all([
1507
1191
  readJson2(path),
1508
- stat3(path),
1509
- stat3(specDir(id))
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 exists2(path)) records.push(await readJson2(path));
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 exists2(path)) records.push(await readJson2(path));
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 mkdir3(specDir(specId), { recursive: true });
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: randomUUID3(),
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 exists2(runStatePath(id))) return id;
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 exists2(modelPath(modelId)) ? await readJson2(modelPath(modelId)) : void 0;
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 exists2(cancellationPath(previous.id))) {
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 exists2(cancellationPath(previous.id))) {
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 exists2(cancellationPath(report.run_id))) {
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 exists2(cancellationPath(report.run_id))) {
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 exists2(cancellationPath(previous.id))) {
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 exists2(cancellationPath(previous.id))) {
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 writeFile3(cancellationPath(state.id), `${(/* @__PURE__ */ new Date()).toISOString()}
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 exists2(cancellationPath(state.id));
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
- if (state.report_path && await exists2(state.report_path)) {
1857
- return readJson2(state.report_path);
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 sep2 } from "path";
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(`..${sep2}`) && !isAbsolute3(candidate);
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-HDGBDHOB.js.map
4813
+ //# sourceMappingURL=chunk-2VJ3VVZF.js.map