trainfabric 0.1.44 → 0.1.46

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.
Files changed (2) hide show
  1. package/dist/index.cjs +101 -9
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -7526,6 +7526,25 @@ var NEVER = INVALID;
7526
7526
  var experimentProviderIds = ["mlflow"];
7527
7527
  var experimentTrackingModes = ["online", "offline"];
7528
7528
  var baseModels = ["llama-3-8b", "mistral-7b", "qwen-2.5-7b"];
7529
+ var runStatuses = [
7530
+ "draft",
7531
+ "validating",
7532
+ "queued",
7533
+ "awaiting_capacity",
7534
+ "scheduled",
7535
+ "provisioning",
7536
+ "launching",
7537
+ "starting",
7538
+ "running",
7539
+ "checkpointing",
7540
+ "evaluating",
7541
+ "completed",
7542
+ "failed",
7543
+ "canceled",
7544
+ "resuming",
7545
+ "paused",
7546
+ "terminated"
7547
+ ];
7529
7548
  var organizationRoles = ["owner", "admin", "member", "billing"];
7530
7549
  var apiKeyScopes = [
7531
7550
  "org:read",
@@ -7629,6 +7648,7 @@ var runCreateSchema = external_exports.object({
7629
7648
  runtimeManifestId: external_exports.string().min(1).optional(),
7630
7649
  profileSessionId: external_exports.string().min(1).optional(),
7631
7650
  pricingQuoteId: external_exports.string().min(1).optional(),
7651
+ maxCostUsd: external_exports.number().positive().max(1e5).optional(),
7632
7652
  experimentTracking: experimentTrackingInputSchema.optional()
7633
7653
  });
7634
7654
  var jobProfileSchema = runCreateSchema;
@@ -7674,6 +7694,7 @@ var runQuoteSchema = external_exports.object({
7674
7694
  hyperparameters: runHyperparametersSchema.optional(),
7675
7695
  runtimeVersion: external_exports.string().min(1).optional(),
7676
7696
  mode: external_exports.enum(trainingModes).optional(),
7697
+ maxCostUsd: external_exports.number().positive().max(1e5).optional(),
7677
7698
  reservationClass: external_exports.enum(reservationClasses).optional(),
7678
7699
  slaClass: external_exports.enum(slaClasses).optional(),
7679
7700
  runtimeManifestId: external_exports.string().min(1).optional(),
@@ -7743,11 +7764,20 @@ var serviceAccountCreateSchema = external_exports.object({
7743
7764
  scopes: external_exports.array(external_exports.enum(apiKeyScopes)).min(1)
7744
7765
  });
7745
7766
  var billingCheckoutSessionCreateSchema = external_exports.object({
7746
- amountUsd: external_exports.number().positive().max(1e5).optional(),
7767
+ amountUsd: external_exports.number().min(5).max(1e5).optional(),
7747
7768
  mode: external_exports.enum(["subscription", "credits"]).default("subscription"),
7748
7769
  planId: external_exports.enum(["hobby", "pro"]).optional(),
7749
7770
  priceId: external_exports.string().min(1).optional()
7750
7771
  });
7772
+ var couponRedeemSchema = external_exports.object({
7773
+ code: external_exports.string().trim().min(1).max(64)
7774
+ });
7775
+ var creditAdjustmentCreateSchema = external_exports.object({
7776
+ amountUsd: external_exports.number().min(-1e5).max(1e5).refine((value) => value !== 0, "Credit adjustment amount cannot be zero."),
7777
+ kind: external_exports.enum(["manual_adjustment", "refund_credit", "refund_debit"]),
7778
+ reason: external_exports.string().trim().min(1).max(500),
7779
+ sourceId: external_exports.string().trim().min(1).max(128).optional()
7780
+ });
7751
7781
  var treasuryCounterpartyCreateSchema = external_exports.object({
7752
7782
  providerId: external_exports.enum(treasuryProviderIds).default("mercury"),
7753
7783
  name: external_exports.string().min(1),
@@ -8594,6 +8624,10 @@ function encodeRunId(runId) {
8594
8624
  }
8595
8625
  return encodeURIComponent(id);
8596
8626
  }
8627
+ function isTransientQuoteError(error) {
8628
+ const message = error instanceof Error ? error.message : String(error);
8629
+ return /status (502|503|504)\b/i.test(message);
8630
+ }
8597
8631
  var RunsClient = class extends ResourceClient {
8598
8632
  describeEmptyQuoteFailure(input) {
8599
8633
  const compute = input.compute && input.compute !== "auto" && input.compute !== "cpu-sim" ? input.compute : void 0;
@@ -8655,7 +8689,7 @@ var RunsClient = class extends ResourceClient {
8655
8689
  projectId: input.projectId ?? this.parent.projectId,
8656
8690
  profileSessionId: detail.session.id
8657
8691
  });
8658
- return this.requestPost("/v1/runs/quotes", payload);
8692
+ return this.requestQuoteWithRetry("/v1/runs/quotes", payload);
8659
8693
  }
8660
8694
  async quoteLegacy(input) {
8661
8695
  const detail = await this.ensureReadyProfile(input);
@@ -8664,7 +8698,23 @@ var RunsClient = class extends ResourceClient {
8664
8698
  projectId: input.projectId ?? this.parent.projectId,
8665
8699
  profileSessionId: detail.session.id
8666
8700
  });
8667
- return this.requestPost("/v1/runs/quote", payload);
8701
+ return this.requestQuoteWithRetry("/v1/runs/quote", payload);
8702
+ }
8703
+ async requestQuoteWithRetry(pathname, payload) {
8704
+ const attempts = Math.max(1, Number(process.env.TRAINFABRIC_QUOTE_RETRY_ATTEMPTS ?? 3));
8705
+ let lastError;
8706
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
8707
+ try {
8708
+ return await this.requestPost(pathname, payload);
8709
+ } catch (error) {
8710
+ lastError = error;
8711
+ if (!isTransientQuoteError(error) || attempt === attempts) {
8712
+ throw error;
8713
+ }
8714
+ await wait(500 * attempt);
8715
+ }
8716
+ }
8717
+ throw lastError instanceof Error ? lastError : new Error("Quote request failed.");
8668
8718
  }
8669
8719
  async create(input) {
8670
8720
  const projectId = input.projectId ?? this.parent.projectId;
@@ -9250,6 +9300,16 @@ function normalizeLearningRate(lr) {
9250
9300
  }
9251
9301
  return parsed;
9252
9302
  }
9303
+ function normalizeMaxCost(maxCost) {
9304
+ if (maxCost === void 0) {
9305
+ return void 0;
9306
+ }
9307
+ const parsed = Number(maxCost);
9308
+ if (!Number.isFinite(parsed) || parsed <= 0 || parsed > 1e5) {
9309
+ throw new Error("Max cost must be a positive USD amount up to 100000.");
9310
+ }
9311
+ return Number(parsed.toFixed(2));
9312
+ }
9253
9313
  function buildComputeSpec(options) {
9254
9314
  const gpuCount = normalizePositiveInteger(options.gpus, "GPU count", 1, 64);
9255
9315
  const nodeCount = normalizePositiveInteger(options.nodes, "Node count", 1, 16);
@@ -9291,7 +9351,7 @@ function buildComputeSpec(options) {
9291
9351
 
9292
9352
  // src/index.ts
9293
9353
  var DEFAULT_TRAINFABRIC_API_URL2 = "https://api.trainfabric.com";
9294
- var CLI_VERSION = "0.1.44";
9354
+ var CLI_VERSION = "0.1.46";
9295
9355
  var CONFIG_DIR = import_node_path3.default.join(import_node_os2.default.homedir(), ".trainfabric");
9296
9356
  var CONFIG_PATH = import_node_path3.default.join(CONFIG_DIR, "config.json");
9297
9357
  var FALLBACK_SECRET_PATH = import_node_path3.default.join(CONFIG_DIR, "session.enc");
@@ -9667,6 +9727,16 @@ function requireProjectId(options, config) {
9667
9727
  }
9668
9728
  return projectId;
9669
9729
  }
9730
+ function normalizeRunStatusFilter(status) {
9731
+ if (status === void 0) {
9732
+ return void 0;
9733
+ }
9734
+ const normalized = String(status).trim().toLowerCase();
9735
+ if (!runStatuses.includes(normalized)) {
9736
+ throw new Error(`Run status is invalid. Use one of: ${runStatuses.join(", ")}.`);
9737
+ }
9738
+ return normalized;
9739
+ }
9670
9740
  function optionWasProvided(command, optionName) {
9671
9741
  return command.getOptionValueSource(optionName) === "cli";
9672
9742
  }
@@ -9720,6 +9790,7 @@ function buildRunInput(options, config = loadConfig()) {
9720
9790
  pricingQuoteId: quoteId,
9721
9791
  evalDatasetId: normalizeOptionalId(options.eval, "dataset", "Eval dataset ID"),
9722
9792
  ...sourceOptions,
9793
+ maxCostUsd: normalizeMaxCost(options.maxCost),
9723
9794
  mode: normalizeTrainingMode(options.mode)
9724
9795
  };
9725
9796
  if (projectId) {
@@ -9814,7 +9885,8 @@ async function watchRun(runId, json = false, timeoutMs, pollMs) {
9814
9885
  });
9815
9886
  handle.on("log", (event) => {
9816
9887
  const payload = event.payload;
9817
- console.log(`[${payload.phase ?? "run"}:${payload.level ?? "info"}] ${payload.message ?? ""}`);
9888
+ const eventLabel = formatRunEventCode(payload.eventCode);
9889
+ console.log(`[${eventLabel ?? payload.phase ?? "run"}:${payload.level ?? "info"}] ${payload.message ?? ""}`);
9818
9890
  });
9819
9891
  handle.on("metric", (event) => {
9820
9892
  const payload = event.payload;
@@ -9845,6 +9917,24 @@ async function watchRun(runId, json = false, timeoutMs, pollMs) {
9845
9917
  );
9846
9918
  }
9847
9919
  }
9920
+ function formatRunEventCode(eventCode) {
9921
+ switch (eventCode) {
9922
+ case "provider_waiting_for_ssh":
9923
+ return "provider-waiting";
9924
+ case "relay_confirmation_timeout_nonfatal":
9925
+ return "relay-monitoring";
9926
+ case "dependency_installing":
9927
+ return "dependency-installing";
9928
+ case "runtime_bootstrap_fallback":
9929
+ return "runtime-bootstrap";
9930
+ case "training_started":
9931
+ return "training-started";
9932
+ case "artifact_syncing":
9933
+ return "artifact-syncing";
9934
+ default:
9935
+ return void 0;
9936
+ }
9937
+ }
9848
9938
  function parseDurationMs(value) {
9849
9939
  if (!value) {
9850
9940
  return void 0;
@@ -10053,7 +10143,7 @@ program2.command("datasets:upload").argument("<file>").option("--project <projec
10053
10143
  });
10054
10144
  printJson(dataset);
10055
10145
  });
10056
- 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; use only with --yes").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. When using --quote, do not pass project, dataset, model, compute, mode, source, or hyperparameter flags; launch with `trainfabric runs:create --quote <quoteId> --yes`.").action(async (options, command) => {
10146
+ 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("--max-cost <usd>", "maximum accepted quoted customer charge in USD").option("--quote <pricingQuoteId>", "launch the exact accepted quote id from runs:quote; use only with --yes").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. When using --quote, do not pass project, dataset, model, compute, mode, source, or hyperparameter flags; launch with `trainfabric runs:create --quote <quoteId> --yes`.").action(async (options, command) => {
10057
10147
  const config = loadConfig();
10058
10148
  assertQuoteCreateHasNoLaunchOverrides(options, command);
10059
10149
  const runInput = buildRunInput(options, config);
@@ -10100,7 +10190,7 @@ program2.command("runtime:build").option("--project <projectId>").requiredOption
10100
10190
  )
10101
10191
  );
10102
10192
  });
10103
- 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("--json", "print raw JSON output; this is the default unless --summary is used").option("--summary", "print a human-readable price summary instead of raw JSON").description("Preview Efficient, Balanced, and Power launch options").action(async (options) => {
10193
+ 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("--max-cost <usd>", "maximum accepted quoted customer charge in USD").option("--repo <path>").option("--git <url>").option("--branch <branch>").option("--json", "print raw JSON output; this is the default unless --summary is used").option("--summary", "print a human-readable price summary instead of raw JSON").description("Preview Efficient, Balanced, and Power launch options").action(async (options) => {
10104
10194
  const config = loadConfig();
10105
10195
  const bundle = filterQuoteBundleForRequestedMode(
10106
10196
  await createClient(config).runs.quote(buildRunInput(options, config)),
@@ -10113,8 +10203,10 @@ program2.command("runs:quote").option("--project <projectId>").requiredOption("-
10113
10203
  printJson(redactInlineSource(bundle));
10114
10204
  }
10115
10205
  });
10116
- program2.command("runs:list").option("--project <projectId>").description("List runs").action(async (options) => {
10117
- printJson(await createClient(loadConfig()).runs.list(normalizeOptionalId(options.project, "project", "Project ID")));
10206
+ program2.command("runs:list").option("--project <projectId>").option("--status <status>", "filter by run status").option("--json", "print raw JSON output; this is the default").description("List runs").action(async (options) => {
10207
+ const status = normalizeRunStatusFilter(options.status);
10208
+ const runs = await createClient(loadConfig()).runs.list(normalizeOptionalId(options.project, "project", "Project ID"));
10209
+ printJson(status ? runs.filter((run) => run.status === status) : runs);
10118
10210
  });
10119
10211
  program2.command("runs:status").argument("<runId>").description("Fetch full run detail").action(async (runId) => {
10120
10212
  const detail = await createClient(loadConfig()).runs.get(normalizeId(runId, "run", "Run ID"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trainfabric",
3
- "version": "0.1.44",
3
+ "version": "0.1.46",
4
4
  "description": "Trainfabric CLI for launching GPU training jobs on the hosted Trainfabric backend.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",