runbios-sdk 0.2.1-dev.62
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 +460 -0
- package/dist/client.d.ts +202 -0
- package/dist/client.js +408 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +93 -0
- package/dist/resources/datasets.d.ts +180 -0
- package/dist/resources/datasets.js +358 -0
- package/dist/resources/gpu-priorities.d.ts +23 -0
- package/dist/resources/gpu-priorities.js +63 -0
- package/dist/resources/gpu.d.ts +60 -0
- package/dist/resources/gpu.js +101 -0
- package/dist/resources/inference.d.ts +224 -0
- package/dist/resources/inference.js +794 -0
- package/dist/resources/models.d.ts +113 -0
- package/dist/resources/models.js +171 -0
- package/dist/resources/training.d.ts +166 -0
- package/dist/resources/training.js +419 -0
- package/dist/resources/wallet.d.ts +53 -0
- package/dist/resources/wallet.js +61 -0
- package/dist/types.d.ts +1916 -0
- package/dist/types.js +4 -0
- package/package.json +52 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import { normalizeGPUPlacement } from './gpu-priorities.js';
|
|
2
|
+
const TRAINING_IDEMPOTENCY_KEY = /^[A-Za-z0-9._:-]{8,128}$/;
|
|
3
|
+
function trainingIdempotencyKey(explicit) {
|
|
4
|
+
const key = explicit?.trim() || globalThis.crypto.randomUUID();
|
|
5
|
+
if (!TRAINING_IDEMPOTENCY_KEY.test(key)) {
|
|
6
|
+
throw new Error("RunBiOS: idempotencyKey must be 8-128 characters using letters, numbers, '.', '_', ':', or '-'");
|
|
7
|
+
}
|
|
8
|
+
return key;
|
|
9
|
+
}
|
|
10
|
+
function buildTrainingRequest(params) {
|
|
11
|
+
let trainingMethod = params.method;
|
|
12
|
+
if (trainingMethod === 'vlm')
|
|
13
|
+
trainingMethod = 'sft';
|
|
14
|
+
const datasetIds = (params.datasetIds || []).filter((id) => id.trim() !== '');
|
|
15
|
+
if (datasetIds.length === 0 && params.datasetId?.trim())
|
|
16
|
+
datasetIds.push(params.datasetId);
|
|
17
|
+
if (datasetIds.length === 0) {
|
|
18
|
+
throw new Error('RunBiOS: datasetId or datasetIds must contain at least one dataset');
|
|
19
|
+
}
|
|
20
|
+
const body = {
|
|
21
|
+
model_id: params.model,
|
|
22
|
+
dataset_ids: datasetIds,
|
|
23
|
+
training_method: trainingMethod,
|
|
24
|
+
train_type: params.adapter,
|
|
25
|
+
};
|
|
26
|
+
if (params.modelRevision !== undefined)
|
|
27
|
+
body.model_revision = params.modelRevision;
|
|
28
|
+
if (params.rlhfAlgorithm !== undefined)
|
|
29
|
+
body.rlhf_type = params.rlhfAlgorithm;
|
|
30
|
+
const queueEnabled = params.queueIfUnavailable ?? false;
|
|
31
|
+
const placement = normalizeGPUPlacement(params.gpuPriorities, queueEnabled, params.gpuType, params.gpuCount, 'queueIfUnavailable');
|
|
32
|
+
body.queue_if_unavailable = queueEnabled;
|
|
33
|
+
if (params.queueDeadline !== undefined) {
|
|
34
|
+
const deadline = params.queueDeadline instanceof Date
|
|
35
|
+
? params.queueDeadline
|
|
36
|
+
: new Date(params.queueDeadline);
|
|
37
|
+
if (Number.isNaN(deadline.getTime())) {
|
|
38
|
+
throw new Error('RunBiOS: queueDeadline must be a valid RFC 3339 timestamp');
|
|
39
|
+
}
|
|
40
|
+
body.queue_deadline = deadline.toISOString();
|
|
41
|
+
}
|
|
42
|
+
if (params.maxPriceHourCents !== undefined) {
|
|
43
|
+
if (!Number.isInteger(params.maxPriceHourCents) || params.maxPriceHourCents < 0) {
|
|
44
|
+
throw new Error('RunBiOS: maxPriceHourCents must be a non-negative integer');
|
|
45
|
+
}
|
|
46
|
+
body.max_price_hour_cents = params.maxPriceHourCents;
|
|
47
|
+
}
|
|
48
|
+
if (placement.gpuType !== undefined)
|
|
49
|
+
body.gpu_type = placement.gpuType;
|
|
50
|
+
if (placement.gpuCount !== undefined)
|
|
51
|
+
body.gpu_count = placement.gpuCount;
|
|
52
|
+
if (placement.priorities !== undefined)
|
|
53
|
+
body.gpu_priorities = placement.priorities;
|
|
54
|
+
if (params.name !== undefined)
|
|
55
|
+
body.name = params.name;
|
|
56
|
+
if (params.workspaceId !== undefined)
|
|
57
|
+
body.workspace_id = params.workspaceId;
|
|
58
|
+
if (params.storageGb !== undefined)
|
|
59
|
+
body.storage_gb = params.storageGb;
|
|
60
|
+
if (params.numCheckpoints !== undefined)
|
|
61
|
+
body.num_checkpoints = params.numCheckpoints;
|
|
62
|
+
if (params.modelParamsB !== undefined)
|
|
63
|
+
body.model_params_b = params.modelParamsB;
|
|
64
|
+
if (params.modelActiveParamsB !== undefined)
|
|
65
|
+
body.model_active_params_b = params.modelActiveParamsB;
|
|
66
|
+
if (params.integrationId !== undefined)
|
|
67
|
+
body.integration_id = params.integrationId;
|
|
68
|
+
if (params.networkVolumeId !== undefined)
|
|
69
|
+
body.network_volume_id = params.networkVolumeId;
|
|
70
|
+
if (params.cacheDataset !== undefined)
|
|
71
|
+
body.cache_dataset = params.cacheDataset;
|
|
72
|
+
if (params.datasetSampleLimits !== undefined)
|
|
73
|
+
body.dataset_sample_limits = params.datasetSampleLimits;
|
|
74
|
+
if (params.datasetMixing !== undefined)
|
|
75
|
+
body.dataset_mixing = params.datasetMixing;
|
|
76
|
+
if (params.mixing !== undefined)
|
|
77
|
+
body.mixing = params.mixing;
|
|
78
|
+
const config = {};
|
|
79
|
+
if (params.epochs !== undefined)
|
|
80
|
+
config.num_train_epochs = params.epochs;
|
|
81
|
+
if (params.batchSize !== undefined)
|
|
82
|
+
config.per_device_train_batch_size = params.batchSize;
|
|
83
|
+
if (params.gradientAccumulation !== undefined)
|
|
84
|
+
config.gradient_accumulation_steps = params.gradientAccumulation;
|
|
85
|
+
if (params.learningRate !== undefined)
|
|
86
|
+
config.learning_rate = params.learningRate;
|
|
87
|
+
if (params.lrScheduler !== undefined)
|
|
88
|
+
config.lr_scheduler_type = params.lrScheduler;
|
|
89
|
+
if (params.warmupRatio !== undefined)
|
|
90
|
+
config.warmup_ratio = params.warmupRatio;
|
|
91
|
+
if (params.warmupSteps !== undefined)
|
|
92
|
+
config.warmup_steps = params.warmupSteps;
|
|
93
|
+
if (params.weightDecay !== undefined)
|
|
94
|
+
config.weight_decay = params.weightDecay;
|
|
95
|
+
if (params.maxGradNorm !== undefined)
|
|
96
|
+
config.max_grad_norm = params.maxGradNorm;
|
|
97
|
+
if (params.maxSeqLength !== undefined)
|
|
98
|
+
config.max_length = params.maxSeqLength;
|
|
99
|
+
if (params.gradientCheckpointing !== undefined)
|
|
100
|
+
config.gradient_checkpointing = params.gradientCheckpointing;
|
|
101
|
+
if (params.mixedPrecision !== undefined) {
|
|
102
|
+
config.torch_dtype = params.mixedPrecision === 'bf16'
|
|
103
|
+
? 'bfloat16'
|
|
104
|
+
: params.mixedPrecision === 'fp16' ? 'float16' : 'float32';
|
|
105
|
+
}
|
|
106
|
+
if (params.seed !== undefined)
|
|
107
|
+
config.seed = params.seed;
|
|
108
|
+
if (params.loraRank !== undefined)
|
|
109
|
+
config.lora_rank = params.loraRank;
|
|
110
|
+
if (params.loraAlpha !== undefined)
|
|
111
|
+
config.lora_alpha = params.loraAlpha;
|
|
112
|
+
if (params.loraDropout !== undefined)
|
|
113
|
+
config.lora_dropout = params.loraDropout;
|
|
114
|
+
if (params.loraTargetModules !== undefined)
|
|
115
|
+
config.target_modules = params.loraTargetModules;
|
|
116
|
+
if (params.quantizationBit !== undefined)
|
|
117
|
+
config.quant_bits = params.quantizationBit;
|
|
118
|
+
if (params.deepspeed !== undefined)
|
|
119
|
+
config.deepspeed = params.deepspeed;
|
|
120
|
+
if (params.saveSteps !== undefined)
|
|
121
|
+
config.save_steps = params.saveSteps;
|
|
122
|
+
if (params.saveEpochs !== undefined) {
|
|
123
|
+
if (params.saveEpochs !== 1) {
|
|
124
|
+
throw new Error('RunBiOS: saveEpochs only supports 1; use extraConfig.save_strategy for explicit checkpoint policy');
|
|
125
|
+
}
|
|
126
|
+
config.save_strategy = 'epoch';
|
|
127
|
+
}
|
|
128
|
+
if (params.maxCheckpoints !== undefined)
|
|
129
|
+
config.save_total_limit = params.maxCheckpoints;
|
|
130
|
+
if (params.evalSteps !== undefined)
|
|
131
|
+
config.eval_steps = params.evalSteps;
|
|
132
|
+
if (params.evalSplit !== undefined) {
|
|
133
|
+
const ratio = typeof params.evalSplit === 'string' ? Number(params.evalSplit) : params.evalSplit;
|
|
134
|
+
if (!Number.isFinite(ratio))
|
|
135
|
+
throw new Error('RunBiOS: evalSplit must be a numeric ratio');
|
|
136
|
+
config.split_dataset_ratio = ratio;
|
|
137
|
+
}
|
|
138
|
+
if (params.extraConfig)
|
|
139
|
+
Object.assign(config, params.extraConfig);
|
|
140
|
+
if (Object.keys(config).length > 0)
|
|
141
|
+
body.config = config;
|
|
142
|
+
return { body, datasetIds, trainingMethod };
|
|
143
|
+
}
|
|
144
|
+
function normalizeJob(raw, fallback = {}) {
|
|
145
|
+
const job = { ...fallback, ...raw };
|
|
146
|
+
const id = String(job.id || job.job_id || '');
|
|
147
|
+
if (!id)
|
|
148
|
+
throw new Error('RunBiOS: training response did not include id or job_id');
|
|
149
|
+
job.id = id;
|
|
150
|
+
if (!job.job_id && raw.job_id)
|
|
151
|
+
job.job_id = String(raw.job_id);
|
|
152
|
+
if (!job.model_id && job.model)
|
|
153
|
+
job.model_id = job.model;
|
|
154
|
+
if (!job.training_method && job.method)
|
|
155
|
+
job.training_method = job.method;
|
|
156
|
+
if (!job.train_type && job.adapter)
|
|
157
|
+
job.train_type = job.adapter;
|
|
158
|
+
if (!job.rlhf_type && job.rlhf_algorithm)
|
|
159
|
+
job.rlhf_type = job.rlhf_algorithm;
|
|
160
|
+
if (!job.dataset_ids && job.dataset_id)
|
|
161
|
+
job.dataset_ids = [job.dataset_id];
|
|
162
|
+
// Compatibility aliases let existing automations migrate without losing the
|
|
163
|
+
// canonical REST field names returned by the current API.
|
|
164
|
+
if (!job.model && job.model_id)
|
|
165
|
+
job.model = job.model_id;
|
|
166
|
+
if (!job.method && job.training_method)
|
|
167
|
+
job.method = job.training_method;
|
|
168
|
+
if (!job.adapter && job.train_type)
|
|
169
|
+
job.adapter = job.train_type;
|
|
170
|
+
if (!job.rlhf_algorithm && job.rlhf_type)
|
|
171
|
+
job.rlhf_algorithm = job.rlhf_type;
|
|
172
|
+
if (!job.dataset_id && job.dataset_ids?.length)
|
|
173
|
+
job.dataset_id = job.dataset_ids[0];
|
|
174
|
+
if (!job.error && job.error_message)
|
|
175
|
+
job.error = job.error_message;
|
|
176
|
+
if (!job.status)
|
|
177
|
+
job.status = 'pending';
|
|
178
|
+
return job;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Create, monitor, and manage fine-tuning training jobs.
|
|
182
|
+
*/
|
|
183
|
+
export class Training {
|
|
184
|
+
_http;
|
|
185
|
+
/** @internal */
|
|
186
|
+
constructor(_http) {
|
|
187
|
+
this._http = _http;
|
|
188
|
+
}
|
|
189
|
+
/** Return the authoritative method, adapter, and hyperparameter contract Run BiOS trains against. */
|
|
190
|
+
async capabilities() {
|
|
191
|
+
return this._http.fetchGet('/api/training/capabilities');
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Create a new training job (book-before-reveal).
|
|
195
|
+
*
|
|
196
|
+
* The call blocks while the ranked GPU ladder is booked (~40s typical). A
|
|
197
|
+
* training id and the "training started" email exist only once a real machine is
|
|
198
|
+
* secured, so the returned `status` is one of:
|
|
199
|
+
*
|
|
200
|
+
* - `"booked"` — a GPU was secured (booked == secured); the job then
|
|
201
|
+
* progresses through provisioning, downloading, and running on its own.
|
|
202
|
+
* - `"securing"` — still booking at the deadline; the async tail continues.
|
|
203
|
+
* Poll {@link get} until it reaches `booked`/`running` (or terminal).
|
|
204
|
+
* Nothing is charged until a machine is real.
|
|
205
|
+
* - `"queued"` — returned only with explicit queue consent
|
|
206
|
+
* (`queueIfUnavailable: true`); waits for stock at zero charge and books
|
|
207
|
+
* via the same path.
|
|
208
|
+
*
|
|
209
|
+
* If the ladder is exhausted at booking time without queue consent, this
|
|
210
|
+
* rejects with a `CAPACITY_UNAVAILABLE` (HTTP 409) carrying neutral
|
|
211
|
+
* alternatives — no phantom job remains and nothing is billed. The SDK never
|
|
212
|
+
* auto-substitutes a GPU; a transient 503 is a retry, never a capacity
|
|
213
|
+
* verdict.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* const job = await client.training.create({
|
|
218
|
+
* model: 'meta-llama/Llama-3.1-8B-Instruct',
|
|
219
|
+
* datasetId: 'ds_abc123',
|
|
220
|
+
* method: 'sft',
|
|
221
|
+
* adapter: 'lora',
|
|
222
|
+
* epochs: 3,
|
|
223
|
+
* learningRate: 2e-4,
|
|
224
|
+
* loraRank: 16,
|
|
225
|
+
* loraAlpha: 32,
|
|
226
|
+
* gpuType: 'A100_80GB',
|
|
227
|
+
* gpuCount: 1,
|
|
228
|
+
* });
|
|
229
|
+
* console.log(`Job ${job.id} created -- status: ${job.status}`);
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
async create(params) {
|
|
233
|
+
const { body, datasetIds, trainingMethod } = buildTrainingRequest(params);
|
|
234
|
+
const result = await this._http.fetchPost('/api/training/jobs', body, {
|
|
235
|
+
'Idempotency-Key': trainingIdempotencyKey(params.idempotencyKey),
|
|
236
|
+
});
|
|
237
|
+
return normalizeJob(result, {
|
|
238
|
+
model_id: params.model,
|
|
239
|
+
model_revision: params.modelRevision,
|
|
240
|
+
training_method: trainingMethod,
|
|
241
|
+
train_type: params.adapter,
|
|
242
|
+
rlhf_type: params.rlhfAlgorithm,
|
|
243
|
+
dataset_ids: datasetIds,
|
|
244
|
+
gpu_type: params.gpuType,
|
|
245
|
+
gpu_count: params.gpuCount,
|
|
246
|
+
status: 'pending',
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/** Validate and canonicalize a training request without creating or billing a job. */
|
|
250
|
+
async preflight(params) {
|
|
251
|
+
const { body } = buildTrainingRequest(params);
|
|
252
|
+
return this._http.fetchPost('/api/training/preflight', body);
|
|
253
|
+
}
|
|
254
|
+
/** Return one server-driven page with pagination metadata. */
|
|
255
|
+
async listPage(params = {}) {
|
|
256
|
+
const q = new URLSearchParams();
|
|
257
|
+
if (params.workspaceId)
|
|
258
|
+
q.set('workspace_id', params.workspaceId);
|
|
259
|
+
if (params.status)
|
|
260
|
+
q.set('status', params.status);
|
|
261
|
+
if (params.limit !== undefined)
|
|
262
|
+
q.set('limit', String(params.limit));
|
|
263
|
+
if (params.offset !== undefined)
|
|
264
|
+
q.set('offset', String(params.offset));
|
|
265
|
+
const qs = q.toString();
|
|
266
|
+
const raw = await this._http.fetchGet(`/api/training/jobs${qs ? `?${qs}` : ''}`);
|
|
267
|
+
const envelope = Array.isArray(raw)
|
|
268
|
+
? { jobs: raw.map((job) => normalizeJob(job)), total: raw.length, limit: raw.length, offset: 0 }
|
|
269
|
+
: {
|
|
270
|
+
jobs: (raw.jobs || []).map((job) => normalizeJob(job)),
|
|
271
|
+
total: Number(raw.total || 0),
|
|
272
|
+
limit: Number(raw.limit || params.limit || 50),
|
|
273
|
+
offset: Number(raw.offset || 0),
|
|
274
|
+
};
|
|
275
|
+
return envelope;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* List training jobs, optionally filtered by workspace or status.
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* ```ts
|
|
282
|
+
* const jobs = await client.training.list({ status: 'running' });
|
|
283
|
+
* for (const job of jobs) {
|
|
284
|
+
* console.log(`${job.id} -- ${job.model} -- ${job.status}`);
|
|
285
|
+
* }
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
async list(params = {}) {
|
|
289
|
+
return (await this.listPage(params)).jobs;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Get detailed information about a training job.
|
|
293
|
+
*
|
|
294
|
+
* @param id - Training job ID.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```ts
|
|
298
|
+
* const job = await client.training.get('job_abc123');
|
|
299
|
+
* console.log(`Status: ${job.status}, Progress: ${job.progress}%`);
|
|
300
|
+
* ```
|
|
301
|
+
*/
|
|
302
|
+
async get(id) {
|
|
303
|
+
const result = await this._http.fetchGet(`/api/training/jobs/${encodeURIComponent(id)}`);
|
|
304
|
+
return normalizeJob(result);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Get training metrics (loss curves, learning rate, throughput) for a job.
|
|
308
|
+
*
|
|
309
|
+
* @param id - Training job ID.
|
|
310
|
+
*
|
|
311
|
+
* @example
|
|
312
|
+
* ```ts
|
|
313
|
+
* const metrics = await client.training.getMetrics('job_abc123');
|
|
314
|
+
* console.log(`Current loss: ${metrics.metrics.at(-1)?.loss}`);
|
|
315
|
+
* console.log(`${metrics.metrics.length} metric points`);
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
async getMetrics(id) {
|
|
319
|
+
const result = await this._http.fetchGet(`/api/training/jobs/${encodeURIComponent(id)}/metrics`);
|
|
320
|
+
const metrics = Array.isArray(result.metrics)
|
|
321
|
+
? result.metrics
|
|
322
|
+
: Array.isArray(result.steps) ? result.steps : [];
|
|
323
|
+
return { ...result, metrics, graph_configs: result.graph_configs || [], steps: metrics };
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* List checkpoints saved during training.
|
|
327
|
+
*
|
|
328
|
+
* @param id - Training job ID.
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* ```ts
|
|
332
|
+
* const checkpoints = await client.training.getCheckpoints('job_abc123');
|
|
333
|
+
* for (const cp of checkpoints) {
|
|
334
|
+
* console.log(`${cp.name}: ${cp.size_bytes} bytes`);
|
|
335
|
+
* }
|
|
336
|
+
* ```
|
|
337
|
+
*/
|
|
338
|
+
async getCheckpoints(id) {
|
|
339
|
+
const result = await this._http.fetchGet(`/api/training/jobs/${encodeURIComponent(id)}/checkpoints`);
|
|
340
|
+
return Array.isArray(result) ? result : result.checkpoints || [];
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Get training logs for a job.
|
|
344
|
+
*
|
|
345
|
+
* @param id - Training job ID.
|
|
346
|
+
* @param tail - Maximum newest entries to return (server clamps to 1-1000).
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* ```ts
|
|
350
|
+
* const logs = await client.training.getLogs('job_abc123');
|
|
351
|
+
* for (const entry of logs.logs) {
|
|
352
|
+
* console.log(entry.level, entry.message);
|
|
353
|
+
* }
|
|
354
|
+
* ```
|
|
355
|
+
*/
|
|
356
|
+
async getLogs(id, tail = 200) {
|
|
357
|
+
const result = await this._http.fetchGet(`/api/training/jobs/${encodeURIComponent(id)}/logs?tail=${encodeURIComponent(String(tail))}`);
|
|
358
|
+
const logs = (result.logs || []).map((entry) => typeof entry === 'string'
|
|
359
|
+
? { level: 'INFO', message: entry, timestamp: '' }
|
|
360
|
+
: entry);
|
|
361
|
+
return { logs, lines: logs.map((entry) => entry.message) };
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Stop a running training job.
|
|
365
|
+
*
|
|
366
|
+
* By default, intermediate data (checkpoints, logs) is preserved.
|
|
367
|
+
* Pass `keepData: false` to clean up all job artifacts.
|
|
368
|
+
*
|
|
369
|
+
* @param id - Training job ID.
|
|
370
|
+
* @param keepData - Whether to keep checkpoints and logs. Defaults to true.
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```ts
|
|
374
|
+
* await client.training.stop('job_abc123');
|
|
375
|
+
* ```
|
|
376
|
+
*/
|
|
377
|
+
async stop(id, keepData = true) {
|
|
378
|
+
return this._http.fetchPost(`/api/training/jobs/${encodeURIComponent(id)}/stop`, { keep_data: keepData });
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Resume a stopped or `interrupted` training job from its last checkpoint.
|
|
382
|
+
*
|
|
383
|
+
* Use this on a `stopped` job, or one resting at `interrupted` — the
|
|
384
|
+
* self-heal state a started job enters when its machine is lost and billing has
|
|
385
|
+
* already been stopped (distinct from `failed`). Resume re-books on secured
|
|
386
|
+
* capacity before reporting resumed, so book-before-reveal still applies.
|
|
387
|
+
*
|
|
388
|
+
* @param id - Training job ID.
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* ```ts
|
|
392
|
+
* await client.training.resume('job_abc123');
|
|
393
|
+
* ```
|
|
394
|
+
*/
|
|
395
|
+
async resume(id, idempotencyKey) {
|
|
396
|
+
const result = await this._http.fetchPost(`/api/training/jobs/${encodeURIComponent(id)}/resume`, undefined, { 'Idempotency-Key': trainingIdempotencyKey(idempotencyKey) });
|
|
397
|
+
const resumedId = result.id || result.job_id;
|
|
398
|
+
if (!resumedId)
|
|
399
|
+
throw new Error('RunBiOS: resume response did not include job_id');
|
|
400
|
+
return { ...result, id: resumedId };
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Delete a specific checkpoint from a training job.
|
|
404
|
+
*
|
|
405
|
+
* @param jobId - Training job ID.
|
|
406
|
+
* @param checkpointId - Checkpoint ID to delete.
|
|
407
|
+
*
|
|
408
|
+
* @example
|
|
409
|
+
* ```ts
|
|
410
|
+
* await client.training.deleteCheckpoint('job_abc123', 'cp_xyz789');
|
|
411
|
+
* ```
|
|
412
|
+
*/
|
|
413
|
+
async getEvals(id) {
|
|
414
|
+
return this._http.fetchGet(`/api/training/jobs/${encodeURIComponent(id)}/evals`);
|
|
415
|
+
}
|
|
416
|
+
async deleteCheckpoint(jobId, checkpointId) {
|
|
417
|
+
await this._http.fetchDelete(`/api/training/jobs/${encodeURIComponent(jobId)}/checkpoints/${encodeURIComponent(checkpointId)}`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { HttpClient } from '../client.js';
|
|
2
|
+
import type { WalletBalance, TransactionListParams, TransactionListResponse } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* View wallet balance, transaction history, and billing information.
|
|
5
|
+
*/
|
|
6
|
+
export declare class Wallet {
|
|
7
|
+
private readonly _http;
|
|
8
|
+
/** @internal */
|
|
9
|
+
constructor(_http: HttpClient);
|
|
10
|
+
/**
|
|
11
|
+
* Get the wallet balance, spendable balance, holds, and accruing usage.
|
|
12
|
+
*
|
|
13
|
+
* `balance_cents` is the deposited balance; `available_balance_cents` is what
|
|
14
|
+
* can actually be spent right now (balance minus `active_holds_cents` and
|
|
15
|
+
* `accruing_cents`). Spend decisions read the latter.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const balance = await client.wallet.getBalance();
|
|
20
|
+
* console.log(`Balance: $${(balance.balance_cents / 100).toFixed(2)}`);
|
|
21
|
+
* console.log(`Spendable: $${(balance.available_balance_cents / 100).toFixed(2)}`);
|
|
22
|
+
* console.log(`On hold: $${((balance.active_holds_cents ?? 0) / 100).toFixed(2)}`);
|
|
23
|
+
* console.log(`Accruing: $${((balance.accruing_cents ?? 0) / 100).toFixed(2)}`);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
getBalance(): Promise<WalletBalance>;
|
|
27
|
+
/**
|
|
28
|
+
* List billing transactions (credits, charges, refunds).
|
|
29
|
+
*
|
|
30
|
+
* Returns the WRAPPED page `{ transactions, total, limit, offset }` -- read
|
|
31
|
+
* `.transactions`, never the response itself.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* const page = await client.wallet.getTransactions({ limit: 20 });
|
|
36
|
+
* console.log(`${page.total} transactions`);
|
|
37
|
+
* for (const t of page.transactions) {
|
|
38
|
+
* console.log(`${t.type}/${t.category}: $${(t.amount_cents / 100).toFixed(2)} -- ${t.description}`);
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
getTransactions(params?: TransactionListParams): Promise<TransactionListResponse>;
|
|
43
|
+
/**
|
|
44
|
+
* Get pricing information for compute and storage.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const pricing = await client.wallet.getPricing();
|
|
49
|
+
* console.log(pricing);
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
getPricing(): Promise<Record<string, unknown>>;
|
|
53
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* View wallet balance, transaction history, and billing information.
|
|
3
|
+
*/
|
|
4
|
+
export class Wallet {
|
|
5
|
+
_http;
|
|
6
|
+
/** @internal */
|
|
7
|
+
constructor(_http) {
|
|
8
|
+
this._http = _http;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get the wallet balance, spendable balance, holds, and accruing usage.
|
|
12
|
+
*
|
|
13
|
+
* `balance_cents` is the deposited balance; `available_balance_cents` is what
|
|
14
|
+
* can actually be spent right now (balance minus `active_holds_cents` and
|
|
15
|
+
* `accruing_cents`). Spend decisions read the latter.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const balance = await client.wallet.getBalance();
|
|
20
|
+
* console.log(`Balance: $${(balance.balance_cents / 100).toFixed(2)}`);
|
|
21
|
+
* console.log(`Spendable: $${(balance.available_balance_cents / 100).toFixed(2)}`);
|
|
22
|
+
* console.log(`On hold: $${((balance.active_holds_cents ?? 0) / 100).toFixed(2)}`);
|
|
23
|
+
* console.log(`Accruing: $${((balance.accruing_cents ?? 0) / 100).toFixed(2)}`);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
async getBalance() {
|
|
27
|
+
return this._http.fetchGet('/api/billing/wallet');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* List billing transactions (credits, charges, refunds).
|
|
31
|
+
*
|
|
32
|
+
* Returns the WRAPPED page `{ transactions, total, limit, offset }` -- read
|
|
33
|
+
* `.transactions`, never the response itself.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const page = await client.wallet.getTransactions({ limit: 20 });
|
|
38
|
+
* console.log(`${page.total} transactions`);
|
|
39
|
+
* for (const t of page.transactions) {
|
|
40
|
+
* console.log(`${t.type}/${t.category}: $${(t.amount_cents / 100).toFixed(2)} -- ${t.description}`);
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
async getTransactions(params = {}) {
|
|
45
|
+
const limit = params.limit ?? 50;
|
|
46
|
+
const offset = params.offset ?? 0;
|
|
47
|
+
return this._http.fetchGet(`/api/billing/transactions?limit=${limit}&offset=${offset}`);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get pricing information for compute and storage.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* const pricing = await client.wallet.getPricing();
|
|
55
|
+
* console.log(pricing);
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
async getPricing() {
|
|
59
|
+
return this._http.fetchGet('/api/billing/pricing');
|
|
60
|
+
}
|
|
61
|
+
}
|