trainfabric 0.1.12 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +59 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ Secrets are stored in macOS Keychain when available. Other platforms use an encr
|
|
|
28
28
|
trainfabric projects:list
|
|
29
29
|
trainfabric datasets:upload ./train.jsonl --project <projectId>
|
|
30
30
|
trainfabric runs:quote --summary --project <projectId> --dataset <datasetId> --model llama-3-8b
|
|
31
|
-
trainfabric runs:create --yes --project <projectId> --dataset <datasetId> --model llama-3-8b
|
|
31
|
+
trainfabric runs:create --yes --quote <quoteId> --project <projectId> --dataset <datasetId> --model llama-3-8b
|
|
32
32
|
trainfabric runs:watch <runId> --timeout 30m
|
|
33
33
|
trainfabric runs:cost-breakdown <runId> --summary
|
|
34
34
|
```
|
package/dist/index.cjs
CHANGED
|
@@ -7975,12 +7975,6 @@ function validateChatJsonl(text) {
|
|
|
7975
7975
|
}
|
|
7976
7976
|
tokenEstimate += estimateTokens(result.data.messages.map((message) => `${message.role}:${message.content}`).join("\n"));
|
|
7977
7977
|
}
|
|
7978
|
-
if (tokenEstimate < 100) {
|
|
7979
|
-
warnings.push({
|
|
7980
|
-
code: "small_dataset",
|
|
7981
|
-
message: "Dataset is valid but very small for a meaningful training run."
|
|
7982
|
-
});
|
|
7983
|
-
}
|
|
7984
7978
|
const invalidWarnings = /* @__PURE__ */ new Set([
|
|
7985
7979
|
"empty_file",
|
|
7986
7980
|
"invalid_jsonl",
|
|
@@ -7988,8 +7982,15 @@ function validateChatJsonl(text) {
|
|
|
7988
7982
|
"missing_assistant",
|
|
7989
7983
|
"empty_assistant"
|
|
7990
7984
|
]);
|
|
7985
|
+
const isValid2 = !warnings.some((warning) => invalidWarnings.has(warning.code));
|
|
7986
|
+
if (tokenEstimate < 100) {
|
|
7987
|
+
warnings.push({
|
|
7988
|
+
code: "small_dataset",
|
|
7989
|
+
message: isValid2 ? "Dataset is valid but very small for a meaningful training run." : "Dataset is very small; fix schema errors before using it for a training run."
|
|
7990
|
+
});
|
|
7991
|
+
}
|
|
7991
7992
|
return {
|
|
7992
|
-
valid:
|
|
7993
|
+
valid: isValid2,
|
|
7993
7994
|
format: "chat_jsonl",
|
|
7994
7995
|
rowCount,
|
|
7995
7996
|
duplicateCount,
|
|
@@ -8921,7 +8922,7 @@ function buildComputeSpec(options) {
|
|
|
8921
8922
|
|
|
8922
8923
|
// src/index.ts
|
|
8923
8924
|
var DEFAULT_TRAINFABRIC_API_URL2 = "https://api.trainfabric.com";
|
|
8924
|
-
var CLI_VERSION = "0.1.
|
|
8925
|
+
var CLI_VERSION = "0.1.14";
|
|
8925
8926
|
var CONFIG_DIR = import_node_path3.default.join(import_node_os2.default.homedir(), ".trainfabric");
|
|
8926
8927
|
var CONFIG_PATH = import_node_path3.default.join(CONFIG_DIR, "config.json");
|
|
8927
8928
|
var FALLBACK_SECRET_PATH = import_node_path3.default.join(CONFIG_DIR, "session.enc");
|
|
@@ -9215,6 +9216,7 @@ function printQuoteSummary(bundle) {
|
|
|
9215
9216
|
console.log(` data path: ${quote.dataPath ?? "auto"}`);
|
|
9216
9217
|
console.log(` GPUs: ${gpuCount}`);
|
|
9217
9218
|
console.log(` pool: ${quote.selectedPoolId}`);
|
|
9219
|
+
console.log(` launch with: --quote ${quote.id}`);
|
|
9218
9220
|
}
|
|
9219
9221
|
console.log("");
|
|
9220
9222
|
console.log("Launch only after the customer accepts the quote. Streaming/data-plane cost is included in the estimate when the selected data path is stream, and realized usage may differ.");
|
|
@@ -9258,15 +9260,23 @@ function visibleConfig(config) {
|
|
|
9258
9260
|
refreshToken: config.refreshToken ? "<stored>" : void 0
|
|
9259
9261
|
};
|
|
9260
9262
|
}
|
|
9261
|
-
function
|
|
9263
|
+
function requireProjectId(options, config) {
|
|
9264
|
+
const projectId = options.project ?? config.projectId;
|
|
9265
|
+
if (!projectId) {
|
|
9266
|
+
throw new Error("Project is required. Pass --project <projectId> or run `trainfabric config:set-project <projectId>`.");
|
|
9267
|
+
}
|
|
9268
|
+
return projectId;
|
|
9269
|
+
}
|
|
9270
|
+
function buildRunInput(options, config = loadConfig()) {
|
|
9262
9271
|
const sourceOptions = buildSourceOptions(options);
|
|
9263
9272
|
return {
|
|
9264
|
-
projectId: options
|
|
9273
|
+
projectId: requireProjectId(options, config),
|
|
9265
9274
|
task: "sft",
|
|
9266
9275
|
method: "lora",
|
|
9267
9276
|
baseModel: normalizeBaseModel(options.model),
|
|
9268
9277
|
datasetId: options.dataset,
|
|
9269
9278
|
evalDatasetId: options.eval,
|
|
9279
|
+
pricingQuoteId: options.quote,
|
|
9270
9280
|
...sourceOptions,
|
|
9271
9281
|
mode: options.mode,
|
|
9272
9282
|
compute: buildComputeSpec(options),
|
|
@@ -9297,7 +9307,16 @@ function assertQuoteOptions(bundle, options) {
|
|
|
9297
9307
|
)}). Omit --accelerator or increase --min-memory.`
|
|
9298
9308
|
);
|
|
9299
9309
|
}
|
|
9300
|
-
|
|
9310
|
+
function filterQuoteBundleForRequestedMode(bundle, options) {
|
|
9311
|
+
if (!options.mode) {
|
|
9312
|
+
return bundle;
|
|
9313
|
+
}
|
|
9314
|
+
return {
|
|
9315
|
+
...bundle,
|
|
9316
|
+
quotes: bundle.quotes.filter((item) => item.mode === options.mode || item.quote.mode === options.mode)
|
|
9317
|
+
};
|
|
9318
|
+
}
|
|
9319
|
+
async function watchRun(runId, json = false, timeoutMs, pollMs) {
|
|
9301
9320
|
const handle = await createClient(loadConfig()).runs.watch(runId);
|
|
9302
9321
|
if (json) {
|
|
9303
9322
|
const emit = (type, payload) => printJson({ type, payload });
|
|
@@ -9334,7 +9353,7 @@ async function watchRun(runId, json = false, timeoutMs) {
|
|
|
9334
9353
|
console.log(`[failed] ${payload.reason ?? "Run failed."}`);
|
|
9335
9354
|
});
|
|
9336
9355
|
}
|
|
9337
|
-
const detail = await handle.wait({ timeoutMs });
|
|
9356
|
+
const detail = await handle.wait({ timeoutMs, pollMs });
|
|
9338
9357
|
printJson(detail);
|
|
9339
9358
|
}
|
|
9340
9359
|
function parseDurationMs(value) {
|
|
@@ -9453,12 +9472,14 @@ program2.command("projects:create").requiredOption("--name <name>").option("--or
|
|
|
9453
9472
|
printJson(await createClient(loadConfig()).projects.create({ name: options.name, organizationId: options.org }));
|
|
9454
9473
|
});
|
|
9455
9474
|
program2.command("datasets:validate").argument("<file>").description("Validate a local dataset file").action(async (file) => {
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
)
|
|
9475
|
+
const validation = await createClient(loadConfig()).datasets.validate({
|
|
9476
|
+
path: file,
|
|
9477
|
+
format: "chat_jsonl"
|
|
9478
|
+
});
|
|
9479
|
+
printJson(validation);
|
|
9480
|
+
if (!validation.valid) {
|
|
9481
|
+
process.exitCode = 1;
|
|
9482
|
+
}
|
|
9462
9483
|
});
|
|
9463
9484
|
program2.command("datasets:list").option("--project <projectId>").description("List datasets").action(async (options) => {
|
|
9464
9485
|
printJson(await createClient(loadConfig()).datasets.list(options.project));
|
|
@@ -9476,36 +9497,43 @@ program2.command("datasets:upload").argument("<file>").option("--project <projec
|
|
|
9476
9497
|
});
|
|
9477
9498
|
printJson(dataset);
|
|
9478
9499
|
});
|
|
9479
|
-
program2.command("runs:create").
|
|
9500
|
+
program2.command("runs:create").option("--project <projectId>").requiredOption("--dataset <datasetId>").requiredOption("--model <baseModel>").option("--eval <evalDatasetId>").option("--epochs <epochs>", "number of epochs", "3").option("--lr <lr>", "learning rate", "0.0002").option("--gpus <gpuCount>", "gpu count", "1").option("--nodes <nodeCount>", "node count", "1").option("--accelerator <acceleratorClass>", "optional hard accelerator constraint (for example: a10g, a100, h100)").option("--min-memory <gigabytes>", "minimum GPU memory in GB").option("--precision <precision>", "fp16_bf16, fp8, or fp32").option("--interconnect <interconnect>", "pcie or nvlink").option("--mode <mode>", "efficient, balanced, or power", "balanced").option("--quote <pricingQuoteId>", "launch the exact accepted quote id from runs:quote").option("--repo <path>", "local repo path for runtime autodetect").option("--git <url>", "git repo URL for runtime metadata").option("--branch <branch>", "git branch for runtime metadata").option("--yes", "confirm that you reviewed pricing with runs:quote --summary and accept fluctuating realized usage").description("Create a training run").action(async (options) => {
|
|
9480
9501
|
if (!options.yes) {
|
|
9481
9502
|
throw new Error("Refusing to launch without explicit cost acceptance. Run `trainfabric runs:quote --summary ...` first, then rerun `runs:create` with --yes.");
|
|
9482
9503
|
}
|
|
9483
|
-
const
|
|
9484
|
-
const
|
|
9504
|
+
const config = loadConfig();
|
|
9505
|
+
const client = createClient(config);
|
|
9506
|
+
const run = await client.runs.create(buildRunInput(options, config));
|
|
9485
9507
|
printJson(run.snapshot);
|
|
9486
9508
|
});
|
|
9487
|
-
program2.command("runtime:detect").
|
|
9509
|
+
program2.command("runtime:detect").option("--project <projectId>").option("--repo <path>").option("--git <url>").option("--branch <branch>").description("Detect a supported runtime from a local repo snapshot or git metadata").action(async (options) => {
|
|
9488
9510
|
const sourceOptions = buildSourceOptions(options);
|
|
9489
9511
|
if (!sourceOptions.source) {
|
|
9490
9512
|
throw new Error("Provide --repo or --git.");
|
|
9491
9513
|
}
|
|
9514
|
+
const config = loadConfig();
|
|
9492
9515
|
printJson(
|
|
9493
|
-
await createClient(
|
|
9494
|
-
projectId: options
|
|
9516
|
+
await createClient(config).runtime.detect({
|
|
9517
|
+
projectId: requireProjectId(options, config),
|
|
9495
9518
|
source: sourceOptions.source
|
|
9496
9519
|
})
|
|
9497
9520
|
);
|
|
9498
9521
|
});
|
|
9499
|
-
program2.command("runtime:build").
|
|
9522
|
+
program2.command("runtime:build").option("--project <projectId>").requiredOption("--detection <detectionId>").description("Build or reuse a cached runtime image from a runtime detection").action(async (options) => {
|
|
9523
|
+
const config = loadConfig();
|
|
9500
9524
|
printJson(
|
|
9501
|
-
await createClient(
|
|
9502
|
-
projectId: options
|
|
9525
|
+
await createClient(config).runtime.build({
|
|
9526
|
+
projectId: requireProjectId(options, config),
|
|
9503
9527
|
detectionId: options.detection
|
|
9504
9528
|
})
|
|
9505
9529
|
);
|
|
9506
9530
|
});
|
|
9507
|
-
program2.command("runs:quote").
|
|
9508
|
-
const
|
|
9531
|
+
program2.command("runs:quote").option("--project <projectId>").requiredOption("--dataset <datasetId>").requiredOption("--model <baseModel>").option("--eval <evalDatasetId>").option("--gpus <gpuCount>", "gpu count", "1").option("--nodes <nodeCount>", "node count", "1").option("--accelerator <acceleratorClass>", "optional hard accelerator constraint (for example: a10g, a100, h100)").option("--min-memory <gigabytes>", "minimum GPU memory in GB").option("--precision <precision>", "fp16_bf16, fp8, or fp32").option("--interconnect <interconnect>", "pcie or nvlink").option("--mode <mode>", "efficient, balanced, or power").option("--repo <path>").option("--git <url>").option("--branch <branch>").option("--summary", "print a human-readable price summary instead of raw JSON").description("Preview Efficient, Balanced, and Power launch options").action(async (options) => {
|
|
9532
|
+
const config = loadConfig();
|
|
9533
|
+
const bundle = filterQuoteBundleForRequestedMode(
|
|
9534
|
+
await createClient(config).runs.quote(buildRunInput(options, config)),
|
|
9535
|
+
options
|
|
9536
|
+
);
|
|
9509
9537
|
assertQuoteOptions(bundle, options);
|
|
9510
9538
|
if (options.summary) {
|
|
9511
9539
|
printQuoteSummary(bundle);
|
|
@@ -9530,8 +9558,8 @@ program2.command("runs:wait").argument("<runId>").option("--timeout <duration>",
|
|
|
9530
9558
|
})
|
|
9531
9559
|
);
|
|
9532
9560
|
});
|
|
9533
|
-
program2.command("runs:watch").argument("<runId>").option("--json", "emit event output as JSON").option("--timeout <duration>", "maximum watch duration, for example 30s, 10m, or 1h").description("Stream a run until it completes").action(async (runId, options) => {
|
|
9534
|
-
await watchRun(String(runId), Boolean(options.json), parseDurationMs(options.timeout));
|
|
9561
|
+
program2.command("runs:watch").argument("<runId>").option("--json", "emit event output as JSON").option("--timeout <duration>", "maximum watch duration, for example 30s, 10m, or 1h").option("--poll <duration>", "poll interval, for example 1s or 500ms").description("Stream a run until it completes").action(async (runId, options) => {
|
|
9562
|
+
await watchRun(String(runId), Boolean(options.json), parseDurationMs(options.timeout), parsePositiveMs(options.poll, 1e3));
|
|
9535
9563
|
});
|
|
9536
9564
|
program2.command("runs:usage").argument("<runId>").option("--summary", "print a human-readable cost summary instead of raw JSON").description("Fetch run usage summary").action(async (runId, options) => {
|
|
9537
9565
|
const usage = await createClient(loadConfig()).runs.usage(String(runId));
|