langsmith 0.10.3 → 0.10.5

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.
Files changed (46) hide show
  1. package/dist/client.cjs +19 -4
  2. package/dist/client.d.ts +2 -1
  3. package/dist/client.js +19 -4
  4. package/dist/evaluation/_runner.cjs +47 -5
  5. package/dist/evaluation/_runner.d.ts +12 -0
  6. package/dist/evaluation/_runner.js +47 -5
  7. package/dist/index.cjs +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js +1 -1
  10. package/dist/sandbox/access_delegation.cjs +24 -0
  11. package/dist/sandbox/access_delegation.d.ts +15 -0
  12. package/dist/sandbox/access_delegation.js +21 -0
  13. package/dist/sandbox/client.cjs +70 -5
  14. package/dist/sandbox/client.d.ts +18 -0
  15. package/dist/sandbox/client.js +70 -5
  16. package/dist/sandbox/command_handle.cjs +34 -0
  17. package/dist/sandbox/command_handle.d.ts +10 -0
  18. package/dist/sandbox/command_handle.js +34 -0
  19. package/dist/sandbox/helpers.cjs +129 -0
  20. package/dist/sandbox/helpers.d.ts +29 -0
  21. package/dist/sandbox/helpers.js +123 -0
  22. package/dist/sandbox/index.cjs +7 -1
  23. package/dist/sandbox/index.d.ts +5 -1
  24. package/dist/sandbox/index.js +2 -0
  25. package/dist/sandbox/mounts.cjs +21 -3
  26. package/dist/sandbox/mounts.d.ts +7 -1
  27. package/dist/sandbox/mounts.js +21 -3
  28. package/dist/sandbox/proxy_config.cjs +41 -10
  29. package/dist/sandbox/proxy_config.d.ts +33 -6
  30. package/dist/sandbox/proxy_config.js +40 -10
  31. package/dist/sandbox/sandbox.cjs +160 -4
  32. package/dist/sandbox/sandbox.d.ts +71 -1
  33. package/dist/sandbox/sandbox.js +161 -5
  34. package/dist/sandbox/service_url.cjs +125 -0
  35. package/dist/sandbox/service_url.d.ts +50 -0
  36. package/dist/sandbox/service_url.js +120 -0
  37. package/dist/sandbox/types.d.ts +251 -8
  38. package/dist/sandbox/ws_execute.cjs +31 -1
  39. package/dist/sandbox/ws_execute.d.ts +9 -0
  40. package/dist/sandbox/ws_execute.js +31 -1
  41. package/dist/utils/error.cjs +17 -22
  42. package/dist/utils/error.js +17 -22
  43. package/dist/wrappers/openai_agents.cjs +37 -28
  44. package/dist/wrappers/openai_agents.d.ts +0 -1
  45. package/dist/wrappers/openai_agents.js +37 -28
  46. package/package.json +2 -2
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServiceLoginUrl = exports.ServiceUrl = exports.SERVICE_TOKEN_HEADER = void 0;
4
+ /** Header the sandbox router reads the minted service token from. */
5
+ exports.SERVICE_TOKEN_HEADER = "X-Langsmith-Sandbox-Service-Token";
6
+ /** Refresh this many seconds before the token actually expires. */
7
+ const REFRESH_MARGIN_SECONDS = 60;
8
+ /**
9
+ * Service URL carrying a short-lived token, refreshed as it nears expiry.
10
+ *
11
+ * Accessors are async because a refresh is a network call.
12
+ */
13
+ class ServiceUrl {
14
+ constructor(data, refresher) {
15
+ Object.defineProperty(this, "_browserUrl", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: void 0
20
+ });
21
+ Object.defineProperty(this, "_serviceUrl", {
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true,
25
+ value: void 0
26
+ });
27
+ Object.defineProperty(this, "_token", {
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true,
31
+ value: void 0
32
+ });
33
+ Object.defineProperty(this, "_expiresAt", {
34
+ enumerable: true,
35
+ configurable: true,
36
+ writable: true,
37
+ value: void 0
38
+ });
39
+ Object.defineProperty(this, "_refresher", {
40
+ enumerable: true,
41
+ configurable: true,
42
+ writable: true,
43
+ value: void 0
44
+ });
45
+ this._browserUrl = data.browser_url ?? "";
46
+ this._serviceUrl = data.service_url ?? "";
47
+ this._token = data.token ?? "";
48
+ this._expiresAt = data.expires_at ?? "";
49
+ this._refresher = refresher;
50
+ }
51
+ _shouldRefresh() {
52
+ if (!this._refresher || !this._expiresAt)
53
+ return false;
54
+ const expires = Date.parse(this._expiresAt);
55
+ if (Number.isNaN(expires))
56
+ return false;
57
+ return (expires - Date.now()) / 1000 <= REFRESH_MARGIN_SECONDS;
58
+ }
59
+ async _maybeRefresh() {
60
+ if (!this._refresher || !this._shouldRefresh())
61
+ return;
62
+ const fresh = await this._refresher();
63
+ this._browserUrl = fresh._browserUrl;
64
+ this._serviceUrl = fresh._serviceUrl;
65
+ this._token = fresh._token;
66
+ this._expiresAt = fresh._expiresAt;
67
+ }
68
+ /** The signed token, refreshed if near expiry. */
69
+ async token() {
70
+ await this._maybeRefresh();
71
+ return this._token;
72
+ }
73
+ /** The service base URL, refreshed if near expiry. */
74
+ async serviceUrl() {
75
+ await this._maybeRefresh();
76
+ return this._serviceUrl;
77
+ }
78
+ /** The browser URL that authenticates then redirects, refreshed if near expiry. */
79
+ async browserUrl() {
80
+ await this._maybeRefresh();
81
+ return this._browserUrl;
82
+ }
83
+ /** ISO 8601 expiry of the current token, refreshed if near expiry. */
84
+ async expiresAt() {
85
+ await this._maybeRefresh();
86
+ return this._expiresAt;
87
+ }
88
+ /** Fetch a path on the service with the token header injected. */
89
+ async fetch(path = "/", init = {}) {
90
+ const base = (await this.serviceUrl()).replace(/\/+$/, "");
91
+ const url = `${base}/${path.replace(/^\/+/, "")}`;
92
+ const headers = new Headers(init.headers);
93
+ headers.set(exports.SERVICE_TOKEN_HEADER, await this.token());
94
+ return fetch(url, { ...init, headers });
95
+ }
96
+ }
97
+ exports.ServiceUrl = ServiceUrl;
98
+ /**
99
+ * Service URL gated by LangSmith login rather than a token.
100
+ *
101
+ * The grant is durable: no token, no expiry, and only usable from a browser
102
+ * signed in to LangSmith — which is why there is no fetch helper here, a
103
+ * programmatic request cannot satisfy the login.
104
+ */
105
+ class ServiceLoginUrl {
106
+ constructor(data) {
107
+ /** The URL to open in a browser. */
108
+ Object.defineProperty(this, "url", {
109
+ enumerable: true,
110
+ configurable: true,
111
+ writable: true,
112
+ value: void 0
113
+ });
114
+ /** Who may open it: "restricted" or "workspace". */
115
+ Object.defineProperty(this, "access", {
116
+ enumerable: true,
117
+ configurable: true,
118
+ writable: true,
119
+ value: void 0
120
+ });
121
+ this.url = data.browser_url || data.service_url || "";
122
+ this.access = data.access ?? "";
123
+ }
124
+ }
125
+ exports.ServiceLoginUrl = ServiceLoginUrl;
@@ -0,0 +1,50 @@
1
+ /** How a service URL is gated. Omit for a minted token. */
2
+ export type ServiceAccess = "restricted" | "workspace";
3
+ /** Header the sandbox router reads the minted service token from. */
4
+ export declare const SERVICE_TOKEN_HEADER = "X-Langsmith-Sandbox-Service-Token";
5
+ export interface ServiceUrlData {
6
+ browser_url?: string;
7
+ service_url?: string;
8
+ token?: string;
9
+ expires_at?: string;
10
+ access?: string;
11
+ }
12
+ /**
13
+ * Service URL carrying a short-lived token, refreshed as it nears expiry.
14
+ *
15
+ * Accessors are async because a refresh is a network call.
16
+ */
17
+ export declare class ServiceUrl {
18
+ private _browserUrl;
19
+ private _serviceUrl;
20
+ private _token;
21
+ private _expiresAt;
22
+ private readonly _refresher?;
23
+ constructor(data: ServiceUrlData, refresher?: () => Promise<ServiceUrl>);
24
+ private _shouldRefresh;
25
+ private _maybeRefresh;
26
+ /** The signed token, refreshed if near expiry. */
27
+ token(): Promise<string>;
28
+ /** The service base URL, refreshed if near expiry. */
29
+ serviceUrl(): Promise<string>;
30
+ /** The browser URL that authenticates then redirects, refreshed if near expiry. */
31
+ browserUrl(): Promise<string>;
32
+ /** ISO 8601 expiry of the current token, refreshed if near expiry. */
33
+ expiresAt(): Promise<string>;
34
+ /** Fetch a path on the service with the token header injected. */
35
+ fetch(path?: string, init?: RequestInit): Promise<Response>;
36
+ }
37
+ /**
38
+ * Service URL gated by LangSmith login rather than a token.
39
+ *
40
+ * The grant is durable: no token, no expiry, and only usable from a browser
41
+ * signed in to LangSmith — which is why there is no fetch helper here, a
42
+ * programmatic request cannot satisfy the login.
43
+ */
44
+ export declare class ServiceLoginUrl {
45
+ /** The URL to open in a browser. */
46
+ readonly url: string;
47
+ /** Who may open it: "restricted" or "workspace". */
48
+ readonly access: string;
49
+ constructor(data: ServiceUrlData);
50
+ }
@@ -0,0 +1,120 @@
1
+ /** Header the sandbox router reads the minted service token from. */
2
+ export const SERVICE_TOKEN_HEADER = "X-Langsmith-Sandbox-Service-Token";
3
+ /** Refresh this many seconds before the token actually expires. */
4
+ const REFRESH_MARGIN_SECONDS = 60;
5
+ /**
6
+ * Service URL carrying a short-lived token, refreshed as it nears expiry.
7
+ *
8
+ * Accessors are async because a refresh is a network call.
9
+ */
10
+ export class ServiceUrl {
11
+ constructor(data, refresher) {
12
+ Object.defineProperty(this, "_browserUrl", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: void 0
17
+ });
18
+ Object.defineProperty(this, "_serviceUrl", {
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true,
22
+ value: void 0
23
+ });
24
+ Object.defineProperty(this, "_token", {
25
+ enumerable: true,
26
+ configurable: true,
27
+ writable: true,
28
+ value: void 0
29
+ });
30
+ Object.defineProperty(this, "_expiresAt", {
31
+ enumerable: true,
32
+ configurable: true,
33
+ writable: true,
34
+ value: void 0
35
+ });
36
+ Object.defineProperty(this, "_refresher", {
37
+ enumerable: true,
38
+ configurable: true,
39
+ writable: true,
40
+ value: void 0
41
+ });
42
+ this._browserUrl = data.browser_url ?? "";
43
+ this._serviceUrl = data.service_url ?? "";
44
+ this._token = data.token ?? "";
45
+ this._expiresAt = data.expires_at ?? "";
46
+ this._refresher = refresher;
47
+ }
48
+ _shouldRefresh() {
49
+ if (!this._refresher || !this._expiresAt)
50
+ return false;
51
+ const expires = Date.parse(this._expiresAt);
52
+ if (Number.isNaN(expires))
53
+ return false;
54
+ return (expires - Date.now()) / 1000 <= REFRESH_MARGIN_SECONDS;
55
+ }
56
+ async _maybeRefresh() {
57
+ if (!this._refresher || !this._shouldRefresh())
58
+ return;
59
+ const fresh = await this._refresher();
60
+ this._browserUrl = fresh._browserUrl;
61
+ this._serviceUrl = fresh._serviceUrl;
62
+ this._token = fresh._token;
63
+ this._expiresAt = fresh._expiresAt;
64
+ }
65
+ /** The signed token, refreshed if near expiry. */
66
+ async token() {
67
+ await this._maybeRefresh();
68
+ return this._token;
69
+ }
70
+ /** The service base URL, refreshed if near expiry. */
71
+ async serviceUrl() {
72
+ await this._maybeRefresh();
73
+ return this._serviceUrl;
74
+ }
75
+ /** The browser URL that authenticates then redirects, refreshed if near expiry. */
76
+ async browserUrl() {
77
+ await this._maybeRefresh();
78
+ return this._browserUrl;
79
+ }
80
+ /** ISO 8601 expiry of the current token, refreshed if near expiry. */
81
+ async expiresAt() {
82
+ await this._maybeRefresh();
83
+ return this._expiresAt;
84
+ }
85
+ /** Fetch a path on the service with the token header injected. */
86
+ async fetch(path = "/", init = {}) {
87
+ const base = (await this.serviceUrl()).replace(/\/+$/, "");
88
+ const url = `${base}/${path.replace(/^\/+/, "")}`;
89
+ const headers = new Headers(init.headers);
90
+ headers.set(SERVICE_TOKEN_HEADER, await this.token());
91
+ return fetch(url, { ...init, headers });
92
+ }
93
+ }
94
+ /**
95
+ * Service URL gated by LangSmith login rather than a token.
96
+ *
97
+ * The grant is durable: no token, no expiry, and only usable from a browser
98
+ * signed in to LangSmith — which is why there is no fetch helper here, a
99
+ * programmatic request cannot satisfy the login.
100
+ */
101
+ export class ServiceLoginUrl {
102
+ constructor(data) {
103
+ /** The URL to open in a browser. */
104
+ Object.defineProperty(this, "url", {
105
+ enumerable: true,
106
+ configurable: true,
107
+ writable: true,
108
+ value: void 0
109
+ });
110
+ /** Who may open it: "restricted" or "workspace". */
111
+ Object.defineProperty(this, "access", {
112
+ enumerable: true,
113
+ configurable: true,
114
+ writable: true,
115
+ value: void 0
116
+ });
117
+ this.url = data.browser_url || data.service_url || "";
118
+ this.access = data.access ?? "";
119
+ }
120
+ }
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Field names use snake_case to match API response format.
5
5
  */
6
+ import type { AccessDelegation } from "./access_delegation.js";
6
7
  /**
7
8
  * Result of executing a command in a sandbox.
8
9
  */
@@ -20,6 +21,164 @@ export interface ResourceStatus {
20
21
  /** Human-readable details when failed. */
21
22
  status_message?: string;
22
23
  }
24
+ /**
25
+ * The user, working directory and environment commands run with.
26
+ *
27
+ * Mirrors `docker run -u / -w / -e`: `user` and `work_dir` replace the layer
28
+ * below, `env_vars` merge into it key by key. It applies at three points, each
29
+ * layered over the one before -- the snapshot, the sandbox, and a single
30
+ * command.
31
+ */
32
+ export interface RunConfig {
33
+ /**
34
+ * Account to run as: `name`, `uid`, `name:group` or `uid:gid`. Defaults to
35
+ * the Docker image's `USER`.
36
+ */
37
+ user?: string;
38
+ /**
39
+ * Absolute working directory. Defaults to the image's `WORKDIR`. A relative
40
+ * path is rejected by the server.
41
+ */
42
+ work_dir?: string;
43
+ /** Environment variables, merged over the layer below. */
44
+ env_vars?: Record<string, string>;
45
+ }
46
+ /**
47
+ * One filesystem entry returned by `sandbox.glob()`.
48
+ */
49
+ export interface FileInfo {
50
+ /** Absolute path of the entry. */
51
+ path: string;
52
+ /** True for a directory. */
53
+ is_dir: boolean;
54
+ /** Size in bytes. */
55
+ size_bytes: number;
56
+ /** RFC 3339 modification timestamp. */
57
+ modified_at?: string;
58
+ }
59
+ /**
60
+ * Entries matching a glob pattern.
61
+ */
62
+ export interface GlobResult {
63
+ matches: FileInfo[];
64
+ /**
65
+ * True when the server hit its result cap or deadline, so the search is a
66
+ * partial answer worth refining.
67
+ */
68
+ truncated: boolean;
69
+ }
70
+ /**
71
+ * One matching line found by `sandbox.grep()`.
72
+ */
73
+ export interface GrepMatch {
74
+ /** Absolute path of the file the match was found in. */
75
+ path: string;
76
+ /** 1-based line number. */
77
+ line: number;
78
+ /** The matching line's text. */
79
+ text: string;
80
+ }
81
+ /**
82
+ * Lines matching a literal search.
83
+ */
84
+ export interface GrepResult {
85
+ matches: GrepMatch[];
86
+ /** True when the server hit its result cap or deadline. */
87
+ truncated: boolean;
88
+ }
89
+ /**
90
+ * Options for the read-only filesystem search operations.
91
+ */
92
+ export interface GlobOptions {
93
+ /** Maximum matches to return. */
94
+ limit?: number;
95
+ /** Request timeout in seconds. */
96
+ timeout?: number;
97
+ headers?: Record<string, string>;
98
+ }
99
+ /**
100
+ * Options for `sandbox.grep()`.
101
+ */
102
+ export interface GrepOptions extends GlobOptions {
103
+ /**
104
+ * Restrict which files are searched. A bare `*.py` matches by basename at
105
+ * any depth; a pattern containing `/` or `**` matches the path relative to
106
+ * the search root.
107
+ */
108
+ glob?: string;
109
+ }
110
+ /**
111
+ * What a `HEAD` on a sandbox file reports, without transferring it.
112
+ */
113
+ export interface FileStat {
114
+ /** The file's size. */
115
+ size_bytes: number;
116
+ /**
117
+ * Strong validator for the current contents. Opaque -- compare it, never
118
+ * parse it. Pass it back as `ifRange` to resume a download safely, or as
119
+ * `ifNoneMatch` to poll for a change.
120
+ */
121
+ etag?: string;
122
+ /** HTTP-date of the last modification, second-resolution. */
123
+ last_modified?: string;
124
+ /** The server's content type for the file. */
125
+ content_type?: string;
126
+ }
127
+ /**
128
+ * Bytes returned by a ranged read, and where they sit in the file.
129
+ */
130
+ export interface FileChunk {
131
+ /** The bytes returned. Empty when `unchanged` is true. */
132
+ content: Uint8Array;
133
+ /**
134
+ * Validator for the version these bytes came from. Pass it as `ifRange` on
135
+ * the next chunk so a rewrite restarts the read instead of splicing two
136
+ * versions together.
137
+ */
138
+ etag?: string;
139
+ /** The file's full size, or undefined when the server did not report it. */
140
+ total_bytes?: number;
141
+ /** Offset of the first byte returned. */
142
+ start: number;
143
+ /**
144
+ * True when the server answered 206 with only part of the file. A false
145
+ * here after a ranged request means the file changed and the server sent it
146
+ * whole -- restart from zero.
147
+ */
148
+ partial: boolean;
149
+ /**
150
+ * True when the caller passed `ifNoneMatch` and the file still matches it.
151
+ * No bytes are returned.
152
+ */
153
+ unchanged: boolean;
154
+ /** HTTP-date of the last modification. */
155
+ last_modified?: string;
156
+ }
157
+ /**
158
+ * Options for a ranged read. Provide `start` (with optional `end`), or
159
+ * `suffixBytes`.
160
+ */
161
+ export interface ReadRangeOptions {
162
+ /** First byte to return. With `end`, an inclusive range. */
163
+ start?: number;
164
+ /** Last byte to return, inclusive. Clamped to EOF rather than rejected. */
165
+ end?: number;
166
+ /** Return the last N bytes. Mutually exclusive with `start`/`end`. */
167
+ suffixBytes?: number;
168
+ /**
169
+ * An `ETag` from an earlier chunk. The range is honored only while the file
170
+ * still matches it.
171
+ */
172
+ ifRange?: string;
173
+ /**
174
+ * An `ETag` the caller already holds. An unchanged file answers with
175
+ * `unchanged: true` and no bytes.
176
+ */
177
+ ifNoneMatch?: string;
178
+ /** Request timeout in seconds. */
179
+ timeout?: number;
180
+ headers?: Record<string, string>;
181
+ }
23
182
  /**
24
183
  * Represents a sandbox snapshot.
25
184
  *
@@ -41,6 +200,13 @@ export interface Snapshot {
41
200
  registry_id?: string;
42
201
  created_at?: string;
43
202
  updated_at?: string;
203
+ /**
204
+ * User, working directory and environment sandboxes built from this
205
+ * snapshot boot with, resolved from the Docker image at build time. Absent
206
+ * on snapshots built before the server recorded it, which boot as root with
207
+ * no image environment.
208
+ */
209
+ run_config?: RunConfig;
44
210
  }
45
211
  /**
46
212
  * Data representing a sandbox instance from the API.
@@ -79,6 +245,16 @@ export interface SandboxData {
79
245
  mem_bytes?: number;
80
246
  /** Root filesystem capacity in bytes. */
81
247
  fs_capacity_bytes?: number;
248
+ /**
249
+ * User, working directory and environment the sandbox's commands run with.
250
+ * Absent on sandboxes created before the server recorded it.
251
+ */
252
+ run_config?: RunConfig;
253
+ /**
254
+ * LangSmith access granted to code inside the sandbox. Absent when it has
255
+ * none.
256
+ */
257
+ access_delegation?: AccessDelegation;
82
258
  }
83
259
  /**
84
260
  * Configuration options for the SandboxClient.
@@ -170,6 +346,10 @@ export interface WsRunOptions {
170
346
  ttlSeconds?: number;
171
347
  /** Whether to allocate a PTY. */
172
348
  pty?: boolean;
349
+ /** Per-command user, working directory and environment. */
350
+ runConfig?: RunConfig;
351
+ /** Half-close the spawned process's stdin so it reads EOF. */
352
+ closeStdin?: boolean;
173
353
  /**
174
354
  * Additional headers attached to the WebSocket upgrade request. Merged on
175
355
  * top of any default headers the SandboxClient was constructed with.
@@ -186,12 +366,30 @@ export interface RunOptions {
186
366
  timeout?: number;
187
367
  /**
188
368
  * Environment variables to set for the command.
369
+ *
370
+ * @deprecated Use `runConfig.env_vars`. The two cannot be combined.
189
371
  */
190
372
  env?: Record<string, string>;
191
373
  /**
192
374
  * Working directory for command execution.
375
+ *
376
+ * @deprecated Use `runConfig.work_dir`. The two cannot be combined.
193
377
  */
194
378
  cwd?: string;
379
+ /**
380
+ * User, working directory and environment for this one command, layered
381
+ * over the sandbox's own.
382
+ */
383
+ runConfig?: RunConfig;
384
+ /**
385
+ * Half-close the command's stdin so a command that reads it sees EOF
386
+ * rather than blocking until the timeout. Defaults to true for a non-PTY
387
+ * command, which means `sendInput()` on the returned handle throws unless
388
+ * this is set to false. Ignored under `pty: true`, where input and output
389
+ * share one terminal file descriptor -- send an EOT byte (0x04) as input
390
+ * instead.
391
+ */
392
+ closeInput?: boolean;
195
393
  /**
196
394
  * Shell to use for command execution. Defaults to "/bin/bash".
197
395
  */
@@ -262,8 +460,20 @@ export interface SandboxProxySecret {
262
460
  /** Workspace secret reference or opaque secret value. */
263
461
  value: string;
264
462
  }
463
+ /** Static credentials used by the sandbox proxy signer. */
464
+ interface AwsStaticAuthConfig {
465
+ access_key_id: SandboxProxySecret;
466
+ secret_access_key: SandboxProxySecret;
467
+ role_arn?: "";
468
+ }
469
+ /** IAM role assumed and renewed by LangSmith, outside the sandbox. */
470
+ interface AwsRoleAuthConfig {
471
+ role_arn: string;
472
+ access_key_id?: never;
473
+ secret_access_key?: never;
474
+ }
265
475
  /** AWS auth rule for sandbox proxy SigV4 signing. */
266
- export interface SandboxAwsAuthRule {
476
+ export interface SandboxAwsAuthRule<Auth extends AwsStaticAuthConfig | AwsRoleAuthConfig = AwsStaticAuthConfig | AwsRoleAuthConfig> {
267
477
  /** Rule name. */
268
478
  name: string;
269
479
  /** AWS auth rules are matched by the sandbox proxy's AWS endpoint matcher. */
@@ -277,11 +487,8 @@ export interface SandboxAwsAuthRule {
277
487
  * the wire.
278
488
  */
279
489
  env_vars?: Record<string, string>;
280
- /** AWS credentials used by the proxy signer. */
281
- aws: {
282
- access_key_id: SandboxProxySecret;
283
- secret_access_key: SandboxProxySecret;
284
- };
490
+ /** Exclusive static credentials or IAM-role descriptor. */
491
+ aws: Auth;
285
492
  }
286
493
  /** GCP auth rule for sandbox proxy OAuth bearer injection. */
287
494
  export interface SandboxGcpAuthRule {
@@ -314,7 +521,7 @@ export type SandboxProxyRule = SandboxAwsAuthRule | SandboxGcpAuthRule | Record<
314
521
  export interface SandboxProxyConfig {
315
522
  /** Header-injection rules keyed by host pattern. */
316
523
  rules?: SandboxProxyRule[];
317
- /** Hosts that bypass the proxy entirely. */
524
+ /** @deprecated Ignored by the server. The sandbox runtime has no proxy bypass list. */
318
525
  no_proxy?: string[];
319
526
  /** Allow/deny list enforced at the proxy sidecar. */
320
527
  access_control?: SandboxAccessControl;
@@ -427,6 +634,7 @@ export type SandboxMount = S3MountSpec | GCSMountSpec | GitMountSpec | ContextHu
427
634
  export interface SandboxAwsMountAuthConfig {
428
635
  access_key_id: SandboxProxySecret;
429
636
  secret_access_key: SandboxProxySecret;
637
+ role_arn?: "";
430
638
  }
431
639
  /** GCP credentials used by the backend to authenticate GCS mounts. */
432
640
  export interface SandboxGcpMountAuthConfig {
@@ -434,7 +642,8 @@ export interface SandboxGcpMountAuthConfig {
434
642
  }
435
643
  /** Provider auth blocks for sandbox mounts. */
436
644
  export interface SandboxMountAuthConfig {
437
- aws?: SandboxAwsMountAuthConfig;
645
+ /** IAM roles here are restricted to this sandbox's S3 mount scopes. */
646
+ aws?: SandboxAwsMountAuthConfig | AwsRoleAuthConfig;
438
647
  gcp?: SandboxGcpMountAuthConfig;
439
648
  }
440
649
  /** Provider auth helper output accepted by mountConfig. */
@@ -507,6 +716,21 @@ export interface CreateSandboxOptions {
507
716
  * auth.
508
717
  */
509
718
  proxyConfig?: SandboxProxyConfig;
719
+ /**
720
+ * User, working directory and environment the sandbox boots with,
721
+ * overriding the snapshot's: `user` and `work_dir` replace, `env_vars`
722
+ * merge. The sandbox's own env vars remain a layer above this one.
723
+ */
724
+ runConfig?: RunConfig;
725
+ /**
726
+ * Grant letting code inside the sandbox call the LangSmith API as you, with
727
+ * no API key of its own. `{ mode: "INHERIT" }` grants everything you can do;
728
+ * `{ mode: "EXPLICIT", permissions: [...] }` grants only the permissions
729
+ * listed, each of which you must already hold. The grant belongs to the
730
+ * sandbox, so anyone who can exec into it can make calls under it. Omit for
731
+ * no access.
732
+ */
733
+ accessDelegation?: AccessDelegation;
510
734
  }
511
735
  /**
512
736
  * Options for creating a snapshot from a Docker image.
@@ -514,6 +738,13 @@ export interface CreateSandboxOptions {
514
738
  export interface CreateSnapshotOptions {
515
739
  /** Private registry ID. */
516
740
  registryId?: string;
741
+ /**
742
+ * Override the Docker image's `USER`, `WORKDIR` and `ENV` for sandboxes
743
+ * built from this snapshot: `user` and `work_dir` replace the image's,
744
+ * `env_vars` merge over it key by key. Omitting it adopts the image's own
745
+ * configuration. Pass `{ user: "0" }` to keep running as root.
746
+ */
747
+ runConfig?: RunConfig;
517
748
  /** Timeout in seconds when waiting for ready. Default: 60. */
518
749
  timeout?: number;
519
750
  /** AbortSignal for cancellation. */
@@ -554,6 +785,11 @@ export interface CaptureSnapshotOptions {
554
785
  dockerImage?: string;
555
786
  /** Filesystem capacity in bytes for Docker image export. */
556
787
  fsCapacityBytes?: number;
788
+ /**
789
+ * Override applied over the configuration the captured sandbox was running
790
+ * with: `user` and `work_dir` replace, `env_vars` merge.
791
+ */
792
+ runConfig?: RunConfig;
557
793
  /** Timeout in seconds when waiting for ready. Default: 60. */
558
794
  timeout?: number;
559
795
  /** AbortSignal for cancellation. */
@@ -669,6 +905,13 @@ export interface UpdateSandboxOptions {
669
905
  * `ready`; start a stopped one first.
670
906
  */
671
907
  proxyConfig?: SandboxProxyConfig;
908
+ /**
909
+ * Merge into the sandbox's stored run configuration: `user` and `work_dir`
910
+ * replace, `env_vars` merge. Takes effect for subsequent commands; commands
911
+ * already running are unaffected, and a stopped sandbox picks it up on its
912
+ * next start. Omitting it leaves the stored value untouched.
913
+ */
914
+ runConfig?: RunConfig;
672
915
  }
673
916
  /**
674
917
  * Options for waiting for a sandbox to become ready.