langsmith 0.5.18 → 0.5.20

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/dist/client.cjs CHANGED
@@ -679,6 +679,24 @@ class Client {
679
679
  }
680
680
  return outputs;
681
681
  }
682
+ /**
683
+ * Filter content from new_token events to prevent streaming LLM output
684
+ * from being uploaded via events.
685
+ */
686
+ _filterNewTokenEvents(events) {
687
+ if (!events || events.length === 0) {
688
+ return events;
689
+ }
690
+ return events.map((event) => {
691
+ if (event.name === "new_token") {
692
+ // Remove the kwargs containing the token data
693
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
694
+ const { kwargs: _, ...rest } = event;
695
+ return rest;
696
+ }
697
+ return event;
698
+ });
699
+ }
682
700
  async prepareRunCreateOrUpdateInputs(run) {
683
701
  const runParams = { ...run };
684
702
  if (runParams.inputs !== undefined) {
@@ -687,6 +705,9 @@ class Client {
687
705
  if (runParams.outputs !== undefined) {
688
706
  runParams.outputs = await this.processOutputs(runParams.outputs);
689
707
  }
708
+ if (runParams.events !== undefined) {
709
+ runParams.events = this._filterNewTokenEvents(runParams.events);
710
+ }
690
711
  return runParams;
691
712
  }
692
713
  async _getResponse(path, queryParams) {
@@ -1531,6 +1552,9 @@ class Client {
1531
1552
  if (run.outputs) {
1532
1553
  run.outputs = await this.processOutputs(run.outputs);
1533
1554
  }
1555
+ if (run.events) {
1556
+ run.events = this._filterNewTokenEvents(run.events);
1557
+ }
1534
1558
  // TODO: Untangle types
1535
1559
  const data = { ...run, id: runId };
1536
1560
  if (!this._filterForSampling([data], true).length) {
package/dist/client.d.ts CHANGED
@@ -445,6 +445,11 @@ export declare class Client implements LangSmithTracingClientInterface {
445
445
  private _getPlatformEndpointPath;
446
446
  private processInputs;
447
447
  private processOutputs;
448
+ /**
449
+ * Filter content from new_token events to prevent streaming LLM output
450
+ * from being uploaded via events.
451
+ */
452
+ private _filterNewTokenEvents;
448
453
  private prepareRunCreateOrUpdateInputs;
449
454
  private _getResponse;
450
455
  private _get;
package/dist/client.js CHANGED
@@ -641,6 +641,24 @@ export class Client {
641
641
  }
642
642
  return outputs;
643
643
  }
644
+ /**
645
+ * Filter content from new_token events to prevent streaming LLM output
646
+ * from being uploaded via events.
647
+ */
648
+ _filterNewTokenEvents(events) {
649
+ if (!events || events.length === 0) {
650
+ return events;
651
+ }
652
+ return events.map((event) => {
653
+ if (event.name === "new_token") {
654
+ // Remove the kwargs containing the token data
655
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
656
+ const { kwargs: _, ...rest } = event;
657
+ return rest;
658
+ }
659
+ return event;
660
+ });
661
+ }
644
662
  async prepareRunCreateOrUpdateInputs(run) {
645
663
  const runParams = { ...run };
646
664
  if (runParams.inputs !== undefined) {
@@ -649,6 +667,9 @@ export class Client {
649
667
  if (runParams.outputs !== undefined) {
650
668
  runParams.outputs = await this.processOutputs(runParams.outputs);
651
669
  }
670
+ if (runParams.events !== undefined) {
671
+ runParams.events = this._filterNewTokenEvents(runParams.events);
672
+ }
652
673
  return runParams;
653
674
  }
654
675
  async _getResponse(path, queryParams) {
@@ -1493,6 +1514,9 @@ export class Client {
1493
1514
  if (run.outputs) {
1494
1515
  run.outputs = await this.processOutputs(run.outputs);
1495
1516
  }
1517
+ if (run.events) {
1518
+ run.events = this._filterNewTokenEvents(run.events);
1519
+ }
1496
1520
  // TODO: Untangle types
1497
1521
  const data = { ...run, id: runId };
1498
1522
  if (!this._filterForSampling([data], true).length) {
@@ -133,6 +133,11 @@ class StreamManager {
133
133
  run_type: "chain",
134
134
  inputs: block.input,
135
135
  start_time: eventTime,
136
+ extra: {
137
+ metadata: {
138
+ ls_agent_type: "subagent",
139
+ },
140
+ },
136
141
  }) ?? this.tools[block.id];
137
142
  this.namespaces[block.id] ??= this.tools[block.id];
138
143
  }
@@ -130,6 +130,11 @@ export class StreamManager {
130
130
  run_type: "chain",
131
131
  inputs: block.input,
132
132
  start_time: eventTime,
133
+ extra: {
134
+ metadata: {
135
+ ls_agent_type: "subagent",
136
+ },
137
+ },
133
138
  }) ?? this.tools[block.id];
134
139
  this.namespaces[block.id] ??= this.tools[block.id];
135
140
  }
@@ -112,6 +112,7 @@ function wrapClaudeAgentQuery(queryFn, defaultThis, baseConfig) {
112
112
  ...baseConfig,
113
113
  metadata: {
114
114
  ls_integration: "claude-agent-sdk-js",
115
+ ls_agent_type: "root",
115
116
  ...baseConfig?.metadata,
116
117
  },
117
118
  __deferredSerializableArgOptions: { maxDepth: 1 },
@@ -109,6 +109,7 @@ function wrapClaudeAgentQuery(queryFn, defaultThis, baseConfig) {
109
109
  ...baseConfig,
110
110
  metadata: {
111
111
  ls_integration: "claude-agent-sdk-js",
112
+ ls_agent_type: "root",
112
113
  ...baseConfig?.metadata,
113
114
  },
114
115
  __deferredSerializableArgOptions: { maxDepth: 1 },
@@ -10,6 +10,27 @@ const async_caller_js_1 = require("../../utils/async_caller.cjs");
10
10
  const sandbox_js_1 = require("./sandbox.cjs");
11
11
  const errors_js_1 = require("./errors.cjs");
12
12
  const helpers_js_1 = require("./helpers.cjs");
13
+ /**
14
+ * Sleep that can be interrupted by an AbortSignal.
15
+ * Resolves after `ms` milliseconds or rejects immediately if the signal fires.
16
+ */
17
+ function sleepWithSignal(ms, signal) {
18
+ if (!signal) {
19
+ return new Promise((resolve) => setTimeout(resolve, ms));
20
+ }
21
+ signal.throwIfAborted();
22
+ return new Promise((resolve, reject) => {
23
+ const timer = setTimeout(() => {
24
+ signal.removeEventListener("abort", onAbort);
25
+ resolve();
26
+ }, ms);
27
+ function onAbort() {
28
+ clearTimeout(timer);
29
+ reject(signal.reason);
30
+ }
31
+ signal.addEventListener("abort", onAbort, { once: true });
32
+ });
33
+ }
13
34
  /**
14
35
  * Get the default sandbox API endpoint from environment.
15
36
  *
@@ -53,6 +74,8 @@ function getDefaultApiKey() {
53
74
  * await sandbox.delete();
54
75
  * }
55
76
  * ```
77
+ *
78
+ * @experimental This feature is experimental, and breaking changes are expected.
56
79
  */
57
80
  class SandboxClient {
58
81
  constructor(config = {}) {
@@ -113,6 +136,25 @@ class SandboxClient {
113
136
  getApiKey() {
114
137
  return this._apiKey;
115
138
  }
139
+ /**
140
+ * JSON POST helper. Sends JSON body, checks response status,
141
+ * and returns the Response for further processing.
142
+ * Throws on non-ok responses via handleClientHttpError.
143
+ * Callers can add specific status checks (e.g. 404) before calling this.
144
+ * @internal
145
+ */
146
+ async _postJson(url, body, options) {
147
+ const response = await this._fetch(url, {
148
+ method: "POST",
149
+ headers: { "Content-Type": "application/json" },
150
+ body: JSON.stringify(body),
151
+ signal: options?.signal,
152
+ });
153
+ if (!response.ok) {
154
+ await (0, helpers_js_1.handleClientHttpError)(response);
155
+ }
156
+ return response;
157
+ }
116
158
  // =========================================================================
117
159
  // Volume Operations
118
160
  // =========================================================================
@@ -538,14 +580,25 @@ class SandboxClient {
538
580
  * ```
539
581
  */
540
582
  async createSandbox(templateName, options = {}) {
541
- const { name, timeout = 30, waitForReady = true, ttlSeconds, idleTtlSeconds, } = options;
583
+ const { snapshotId, name, timeout = 30, waitForReady = true, ttlSeconds, idleTtlSeconds, vCpus, memBytes, fsCapacityBytes, } = options;
584
+ if (!templateName && !snapshotId) {
585
+ throw new Error("Either templateName or snapshotId is required");
586
+ }
587
+ if (templateName && snapshotId) {
588
+ throw new Error("Cannot specify both templateName and snapshotId");
589
+ }
542
590
  (0, helpers_js_1.validateTtl)(ttlSeconds, "ttlSeconds");
543
591
  (0, helpers_js_1.validateTtl)(idleTtlSeconds, "idleTtlSeconds");
544
592
  const url = `${this._baseUrl}/boxes`;
545
593
  const payload = {
546
- template_name: templateName,
547
594
  wait_for_ready: waitForReady,
548
595
  };
596
+ if (templateName) {
597
+ payload.template_name = templateName;
598
+ }
599
+ if (snapshotId) {
600
+ payload.snapshot_id = snapshotId;
601
+ }
549
602
  if (waitForReady) {
550
603
  payload.timeout = timeout;
551
604
  }
@@ -558,6 +611,15 @@ class SandboxClient {
558
611
  if (idleTtlSeconds !== undefined) {
559
612
  payload.idle_ttl_seconds = idleTtlSeconds;
560
613
  }
614
+ if (vCpus !== undefined) {
615
+ payload.vcpus = vCpus;
616
+ }
617
+ if (memBytes !== undefined) {
618
+ payload.mem_bytes = memBytes;
619
+ }
620
+ if (fsCapacityBytes !== undefined) {
621
+ payload.fs_capacity_bytes = fsCapacityBytes;
622
+ }
561
623
  const httpTimeout = waitForReady ? (timeout + 30) * 1000 : 30 * 1000;
562
624
  const response = await this._fetch(url, {
563
625
  method: "POST",
@@ -580,9 +642,9 @@ class SandboxClient {
580
642
  * @returns Sandbox.
581
643
  * @throws LangSmithResourceNotFoundError if sandbox not found.
582
644
  */
583
- async getSandbox(name) {
645
+ async getSandbox(name, options) {
584
646
  const url = `${this._baseUrl}/boxes/${encodeURIComponent(name)}`;
585
- const response = await this._fetch(url);
647
+ const response = await this._fetch(url, { signal: options?.signal });
586
648
  if (!response.ok) {
587
649
  if (response.status === 404) {
588
650
  throw new errors_js_1.LangSmithResourceNotFoundError(`Sandbox '${name}' not found`, "sandbox");
@@ -677,9 +739,9 @@ class SandboxClient {
677
739
  * @returns ResourceStatus with status and optional status_message.
678
740
  * @throws LangSmithResourceNotFoundError if sandbox not found.
679
741
  */
680
- async getSandboxStatus(name) {
742
+ async getSandboxStatus(name, options) {
681
743
  const url = `${this._baseUrl}/boxes/${encodeURIComponent(name)}/status`;
682
- const response = await this._fetch(url);
744
+ const response = await this._fetch(url, { signal: options?.signal });
683
745
  if (!response.ok) {
684
746
  if (response.status === 404) {
685
747
  throw new errors_js_1.LangSmithResourceNotFoundError(`Sandbox '${name}' not found`, "sandbox");
@@ -709,22 +771,183 @@ class SandboxClient {
709
771
  * ```
710
772
  */
711
773
  async waitForSandbox(name, options = {}) {
712
- const { timeout = 120, pollInterval = 1.0 } = options;
774
+ const { timeout = 120, pollInterval = 1.0, signal } = options;
713
775
  const deadline = Date.now() + timeout * 1000;
714
776
  let lastStatus = "provisioning";
715
777
  while (Date.now() < deadline) {
716
- const statusResult = await this.getSandboxStatus(name);
778
+ signal?.throwIfAborted();
779
+ const statusResult = await this.getSandboxStatus(name, { signal });
717
780
  lastStatus = statusResult.status;
718
781
  if (statusResult.status === "ready") {
719
- return this.getSandbox(name);
782
+ return this.getSandbox(name, { signal });
720
783
  }
721
784
  if (statusResult.status === "failed") {
722
785
  throw new errors_js_1.LangSmithResourceCreationError(statusResult.status_message ?? `Sandbox '${name}' creation failed`, "sandbox");
723
786
  }
724
- // Wait before polling again
725
- await new Promise((resolve) => setTimeout(resolve, pollInterval * 1000));
787
+ // Wait before polling again, capped to remaining time + jitter
788
+ const remaining = deadline - Date.now();
789
+ const jitter = pollInterval * 200 * (Math.random() - 0.5); // ±10%
790
+ const delay = Math.min(pollInterval * 1000 + jitter, remaining);
791
+ if (delay > 0) {
792
+ await sleepWithSignal(delay, signal);
793
+ }
726
794
  }
727
795
  throw new errors_js_1.LangSmithResourceTimeoutError(`Sandbox '${name}' did not become ready within ${timeout}s`, "sandbox", lastStatus);
728
796
  }
797
+ /**
798
+ * Start a stopped sandbox and wait until ready.
799
+ *
800
+ * @param name - Sandbox name.
801
+ * @param options - Options with timeout.
802
+ * @returns Sandbox in "ready" status.
803
+ */
804
+ async startSandbox(name, options = {}) {
805
+ const { timeout = 120, signal } = options;
806
+ const url = `${this._baseUrl}/boxes/${encodeURIComponent(name)}/start`;
807
+ await this._postJson(url, {}, { signal });
808
+ return this.waitForSandbox(name, { timeout, signal });
809
+ }
810
+ /**
811
+ * Stop a running sandbox (preserves sandbox files for later restart).
812
+ *
813
+ * @param name - Sandbox name.
814
+ */
815
+ async stopSandbox(name) {
816
+ const url = `${this._baseUrl}/boxes/${encodeURIComponent(name)}/stop`;
817
+ await this._postJson(url, {});
818
+ }
819
+ // =========================================================================
820
+ // Snapshot Operations
821
+ // =========================================================================
822
+ /**
823
+ * Build a snapshot from a Docker image.
824
+ *
825
+ * Blocks until the snapshot is ready (polls with 2s interval).
826
+ *
827
+ * @param name - Snapshot name.
828
+ * @param dockerImage - Docker image to build from (e.g., "python:3.12-slim").
829
+ * @param fsCapacityBytes - Filesystem capacity in bytes.
830
+ * @param options - Additional options (registry credentials, timeout).
831
+ * @returns Snapshot in "ready" status.
832
+ */
833
+ async createSnapshot(name, dockerImage, fsCapacityBytes, options = {}) {
834
+ const { registryId, registryUrl, registryUsername, registryPassword, timeout = 60, signal, } = options;
835
+ const url = `${this._baseUrl}/snapshots`;
836
+ const payload = {
837
+ name,
838
+ docker_image: dockerImage,
839
+ fs_capacity_bytes: fsCapacityBytes,
840
+ };
841
+ if (registryId !== undefined) {
842
+ payload.registry_id = registryId;
843
+ }
844
+ if (registryUrl !== undefined) {
845
+ payload.registry_url = registryUrl;
846
+ }
847
+ if (registryUsername !== undefined) {
848
+ payload.registry_username = registryUsername;
849
+ }
850
+ if (registryPassword !== undefined) {
851
+ payload.registry_password = registryPassword;
852
+ }
853
+ const response = await this._postJson(url, payload, { signal });
854
+ const snapshot = (await response.json());
855
+ return this.waitForSnapshot(snapshot.id, { timeout, signal });
856
+ }
857
+ /**
858
+ * Capture a snapshot from a running sandbox.
859
+ *
860
+ * Blocks until the snapshot is ready (polls with 2s interval).
861
+ *
862
+ * @param sandboxName - Name of the sandbox to capture from.
863
+ * @param name - Snapshot name.
864
+ * @param options - Capture options (checkpoint, timeout).
865
+ * @returns Snapshot in "ready" status.
866
+ */
867
+ async captureSnapshot(sandboxName, name, options = {}) {
868
+ const { checkpoint, timeout = 60, signal } = options;
869
+ const url = `${this._baseUrl}/boxes/${encodeURIComponent(sandboxName)}/snapshot`;
870
+ const payload = { name };
871
+ if (checkpoint !== undefined) {
872
+ payload.checkpoint = checkpoint;
873
+ }
874
+ const response = await this._postJson(url, payload, { signal });
875
+ const snapshot = (await response.json());
876
+ return this.waitForSnapshot(snapshot.id, { timeout, signal });
877
+ }
878
+ /**
879
+ * Get a snapshot by ID.
880
+ *
881
+ * @param snapshotId - Snapshot UUID.
882
+ * @returns Snapshot.
883
+ */
884
+ async getSnapshot(snapshotId, options) {
885
+ const url = `${this._baseUrl}/snapshots/${encodeURIComponent(snapshotId)}`;
886
+ const response = await this._fetch(url, { signal: options?.signal });
887
+ if (!response.ok) {
888
+ if (response.status === 404) {
889
+ throw new errors_js_1.LangSmithResourceNotFoundError(`Snapshot '${snapshotId}' not found`, "snapshot");
890
+ }
891
+ await (0, helpers_js_1.handleClientHttpError)(response);
892
+ }
893
+ return (await response.json());
894
+ }
895
+ /**
896
+ * List all snapshots.
897
+ *
898
+ * @returns List of Snapshots.
899
+ */
900
+ async listSnapshots() {
901
+ const url = `${this._baseUrl}/snapshots`;
902
+ const response = await this._fetch(url);
903
+ if (!response.ok) {
904
+ await (0, helpers_js_1.handleClientHttpError)(response);
905
+ }
906
+ const data = await response.json();
907
+ return (data.snapshots ?? []);
908
+ }
909
+ /**
910
+ * Delete a snapshot.
911
+ *
912
+ * @param snapshotId - Snapshot UUID.
913
+ */
914
+ async deleteSnapshot(snapshotId) {
915
+ const url = `${this._baseUrl}/snapshots/${encodeURIComponent(snapshotId)}`;
916
+ const response = await this._fetch(url, { method: "DELETE" });
917
+ if (!response.ok) {
918
+ await (0, helpers_js_1.handleClientHttpError)(response);
919
+ }
920
+ }
921
+ /**
922
+ * Poll until a snapshot reaches "ready" or "failed" status.
923
+ *
924
+ * @param snapshotId - Snapshot UUID.
925
+ * @param options - Polling options (timeout, pollInterval).
926
+ * @returns Snapshot in "ready" status.
927
+ */
928
+ async waitForSnapshot(snapshotId, options = {}) {
929
+ const { timeout = 300, pollInterval = 2.0, signal } = options;
930
+ const deadline = Date.now() + timeout * 1000;
931
+ let lastStatus = "building";
932
+ while (Date.now() < deadline) {
933
+ signal?.throwIfAborted();
934
+ const snapshot = await this.getSnapshot(snapshotId, { signal });
935
+ lastStatus = snapshot.status;
936
+ if (snapshot.status === "ready") {
937
+ return snapshot;
938
+ }
939
+ if (snapshot.status === "failed") {
940
+ throw new errors_js_1.LangSmithResourceCreationError(snapshot.status_message ?? `Snapshot '${snapshotId}' build failed`, "snapshot");
941
+ }
942
+ // Cap sleep to remaining time + jitter
943
+ const remaining = deadline - Date.now();
944
+ const jitter = pollInterval * 200 * (Math.random() - 0.5); // ±10%
945
+ const delay = Math.min(pollInterval * 1000 + jitter, remaining);
946
+ if (delay > 0) {
947
+ await sleepWithSignal(delay, signal);
948
+ }
949
+ }
950
+ throw new errors_js_1.LangSmithResourceTimeoutError(`Snapshot '${snapshotId}' did not become ready within ${timeout}s`, "snapshot", lastStatus);
951
+ }
729
952
  }
730
953
  exports.SandboxClient = SandboxClient;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Main SandboxClient class for interacting with the sandbox server API.
3
3
  */
4
- import type { CreatePoolOptions, CreateSandboxOptions, CreateTemplateOptions, CreateVolumeOptions, Pool, ResourceStatus, SandboxClientConfig, SandboxTemplate, UpdatePoolOptions, UpdateSandboxOptions, UpdateTemplateOptions, UpdateVolumeOptions, Volume, WaitForSandboxOptions } from "./types.js";
4
+ import type { CaptureSnapshotOptions, CreatePoolOptions, CreateSandboxOptions, CreateSnapshotOptions, CreateTemplateOptions, CreateVolumeOptions, Pool, ResourceStatus, SandboxClientConfig, SandboxTemplate, Snapshot, StartSandboxOptions, UpdatePoolOptions, UpdateSandboxOptions, UpdateTemplateOptions, UpdateVolumeOptions, Volume, WaitForSandboxOptions, WaitForSnapshotOptions } from "./types.js";
5
5
  import { Sandbox } from "./sandbox.js";
6
6
  /**
7
7
  * Client for interacting with the Sandbox Server API.
@@ -30,6 +30,8 @@ import { Sandbox } from "./sandbox.js";
30
30
  * await sandbox.delete();
31
31
  * }
32
32
  * ```
33
+ *
34
+ * @experimental This feature is experimental, and breaking changes are expected.
33
35
  */
34
36
  export declare class SandboxClient {
35
37
  private _baseUrl;
@@ -204,7 +206,7 @@ export declare class SandboxClient {
204
206
  * }
205
207
  * ```
206
208
  */
207
- createSandbox(templateName: string, options?: CreateSandboxOptions): Promise<Sandbox>;
209
+ createSandbox(templateName?: string, options?: CreateSandboxOptions): Promise<Sandbox>;
208
210
  /**
209
211
  * Get a Sandbox by name.
210
212
  *
@@ -214,7 +216,9 @@ export declare class SandboxClient {
214
216
  * @returns Sandbox.
215
217
  * @throws LangSmithResourceNotFoundError if sandbox not found.
216
218
  */
217
- getSandbox(name: string): Promise<Sandbox>;
219
+ getSandbox(name: string, options?: {
220
+ signal?: AbortSignal;
221
+ }): Promise<Sandbox>;
218
222
  /**
219
223
  * List all Sandboxes.
220
224
  *
@@ -256,7 +260,9 @@ export declare class SandboxClient {
256
260
  * @returns ResourceStatus with status and optional status_message.
257
261
  * @throws LangSmithResourceNotFoundError if sandbox not found.
258
262
  */
259
- getSandboxStatus(name: string): Promise<ResourceStatus>;
263
+ getSandboxStatus(name: string, options?: {
264
+ signal?: AbortSignal;
265
+ }): Promise<ResourceStatus>;
260
266
  /**
261
267
  * Wait for a sandbox to become ready.
262
268
  *
@@ -278,4 +284,70 @@ export declare class SandboxClient {
278
284
  * ```
279
285
  */
280
286
  waitForSandbox(name: string, options?: WaitForSandboxOptions): Promise<Sandbox>;
287
+ /**
288
+ * Start a stopped sandbox and wait until ready.
289
+ *
290
+ * @param name - Sandbox name.
291
+ * @param options - Options with timeout.
292
+ * @returns Sandbox in "ready" status.
293
+ */
294
+ startSandbox(name: string, options?: StartSandboxOptions): Promise<Sandbox>;
295
+ /**
296
+ * Stop a running sandbox (preserves sandbox files for later restart).
297
+ *
298
+ * @param name - Sandbox name.
299
+ */
300
+ stopSandbox(name: string): Promise<void>;
301
+ /**
302
+ * Build a snapshot from a Docker image.
303
+ *
304
+ * Blocks until the snapshot is ready (polls with 2s interval).
305
+ *
306
+ * @param name - Snapshot name.
307
+ * @param dockerImage - Docker image to build from (e.g., "python:3.12-slim").
308
+ * @param fsCapacityBytes - Filesystem capacity in bytes.
309
+ * @param options - Additional options (registry credentials, timeout).
310
+ * @returns Snapshot in "ready" status.
311
+ */
312
+ createSnapshot(name: string, dockerImage: string, fsCapacityBytes: number, options?: CreateSnapshotOptions): Promise<Snapshot>;
313
+ /**
314
+ * Capture a snapshot from a running sandbox.
315
+ *
316
+ * Blocks until the snapshot is ready (polls with 2s interval).
317
+ *
318
+ * @param sandboxName - Name of the sandbox to capture from.
319
+ * @param name - Snapshot name.
320
+ * @param options - Capture options (checkpoint, timeout).
321
+ * @returns Snapshot in "ready" status.
322
+ */
323
+ captureSnapshot(sandboxName: string, name: string, options?: CaptureSnapshotOptions): Promise<Snapshot>;
324
+ /**
325
+ * Get a snapshot by ID.
326
+ *
327
+ * @param snapshotId - Snapshot UUID.
328
+ * @returns Snapshot.
329
+ */
330
+ getSnapshot(snapshotId: string, options?: {
331
+ signal?: AbortSignal;
332
+ }): Promise<Snapshot>;
333
+ /**
334
+ * List all snapshots.
335
+ *
336
+ * @returns List of Snapshots.
337
+ */
338
+ listSnapshots(): Promise<Snapshot[]>;
339
+ /**
340
+ * Delete a snapshot.
341
+ *
342
+ * @param snapshotId - Snapshot UUID.
343
+ */
344
+ deleteSnapshot(snapshotId: string): Promise<void>;
345
+ /**
346
+ * Poll until a snapshot reaches "ready" or "failed" status.
347
+ *
348
+ * @param snapshotId - Snapshot UUID.
349
+ * @param options - Polling options (timeout, pollInterval).
350
+ * @returns Snapshot in "ready" status.
351
+ */
352
+ waitForSnapshot(snapshotId: string, options?: WaitForSnapshotOptions): Promise<Snapshot>;
281
353
  }