Skip to content

Commit c79686e

Browse files
fix(api): don't ignore devbox keep_alive, suspend and resume in api
1 parent d54e9d0 commit c79686e

6 files changed

Lines changed: 82 additions & 3 deletions

File tree

.stats.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 94
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-c15740e10009ccfaf6cb6ae4463496618c05d033bdd779bf501f5afb0c05ffc9.yml
3-
openapi_spec_hash: a08d1a45d83ed2956ab643d1c6c07a40
1+
configured_endpoints: 97
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-d2463b4c27719ea7275c8f587fa2c90e333471fdede11e5f944faa92dfb417d1.yml
3+
openapi_spec_hash: 132c1d9f04583e997df5d7698e155fff
44
config_hash: 2363f563f42501d2b1587a4f64bdccaf

api.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ Types:
9797
- <code><a href="./src/resources/devboxes/devboxes.ts">DevboxView</a></code>
9898
- <code><a href="./src/resources/devboxes/devboxes.ts">DevboxCreateSSHKeyResponse</a></code>
9999
- <code><a href="./src/resources/devboxes/devboxes.ts">DevboxDeleteDiskSnapshotResponse</a></code>
100+
- <code><a href="./src/resources/devboxes/devboxes.ts">DevboxKeepAliveResponse</a></code>
100101
- <code><a href="./src/resources/devboxes/devboxes.ts">DevboxReadFileContentsResponse</a></code>
101102
- <code><a href="./src/resources/devboxes/devboxes.ts">DevboxRemoveTunnelResponse</a></code>
102103
- <code><a href="./src/resources/devboxes/devboxes.ts">DevboxUploadFileResponse</a></code>
@@ -114,12 +115,15 @@ Methods:
114115
- <code title="post /v1/devboxes/{id}/execute">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">execute</a>(id, { ...params }) -> DevboxAsyncExecutionDetailView</code>
115116
- <code title="post /v1/devboxes/{id}/execute_async">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">executeAsync</a>(id, { ...params }) -> DevboxAsyncExecutionDetailView</code>
116117
- <code title="post /v1/devboxes/{id}/execute_sync">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">executeSync</a>(id, { ...params }) -> DevboxExecutionDetailView</code>
118+
- <code title="post /v1/devboxes/{id}/keep_alive">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">keepAlive</a>(id) -> unknown</code>
117119
- <code title="get /v1/devboxes/disk_snapshots">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">listDiskSnapshots</a>({ ...params }) -> DevboxSnapshotViewsDiskSnapshotsCursorIDPage</code>
118120
- <code title="post /v1/devboxes/{id}/read_file_contents">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">readFileContents</a>(id, { ...params }) -> string</code>
119121
- <code title="post /v1/devboxes/{id}/remove_tunnel">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">removeTunnel</a>(id, { ...params }) -> unknown</code>
122+
- <code title="post /v1/devboxes/{id}/resume">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">resume</a>(id) -> DevboxView</code>
120123
- <code title="post /v1/devboxes/{id}/shutdown">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">shutdown</a>(id) -> DevboxView</code>
121124
- <code title="post /v1/devboxes/{id}/snapshot_disk">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">snapshotDisk</a>(id, { ...params }) -> DevboxSnapshotView</code>
122125
- <code title="post /v1/devboxes/{id}/snapshot_disk_async">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">snapshotDiskAsync</a>(id, { ...params }) -> DevboxSnapshotView</code>
126+
- <code title="post /v1/devboxes/{id}/suspend">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">suspend</a>(id) -> DevboxView</code>
123127
- <code title="post /v1/devboxes/{id}/upload_file">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">uploadFile</a>(id, { ...params }) -> unknown</code>
124128
- <code title="post /v1/devboxes/{devbox_id}/executions/{execution_id}/wait_for_status">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">waitForCommand</a>(devboxId, executionId, { ...params }) -> DevboxAsyncExecutionDetailView</code>
125129
- <code title="post /v1/devboxes/{id}/write_file_contents">client.devboxes.<a href="./src/resources/devboxes/devboxes.ts">writeFileContents</a>(id, { ...params }) -> DevboxExecutionDetailView</code>

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ import {
125125
DevboxExecuteParams,
126126
DevboxExecuteSyncParams,
127127
DevboxExecutionDetailView,
128+
DevboxKeepAliveResponse,
128129
DevboxKillExecutionRequest,
129130
DevboxListDiskSnapshotsParams,
130131
DevboxListParams,
@@ -496,6 +497,7 @@ export declare namespace Runloop {
496497
type DevboxView as DevboxView,
497498
type DevboxCreateSSHKeyResponse as DevboxCreateSSHKeyResponse,
498499
type DevboxDeleteDiskSnapshotResponse as DevboxDeleteDiskSnapshotResponse,
500+
type DevboxKeepAliveResponse as DevboxKeepAliveResponse,
499501
type DevboxReadFileContentsResponse as DevboxReadFileContentsResponse,
500502
type DevboxRemoveTunnelResponse as DevboxRemoveTunnelResponse,
501503
type DevboxUploadFileResponse as DevboxUploadFileResponse,

src/resources/devboxes/devboxes.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,15 @@ export class Devboxes extends APIResource {
395395
return this._client.post(`/v1/devboxes/${id}/remove_tunnel`, { body, ...options });
396396
}
397397

398+
/**
399+
* Resume a suspended Devbox with the disk state captured as suspend time. Note
400+
* that any previously running processes or daemons will need to be restarted using
401+
* the Devbox shell tools.
402+
*/
403+
resume(id: string, options?: Core.RequestOptions): Core.APIPromise<DevboxView> {
404+
return this._client.post(`/v1/devboxes/${id}/resume`, options);
405+
}
406+
398407
/**
399408
* Shutdown a running Devbox. This will permanently stop the Devbox. If you want to
400409
* save the state of the Devbox, you should take a snapshot before shutting down or
@@ -451,6 +460,15 @@ export class Devboxes extends APIResource {
451460
return this._client.post(`/v1/devboxes/${id}/snapshot_disk_async`, { body, ...options });
452461
}
453462

463+
/**
464+
* Suspend a running Devbox and create a disk snapshot to enable resuming the
465+
* Devbox later with the same disk. Note this will not snapshot memory state such
466+
* as running processes.
467+
*/
468+
suspend(id: string, options?: Core.RequestOptions): Core.APIPromise<DevboxView> {
469+
return this._client.post(`/v1/devboxes/${id}/suspend`, options);
470+
}
471+
454472
/**
455473
* Upload file contents of any type (binary, text, etc) to a Devbox. Note this API
456474
* is suitable for large files (larger than 100MB) and efficiently uploads files

src/resources/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export {
6161
type DevboxView,
6262
type DevboxCreateSSHKeyResponse,
6363
type DevboxDeleteDiskSnapshotResponse,
64+
type DevboxKeepAliveResponse,
6465
type DevboxReadFileContentsResponse,
6566
type DevboxRemoveTunnelResponse,
6667
type DevboxUploadFileResponse,

tests/api-resources/devboxes/devboxes.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,24 @@ describe('resource devboxes', () => {
262262
});
263263
});
264264

265+
test('keepAlive', async () => {
266+
const responsePromise = client.devboxes.keepAlive('id');
267+
const rawResponse = await responsePromise.asResponse();
268+
expect(rawResponse).toBeInstanceOf(Response);
269+
const response = await responsePromise;
270+
expect(response).not.toBeInstanceOf(Response);
271+
const dataAndResponse = await responsePromise.withResponse();
272+
expect(dataAndResponse.data).toBe(response);
273+
expect(dataAndResponse.response).toBe(rawResponse);
274+
});
275+
276+
test('keepAlive: request options instead of params are passed correctly', async () => {
277+
// ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
278+
await expect(client.devboxes.keepAlive('id', { path: '/_stainless_unknown_path' })).rejects.toThrow(
279+
Runloop.NotFoundError,
280+
);
281+
});
282+
265283
test('listDiskSnapshots', async () => {
266284
const responsePromise = client.devboxes.listDiskSnapshots();
267285
const rawResponse = await responsePromise.asResponse();
@@ -327,6 +345,24 @@ describe('resource devboxes', () => {
327345
const response = await client.devboxes.removeTunnel('id', { port: 0 });
328346
});
329347

348+
test('resume', async () => {
349+
const responsePromise = client.devboxes.resume('id');
350+
const rawResponse = await responsePromise.asResponse();
351+
expect(rawResponse).toBeInstanceOf(Response);
352+
const response = await responsePromise;
353+
expect(response).not.toBeInstanceOf(Response);
354+
const dataAndResponse = await responsePromise.withResponse();
355+
expect(dataAndResponse.data).toBe(response);
356+
expect(dataAndResponse.response).toBe(rawResponse);
357+
});
358+
359+
test('resume: request options instead of params are passed correctly', async () => {
360+
// ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
361+
await expect(client.devboxes.resume('id', { path: '/_stainless_unknown_path' })).rejects.toThrow(
362+
Runloop.NotFoundError,
363+
);
364+
});
365+
330366
test('shutdown', async () => {
331367
const responsePromise = client.devboxes.shutdown('id');
332368
const rawResponse = await responsePromise.asResponse();
@@ -403,6 +439,24 @@ describe('resource devboxes', () => {
403439
).rejects.toThrow(Runloop.NotFoundError);
404440
});
405441

442+
test('suspend', async () => {
443+
const responsePromise = client.devboxes.suspend('id');
444+
const rawResponse = await responsePromise.asResponse();
445+
expect(rawResponse).toBeInstanceOf(Response);
446+
const response = await responsePromise;
447+
expect(response).not.toBeInstanceOf(Response);
448+
const dataAndResponse = await responsePromise.withResponse();
449+
expect(dataAndResponse.data).toBe(response);
450+
expect(dataAndResponse.response).toBe(rawResponse);
451+
});
452+
453+
test('suspend: request options instead of params are passed correctly', async () => {
454+
// ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
455+
await expect(client.devboxes.suspend('id', { path: '/_stainless_unknown_path' })).rejects.toThrow(
456+
Runloop.NotFoundError,
457+
);
458+
});
459+
406460
test('uploadFile: only required params', async () => {
407461
const responsePromise = client.devboxes.uploadFile('id', { path: 'path' });
408462
const rawResponse = await responsePromise.asResponse();

0 commit comments

Comments
 (0)