badgr-cli 1.0.35 → 1.0.36
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 +102 -0
- package/package.json +1 -1
- package/src/badgr.js +43 -31
- package/src/batch.js +157 -0
- package/src/commands/comfyui.js +318 -0
- package/src/commands/down.js +87 -1
- package/src/commands/embed.js +229 -0
- package/src/commands/run.js +17 -10
- package/src/commands/serve.js +55 -2
- package/src/commands/train.js +255 -0
- package/src/commands/transcribe.js +221 -0
- package/tests/launch-readiness.test.js +51 -0
- package/tests/serve-lifecycle.test.js +18 -17
- package/tests/workload-templates.test.js +808 -0
|
@@ -22,6 +22,7 @@ import { serveCommand } from '../src/commands/serve.js';
|
|
|
22
22
|
vi.mock('../src/api.js', () => ({
|
|
23
23
|
callApi: vi.fn(),
|
|
24
24
|
terminateDeployment: vi.fn().mockResolvedValue({}),
|
|
25
|
+
listDeployments: vi.fn().mockResolvedValue({ deployments: [], count: 0 }),
|
|
25
26
|
}));
|
|
26
27
|
|
|
27
28
|
vi.mock('../src/store.js', () => ({
|
|
@@ -107,7 +108,7 @@ describe('successful serve', () => {
|
|
|
107
108
|
text: async () => '',
|
|
108
109
|
});
|
|
109
110
|
|
|
110
|
-
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct', '--gpu', 'L40S'], chalk);
|
|
111
|
+
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct', '--gpu', 'L40S', '--max-cost', '5'], chalk);
|
|
111
112
|
await vi.advanceTimersByTimeAsync(5000);
|
|
112
113
|
await p;
|
|
113
114
|
|
|
@@ -131,7 +132,7 @@ describe('successful serve', () => {
|
|
|
131
132
|
|
|
132
133
|
global.fetch = vi.fn().mockResolvedValue({ ok: true, status: 200, json: async () => ({}) });
|
|
133
134
|
|
|
134
|
-
const p = serveCommand(config, ['mistralai/Mistral-7B-v0.1', '--gpu', 'A100'], chalk);
|
|
135
|
+
const p = serveCommand(config, ['mistralai/Mistral-7B-v0.1', '--gpu', 'A100', '--max-cost', '5'], chalk);
|
|
135
136
|
await vi.advanceTimersByTimeAsync(5000);
|
|
136
137
|
await p;
|
|
137
138
|
|
|
@@ -156,7 +157,7 @@ describe('billing ends when deployment stops', () => {
|
|
|
156
157
|
|
|
157
158
|
global.fetch = vi.fn().mockResolvedValue({ ok: true, status: 200, json: async () => ({}) });
|
|
158
159
|
|
|
159
|
-
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct'], chalk);
|
|
160
|
+
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct', '--max-cost', '5'], chalk);
|
|
160
161
|
await vi.advanceTimersByTimeAsync(5000);
|
|
161
162
|
await p;
|
|
162
163
|
|
|
@@ -182,7 +183,7 @@ describe('deployment fails during startup', () => {
|
|
|
182
183
|
.mockResolvedValueOnce(makeServeDep()) // POST /serve
|
|
183
184
|
.mockResolvedValueOnce({ status: 'failed', error: 'OOM: not enough VRAM' }); // pre-health check
|
|
184
185
|
|
|
185
|
-
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct'], chalk);
|
|
186
|
+
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct', '--max-cost', '5'], chalk);
|
|
186
187
|
await vi.advanceTimersByTimeAsync(2000);
|
|
187
188
|
await p;
|
|
188
189
|
|
|
@@ -201,7 +202,7 @@ describe('deployment fails during startup', () => {
|
|
|
201
202
|
// Health check endpoint doesn't respond (dep crashed)
|
|
202
203
|
global.fetch = vi.fn().mockRejectedValue(new Error('Connection refused'));
|
|
203
204
|
|
|
204
|
-
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct'], chalk);
|
|
205
|
+
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct', '--max-cost', '5'], chalk);
|
|
205
206
|
// need to advance past the 8000ms sleep in waitForEndpoint loop
|
|
206
207
|
await vi.advanceTimersByTimeAsync(10000);
|
|
207
208
|
await p;
|
|
@@ -227,7 +228,7 @@ describe('health check timeout', () => {
|
|
|
227
228
|
// Health endpoint never responds
|
|
228
229
|
global.fetch = vi.fn().mockRejectedValue(new Error('ETIMEDOUT'));
|
|
229
230
|
|
|
230
|
-
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct'], chalk);
|
|
231
|
+
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct', '--max-cost', '5'], chalk);
|
|
231
232
|
// waitForEndpoint timeout is 5 * 60 * 1000 = 300000ms
|
|
232
233
|
await vi.advanceTimersByTimeAsync(310000);
|
|
233
234
|
await p;
|
|
@@ -256,7 +257,7 @@ describe('invalid model ID or no capacity', () => {
|
|
|
256
257
|
const errLines = [];
|
|
257
258
|
console.error.mockImplementation(msg => errLines.push(msg));
|
|
258
259
|
|
|
259
|
-
await serveCommand(config, ['invalid/nonexistent-model-xyz'], chalk);
|
|
260
|
+
await serveCommand(config, ['invalid/nonexistent-model-xyz', '--max-cost', '5'], chalk);
|
|
260
261
|
|
|
261
262
|
expect(process.exitCode).toBe(1);
|
|
262
263
|
const combined = errLines.join('\n');
|
|
@@ -276,7 +277,7 @@ describe('invalid model ID or no capacity', () => {
|
|
|
276
277
|
const errLines = [];
|
|
277
278
|
console.error.mockImplementation(msg => errLines.push(msg));
|
|
278
279
|
|
|
279
|
-
await serveCommand(config, ['my-org/private-model'], chalk);
|
|
280
|
+
await serveCommand(config, ['my-org/private-model', '--max-cost', '5'], chalk);
|
|
280
281
|
|
|
281
282
|
expect(process.exitCode).toBe(1);
|
|
282
283
|
// Debug info hidden by default (BADGR_DEBUG not set)
|
|
@@ -293,7 +294,7 @@ describe('invalid model ID or no capacity', () => {
|
|
|
293
294
|
});
|
|
294
295
|
api.callApi.mockRejectedValue(provErr);
|
|
295
296
|
|
|
296
|
-
await serveCommand(config, ['some/model', '--task', 'unknown_task'], chalk);
|
|
297
|
+
await serveCommand(config, ['some/model', '--task', 'unknown_task', '--max-cost', '5'], chalk);
|
|
297
298
|
|
|
298
299
|
expect(process.exitCode).toBe(1);
|
|
299
300
|
expect(store.addDeployment).not.toHaveBeenCalled();
|
|
@@ -309,7 +310,7 @@ describe('--no-wait flag', () => {
|
|
|
309
310
|
api.callApi.mockResolvedValueOnce(makeServeDep());
|
|
310
311
|
global.fetch = vi.fn(); // should never be called
|
|
311
312
|
|
|
312
|
-
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct', '--no-wait'], chalk);
|
|
313
|
+
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct', '--no-wait', '--max-cost', '5'], chalk);
|
|
313
314
|
await vi.advanceTimersByTimeAsync(100);
|
|
314
315
|
await p;
|
|
315
316
|
|
|
@@ -333,7 +334,7 @@ describe('custom image health check', () => {
|
|
|
333
334
|
|
|
334
335
|
const p = serveCommand(
|
|
335
336
|
config,
|
|
336
|
-
['--image', 'ghcr.io/my-org/diffusers-api:latest', '--gpu', 'L40S'],
|
|
337
|
+
['--image', 'ghcr.io/my-org/diffusers-api:latest', '--gpu', 'L40S', '--max-cost', '5'],
|
|
337
338
|
chalk,
|
|
338
339
|
);
|
|
339
340
|
await vi.advanceTimersByTimeAsync(100);
|
|
@@ -356,7 +357,7 @@ describe('custom image health check', () => {
|
|
|
356
357
|
|
|
357
358
|
const p = serveCommand(
|
|
358
359
|
config,
|
|
359
|
-
['--image', 'ghcr.io/my-org/comfyui-custom:latest', '--gpu', 'A100'],
|
|
360
|
+
['--image', 'ghcr.io/my-org/comfyui-custom:latest', '--gpu', 'A100', '--max-cost', '5'],
|
|
360
361
|
chalk,
|
|
361
362
|
);
|
|
362
363
|
await vi.advanceTimersByTimeAsync(5000);
|
|
@@ -380,7 +381,7 @@ describe('custom image health check', () => {
|
|
|
380
381
|
|
|
381
382
|
const p = serveCommand(
|
|
382
383
|
config,
|
|
383
|
-
['--image', 'ghcr.io/my-org/stable-diffusion:latest', '--health-path', '/health'],
|
|
384
|
+
['--image', 'ghcr.io/my-org/stable-diffusion:latest', '--health-path', '/health', '--max-cost', '5'],
|
|
384
385
|
chalk,
|
|
385
386
|
);
|
|
386
387
|
await vi.advanceTimersByTimeAsync(5000);
|
|
@@ -404,7 +405,7 @@ describe('custom image health check', () => {
|
|
|
404
405
|
|
|
405
406
|
const p = serveCommand(
|
|
406
407
|
config,
|
|
407
|
-
['meta-llama/Llama-3.1-8B-Instruct', '--health-path', '/v1/health'],
|
|
408
|
+
['meta-llama/Llama-3.1-8B-Instruct', '--health-path', '/v1/health', '--max-cost', '5'],
|
|
408
409
|
chalk,
|
|
409
410
|
);
|
|
410
411
|
await vi.advanceTimersByTimeAsync(5000);
|
|
@@ -433,7 +434,7 @@ describe('tier-2 fallback for serve', () => {
|
|
|
433
434
|
|
|
434
435
|
global.fetch = vi.fn().mockResolvedValue({ ok: true, status: 200, json: async () => ({}) });
|
|
435
436
|
|
|
436
|
-
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct'], chalk);
|
|
437
|
+
const p = serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct', '--max-cost', '5'], chalk);
|
|
437
438
|
await vi.advanceTimersByTimeAsync(5000);
|
|
438
439
|
await p;
|
|
439
440
|
|
|
@@ -450,7 +451,7 @@ describe('tier-2 fallback for serve', () => {
|
|
|
450
451
|
});
|
|
451
452
|
api.callApi.mockRejectedValueOnce(capacityErr);
|
|
452
453
|
|
|
453
|
-
await serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct', '--no-fallback'], chalk);
|
|
454
|
+
await serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct', '--no-fallback', '--max-cost', '5'], chalk);
|
|
454
455
|
|
|
455
456
|
const postCalls = api.callApi.mock.calls.filter(c => c[1]?.method === 'POST');
|
|
456
457
|
expect(postCalls.length).toBe(1);
|
|
@@ -466,7 +467,7 @@ describe('missing endpoint URL guard', () => {
|
|
|
466
467
|
it('exits with error when backend returns no endpoint_url', async () => {
|
|
467
468
|
api.callApi.mockResolvedValueOnce(makeServeDep({ endpoint_url: null, openai_base_url: null }));
|
|
468
469
|
|
|
469
|
-
await serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct'], chalk);
|
|
470
|
+
await serveCommand(config, ['meta-llama/Llama-3.1-8B-Instruct', '--max-cost', '5'], chalk);
|
|
470
471
|
|
|
471
472
|
expect(process.exitCode).toBe(1);
|
|
472
473
|
expect(store.updateReceipt).toHaveBeenCalledWith('rcpt-serve-001', expect.objectContaining({
|