trainfabric 0.1.29 → 0.1.31
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 +3 -1
- package/dist/index.cjs +156 -50
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,9 +26,11 @@ Secrets are stored in macOS Keychain when available. Other platforms use an encr
|
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
28
|
trainfabric projects:list
|
|
29
|
+
trainfabric projects:create --name <name>
|
|
30
|
+
trainfabric projects:delete <projectId>
|
|
29
31
|
trainfabric datasets:upload ./train.jsonl --project <projectId>
|
|
30
32
|
trainfabric runs:quote --summary --project <projectId> --dataset <datasetId> --model llama-3-8b
|
|
31
|
-
trainfabric runs:create --yes --quote <quoteId>
|
|
33
|
+
trainfabric runs:create --yes --quote <quoteId>
|
|
32
34
|
trainfabric runs:watch <runId> --timeout 30m
|
|
33
35
|
trainfabric runs:cost-breakdown <runId> --summary
|
|
34
36
|
```
|
package/dist/index.cjs
CHANGED
|
@@ -8077,6 +8077,15 @@ var ResourceClient = class {
|
|
|
8077
8077
|
};
|
|
8078
8078
|
|
|
8079
8079
|
// ../sdk/dist/client/admin.js
|
|
8080
|
+
var apiKeyIdPattern = /^key_[A-Za-z0-9_-]+$/;
|
|
8081
|
+
var serviceAccountIdPattern = /^svc_[A-Za-z0-9_-]+$/;
|
|
8082
|
+
function normalizeRequiredId(value, pattern, label) {
|
|
8083
|
+
const id = String(value ?? "").trim();
|
|
8084
|
+
if (!pattern.test(id)) {
|
|
8085
|
+
throw new Error(`${label} is invalid.`);
|
|
8086
|
+
}
|
|
8087
|
+
return encodeURIComponent(id);
|
|
8088
|
+
}
|
|
8080
8089
|
var ApiKeysClient = class extends ResourceClient {
|
|
8081
8090
|
create(input) {
|
|
8082
8091
|
apiKeyCreateSchema.parse(input);
|
|
@@ -8086,7 +8095,7 @@ var ApiKeysClient = class extends ResourceClient {
|
|
|
8086
8095
|
return this.requestGet("/v1/api-keys");
|
|
8087
8096
|
}
|
|
8088
8097
|
revoke(apiKeyId) {
|
|
8089
|
-
return this.requestDelete(`/v1/api-keys/${apiKeyId}`);
|
|
8098
|
+
return this.requestDelete(`/v1/api-keys/${normalizeRequiredId(apiKeyId, apiKeyIdPattern, "API key ID")}`);
|
|
8090
8099
|
}
|
|
8091
8100
|
};
|
|
8092
8101
|
var ServiceAccountsClient = class extends ResourceClient {
|
|
@@ -8098,7 +8107,7 @@ var ServiceAccountsClient = class extends ResourceClient {
|
|
|
8098
8107
|
return this.requestGet("/v1/service-accounts");
|
|
8099
8108
|
}
|
|
8100
8109
|
revoke(serviceAccountId) {
|
|
8101
|
-
return this.requestDelete(`/v1/service-accounts/${serviceAccountId}`);
|
|
8110
|
+
return this.requestDelete(`/v1/service-accounts/${normalizeRequiredId(serviceAccountId, serviceAccountIdPattern, "Service account ID")}`);
|
|
8102
8111
|
}
|
|
8103
8112
|
};
|
|
8104
8113
|
|
|
@@ -8164,6 +8173,14 @@ var ClusterClient = class extends ResourceClient {
|
|
|
8164
8173
|
// ../sdk/dist/client/datasets.js
|
|
8165
8174
|
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
8166
8175
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
8176
|
+
var datasetIdPattern = /^ds_[A-Za-z0-9_-]+$/;
|
|
8177
|
+
function encodeDatasetId(datasetId) {
|
|
8178
|
+
const id = String(datasetId ?? "").trim();
|
|
8179
|
+
if (!datasetIdPattern.test(id)) {
|
|
8180
|
+
throw new Error("Dataset ID is invalid.");
|
|
8181
|
+
}
|
|
8182
|
+
return encodeURIComponent(id);
|
|
8183
|
+
}
|
|
8167
8184
|
var DatasetsClient = class extends ResourceClient {
|
|
8168
8185
|
async create(input) {
|
|
8169
8186
|
const validation = await this.validate({
|
|
@@ -8178,7 +8195,7 @@ var DatasetsClient = class extends ResourceClient {
|
|
|
8178
8195
|
throw new Error("projectId is required.");
|
|
8179
8196
|
}
|
|
8180
8197
|
const fileName = import_node_path.default.basename(input.path);
|
|
8181
|
-
const fileBuffer = await
|
|
8198
|
+
const fileBuffer = await readDatasetFile(input.path);
|
|
8182
8199
|
const uploadSessionInput = uploadSessionCreateSchema.parse({
|
|
8183
8200
|
projectId,
|
|
8184
8201
|
fileName,
|
|
@@ -8204,21 +8221,46 @@ var DatasetsClient = class extends ResourceClient {
|
|
|
8204
8221
|
if (input.format !== "chat_jsonl") {
|
|
8205
8222
|
throw new Error("Only chat_jsonl datasets are supported.");
|
|
8206
8223
|
}
|
|
8207
|
-
return validateChatJsonl(await
|
|
8224
|
+
return validateChatJsonl(await readDatasetFile(input.path, "utf8"));
|
|
8208
8225
|
}
|
|
8209
8226
|
get(datasetId) {
|
|
8210
|
-
return this.requestGet(`/v1/datasets/${datasetId}`);
|
|
8227
|
+
return this.requestGet(`/v1/datasets/${encodeDatasetId(datasetId)}`);
|
|
8211
8228
|
}
|
|
8212
8229
|
list(projectId) {
|
|
8213
8230
|
const effectiveProjectId = projectId ?? this.parent.projectId;
|
|
8214
|
-
|
|
8231
|
+
const params = new URLSearchParams();
|
|
8232
|
+
if (effectiveProjectId) {
|
|
8233
|
+
params.set("projectId", effectiveProjectId);
|
|
8234
|
+
}
|
|
8235
|
+
const query = params.toString();
|
|
8236
|
+
return this.requestGet(`/v1/datasets${query ? `?${query}` : ""}`);
|
|
8215
8237
|
}
|
|
8216
8238
|
delete(datasetId) {
|
|
8217
|
-
return this.requestDelete(`/v1/datasets/${datasetId}`);
|
|
8239
|
+
return this.requestDelete(`/v1/datasets/${encodeDatasetId(datasetId)}`);
|
|
8218
8240
|
}
|
|
8219
8241
|
};
|
|
8242
|
+
async function readDatasetFile(pathname, encoding) {
|
|
8243
|
+
let stats;
|
|
8244
|
+
try {
|
|
8245
|
+
stats = await import_promises.default.stat(pathname);
|
|
8246
|
+
} catch {
|
|
8247
|
+
throw new Error(`Dataset file not found: ${pathname}`);
|
|
8248
|
+
}
|
|
8249
|
+
if (!stats.isFile()) {
|
|
8250
|
+
throw new Error(`Dataset path must be a file: ${pathname}`);
|
|
8251
|
+
}
|
|
8252
|
+
return encoding ? import_promises.default.readFile(pathname, encoding) : import_promises.default.readFile(pathname);
|
|
8253
|
+
}
|
|
8220
8254
|
|
|
8221
8255
|
// ../sdk/dist/client/deployments.js
|
|
8256
|
+
var deploymentIdPattern = /^dep_[A-Za-z0-9_-]+$/;
|
|
8257
|
+
function encodeDeploymentId(deploymentId) {
|
|
8258
|
+
const id = String(deploymentId ?? "").trim();
|
|
8259
|
+
if (!deploymentIdPattern.test(id)) {
|
|
8260
|
+
throw new Error("Deployment ID is invalid.");
|
|
8261
|
+
}
|
|
8262
|
+
return encodeURIComponent(id);
|
|
8263
|
+
}
|
|
8222
8264
|
var DeploymentsClient = class extends ResourceClient {
|
|
8223
8265
|
list() {
|
|
8224
8266
|
return this.requestGet("/v1/deployments");
|
|
@@ -8227,23 +8269,31 @@ var DeploymentsClient = class extends ResourceClient {
|
|
|
8227
8269
|
return this.requestPost("/v1/deployments", input);
|
|
8228
8270
|
}
|
|
8229
8271
|
get(id) {
|
|
8230
|
-
return this.requestGet(`/v1/deployments/${id}`);
|
|
8272
|
+
return this.requestGet(`/v1/deployments/${encodeDeploymentId(id)}`);
|
|
8231
8273
|
}
|
|
8232
8274
|
delete(id) {
|
|
8233
|
-
return this.requestDelete(`/v1/deployments/${id}`);
|
|
8275
|
+
return this.requestDelete(`/v1/deployments/${encodeDeploymentId(id)}`);
|
|
8234
8276
|
}
|
|
8235
8277
|
};
|
|
8236
8278
|
|
|
8237
8279
|
// ../sdk/dist/client/models.js
|
|
8280
|
+
var modelIdPattern = /^mdl_[A-Za-z0-9_-]+$/;
|
|
8281
|
+
function normalizeModelId(modelId) {
|
|
8282
|
+
const normalized = String(modelId ?? "").trim();
|
|
8283
|
+
if (!modelIdPattern.test(normalized)) {
|
|
8284
|
+
throw new Error("Model ID is invalid.");
|
|
8285
|
+
}
|
|
8286
|
+
return encodeURIComponent(normalized);
|
|
8287
|
+
}
|
|
8238
8288
|
var ModelsClient = class extends ResourceClient {
|
|
8239
8289
|
list() {
|
|
8240
8290
|
return this.requestGet("/v1/models");
|
|
8241
8291
|
}
|
|
8242
8292
|
get(modelId) {
|
|
8243
|
-
return this.requestGet(`/v1/models/${modelId}`);
|
|
8293
|
+
return this.requestGet(`/v1/models/${normalizeModelId(modelId)}`);
|
|
8244
8294
|
}
|
|
8245
8295
|
export(modelId) {
|
|
8246
|
-
return this.requestPost(`/v1/models/${modelId}/export`);
|
|
8296
|
+
return this.requestPost(`/v1/models/${normalizeModelId(modelId)}/export`);
|
|
8247
8297
|
}
|
|
8248
8298
|
};
|
|
8249
8299
|
|
|
@@ -8255,12 +8305,20 @@ var ProjectsClient = class extends ResourceClient {
|
|
|
8255
8305
|
organizationId: input.organizationId ?? this.parent.orgId
|
|
8256
8306
|
});
|
|
8257
8307
|
}
|
|
8308
|
+
delete(projectId) {
|
|
8309
|
+
return this.requestDelete(`/v1/projects/${projectId}`);
|
|
8310
|
+
}
|
|
8258
8311
|
get(projectId) {
|
|
8259
8312
|
return this.requestGet(`/v1/projects/${projectId}`);
|
|
8260
8313
|
}
|
|
8261
8314
|
list(organizationId) {
|
|
8262
8315
|
const suffix = organizationId ?? this.parent.orgId;
|
|
8263
|
-
|
|
8316
|
+
const params = new URLSearchParams();
|
|
8317
|
+
if (suffix) {
|
|
8318
|
+
params.set("organizationId", suffix);
|
|
8319
|
+
}
|
|
8320
|
+
const query = params.toString();
|
|
8321
|
+
return this.requestGet(`/v1/projects${query ? `?${query}` : ""}`);
|
|
8264
8322
|
}
|
|
8265
8323
|
};
|
|
8266
8324
|
var OrganizationsClient = class extends ResourceClient {
|
|
@@ -8420,15 +8478,6 @@ var RunHandle = class {
|
|
|
8420
8478
|
this.snapshot = detail.run;
|
|
8421
8479
|
if (["completed", "failed", "canceled", "terminated"].includes(detail.run.status)) {
|
|
8422
8480
|
this.close();
|
|
8423
|
-
if (detail.run.status === "failed") {
|
|
8424
|
-
throw new Error(detail.run.failureReason ?? "Run failed.");
|
|
8425
|
-
}
|
|
8426
|
-
if (detail.run.status === "canceled") {
|
|
8427
|
-
throw new Error("Run was canceled.");
|
|
8428
|
-
}
|
|
8429
|
-
if (detail.run.status === "terminated") {
|
|
8430
|
-
throw new Error("Run was terminated.");
|
|
8431
|
-
}
|
|
8432
8481
|
return detail;
|
|
8433
8482
|
}
|
|
8434
8483
|
if (timeoutMs !== void 0 && Date.now() - startedAt > timeoutMs) {
|
|
@@ -8514,6 +8563,14 @@ var RunHandle = class {
|
|
|
8514
8563
|
};
|
|
8515
8564
|
|
|
8516
8565
|
// ../sdk/dist/client/runs.js
|
|
8566
|
+
var runIdPattern = /^run_[A-Za-z0-9_-]+$/;
|
|
8567
|
+
function encodeRunId(runId) {
|
|
8568
|
+
const id = String(runId ?? "").trim();
|
|
8569
|
+
if (!runIdPattern.test(id)) {
|
|
8570
|
+
throw new Error("Run ID is invalid.");
|
|
8571
|
+
}
|
|
8572
|
+
return encodeURIComponent(id);
|
|
8573
|
+
}
|
|
8517
8574
|
var RunsClient = class extends ResourceClient {
|
|
8518
8575
|
describeEmptyQuoteFailure(input) {
|
|
8519
8576
|
const compute = input.compute && input.compute !== "auto" && input.compute !== "cpu-sim" ? input.compute : void 0;
|
|
@@ -8611,47 +8668,52 @@ var RunsClient = class extends ResourceClient {
|
|
|
8611
8668
|
mode: selectedModeQuote.mode
|
|
8612
8669
|
};
|
|
8613
8670
|
}
|
|
8614
|
-
const parsed = runCreateSchema.parse(payload);
|
|
8671
|
+
const parsed = input.pricingQuoteId ? payload : runCreateSchema.parse(payload);
|
|
8615
8672
|
const run = await this.requestPost("/v1/runs", parsed);
|
|
8616
8673
|
return new RunHandle(this.parent, run);
|
|
8617
8674
|
}
|
|
8618
8675
|
get(runId) {
|
|
8619
|
-
return this.requestGet(`/v1/runs/${runId}`);
|
|
8676
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}`);
|
|
8620
8677
|
}
|
|
8621
8678
|
list(projectId) {
|
|
8622
8679
|
const effectiveProjectId = projectId ?? this.parent.projectId;
|
|
8623
|
-
|
|
8680
|
+
const params = new URLSearchParams();
|
|
8681
|
+
if (effectiveProjectId) {
|
|
8682
|
+
params.set("projectId", effectiveProjectId);
|
|
8683
|
+
}
|
|
8684
|
+
const query = params.toString();
|
|
8685
|
+
return this.requestGet(`/v1/runs${query ? `?${query}` : ""}`);
|
|
8624
8686
|
}
|
|
8625
8687
|
cancel(runId) {
|
|
8626
|
-
return this.requestPost(`/v1/runs/${runId}/cancel`);
|
|
8688
|
+
return this.requestPost(`/v1/runs/${encodeRunId(runId)}/cancel`);
|
|
8627
8689
|
}
|
|
8628
8690
|
resume(runId) {
|
|
8629
|
-
return this.requestPost(`/v1/runs/${runId}/resume`);
|
|
8691
|
+
return this.requestPost(`/v1/runs/${encodeRunId(runId)}/resume`);
|
|
8630
8692
|
}
|
|
8631
8693
|
terminate(runId) {
|
|
8632
|
-
return this.requestPost(`/v1/runs/${runId}/terminate`);
|
|
8694
|
+
return this.requestPost(`/v1/runs/${encodeRunId(runId)}/terminate`);
|
|
8633
8695
|
}
|
|
8634
8696
|
logs(runId) {
|
|
8635
|
-
return this.requestGet(`/v1/runs/${runId}/logs`);
|
|
8697
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}/logs`);
|
|
8636
8698
|
}
|
|
8637
8699
|
async watch(runId) {
|
|
8638
8700
|
const detail = await this.get(runId);
|
|
8639
8701
|
return new RunHandle(this.parent, detail.run);
|
|
8640
8702
|
}
|
|
8641
8703
|
allocation(runId) {
|
|
8642
|
-
return this.requestGet(`/v1/runs/${runId}/allocation`);
|
|
8704
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}/allocation`);
|
|
8643
8705
|
}
|
|
8644
8706
|
usage(runId) {
|
|
8645
|
-
return this.requestGet(`/v1/runs/${runId}/usage`);
|
|
8707
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}/usage`);
|
|
8646
8708
|
}
|
|
8647
8709
|
costBreakdown(runId) {
|
|
8648
|
-
return this.requestGet(`/v1/runs/${runId}/cost-breakdown`);
|
|
8710
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}/cost-breakdown`);
|
|
8649
8711
|
}
|
|
8650
8712
|
configuration(runId) {
|
|
8651
|
-
return this.requestGet(`/v1/runs/${runId}/configuration`);
|
|
8713
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}/configuration`);
|
|
8652
8714
|
}
|
|
8653
8715
|
explanation(runId) {
|
|
8654
|
-
return this.requestGet(`/v1/runs/${runId}/explanation`);
|
|
8716
|
+
return this.requestGet(`/v1/runs/${encodeRunId(runId)}/explanation`);
|
|
8655
8717
|
}
|
|
8656
8718
|
async wait(runId, options) {
|
|
8657
8719
|
const handle = await this.watch(runId);
|
|
@@ -8666,7 +8728,12 @@ var RuntimeClient = class extends ResourceClient {
|
|
|
8666
8728
|
projectId: input.projectId ?? this.parent.projectId,
|
|
8667
8729
|
source: input.source
|
|
8668
8730
|
});
|
|
8669
|
-
return this.requestPost("/v1/runtime/detect", payload)
|
|
8731
|
+
return this.requestPost("/v1/runtime/detect", payload).catch((error) => {
|
|
8732
|
+
if (input.source.kind === "git" && error instanceof Error && /Request failed with status 404/.test(error.message)) {
|
|
8733
|
+
throw new Error("Git repository could not be resolved. Check the repository URL, branch, and access permissions.");
|
|
8734
|
+
}
|
|
8735
|
+
throw error;
|
|
8736
|
+
});
|
|
8670
8737
|
}
|
|
8671
8738
|
build(input) {
|
|
8672
8739
|
const payload = runtimeBuildCreateSchema.parse({
|
|
@@ -8828,6 +8895,7 @@ var idPatterns = {
|
|
|
8828
8895
|
org: /^org_[A-Za-z0-9_-]+$/,
|
|
8829
8896
|
pool: /^pool_[A-Za-z0-9_-]+$/,
|
|
8830
8897
|
project: /^proj_[A-Za-z0-9_-]+$/,
|
|
8898
|
+
quote: /^quote_[A-Za-z0-9_-]+$/,
|
|
8831
8899
|
run: /^run_[A-Za-z0-9_-]+$/,
|
|
8832
8900
|
serviceAccount: /^svc_[A-Za-z0-9_-]+$/,
|
|
8833
8901
|
supplier: /^[A-Za-z][A-Za-z0-9_-]*$/
|
|
@@ -9139,7 +9207,7 @@ function buildComputeSpec(options) {
|
|
|
9139
9207
|
|
|
9140
9208
|
// src/index.ts
|
|
9141
9209
|
var DEFAULT_TRAINFABRIC_API_URL2 = "https://api.trainfabric.com";
|
|
9142
|
-
var CLI_VERSION = "0.1.
|
|
9210
|
+
var CLI_VERSION = "0.1.31";
|
|
9143
9211
|
var CONFIG_DIR = import_node_path3.default.join(import_node_os2.default.homedir(), ".trainfabric");
|
|
9144
9212
|
var CONFIG_PATH = import_node_path3.default.join(CONFIG_DIR, "config.json");
|
|
9145
9213
|
var FALLBACK_SECRET_PATH = import_node_path3.default.join(CONFIG_DIR, "session.enc");
|
|
@@ -9486,23 +9554,43 @@ function requireProjectId(options, config) {
|
|
|
9486
9554
|
}
|
|
9487
9555
|
function buildRunInput(options, config = loadConfig()) {
|
|
9488
9556
|
const sourceOptions = buildSourceOptions(options);
|
|
9489
|
-
|
|
9490
|
-
|
|
9557
|
+
const quoteId = options.quote === void 0 ? void 0 : normalizeId(options.quote, "quote", "Pricing quote ID");
|
|
9558
|
+
if (!quoteId && !options.dataset) {
|
|
9559
|
+
throw new Error("Dataset is required unless --quote is provided.");
|
|
9560
|
+
}
|
|
9561
|
+
if (!quoteId && !options.model) {
|
|
9562
|
+
throw new Error("Model is required unless --quote is provided.");
|
|
9563
|
+
}
|
|
9564
|
+
const projectId = normalizeOptionalId(options.project ?? config.projectId, "project", "Project ID");
|
|
9565
|
+
if (!quoteId && !projectId) {
|
|
9566
|
+
throw new Error("Project is required. Pass --project <projectId> or run `trainfabric config:set-project <projectId>`.");
|
|
9567
|
+
}
|
|
9568
|
+
const input = {
|
|
9491
9569
|
task: "sft",
|
|
9492
9570
|
method: "lora",
|
|
9493
|
-
|
|
9494
|
-
datasetId: normalizeId(options.dataset, "dataset", "Dataset ID"),
|
|
9571
|
+
pricingQuoteId: quoteId,
|
|
9495
9572
|
evalDatasetId: normalizeOptionalId(options.eval, "dataset", "Eval dataset ID"),
|
|
9496
|
-
pricingQuoteId: options.quote,
|
|
9497
9573
|
...sourceOptions,
|
|
9498
|
-
mode: normalizeTrainingMode(options.mode)
|
|
9499
|
-
|
|
9500
|
-
|
|
9574
|
+
mode: normalizeTrainingMode(options.mode)
|
|
9575
|
+
};
|
|
9576
|
+
if (projectId) {
|
|
9577
|
+
input.projectId = projectId;
|
|
9578
|
+
}
|
|
9579
|
+
if (options.model) {
|
|
9580
|
+
input.baseModel = normalizeBaseModel(options.model);
|
|
9581
|
+
}
|
|
9582
|
+
if (options.dataset) {
|
|
9583
|
+
input.datasetId = normalizeId(options.dataset, "dataset", "Dataset ID");
|
|
9584
|
+
}
|
|
9585
|
+
if (!quoteId) {
|
|
9586
|
+
input.compute = buildComputeSpec(options);
|
|
9587
|
+
input.hyperparameters = {
|
|
9501
9588
|
epochs: normalizeEpochs(options.epochs),
|
|
9502
9589
|
lr: normalizeLearningRate(options.lr),
|
|
9503
9590
|
batchSize: "auto"
|
|
9504
|
-
}
|
|
9505
|
-
}
|
|
9591
|
+
};
|
|
9592
|
+
}
|
|
9593
|
+
return input;
|
|
9506
9594
|
}
|
|
9507
9595
|
function assertQuoteOptions(bundle, options) {
|
|
9508
9596
|
if (bundle.quotes.length > 0) {
|
|
@@ -9761,6 +9849,11 @@ program2.command("projects:create").requiredOption("--name <name>").option("--or
|
|
|
9761
9849
|
})
|
|
9762
9850
|
);
|
|
9763
9851
|
});
|
|
9852
|
+
program2.command("projects:delete").argument("<projectId>").description("Delete an empty project").action(async (projectId) => {
|
|
9853
|
+
const normalizedProjectId = normalizeId(projectId, "project", "Project ID");
|
|
9854
|
+
await createClient(loadConfig()).projects.delete(normalizedProjectId);
|
|
9855
|
+
printJson({ deleted: true, id: normalizedProjectId });
|
|
9856
|
+
});
|
|
9764
9857
|
program2.command("datasets:validate").argument("<file>").description("Validate a local dataset file").action(async (file) => {
|
|
9765
9858
|
assertReadableFile(file, "Dataset path");
|
|
9766
9859
|
const validation = await createClient(loadConfig()).datasets.validate({
|
|
@@ -9796,7 +9889,7 @@ program2.command("datasets:upload").argument("<file>").option("--project <projec
|
|
|
9796
9889
|
});
|
|
9797
9890
|
printJson(dataset);
|
|
9798
9891
|
});
|
|
9799
|
-
program2.command("runs:create").option("--project <projectId>").
|
|
9892
|
+
program2.command("runs:create").option("--project <projectId>").option("--dataset <datasetId>").option("--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").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) => {
|
|
9800
9893
|
const config = loadConfig();
|
|
9801
9894
|
const runInput = buildRunInput(options, config);
|
|
9802
9895
|
if (!options.yes) {
|
|
@@ -9812,10 +9905,23 @@ program2.command("runtime:detect").option("--project <projectId>").option("--rep
|
|
|
9812
9905
|
throw new Error("Provide --repo or --git.");
|
|
9813
9906
|
}
|
|
9814
9907
|
const config = loadConfig();
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9908
|
+
let detection;
|
|
9909
|
+
try {
|
|
9910
|
+
detection = await createClient(config).runtime.detect({
|
|
9911
|
+
projectId: requireProjectId(options, config),
|
|
9912
|
+
source: sourceOptions.source
|
|
9913
|
+
});
|
|
9914
|
+
} catch (error) {
|
|
9915
|
+
if (sourceOptions.source.kind === "git" && error instanceof Error && /Request failed with status 404/.test(error.message)) {
|
|
9916
|
+
throw new Error("Git repository could not be resolved. Check the repository URL, branch, and access permissions.");
|
|
9917
|
+
}
|
|
9918
|
+
throw error;
|
|
9919
|
+
}
|
|
9920
|
+
if (sourceOptions.source.kind === "git" && detection.status !== "detected") {
|
|
9921
|
+
throw new Error(
|
|
9922
|
+
`Runtime source is ${detection.status}. Git repository could not be resolved into a supported runtime source.`
|
|
9923
|
+
);
|
|
9924
|
+
}
|
|
9819
9925
|
printJson(redactInlineSource(detection));
|
|
9820
9926
|
});
|
|
9821
9927
|
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) => {
|