langsmith 0.5.7 → 0.5.9

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
@@ -3195,7 +3195,7 @@ class Client {
3195
3195
  (0, _uuid_js_1.assertUuid)(feedback_source.metadata["__run"].run_id);
3196
3196
  }
3197
3197
  const feedback = {
3198
- id: feedbackId ?? uuid.v4(),
3198
+ id: feedbackId ?? uuid.v7(),
3199
3199
  run_id: runId,
3200
3200
  key,
3201
3201
  score: _formatFeedbackScore(score),
package/dist/client.js CHANGED
@@ -3157,7 +3157,7 @@ export class Client {
3157
3157
  assertUuid(feedback_source.metadata["__run"].run_id);
3158
3158
  }
3159
3159
  const feedback = {
3160
- id: feedbackId ?? uuid.v4(),
3160
+ id: feedbackId ?? uuid.v7(),
3161
3161
  run_id: runId,
3162
3162
  key,
3163
3163
  score: _formatFeedbackScore(score),
@@ -67,7 +67,7 @@ class DynamicRunEvaluator {
67
67
  * @returns A promise that extracts to the evaluation result.
68
68
  */
69
69
  async evaluateRun(run, example, options) {
70
- let sourceRunId = (0, uuid_1.v4)();
70
+ let sourceRunId = (0, uuid_1.v7)();
71
71
  const metadata = {
72
72
  targetRunId: run.id,
73
73
  };
@@ -1,4 +1,4 @@
1
- import { v4 as uuidv4 } from "uuid";
1
+ import { v7 as uuidv7 } from "uuid";
2
2
  import { traceable } from "../traceable.js";
3
3
  /**
4
4
  * Wraps an evaluator function + implements the RunEvaluator interface.
@@ -63,7 +63,7 @@ export class DynamicRunEvaluator {
63
63
  * @returns A promise that extracts to the evaluation result.
64
64
  */
65
65
  async evaluateRun(run, example, options) {
66
- let sourceRunId = uuidv4();
66
+ let sourceRunId = uuidv7();
67
67
  const metadata = {
68
68
  targetRunId: run.id,
69
69
  };
@@ -530,21 +530,24 @@ class SandboxClient {
530
530
  * ```
531
531
  */
532
532
  async createSandbox(templateName, options = {}) {
533
- const { name, timeout = 30 } = options;
533
+ const { name, timeout = 30, waitForReady = true } = options;
534
534
  const url = `${this._baseUrl}/boxes`;
535
535
  const payload = {
536
536
  template_name: templateName,
537
- wait_for_ready: true,
538
- timeout,
537
+ wait_for_ready: waitForReady,
539
538
  };
539
+ if (waitForReady) {
540
+ payload.timeout = timeout;
541
+ }
540
542
  if (name) {
541
543
  payload.name = name;
542
544
  }
545
+ const httpTimeout = waitForReady ? (timeout + 30) * 1000 : 30 * 1000;
543
546
  const response = await this._fetch(url, {
544
547
  method: "POST",
545
548
  headers: { "Content-Type": "application/json" },
546
549
  body: JSON.stringify(payload),
547
- signal: AbortSignal.timeout((timeout + 30) * 1000),
550
+ signal: AbortSignal.timeout(httpTimeout),
548
551
  });
549
552
  if (!response.ok) {
550
553
  await (0, helpers_js_1.handleSandboxCreationError)(response);
@@ -635,5 +638,64 @@ class SandboxClient {
635
638
  await (0, helpers_js_1.handleClientHttpError)(response);
636
639
  }
637
640
  }
641
+ /**
642
+ * Get the provisioning status of a sandbox.
643
+ *
644
+ * This is a lightweight endpoint designed for polling during async creation.
645
+ * Use this instead of getSandbox() when you only need the status.
646
+ *
647
+ * @param name - Sandbox name.
648
+ * @returns ResourceStatus with status and optional status_message.
649
+ * @throws LangSmithResourceNotFoundError if sandbox not found.
650
+ */
651
+ async getSandboxStatus(name) {
652
+ const url = `${this._baseUrl}/boxes/${encodeURIComponent(name)}/status`;
653
+ const response = await this._fetch(url);
654
+ if (!response.ok) {
655
+ if (response.status === 404) {
656
+ throw new errors_js_1.LangSmithResourceNotFoundError(`Sandbox '${name}' not found`, "sandbox");
657
+ }
658
+ await (0, helpers_js_1.handleClientHttpError)(response);
659
+ }
660
+ return (await response.json());
661
+ }
662
+ /**
663
+ * Wait for a sandbox to become ready.
664
+ *
665
+ * Polls getSandboxStatus() until the sandbox reaches "ready" or "failed" status,
666
+ * then returns the full Sandbox object.
667
+ *
668
+ * @param name - Sandbox name.
669
+ * @param options - Polling options (timeout, pollInterval).
670
+ * @returns Ready Sandbox.
671
+ * @throws LangSmithResourceCreationError if sandbox status becomes "failed".
672
+ * @throws LangSmithResourceTimeoutError if timeout expires while still provisioning.
673
+ * @throws LangSmithResourceNotFoundError if sandbox not found.
674
+ *
675
+ * @example
676
+ * ```typescript
677
+ * const sandbox = await client.createSandbox("python-sandbox", { waitForReady: false });
678
+ * // ... do other work ...
679
+ * const readySandbox = await client.waitForSandbox(sandbox.name);
680
+ * ```
681
+ */
682
+ async waitForSandbox(name, options = {}) {
683
+ const { timeout = 120, pollInterval = 1.0 } = options;
684
+ const deadline = Date.now() + timeout * 1000;
685
+ let lastStatus = "provisioning";
686
+ while (Date.now() < deadline) {
687
+ const statusResult = await this.getSandboxStatus(name);
688
+ lastStatus = statusResult.status;
689
+ if (statusResult.status === "ready") {
690
+ return this.getSandbox(name);
691
+ }
692
+ if (statusResult.status === "failed") {
693
+ throw new errors_js_1.LangSmithResourceCreationError(statusResult.status_message ?? `Sandbox '${name}' creation failed`, "sandbox");
694
+ }
695
+ // Wait before polling again
696
+ await new Promise((resolve) => setTimeout(resolve, pollInterval * 1000));
697
+ }
698
+ throw new errors_js_1.LangSmithResourceTimeoutError(`Sandbox '${name}' did not become ready within ${timeout}s`, "sandbox", lastStatus);
699
+ }
638
700
  }
639
701
  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, SandboxClientConfig, SandboxTemplate, UpdatePoolOptions, UpdateTemplateOptions, UpdateVolumeOptions, Volume } from "./types.js";
4
+ import type { CreatePoolOptions, CreateSandboxOptions, CreateTemplateOptions, CreateVolumeOptions, Pool, ResourceStatus, SandboxClientConfig, SandboxTemplate, UpdatePoolOptions, UpdateTemplateOptions, UpdateVolumeOptions, Volume, WaitForSandboxOptions } from "./types.js";
5
5
  import { Sandbox } from "./sandbox.js";
6
6
  /**
7
7
  * Client for interacting with the Sandbox Server API.
@@ -237,4 +237,36 @@ export declare class SandboxClient {
237
237
  * @throws LangSmithResourceNotFoundError if sandbox not found.
238
238
  */
239
239
  deleteSandbox(name: string): Promise<void>;
240
+ /**
241
+ * Get the provisioning status of a sandbox.
242
+ *
243
+ * This is a lightweight endpoint designed for polling during async creation.
244
+ * Use this instead of getSandbox() when you only need the status.
245
+ *
246
+ * @param name - Sandbox name.
247
+ * @returns ResourceStatus with status and optional status_message.
248
+ * @throws LangSmithResourceNotFoundError if sandbox not found.
249
+ */
250
+ getSandboxStatus(name: string): Promise<ResourceStatus>;
251
+ /**
252
+ * Wait for a sandbox to become ready.
253
+ *
254
+ * Polls getSandboxStatus() until the sandbox reaches "ready" or "failed" status,
255
+ * then returns the full Sandbox object.
256
+ *
257
+ * @param name - Sandbox name.
258
+ * @param options - Polling options (timeout, pollInterval).
259
+ * @returns Ready Sandbox.
260
+ * @throws LangSmithResourceCreationError if sandbox status becomes "failed".
261
+ * @throws LangSmithResourceTimeoutError if timeout expires while still provisioning.
262
+ * @throws LangSmithResourceNotFoundError if sandbox not found.
263
+ *
264
+ * @example
265
+ * ```typescript
266
+ * const sandbox = await client.createSandbox("python-sandbox", { waitForReady: false });
267
+ * // ... do other work ...
268
+ * const readySandbox = await client.waitForSandbox(sandbox.name);
269
+ * ```
270
+ */
271
+ waitForSandbox(name: string, options?: WaitForSandboxOptions): Promise<Sandbox>;
240
272
  }
@@ -5,7 +5,7 @@ import { getLangSmithEnvironmentVariable } from "../../utils/env.js";
5
5
  import { _getFetchImplementation } from "../../singletons/fetch.js";
6
6
  import { AsyncCaller } from "../../utils/async_caller.js";
7
7
  import { Sandbox } from "./sandbox.js";
8
- import { LangSmithResourceNameConflictError, LangSmithResourceNotFoundError, LangSmithSandboxAPIError, } from "./errors.js";
8
+ import { LangSmithResourceCreationError, LangSmithResourceNameConflictError, LangSmithResourceNotFoundError, LangSmithResourceTimeoutError, LangSmithSandboxAPIError, } from "./errors.js";
9
9
  import { handleClientHttpError, handleConflictError, handlePoolError, handleResourceInUseError, handleSandboxCreationError, handleVolumeCreationError, } from "./helpers.js";
10
10
  /**
11
11
  * Get the default sandbox API endpoint from environment.
@@ -527,21 +527,24 @@ export class SandboxClient {
527
527
  * ```
528
528
  */
529
529
  async createSandbox(templateName, options = {}) {
530
- const { name, timeout = 30 } = options;
530
+ const { name, timeout = 30, waitForReady = true } = options;
531
531
  const url = `${this._baseUrl}/boxes`;
532
532
  const payload = {
533
533
  template_name: templateName,
534
- wait_for_ready: true,
535
- timeout,
534
+ wait_for_ready: waitForReady,
536
535
  };
536
+ if (waitForReady) {
537
+ payload.timeout = timeout;
538
+ }
537
539
  if (name) {
538
540
  payload.name = name;
539
541
  }
542
+ const httpTimeout = waitForReady ? (timeout + 30) * 1000 : 30 * 1000;
540
543
  const response = await this._fetch(url, {
541
544
  method: "POST",
542
545
  headers: { "Content-Type": "application/json" },
543
546
  body: JSON.stringify(payload),
544
- signal: AbortSignal.timeout((timeout + 30) * 1000),
547
+ signal: AbortSignal.timeout(httpTimeout),
545
548
  });
546
549
  if (!response.ok) {
547
550
  await handleSandboxCreationError(response);
@@ -632,4 +635,63 @@ export class SandboxClient {
632
635
  await handleClientHttpError(response);
633
636
  }
634
637
  }
638
+ /**
639
+ * Get the provisioning status of a sandbox.
640
+ *
641
+ * This is a lightweight endpoint designed for polling during async creation.
642
+ * Use this instead of getSandbox() when you only need the status.
643
+ *
644
+ * @param name - Sandbox name.
645
+ * @returns ResourceStatus with status and optional status_message.
646
+ * @throws LangSmithResourceNotFoundError if sandbox not found.
647
+ */
648
+ async getSandboxStatus(name) {
649
+ const url = `${this._baseUrl}/boxes/${encodeURIComponent(name)}/status`;
650
+ const response = await this._fetch(url);
651
+ if (!response.ok) {
652
+ if (response.status === 404) {
653
+ throw new LangSmithResourceNotFoundError(`Sandbox '${name}' not found`, "sandbox");
654
+ }
655
+ await handleClientHttpError(response);
656
+ }
657
+ return (await response.json());
658
+ }
659
+ /**
660
+ * Wait for a sandbox to become ready.
661
+ *
662
+ * Polls getSandboxStatus() until the sandbox reaches "ready" or "failed" status,
663
+ * then returns the full Sandbox object.
664
+ *
665
+ * @param name - Sandbox name.
666
+ * @param options - Polling options (timeout, pollInterval).
667
+ * @returns Ready Sandbox.
668
+ * @throws LangSmithResourceCreationError if sandbox status becomes "failed".
669
+ * @throws LangSmithResourceTimeoutError if timeout expires while still provisioning.
670
+ * @throws LangSmithResourceNotFoundError if sandbox not found.
671
+ *
672
+ * @example
673
+ * ```typescript
674
+ * const sandbox = await client.createSandbox("python-sandbox", { waitForReady: false });
675
+ * // ... do other work ...
676
+ * const readySandbox = await client.waitForSandbox(sandbox.name);
677
+ * ```
678
+ */
679
+ async waitForSandbox(name, options = {}) {
680
+ const { timeout = 120, pollInterval = 1.0 } = options;
681
+ const deadline = Date.now() + timeout * 1000;
682
+ let lastStatus = "provisioning";
683
+ while (Date.now() < deadline) {
684
+ const statusResult = await this.getSandboxStatus(name);
685
+ lastStatus = statusResult.status;
686
+ if (statusResult.status === "ready") {
687
+ return this.getSandbox(name);
688
+ }
689
+ if (statusResult.status === "failed") {
690
+ throw new LangSmithResourceCreationError(statusResult.status_message ?? `Sandbox '${name}' creation failed`, "sandbox");
691
+ }
692
+ // Wait before polling again
693
+ await new Promise((resolve) => setTimeout(resolve, pollInterval * 1000));
694
+ }
695
+ throw new LangSmithResourceTimeoutError(`Sandbox '${name}' did not become ready within ${timeout}s`, "sandbox", lastStatus);
696
+ }
635
697
  }
@@ -7,7 +7,7 @@
7
7
  * properties for specific handling when needed.
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.LangSmithSandboxOperationError = exports.LangSmithSandboxNotReadyError = exports.LangSmithDataplaneNotConfiguredError = exports.LangSmithSandboxCreationError = exports.LangSmithQuotaExceededError = exports.LangSmithValidationError = exports.LangSmithResourceNameConflictError = exports.LangSmithResourceAlreadyExistsError = exports.LangSmithResourceInUseError = exports.LangSmithResourceTimeoutError = exports.LangSmithResourceNotFoundError = exports.LangSmithSandboxConnectionError = exports.LangSmithSandboxAuthenticationError = exports.LangSmithSandboxAPIError = exports.LangSmithSandboxError = void 0;
10
+ exports.LangSmithSandboxOperationError = exports.LangSmithSandboxNotReadyError = exports.LangSmithDataplaneNotConfiguredError = exports.LangSmithSandboxCreationError = exports.LangSmithResourceCreationError = exports.LangSmithQuotaExceededError = exports.LangSmithValidationError = exports.LangSmithResourceNameConflictError = exports.LangSmithResourceAlreadyExistsError = exports.LangSmithResourceInUseError = exports.LangSmithResourceTimeoutError = exports.LangSmithResourceNotFoundError = exports.LangSmithSandboxConnectionError = exports.LangSmithSandboxAuthenticationError = exports.LangSmithSandboxAPIError = exports.LangSmithSandboxError = void 0;
11
11
  /**
12
12
  * Base exception for sandbox client errors.
13
13
  */
@@ -215,8 +215,44 @@ class LangSmithQuotaExceededError extends LangSmithSandboxError {
215
215
  }
216
216
  exports.LangSmithQuotaExceededError = LangSmithQuotaExceededError;
217
217
  // =============================================================================
218
- // Sandbox Creation Errors
218
+ // Resource Creation Errors
219
219
  // =============================================================================
220
+ /**
221
+ * Raised when resource provisioning fails (general-purpose).
222
+ */
223
+ class LangSmithResourceCreationError extends LangSmithSandboxError {
224
+ constructor(message, resourceType, errorType) {
225
+ super(message);
226
+ /**
227
+ * Type of resource that failed (e.g., "sandbox", "volume").
228
+ */
229
+ Object.defineProperty(this, "resourceType", {
230
+ enumerable: true,
231
+ configurable: true,
232
+ writable: true,
233
+ value: void 0
234
+ });
235
+ /**
236
+ * Machine-readable error type (ImagePull, CrashLoop, SandboxConfig, Unschedulable).
237
+ */
238
+ Object.defineProperty(this, "errorType", {
239
+ enumerable: true,
240
+ configurable: true,
241
+ writable: true,
242
+ value: void 0
243
+ });
244
+ this.name = "LangSmithResourceCreationError";
245
+ this.resourceType = resourceType;
246
+ this.errorType = errorType;
247
+ }
248
+ toString() {
249
+ if (this.errorType) {
250
+ return `${super.toString()} [${this.errorType}]`;
251
+ }
252
+ return super.toString();
253
+ }
254
+ }
255
+ exports.LangSmithResourceCreationError = LangSmithResourceCreationError;
220
256
  /**
221
257
  * Raised when sandbox creation fails.
222
258
  */
@@ -92,6 +92,21 @@ export declare class LangSmithQuotaExceededError extends LangSmithSandboxError {
92
92
  quotaType?: string;
93
93
  constructor(message: string, quotaType?: string);
94
94
  }
95
+ /**
96
+ * Raised when resource provisioning fails (general-purpose).
97
+ */
98
+ export declare class LangSmithResourceCreationError extends LangSmithSandboxError {
99
+ /**
100
+ * Type of resource that failed (e.g., "sandbox", "volume").
101
+ */
102
+ resourceType?: string;
103
+ /**
104
+ * Machine-readable error type (ImagePull, CrashLoop, SandboxConfig, Unschedulable).
105
+ */
106
+ errorType?: string;
107
+ constructor(message: string, resourceType?: string, errorType?: string);
108
+ toString(): string;
109
+ }
95
110
  /**
96
111
  * Raised when sandbox creation fails.
97
112
  */
@@ -201,8 +201,43 @@ export class LangSmithQuotaExceededError extends LangSmithSandboxError {
201
201
  }
202
202
  }
203
203
  // =============================================================================
204
- // Sandbox Creation Errors
204
+ // Resource Creation Errors
205
205
  // =============================================================================
206
+ /**
207
+ * Raised when resource provisioning fails (general-purpose).
208
+ */
209
+ export class LangSmithResourceCreationError extends LangSmithSandboxError {
210
+ constructor(message, resourceType, errorType) {
211
+ super(message);
212
+ /**
213
+ * Type of resource that failed (e.g., "sandbox", "volume").
214
+ */
215
+ Object.defineProperty(this, "resourceType", {
216
+ enumerable: true,
217
+ configurable: true,
218
+ writable: true,
219
+ value: void 0
220
+ });
221
+ /**
222
+ * Machine-readable error type (ImagePull, CrashLoop, SandboxConfig, Unschedulable).
223
+ */
224
+ Object.defineProperty(this, "errorType", {
225
+ enumerable: true,
226
+ configurable: true,
227
+ writable: true,
228
+ value: void 0
229
+ });
230
+ this.name = "LangSmithResourceCreationError";
231
+ this.resourceType = resourceType;
232
+ this.errorType = errorType;
233
+ }
234
+ toString() {
235
+ if (this.errorType) {
236
+ return `${super.toString()} [${this.errorType}]`;
237
+ }
238
+ return super.toString();
239
+ }
240
+ }
206
241
  /**
207
242
  * Raised when sandbox creation fails.
208
243
  */
@@ -24,7 +24,7 @@
24
24
  * @packageDocumentation
25
25
  */
26
26
  Object.defineProperty(exports, "__esModule", { value: true });
27
- exports.LangSmithDataplaneNotConfiguredError = exports.LangSmithSandboxOperationError = exports.LangSmithSandboxNotReadyError = exports.LangSmithSandboxCreationError = exports.LangSmithQuotaExceededError = exports.LangSmithValidationError = exports.LangSmithResourceNameConflictError = exports.LangSmithResourceAlreadyExistsError = exports.LangSmithResourceInUseError = exports.LangSmithResourceTimeoutError = exports.LangSmithResourceNotFoundError = exports.LangSmithSandboxConnectionError = exports.LangSmithSandboxAuthenticationError = exports.LangSmithSandboxAPIError = exports.LangSmithSandboxError = exports.Sandbox = exports.SandboxClient = void 0;
27
+ exports.LangSmithDataplaneNotConfiguredError = exports.LangSmithSandboxOperationError = exports.LangSmithSandboxNotReadyError = exports.LangSmithSandboxCreationError = exports.LangSmithResourceCreationError = exports.LangSmithQuotaExceededError = exports.LangSmithValidationError = exports.LangSmithResourceNameConflictError = exports.LangSmithResourceAlreadyExistsError = exports.LangSmithResourceInUseError = exports.LangSmithResourceTimeoutError = exports.LangSmithResourceNotFoundError = exports.LangSmithSandboxConnectionError = exports.LangSmithSandboxAuthenticationError = exports.LangSmithSandboxAPIError = exports.LangSmithSandboxError = exports.Sandbox = exports.SandboxClient = void 0;
28
28
  // Emit warning on import (alpha feature)
29
29
  console.warn("langsmith/experimental/sandbox is in alpha. " +
30
30
  "This feature is experimental, and breaking changes are expected.");
@@ -49,6 +49,8 @@ Object.defineProperty(exports, "LangSmithResourceNameConflictError", { enumerabl
49
49
  // Validation and quota errors
50
50
  Object.defineProperty(exports, "LangSmithValidationError", { enumerable: true, get: function () { return errors_js_1.LangSmithValidationError; } });
51
51
  Object.defineProperty(exports, "LangSmithQuotaExceededError", { enumerable: true, get: function () { return errors_js_1.LangSmithQuotaExceededError; } });
52
+ // Resource creation errors
53
+ Object.defineProperty(exports, "LangSmithResourceCreationError", { enumerable: true, get: function () { return errors_js_1.LangSmithResourceCreationError; } });
52
54
  // Sandbox-specific errors
53
55
  Object.defineProperty(exports, "LangSmithSandboxCreationError", { enumerable: true, get: function () { return errors_js_1.LangSmithSandboxCreationError; } });
54
56
  Object.defineProperty(exports, "LangSmithSandboxNotReadyError", { enumerable: true, get: function () { return errors_js_1.LangSmithSandboxNotReadyError; } });
@@ -24,5 +24,5 @@
24
24
  */
25
25
  export { SandboxClient } from "./client.js";
26
26
  export { Sandbox } from "./sandbox.js";
27
- export type { ExecutionResult, ResourceSpec, VolumeMountSpec, Volume, SandboxTemplate, Pool, SandboxData, SandboxClientConfig, RunOptions, CreateSandboxOptions, CreateVolumeOptions, CreateTemplateOptions, UpdateTemplateOptions, CreatePoolOptions, UpdateVolumeOptions, UpdatePoolOptions, } from "./types.js";
28
- export { LangSmithSandboxError, LangSmithSandboxAPIError, LangSmithSandboxAuthenticationError, LangSmithSandboxConnectionError, LangSmithResourceNotFoundError, LangSmithResourceTimeoutError, LangSmithResourceInUseError, LangSmithResourceAlreadyExistsError, LangSmithResourceNameConflictError, LangSmithValidationError, LangSmithQuotaExceededError, LangSmithSandboxCreationError, LangSmithSandboxNotReadyError, LangSmithSandboxOperationError, LangSmithDataplaneNotConfiguredError, } from "./errors.js";
27
+ export type { ExecutionResult, ResourceSpec, ResourceStatus, VolumeMountSpec, Volume, SandboxTemplate, Pool, SandboxData, SandboxClientConfig, RunOptions, CreateSandboxOptions, WaitForSandboxOptions, CreateVolumeOptions, CreateTemplateOptions, UpdateTemplateOptions, CreatePoolOptions, UpdateVolumeOptions, UpdatePoolOptions, } from "./types.js";
28
+ export { LangSmithSandboxError, LangSmithSandboxAPIError, LangSmithSandboxAuthenticationError, LangSmithSandboxConnectionError, LangSmithResourceNotFoundError, LangSmithResourceTimeoutError, LangSmithResourceInUseError, LangSmithResourceAlreadyExistsError, LangSmithResourceNameConflictError, LangSmithValidationError, LangSmithQuotaExceededError, LangSmithResourceCreationError, LangSmithSandboxCreationError, LangSmithSandboxNotReadyError, LangSmithSandboxOperationError, LangSmithDataplaneNotConfiguredError, } from "./errors.js";
@@ -36,5 +36,7 @@ LangSmithSandboxError, LangSmithSandboxAPIError, LangSmithSandboxAuthenticationE
36
36
  LangSmithResourceNotFoundError, LangSmithResourceTimeoutError, LangSmithResourceInUseError, LangSmithResourceAlreadyExistsError, LangSmithResourceNameConflictError,
37
37
  // Validation and quota errors
38
38
  LangSmithValidationError, LangSmithQuotaExceededError,
39
+ // Resource creation errors
40
+ LangSmithResourceCreationError,
39
41
  // Sandbox-specific errors
40
42
  LangSmithSandboxCreationError, LangSmithSandboxNotReadyError, LangSmithSandboxOperationError, LangSmithDataplaneNotConfiguredError, } from "./errors.js";
@@ -48,6 +48,20 @@ class Sandbox {
48
48
  writable: true,
49
49
  value: void 0
50
50
  });
51
+ /** Provisioning status ("provisioning", "ready", "failed"). */
52
+ Object.defineProperty(this, "status", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: void 0
57
+ });
58
+ /** Human-readable status message (e.g., error details when failed). */
59
+ Object.defineProperty(this, "status_message", {
60
+ enumerable: true,
61
+ configurable: true,
62
+ writable: true,
63
+ value: void 0
64
+ });
51
65
  /** Unique identifier (UUID). Remains constant even if name changes. */
52
66
  Object.defineProperty(this, "id", {
53
67
  enumerable: true,
@@ -78,6 +92,8 @@ class Sandbox {
78
92
  this.name = data.name;
79
93
  this.template_name = data.template_name;
80
94
  this.dataplane_url = data.dataplane_url;
95
+ this.status = data.status;
96
+ this.status_message = data.status_message;
81
97
  this.id = data.id;
82
98
  this.created_at = data.created_at;
83
99
  this.updated_at = data.updated_at;
@@ -85,9 +101,14 @@ class Sandbox {
85
101
  }
86
102
  /**
87
103
  * Validate and return the dataplane URL.
104
+ * @throws LangSmithSandboxNotReadyError if sandbox status is not "ready".
88
105
  * @throws LangSmithDataplaneNotConfiguredError if dataplane_url is not configured.
89
106
  */
90
107
  requireDataplaneUrl() {
108
+ if (this.status && this.status !== "ready") {
109
+ throw new errors_js_1.LangSmithSandboxNotReadyError(`Sandbox '${this.name}' is not ready (status: ${this.status}). ` +
110
+ "Use waitForSandbox() to wait for the sandbox to become ready.");
111
+ }
91
112
  if (!this.dataplane_url) {
92
113
  throw new errors_js_1.LangSmithDataplaneNotConfiguredError(`Sandbox '${this.name}' does not have a dataplane_url configured. ` +
93
114
  "Runtime operations require a dataplane URL.");
@@ -27,6 +27,10 @@ export declare class Sandbox {
27
27
  readonly template_name: string;
28
28
  /** URL for data plane operations (file I/O, command execution). */
29
29
  readonly dataplane_url?: string;
30
+ /** Provisioning status ("provisioning", "ready", "failed"). */
31
+ readonly status?: string;
32
+ /** Human-readable status message (e.g., error details when failed). */
33
+ readonly status_message?: string;
30
34
  /** Unique identifier (UUID). Remains constant even if name changes. */
31
35
  readonly id?: string;
32
36
  /** Timestamp when the sandbox was created. */
@@ -36,6 +40,7 @@ export declare class Sandbox {
36
40
  private _client;
37
41
  /**
38
42
  * Validate and return the dataplane URL.
43
+ * @throws LangSmithSandboxNotReadyError if sandbox status is not "ready".
39
44
  * @throws LangSmithDataplaneNotConfiguredError if dataplane_url is not configured.
40
45
  */
41
46
  private requireDataplaneUrl;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Sandbox class for interacting with a specific sandbox instance.
3
3
  */
4
- import { LangSmithDataplaneNotConfiguredError } from "./errors.js";
4
+ import { LangSmithDataplaneNotConfiguredError, LangSmithSandboxNotReadyError, } from "./errors.js";
5
5
  import { handleSandboxHttpError } from "./helpers.js";
6
6
  /**
7
7
  * Represents an active sandbox for running commands and file operations.
@@ -45,6 +45,20 @@ export class Sandbox {
45
45
  writable: true,
46
46
  value: void 0
47
47
  });
48
+ /** Provisioning status ("provisioning", "ready", "failed"). */
49
+ Object.defineProperty(this, "status", {
50
+ enumerable: true,
51
+ configurable: true,
52
+ writable: true,
53
+ value: void 0
54
+ });
55
+ /** Human-readable status message (e.g., error details when failed). */
56
+ Object.defineProperty(this, "status_message", {
57
+ enumerable: true,
58
+ configurable: true,
59
+ writable: true,
60
+ value: void 0
61
+ });
48
62
  /** Unique identifier (UUID). Remains constant even if name changes. */
49
63
  Object.defineProperty(this, "id", {
50
64
  enumerable: true,
@@ -75,6 +89,8 @@ export class Sandbox {
75
89
  this.name = data.name;
76
90
  this.template_name = data.template_name;
77
91
  this.dataplane_url = data.dataplane_url;
92
+ this.status = data.status;
93
+ this.status_message = data.status_message;
78
94
  this.id = data.id;
79
95
  this.created_at = data.created_at;
80
96
  this.updated_at = data.updated_at;
@@ -82,9 +98,14 @@ export class Sandbox {
82
98
  }
83
99
  /**
84
100
  * Validate and return the dataplane URL.
101
+ * @throws LangSmithSandboxNotReadyError if sandbox status is not "ready".
85
102
  * @throws LangSmithDataplaneNotConfiguredError if dataplane_url is not configured.
86
103
  */
87
104
  requireDataplaneUrl() {
105
+ if (this.status && this.status !== "ready") {
106
+ throw new LangSmithSandboxNotReadyError(`Sandbox '${this.name}' is not ready (status: ${this.status}). ` +
107
+ "Use waitForSandbox() to wait for the sandbox to become ready.");
108
+ }
88
109
  if (!this.dataplane_url) {
89
110
  throw new LangSmithDataplaneNotConfiguredError(`Sandbox '${this.name}' does not have a dataplane_url configured. ` +
90
111
  "Runtime operations require a dataplane URL.");
@@ -64,6 +64,15 @@ export interface Pool {
64
64
  created_at?: string;
65
65
  updated_at?: string;
66
66
  }
67
+ /**
68
+ * Lightweight provisioning status for any async-created resource.
69
+ */
70
+ export interface ResourceStatus {
71
+ /** One of "provisioning", "ready", "failed". */
72
+ status: string;
73
+ /** Human-readable details when failed. */
74
+ status_message?: string;
75
+ }
67
76
  /**
68
77
  * Data representing a sandbox instance from the API.
69
78
  */
@@ -72,6 +81,8 @@ export interface SandboxData {
72
81
  name: string;
73
82
  template_name: string;
74
83
  dataplane_url?: string;
84
+ status?: string;
85
+ status_message?: string;
75
86
  created_at?: string;
76
87
  updated_at?: string;
77
88
  }
@@ -137,6 +148,28 @@ export interface CreateSandboxOptions {
137
148
  * Timeout in seconds when waiting for ready.
138
149
  */
139
150
  timeout?: number;
151
+ /**
152
+ * Whether to wait for the sandbox to be ready before returning.
153
+ * When false, returns immediately with status "provisioning".
154
+ * Use getSandboxStatus() or waitForSandbox() to poll for readiness.
155
+ * Default: true.
156
+ */
157
+ waitForReady?: boolean;
158
+ }
159
+ /**
160
+ * Options for waiting for a sandbox to become ready.
161
+ */
162
+ export interface WaitForSandboxOptions {
163
+ /**
164
+ * Maximum time in seconds to wait for the sandbox to become ready.
165
+ * Default: 120.
166
+ */
167
+ timeout?: number;
168
+ /**
169
+ * Time in seconds between status polls.
170
+ * Default: 1.0.
171
+ */
172
+ pollInterval?: number;
140
173
  }
141
174
  /**
142
175
  * Options for creating a volume.
package/dist/index.cjs CHANGED
@@ -18,4 +18,4 @@ Object.defineProperty(exports, "PromptCache", { enumerable: true, get: function
18
18
  Object.defineProperty(exports, "configureGlobalPromptCache", { enumerable: true, get: function () { return index_js_1.configureGlobalPromptCache; } });
19
19
  Object.defineProperty(exports, "promptCacheSingleton", { enumerable: true, get: function () { return index_js_1.promptCacheSingleton; } });
20
20
  // Update using yarn bump-version
21
- exports.__version__ = "0.5.7";
21
+ exports.__version__ = "0.5.9";
package/dist/index.d.ts CHANGED
@@ -5,4 +5,4 @@ export { overrideFetchImplementation } from "./singletons/fetch.js";
5
5
  export { getDefaultProjectName } from "./utils/project.js";
6
6
  export { uuid7, uuid7FromTime } from "./uuid.js";
7
7
  export { Cache, PromptCache, type CacheConfig, type CacheMetrics, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
8
- export declare const __version__ = "0.5.7";
8
+ export declare const __version__ = "0.5.9";
package/dist/index.js CHANGED
@@ -5,4 +5,4 @@ export { getDefaultProjectName } from "./utils/project.js";
5
5
  export { uuid7, uuid7FromTime } from "./uuid.js";
6
6
  export { Cache, PromptCache, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
7
7
  // Update using yarn bump-version
8
- export const __version__ = "0.5.7";
8
+ export const __version__ = "0.5.9";
@@ -418,6 +418,15 @@ class RunTree {
418
418
  execution_order: child_execution_order,
419
419
  child_execution_order: child_execution_order,
420
420
  });
421
+ // Propagate all parent metadata; child metadata takes precedence.
422
+ const parentMeta = this.extra?.metadata ?? {};
423
+ const childMeta = child.extra?.metadata ?? {};
424
+ if (Object.keys(parentMeta).length > 0) {
425
+ child.extra = {
426
+ ...child.extra,
427
+ metadata: { ...parentMeta, ...childMeta },
428
+ };
429
+ }
421
430
  // Copy context vars over into the new run tree.
422
431
  if (constants_js_1._LC_CONTEXT_VARIABLES_KEY in this) {
423
432
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -480,14 +489,12 @@ class RunTree {
480
489
  }
481
490
  }
482
491
  }
492
+ const parent_run_id = run.parent_run?.id ?? run.parent_run_id;
483
493
  let child_runs;
484
- let parent_run_id;
485
494
  if (!excludeChildRuns) {
486
495
  child_runs = run.child_runs.map((child_run) => this._convertToCreate(child_run, runtimeEnv, excludeChildRuns));
487
- parent_run_id = undefined;
488
496
  }
489
497
  else {
490
- parent_run_id = run.parent_run?.id ?? run.parent_run_id;
491
498
  child_runs = [];
492
499
  }
493
500
  return {
package/dist/run_trees.js CHANGED
@@ -412,6 +412,15 @@ export class RunTree {
412
412
  execution_order: child_execution_order,
413
413
  child_execution_order: child_execution_order,
414
414
  });
415
+ // Propagate all parent metadata; child metadata takes precedence.
416
+ const parentMeta = this.extra?.metadata ?? {};
417
+ const childMeta = child.extra?.metadata ?? {};
418
+ if (Object.keys(parentMeta).length > 0) {
419
+ child.extra = {
420
+ ...child.extra,
421
+ metadata: { ...parentMeta, ...childMeta },
422
+ };
423
+ }
415
424
  // Copy context vars over into the new run tree.
416
425
  if (_LC_CONTEXT_VARIABLES_KEY in this) {
417
426
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -474,14 +483,12 @@ export class RunTree {
474
483
  }
475
484
  }
476
485
  }
486
+ const parent_run_id = run.parent_run?.id ?? run.parent_run_id;
477
487
  let child_runs;
478
- let parent_run_id;
479
488
  if (!excludeChildRuns) {
480
489
  child_runs = run.child_runs.map((child_run) => this._convertToCreate(child_run, runtimeEnv, excludeChildRuns));
481
- parent_run_id = undefined;
482
490
  }
483
491
  else {
484
- parent_run_id = run.parent_run?.id ?? run.parent_run_id;
485
492
  child_runs = [];
486
493
  }
487
494
  return {
@@ -22,7 +22,7 @@ function wrapEvaluator(evaluator) {
22
22
  `See this page for more information: https://docs.smith.langchain.com/evaluation/how_to_guides/vitest_jest`,
23
23
  ].join("\n"));
24
24
  }
25
- let evalRunId = config?.runId ?? config?.id ?? (0, uuid_1.v4)();
25
+ let evalRunId = config?.runId ?? config?.id ?? (0, uuid_1.v7)();
26
26
  let evalResult;
27
27
  if ((0, globals_js_1.trackingEnabled)(context)) {
28
28
  const wrappedEvaluator = (0, traceable_js_1.traceable)(async (_runTree, params) => {
@@ -83,7 +83,7 @@ async function evaluatedBy(outputs, evaluator) {
83
83
  ].join("\n"));
84
84
  }
85
85
  const wrappedEvaluator = wrapEvaluator(evaluator);
86
- const evalRunId = (0, uuid_1.v4)();
86
+ const evalRunId = (0, uuid_1.v7)();
87
87
  const evalResult = await wrappedEvaluator({
88
88
  inputs: context.currentExample?.inputs ?? {},
89
89
  referenceOutputs: context?.currentExample?.outputs ?? {},
@@ -1,6 +1,6 @@
1
1
  import { ROOT, traceable } from "../../../traceable.js";
2
2
  import { testWrapperAsyncLocalStorageInstance, _logTestFeedback, trackingEnabled, } from "../globals.js";
3
- import { v4 } from "uuid";
3
+ import { v7 } from "uuid";
4
4
  function isEvaluationResult(x) {
5
5
  return (x != null &&
6
6
  typeof x === "object" &&
@@ -18,7 +18,7 @@ export function wrapEvaluator(evaluator) {
18
18
  `See this page for more information: https://docs.smith.langchain.com/evaluation/how_to_guides/vitest_jest`,
19
19
  ].join("\n"));
20
20
  }
21
- let evalRunId = config?.runId ?? config?.id ?? v4();
21
+ let evalRunId = config?.runId ?? config?.id ?? v7();
22
22
  let evalResult;
23
23
  if (trackingEnabled(context)) {
24
24
  const wrappedEvaluator = traceable(async (_runTree, params) => {
@@ -79,7 +79,7 @@ export async function evaluatedBy(outputs, evaluator) {
79
79
  ].join("\n"));
80
80
  }
81
81
  const wrappedEvaluator = wrapEvaluator(evaluator);
82
- const evalRunId = v4();
82
+ const evalRunId = v7();
83
83
  const evalResult = await wrappedEvaluator({
84
84
  inputs: context.currentExample?.inputs ?? {},
85
85
  referenceOutputs: context?.currentExample?.outputs ?? {},
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.wrapAnthropic = void 0;
4
+ exports.createUsageMetadata = createUsageMetadata;
4
5
  const traceable_js_1 = require("../traceable.cjs");
5
6
  const usage_js_1 = require("../utils/usage.cjs");
6
7
  const TRACED_INVOCATION_KEYS = ["top_k", "top_p", "stream", "thinking"];
@@ -17,14 +18,18 @@ function createUsageMetadata(anthropicUsage) {
17
18
  const outputTokens = typeof anthropicUsage.output_tokens === "number"
18
19
  ? anthropicUsage.output_tokens
19
20
  : 0;
20
- const totalTokens = inputTokens + outputTokens;
21
21
  const inputTokenDetails = (0, usage_js_1.convertAnthropicUsageToInputTokenDetails)(
22
22
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
23
  anthropicUsage);
24
+ // Anthropic cache tokens are ADDITIVE (not subsets of input_tokens like OpenAI).
25
+ // Sum them into input_tokens so the backend cost calculation is correct.
26
+ const cacheTokenSum = Object.values(inputTokenDetails).reduce((sum, v) => sum + (v ?? 0), 0);
27
+ const adjustedInputTokens = inputTokens + cacheTokenSum;
28
+ const adjustedTotalTokens = adjustedInputTokens + outputTokens;
24
29
  return {
25
- input_tokens: inputTokens,
30
+ input_tokens: adjustedInputTokens,
26
31
  output_tokens: outputTokens,
27
- total_tokens: totalTokens,
32
+ total_tokens: adjustedTotalTokens,
28
33
  ...(Object.keys(inputTokenDetails).length > 0 && {
29
34
  input_token_details: inputTokenDetails,
30
35
  }),
@@ -2,6 +2,7 @@ import type Anthropic from "@anthropic-ai/sdk";
2
2
  import type { Stream } from "@anthropic-ai/sdk/streaming";
3
3
  import type { MessageStream } from "@anthropic-ai/sdk/lib/MessageStream";
4
4
  import type { RunTreeConfig } from "../index.js";
5
+ import { KVMap } from "../schemas.js";
5
6
  type ExtraRunTreeConfig = Pick<Partial<RunTreeConfig>, "name" | "metadata" | "tags">;
6
7
  type MessagesNamespace = {
7
8
  create: (...args: any[]) => any;
@@ -31,6 +32,10 @@ type PatchedAnthropicClient<T extends AnthropicType> = T & {
31
32
  };
32
33
  };
33
34
  };
35
+ /**
36
+ * Create usage metadata from Anthropic's token usage format.
37
+ */
38
+ export declare function createUsageMetadata(anthropicUsage: Partial<Anthropic.Messages.Usage>): KVMap | undefined;
34
39
  /**
35
40
  * Wraps an Anthropic client's completion methods, enabling automatic LangSmith
36
41
  * tracing. Method signatures are unchanged, with the exception that you can pass
@@ -4,7 +4,7 @@ const TRACED_INVOCATION_KEYS = ["top_k", "top_p", "stream", "thinking"];
4
4
  /**
5
5
  * Create usage metadata from Anthropic's token usage format.
6
6
  */
7
- function createUsageMetadata(anthropicUsage) {
7
+ export function createUsageMetadata(anthropicUsage) {
8
8
  if (!anthropicUsage) {
9
9
  return undefined;
10
10
  }
@@ -14,14 +14,18 @@ function createUsageMetadata(anthropicUsage) {
14
14
  const outputTokens = typeof anthropicUsage.output_tokens === "number"
15
15
  ? anthropicUsage.output_tokens
16
16
  : 0;
17
- const totalTokens = inputTokens + outputTokens;
18
17
  const inputTokenDetails = convertAnthropicUsageToInputTokenDetails(
19
18
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
19
  anthropicUsage);
20
+ // Anthropic cache tokens are ADDITIVE (not subsets of input_tokens like OpenAI).
21
+ // Sum them into input_tokens so the backend cost calculation is correct.
22
+ const cacheTokenSum = Object.values(inputTokenDetails).reduce((sum, v) => sum + (v ?? 0), 0);
23
+ const adjustedInputTokens = inputTokens + cacheTokenSum;
24
+ const adjustedTotalTokens = adjustedInputTokens + outputTokens;
21
25
  return {
22
- input_tokens: inputTokens,
26
+ input_tokens: adjustedInputTokens,
23
27
  output_tokens: outputTokens,
24
- total_tokens: totalTokens,
28
+ total_tokens: adjustedTotalTokens,
25
29
  ...(Object.keys(inputTokenDetails).length > 0 && {
26
30
  input_token_details: inputTokenDetails,
27
31
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.5.7",
3
+ "version": "0.5.9",
4
4
  "description": "Client library to connect to the LangSmith Observability and Evaluation Platform.",
5
5
  "packageManager": "yarn@1.22.19",
6
6
  "files": [
@@ -158,7 +158,7 @@
158
158
  "@ai-sdk/provider": "^3.0.0",
159
159
  "@anthropic-ai/claude-agent-sdk": "^0.2.34",
160
160
  "@google/genai": "^1.29.0",
161
- "@anthropic-ai/sdk": "^0.74.0",
161
+ "@anthropic-ai/sdk": "^0.78.0",
162
162
  "@babel/preset-env": "^7.22.4",
163
163
  "@faker-js/faker": "^8.4.1",
164
164
  "@jest/globals": "^29.5.0",
@@ -167,7 +167,7 @@
167
167
  "@langchain/langgraph": "^0.3.6",
168
168
  "@langchain/openai": "^0.5.16",
169
169
  "@opentelemetry/api": "^1.9.0",
170
- "@opentelemetry/auto-instrumentations-node": "^0.69.0",
170
+ "@opentelemetry/auto-instrumentations-node": "^0.70.1",
171
171
  "@opentelemetry/sdk-node": "^0.212.0",
172
172
  "@opentelemetry/sdk-trace-base": "^2.0.0",
173
173
  "@opentelemetry/sdk-trace-node": "^2.0.0",