langsmith 0.10.11 → 0.10.13

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 (119) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +198 -198
  3. package/lib/address.d.mts +35 -56
  4. package/lib/address.d.mts.map +1 -1
  5. package/lib/address.d.ts +35 -56
  6. package/lib/address.d.ts.map +1 -1
  7. package/lib/address.js +91 -156
  8. package/lib/address.js.map +1 -1
  9. package/lib/address.mjs +83 -151
  10. package/lib/address.mjs.map +1 -1
  11. package/lib/client.d.mts +1 -1
  12. package/lib/client.d.mts.map +1 -1
  13. package/lib/client.d.ts +1 -1
  14. package/lib/client.d.ts.map +1 -1
  15. package/lib/client.js +11 -10
  16. package/lib/client.js.map +1 -1
  17. package/lib/client.mjs +4 -3
  18. package/lib/client.mjs.map +1 -1
  19. package/lib/run_trees.d.mts +1 -1
  20. package/lib/run_trees.d.mts.map +1 -1
  21. package/lib/run_trees.d.ts +1 -1
  22. package/lib/run_trees.d.ts.map +1 -1
  23. package/lib/run_trees.js +11 -9
  24. package/lib/run_trees.js.map +1 -1
  25. package/lib/run_trees.mjs +7 -5
  26. package/lib/run_trees.mjs.map +1 -1
  27. package/lib/sandbox/index.d.mts +1 -1
  28. package/lib/sandbox/index.d.mts.map +1 -1
  29. package/lib/sandbox/index.d.ts +1 -1
  30. package/lib/sandbox/index.d.ts.map +1 -1
  31. package/lib/sandbox/index.js.map +1 -1
  32. package/lib/sandbox/index.mjs.map +1 -1
  33. package/lib/sandbox/mounts.d.mts +3 -2
  34. package/lib/sandbox/mounts.d.mts.map +1 -1
  35. package/lib/sandbox/mounts.d.ts +3 -2
  36. package/lib/sandbox/mounts.d.ts.map +1 -1
  37. package/lib/sandbox/mounts.js +6 -1
  38. package/lib/sandbox/mounts.js.map +1 -1
  39. package/lib/sandbox/mounts.mjs +6 -1
  40. package/lib/sandbox/mounts.mjs.map +1 -1
  41. package/lib/sandbox/types.d.mts +7 -0
  42. package/lib/sandbox/types.d.mts.map +1 -1
  43. package/lib/sandbox/types.d.ts +7 -0
  44. package/lib/sandbox/types.d.ts.map +1 -1
  45. package/lib/sandbox/verify.d.mts.map +1 -1
  46. package/lib/sandbox/verify.d.ts.map +1 -1
  47. package/lib/sandbox/verify.js +81 -19
  48. package/lib/sandbox/verify.js.map +1 -1
  49. package/lib/sandbox/verify.mjs +81 -19
  50. package/lib/sandbox/verify.mjs.map +1 -1
  51. package/lib/utils/addressing.d.mts +1 -1
  52. package/lib/utils/addressing.d.mts.map +1 -1
  53. package/lib/utils/addressing.d.ts +1 -1
  54. package/lib/utils/addressing.d.ts.map +1 -1
  55. package/lib/utils/addressing.js +4 -4
  56. package/lib/utils/addressing.js.map +1 -1
  57. package/lib/utils/addressing.mjs +5 -5
  58. package/lib/utils/addressing.mjs.map +1 -1
  59. package/package.json +22 -10
  60. package/resources/annotation-queues/annotation-queues.d.mts +33 -2
  61. package/resources/annotation-queues/annotation-queues.d.mts.map +1 -1
  62. package/resources/annotation-queues/annotation-queues.d.ts +33 -2
  63. package/resources/annotation-queues/annotation-queues.d.ts.map +1 -1
  64. package/resources/annotation-queues/annotation-queues.js.map +1 -1
  65. package/resources/annotation-queues/annotation-queues.mjs.map +1 -1
  66. package/resources/runs/runs.d.mts +14 -1
  67. package/resources/runs/runs.d.mts.map +1 -1
  68. package/resources/runs/runs.d.ts +14 -1
  69. package/resources/runs/runs.d.ts.map +1 -1
  70. package/resources/runs/runs.js +4 -0
  71. package/resources/runs/runs.js.map +1 -1
  72. package/resources/runs/runs.mjs +4 -0
  73. package/resources/runs/runs.mjs.map +1 -1
  74. package/resources/sandboxes/boxes.d.mts +32 -0
  75. package/resources/sandboxes/boxes.d.mts.map +1 -1
  76. package/resources/sandboxes/boxes.d.ts +32 -0
  77. package/resources/sandboxes/boxes.d.ts.map +1 -1
  78. package/resources/sandboxes/sandboxes.d.mts +32 -0
  79. package/resources/sandboxes/sandboxes.d.mts.map +1 -1
  80. package/resources/sandboxes/sandboxes.d.ts +32 -0
  81. package/resources/sandboxes/sandboxes.d.ts.map +1 -1
  82. package/resources/sandboxes/sandboxes.js.map +1 -1
  83. package/resources/sandboxes/sandboxes.mjs.map +1 -1
  84. package/resources/threads/threads.d.mts +13 -1
  85. package/resources/threads/threads.d.mts.map +1 -1
  86. package/resources/threads/threads.d.ts +13 -1
  87. package/resources/threads/threads.d.ts.map +1 -1
  88. package/resources/threads/threads.js +4 -0
  89. package/resources/threads/threads.js.map +1 -1
  90. package/resources/threads/threads.mjs +4 -0
  91. package/resources/threads/threads.mjs.map +1 -1
  92. package/resources/traces.d.mts +34 -16
  93. package/resources/traces.d.mts.map +1 -1
  94. package/resources/traces.d.ts +34 -16
  95. package/resources/traces.d.ts.map +1 -1
  96. package/resources/traces.js +7 -1
  97. package/resources/traces.js.map +1 -1
  98. package/resources/traces.mjs +7 -1
  99. package/resources/traces.mjs.map +1 -1
  100. package/src/lib/address.ts +138 -180
  101. package/src/lib/client.ts +4 -5
  102. package/src/lib/run_trees.ts +8 -5
  103. package/src/lib/sandbox/README.md +3 -2
  104. package/src/lib/sandbox/index.ts +1 -0
  105. package/src/lib/sandbox/mounts.ts +8 -0
  106. package/src/lib/sandbox/types.ts +8 -0
  107. package/src/lib/sandbox/verify.ts +107 -28
  108. package/src/lib/utils/addressing.ts +8 -5
  109. package/src/resources/annotation-queues/annotation-queues.ts +46 -2
  110. package/src/resources/runs/runs.ts +15 -1
  111. package/src/resources/sandboxes/boxes.ts +40 -0
  112. package/src/resources/sandboxes/sandboxes.ts +40 -0
  113. package/src/resources/threads/threads.ts +14 -1
  114. package/src/resources/traces.ts +38 -16
  115. package/src/version.ts +1 -1
  116. package/version.d.mts +1 -1
  117. package/version.d.ts +1 -1
  118. package/version.js +1 -1
  119. package/version.mjs +1 -1
package/src/lib/client.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { addressToLrn } from "./address.js";
1
2
  import * as uuid from "./utils/uuid/src/index.js";
2
3
  import { getOpenAPIBaseUrl } from "./utils/api_url.js";
3
4
  import type { OTELContext } from "./experimental/otel/types.js";
@@ -1861,7 +1862,7 @@ export class Client implements LangSmithTracingClientInterface {
1861
1862
 
1862
1863
  /**
1863
1864
  * (beta) Access the sessions resource, which resolves an address to the
1864
- * project its traces go to: `client.sessions.resolve(address.toApiAddress())`.
1865
+ * project its traces go to: `client.sessions.resolve(address)`.
1865
1866
  */
1866
1867
  public get sessions(): Sessions {
1867
1868
  this._checkStainlessVersion("0.18.0");
@@ -3359,9 +3360,7 @@ export class Client implements LangSmithTracingClientInterface {
3359
3360
 
3360
3361
  /** The ID of the project an address names, with one request. */
3361
3362
  private async _resolveAddress(address: Address): Promise<string> {
3362
- const { session_id: sessionId } = await this.sessions.resolve(
3363
- address.toApiAddress(),
3364
- );
3363
+ const { session_id: sessionId } = await this.sessions.resolve(address);
3365
3364
  assertUuid(sessionId);
3366
3365
  return sessionId;
3367
3366
  }
@@ -5672,7 +5671,7 @@ export class Client implements LangSmithTracingClientInterface {
5672
5671
  return feedback as Feedback;
5673
5672
  }
5674
5673
  const body = JSON.stringify(
5675
- address ? { ...feedback, address: address._toLrn() } : feedback,
5674
+ address ? { ...feedback, address: addressToLrn(address) } : feedback,
5676
5675
  );
5677
5676
  const url = `${this.apiUrl}/feedback`;
5678
5677
  await this.caller.call(async () => {
@@ -1,3 +1,4 @@
1
+ import { addressToLrn, addressFromLrn } from "./address.js";
1
2
  import { Client } from "./client.js";
2
3
  import { isEnvTracingEnabled } from "./env.js";
3
4
  import {
@@ -33,7 +34,7 @@ import {
33
34
  rejectConflicting,
34
35
  resolveFromEnv,
35
36
  } from "./utils/addressing.js";
36
- import { AgentAddress, EnvAddressError, ensureAgent } from "./address.js";
37
+ import { type AgentAddress, EnvAddressError, ensureAgent } from "./address.js";
37
38
 
38
39
  const TIMESTAMP_LENGTH = 36;
39
40
  // DNS namespace for UUID v5 (same as Python's uuid.NAMESPACE_DNS)
@@ -197,7 +198,7 @@ const HEADER_SAFE_REPLICA_FIELDS = new Set([
197
198
  /** Rebuilds an untrusted header address; `undefined` if unusable. */
198
199
  function addressFromHeader(value: unknown): AgentAddress | undefined {
199
200
  try {
200
- return AgentAddress._fromLrn(value);
201
+ return addressFromLrn(value);
201
202
  } catch {
202
203
  // Values are untrusted, so not logged.
203
204
  console.warn("Ignoring an unusable address in a `baggage` header.");
@@ -301,7 +302,7 @@ class Baggage {
301
302
  }
302
303
  if (this.address) {
303
304
  items.push(
304
- `langsmith-address=${encodeURIComponent(this.address._toLrn())}`,
305
+ `langsmith-address=${encodeURIComponent(addressToLrn(this.address))}`,
305
306
  );
306
307
  }
307
308
 
@@ -752,7 +753,8 @@ export class RunTree implements BaseRun {
752
753
  primary === undefined &&
753
754
  !this.replicas?.some((r) => r.primary === true) &&
754
755
  projectName === this.project_name &&
755
- address?._toLrn() === this.address?._toLrn()
756
+ (address ? addressToLrn(address) : undefined) ===
757
+ (this.address ? addressToLrn(this.address) : undefined)
756
758
  ) {
757
759
  return {
758
760
  ...baseRun,
@@ -760,7 +762,8 @@ export class RunTree implements BaseRun {
760
762
  address,
761
763
  };
762
764
  }
763
- const seed = projectName ?? address?._toLrn() ?? "agent//";
765
+ const seed =
766
+ projectName ?? (address ? addressToLrn(address) : undefined) ?? "agent//";
764
767
 
765
768
  // Apply reroot logic before ID remapping
766
769
  if (reroot) {
@@ -679,8 +679,9 @@ try {
679
679
 
680
680
  ## Verifying Requests from LangSmith
681
681
 
682
- `SandboxTokenVerifier` checks EdDSA signatures against LangSmith's JWKS
683
- (derived from `LANGSMITH_ENDPOINT`, cached) using Web Crypto, so it needs a
682
+ `SandboxTokenVerifier` checks signatures against LangSmith's JWKS (derived from
683
+ `LANGSMITH_ENDPOINT`, cached); user tokens may use any JOSE asymmetric algorithm
684
+ (RS*, PS*, ES\*, EdDSA), chosen by the JWKS key. It uses Web Crypto, so it needs a
684
685
  runtime with Ed25519 support (Node.js 20+, Deno, Bun, Cloudflare Workers). The
685
686
  JWKS must be served over HTTPS (localhost is exempt); for a plain-HTTP
686
687
  self-hosted deployment on a trusted network, pass `allowInsecureJwks: true`.
@@ -108,6 +108,7 @@ export type {
108
108
  SandboxProxySecret,
109
109
  SandboxMount,
110
110
  MountCacheConfig,
111
+ MountEncryptionConfig,
111
112
  ContextHubMountConfig,
112
113
  ContextHubMountSpec,
113
114
  GCSMountConfig,
@@ -4,6 +4,7 @@ import type {
4
4
  GitMountRefSpec,
5
5
  GitMountSpec,
6
6
  MountCacheConfig,
7
+ MountEncryptionConfig,
7
8
  SandboxAwsAuthRule,
8
9
  SandboxGcpAuthRule,
9
10
  S3MountSpec,
@@ -98,6 +99,7 @@ export function s3Mount({
98
99
  pathStyle = false,
99
100
  readOnly,
100
101
  cache,
102
+ encryption,
101
103
  }: {
102
104
  id: string;
103
105
  mountPath: string;
@@ -108,6 +110,7 @@ export function s3Mount({
108
110
  pathStyle?: boolean;
109
111
  readOnly?: boolean;
110
112
  cache?: MountCacheConfig;
113
+ encryption?: MountEncryptionConfig;
111
114
  }): S3MountSpec {
112
115
  const mount: S3MountSpec = {
113
116
  id: requireNonEmptyString(id, "id"),
@@ -129,6 +132,11 @@ export function s3Mount({
129
132
  if (cache !== undefined) {
130
133
  mount.cache = { ...cache };
131
134
  }
135
+ if (encryption !== undefined) {
136
+ mount.encryption = {
137
+ kms_key: requireNonEmptyString(encryption.kms_key, "encryption.kms_key"),
138
+ };
139
+ }
132
140
  return mount;
133
141
  }
134
142
 
@@ -603,10 +603,18 @@ export interface S3MountConfig {
603
603
  path_style?: boolean;
604
604
  }
605
605
 
606
+ /** Customer-managed key that uploads through a mount are encrypted with. */
607
+ export interface MountEncryptionConfig {
608
+ /** KMS key ARN in the mount's region; uploads use SSE-KMS with this key. */
609
+ kms_key: string;
610
+ }
611
+
606
612
  /** S3-backed sandbox mount specification. */
607
613
  export interface S3MountSpec extends SandboxBucketMountBase {
608
614
  /** Mount type. */
609
615
  type: "s3";
616
+ /** Optional customer-managed key for uploads. */
617
+ encryption?: MountEncryptionConfig;
610
618
  /** S3 mount configuration. */
611
619
  s3: S3MountConfig;
612
620
  }
@@ -99,7 +99,72 @@ interface Jwk {
99
99
  kty?: string;
100
100
  crv?: string;
101
101
  kid?: string;
102
+ alg?: string;
102
103
  x?: string;
104
+ y?: string;
105
+ n?: string;
106
+ e?: string;
107
+ }
108
+
109
+ interface VerificationKey {
110
+ alg: string;
111
+ key: CryptoKey;
112
+ }
113
+
114
+ interface AlgorithmSpec {
115
+ kty: string;
116
+ crv?: string;
117
+ importParams: AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams;
118
+ verifyParams: AlgorithmIdentifier | RsaPssParams | EcdsaParams;
119
+ }
120
+
121
+ // Every JOSE asymmetric algorithm; the JWKS key picks which one a token may use.
122
+ const ALGORITHMS: Record<string, AlgorithmSpec> = {
123
+ EdDSA: {
124
+ kty: "OKP",
125
+ crv: "Ed25519",
126
+ importParams: { name: "Ed25519" },
127
+ verifyParams: { name: "Ed25519" },
128
+ },
129
+ };
130
+ for (const [bits, curve] of [
131
+ [256, "P-256"],
132
+ [384, "P-384"],
133
+ [512, "P-521"],
134
+ ] as const) {
135
+ const hash = `SHA-${bits}`;
136
+ ALGORITHMS[`RS${bits}`] = {
137
+ kty: "RSA",
138
+ importParams: { name: "RSASSA-PKCS1-v1_5", hash },
139
+ verifyParams: { name: "RSASSA-PKCS1-v1_5" },
140
+ };
141
+ // JWS RSA-PSS uses a salt as long as the hash.
142
+ ALGORITHMS[`PS${bits}`] = {
143
+ kty: "RSA",
144
+ importParams: { name: "RSA-PSS", hash },
145
+ verifyParams: { name: "RSA-PSS", saltLength: bits / 8 },
146
+ };
147
+ // The JWS ECDSA signature is raw r||s, which Web Crypto verifies directly.
148
+ ALGORITHMS[`ES${bits}`] = {
149
+ kty: "EC",
150
+ crv: curve,
151
+ importParams: { name: "ECDSA", namedCurve: curve },
152
+ verifyParams: { name: "ECDSA", hash },
153
+ };
154
+ }
155
+
156
+ const USER_TOKEN_ALGORITHMS = Object.keys(ALGORITHMS);
157
+ const CALLBACK_ALGORITHMS = ["EdDSA"];
158
+
159
+ /** A JWK's algorithm: its `alg` member if supported, else derived from its key type. */
160
+ function jwkAlgorithm(jwk: Jwk): string | undefined {
161
+ if (jwk.alg !== undefined) {
162
+ return USER_TOKEN_ALGORITHMS.includes(jwk.alg) ? jwk.alg : undefined;
163
+ }
164
+ if (jwk.kty === "RSA") return "RS256";
165
+ return USER_TOKEN_ALGORITHMS.find(
166
+ (alg) => ALGORITHMS[alg].kty === jwk.kty && ALGORITHMS[alg].crv === jwk.crv,
167
+ );
103
168
  }
104
169
 
105
170
  function fail(message: string): never {
@@ -202,7 +267,7 @@ function timingSafeEqual(a: string, b: string): boolean {
202
267
  export class SandboxTokenVerifier {
203
268
  private readonly jwksUrl: string;
204
269
  private readonly timeoutMs: number;
205
- private keys = new Map<string, Promise<CryptoKey>>();
270
+ private keys = new Map<string, VerificationKey>();
206
271
  private fetchedAt = 0;
207
272
  private inflight?: Promise<void>;
208
273
 
@@ -233,6 +298,7 @@ export class SandboxTokenVerifier {
233
298
  ): Promise<SandboxUser> {
234
299
  const claims = await this.verify(
235
300
  token,
301
+ USER_TOKEN_ALGORITHMS,
236
302
  serviceHost(options.audience),
237
303
  options.issuer,
238
304
  );
@@ -260,6 +326,7 @@ export class SandboxTokenVerifier {
260
326
  ): Promise<SandboxCallback> {
261
327
  const claims = await this.verify(
262
328
  options.signature,
329
+ CALLBACK_ALGORITHMS,
263
330
  options.aud,
264
331
  options.issuer,
265
332
  );
@@ -293,6 +360,7 @@ export class SandboxTokenVerifier {
293
360
 
294
361
  private async verify(
295
362
  token: string,
363
+ algorithms: string[],
296
364
  audience: AudienceMatcher | undefined,
297
365
  issuer: string | undefined,
298
366
  ): Promise<Claims> {
@@ -308,14 +376,19 @@ export class SandboxTokenVerifier {
308
376
  } catch (e) {
309
377
  fail(`malformed token: ${(e as Error).message}`);
310
378
  }
311
- if (header.alg !== "EdDSA") {
379
+ if (!algorithms.includes(header.alg as string)) {
312
380
  fail(`unexpected signing algorithm: ${JSON.stringify(header.alg)}`);
313
381
  }
314
382
  if (typeof header.kid !== "string" || !header.kid) fail("token has no kid");
315
383
 
316
- const key = await this.key(header.kid);
384
+ const { alg, key } = await this.key(header.kid);
385
+ // The key belongs to one algorithm; the token must claim that one.
386
+ if (header.alg !== alg) {
387
+ fail(`unexpected signing algorithm: ${JSON.stringify(header.alg)}`);
388
+ }
317
389
  const signed = new TextEncoder().encode(`${parts[0]}.${parts[1]}`);
318
- if (!(await subtle().verify({ name: "Ed25519" }, key, signature, signed))) {
390
+ const { verifyParams } = ALGORITHMS[alg];
391
+ if (!(await subtle().verify(verifyParams, key, signature, signed))) {
319
392
  fail("invalid signature");
320
393
  }
321
394
 
@@ -347,7 +420,7 @@ export class SandboxTokenVerifier {
347
420
  return claims;
348
421
  }
349
422
 
350
- private async key(kid: string): Promise<CryptoKey> {
423
+ private async key(kid: string): Promise<VerificationKey> {
351
424
  const age = Date.now() - this.fetchedAt;
352
425
  const fresh = this.keys.has(kid) && age < JWKS_TTL_MS;
353
426
  if (!fresh && (this.fetchedAt === 0 || age >= JWKS_MIN_REFRESH_MS)) {
@@ -356,17 +429,9 @@ export class SandboxTokenVerifier {
356
429
  });
357
430
  await this.inflight;
358
431
  }
359
- const key = this.keys.get(kid);
360
- if (!key) fail(`unknown signing key: ${kid}`);
361
- try {
362
- return await key;
363
- } catch (e) {
364
- fail(
365
- `signing key ${kid} is not a usable Ed25519 key: ${
366
- (e as Error).message
367
- }`,
368
- );
369
- }
432
+ const entry = this.keys.get(kid);
433
+ if (!entry) fail(`unknown signing key: ${kid}`);
434
+ return entry;
370
435
  }
371
436
 
372
437
  private async refresh(): Promise<void> {
@@ -386,20 +451,34 @@ export class SandboxTokenVerifier {
386
451
  if (!Array.isArray(entries)) {
387
452
  fail("invalid JWKS: expected an object with a keys array");
388
453
  }
389
- const keys = new Map<string, Promise<CryptoKey>>();
454
+ const keys = new Map<string, VerificationKey>();
455
+ const webCrypto = subtle();
390
456
  for (const jwk of entries as (Jwk | null)[]) {
391
- if (typeof jwk !== "object" || jwk === null) continue;
392
- if (jwk.kty !== "OKP" || jwk.crv !== "Ed25519" || !jwk.kid || !jwk.x)
457
+ if (typeof jwk !== "object" || jwk === null || !jwk.kid) continue;
458
+ const alg = jwkAlgorithm(jwk);
459
+ if (!alg) continue;
460
+ const { kty, crv, importParams } = ALGORITHMS[alg];
461
+ if (jwk.kty !== kty || jwk.crv !== crv) continue;
462
+ try {
463
+ // Import with the key's own algorithm: Web Crypto fixes the RSA hash here.
464
+ const key = await webCrypto.importKey(
465
+ "jwk",
466
+ {
467
+ kty: jwk.kty,
468
+ crv: jwk.crv,
469
+ x: jwk.x,
470
+ y: jwk.y,
471
+ n: jwk.n,
472
+ e: jwk.e,
473
+ },
474
+ importParams,
475
+ false,
476
+ ["verify"],
477
+ );
478
+ keys.set(jwk.kid, { alg, key });
479
+ } catch {
393
480
  continue;
394
- const imported = subtle().importKey(
395
- "jwk",
396
- { kty: "OKP", crv: "Ed25519", x: jwk.x },
397
- { name: "Ed25519" },
398
- false,
399
- ["verify"],
400
- );
401
- imported.catch(() => undefined);
402
- keys.set(jwk.kid, imported);
481
+ }
403
482
  }
404
483
  this.keys = keys;
405
484
  this.fetchedAt = Date.now();
@@ -1,5 +1,8 @@
1
1
  import {
2
- AgentAddress,
2
+ type AgentAddress,
3
+ addressFromEnv,
4
+ addressFromLrn,
5
+ addressToLrn,
3
6
  EnvAddressError,
4
7
  ensureAgent,
5
8
  envNames,
@@ -47,7 +50,7 @@ function getEnvProject(): string | undefined {
47
50
  */
48
51
  export function resolveFromEnv(): Tier {
49
52
  const project = getEnvProject();
50
- const address = AgentAddress.fromEnv();
53
+ const address = addressFromEnv();
51
54
  if (project && address) {
52
55
  throw new EnvAddressError(
53
56
  "LANGSMITH_AGENT_* and a project are both set in the environment.",
@@ -92,7 +95,7 @@ export function applyToPayload(
92
95
  // is sent. It is parsed again, so a malformed one cannot fail the whole
93
96
  // batch in the backend.
94
97
  try {
95
- address = AgentAddress._fromLrn(payload.address);
98
+ address = addressFromLrn(payload.address);
96
99
  } catch {
97
100
  throw new Error("The run's `address` is not a valid agent address.");
98
101
  }
@@ -103,7 +106,7 @@ export function applyToPayload(
103
106
  const namedProject =
104
107
  payload.session_id != null || payload.session_name != null;
105
108
  if (!address && !update && !namedProject) {
106
- address = AgentAddress.fromEnv();
109
+ address = addressFromEnv();
107
110
  }
108
111
  if (!address) {
109
112
  return;
@@ -112,7 +115,7 @@ export function applyToPayload(
112
115
  "Sending runs to an `address` is in beta and enabled per workspace; a " +
113
116
  "workspace without it rejects the runs.",
114
117
  );
115
- payload.address = address._toLrn();
118
+ payload.address = addressToLrn(address);
116
119
  if (!namedProject) {
117
120
  delete payload.session_name;
118
121
  delete payload.session_id;
@@ -194,6 +194,8 @@ export interface AnnotationQueueRubricItemSchema {
194
194
 
195
195
  description?: string | null;
196
196
 
197
+ feedback_config?: AnnotationQueueRubricItemSchema.FeedbackConfig | null;
198
+
197
199
  feedback_config_id?: string | null;
198
200
 
199
201
  is_assertion?: boolean | null;
@@ -207,6 +209,48 @@ export interface AnnotationQueueRubricItemSchema {
207
209
  value_descriptions?: { [key: string]: string } | null;
208
210
  }
209
211
 
212
+ export namespace AnnotationQueueRubricItemSchema {
213
+ export interface FeedbackConfig {
214
+ id: string;
215
+
216
+ feedback_config: FeedbackConfig.FeedbackConfig;
217
+
218
+ feedback_key: string;
219
+
220
+ modified_at: string;
221
+
222
+ tenant_id: string;
223
+
224
+ is_lower_score_better?: boolean | null;
225
+ }
226
+
227
+ export namespace FeedbackConfig {
228
+ export interface FeedbackConfig {
229
+ /**
230
+ * Enum for feedback types.
231
+ */
232
+ type: 'continuous' | 'categorical' | 'freeform';
233
+
234
+ categories?: Array<FeedbackConfig.Category> | null;
235
+
236
+ max?: number | null;
237
+
238
+ min?: number | null;
239
+ }
240
+
241
+ export namespace FeedbackConfig {
242
+ /**
243
+ * Specific value and label pair for feedback
244
+ */
245
+ export interface Category {
246
+ value: number;
247
+
248
+ label?: string | null;
249
+ }
250
+ }
251
+ }
252
+ }
253
+
210
254
  /**
211
255
  * AnnotationQueue schema.
212
256
  */
@@ -519,7 +563,7 @@ export interface AnnotationQueueUpdateParams {
519
563
 
520
564
  description?: string | null;
521
565
 
522
- enable_reservations?: boolean;
566
+ enable_reservations?: boolean | DatasetsAPI.Missing;
523
567
 
524
568
  metadata?: { [key: string]: unknown } | DatasetsAPI.Missing | null;
525
569
 
@@ -527,7 +571,7 @@ export interface AnnotationQueueUpdateParams {
527
571
 
528
572
  num_reviewers_per_item?: number | DatasetsAPI.Missing | null;
529
573
 
530
- reservation_minutes?: number | null;
574
+ reservation_minutes?: number | DatasetsAPI.Missing | null;
531
575
 
532
576
  reviewer_access_mode?: 'any' | 'assigned' | null;
533
577
 
@@ -41,6 +41,10 @@ export class Runs extends APIResource {
41
41
  * start_time. Supports filters, cursor pagination, and `selects` to select fields
42
42
  * to return.
43
43
  *
44
+ * When `ai_search` is set, `Accept: text/event-stream` is required; requests
45
+ * without it return 406. AI search is unavailable on deployments that route
46
+ * queries to the v1 backend and returns 501 there.
47
+ *
44
48
  * Self-hosted deployments require LangSmith `v0.16` or later.
45
49
  *
46
50
  * @example
@@ -872,6 +876,15 @@ export interface RunGetURLParams {
872
876
  }
873
877
 
874
878
  export interface RunQueryV2Params extends ItemsCursorPostPaginationParams {
879
+ /**
880
+ * Body param: `ai_search` is a plain-language criterion evaluated against the
881
+ * messages from the agent trajectory scoped to the run. AND-ed with the ordinary
882
+ * filters. Requires semantic filtering enabled for the deployment. Must contain
883
+ * nonempty text of at most 2000 UTF-8 bytes. Not supported on public dataset
884
+ * queries.
885
+ */
886
+ ai_search?: string;
887
+
875
888
  /**
876
889
  * Body param: `filter` narrows results to runs matching this LangSmith filter
877
890
  * expression, evaluated against each individual run. For example: and(eq(run_type,
@@ -972,7 +985,8 @@ export interface RunQueryV2Params extends ItemsCursorPostPaginationParams {
972
985
  tree_filter?: string;
973
986
 
974
987
  /**
975
- * Header param: application/json or text/event-stream
988
+ * Header param: application/json, or text/event-stream (required when ai_search is
989
+ * set)
976
990
  */
977
991
  Accept?: string;
978
992
  }
@@ -404,6 +404,8 @@ export namespace BoxCreateParams {
404
404
 
405
405
  contexthub?: SandboxapiS3BucketMountSpec.Contexthub;
406
406
 
407
+ encryption?: SandboxapiS3BucketMountSpec.Encryption;
408
+
407
409
  gcs?: SandboxapiS3BucketMountSpec.Gcs;
408
410
 
409
411
  git?: SandboxapiS3BucketMountSpec.Git;
@@ -445,6 +447,14 @@ export namespace BoxCreateParams {
445
447
  initial_pull_only?: boolean;
446
448
  }
447
449
 
450
+ export interface Encryption {
451
+ /**
452
+ * KMSKey is the key to encrypt uploads with. S3 mounts take a KMS key ARN in the
453
+ * mount's region.
454
+ */
455
+ kms_key: string;
456
+ }
457
+
448
458
  export interface Gcs {
449
459
  bucket: string;
450
460
 
@@ -481,6 +491,8 @@ export namespace BoxCreateParams {
481
491
 
482
492
  contexthub?: SandboxapiGcsBucketMountSpec.Contexthub;
483
493
 
494
+ encryption?: SandboxapiGcsBucketMountSpec.Encryption;
495
+
484
496
  git?: SandboxapiGcsBucketMountSpec.Git;
485
497
 
486
498
  read_only?: boolean;
@@ -516,6 +528,14 @@ export namespace BoxCreateParams {
516
528
  initial_pull_only?: boolean;
517
529
  }
518
530
 
531
+ export interface Encryption {
532
+ /**
533
+ * KMSKey is the key to encrypt uploads with. S3 mounts take a KMS key ARN in the
534
+ * mount's region.
535
+ */
536
+ kms_key: string;
537
+ }
538
+
519
539
  export interface Git {
520
540
  remote_url: string;
521
541
 
@@ -558,6 +578,8 @@ export namespace BoxCreateParams {
558
578
 
559
579
  contexthub?: SandboxapiGitRepoMountSpec.Contexthub;
560
580
 
581
+ encryption?: SandboxapiGitRepoMountSpec.Encryption;
582
+
561
583
  gcs?: SandboxapiGitRepoMountSpec.Gcs;
562
584
 
563
585
  read_only?: boolean;
@@ -603,6 +625,14 @@ export namespace BoxCreateParams {
603
625
  initial_pull_only?: boolean;
604
626
  }
605
627
 
628
+ export interface Encryption {
629
+ /**
630
+ * KMSKey is the key to encrypt uploads with. S3 mounts take a KMS key ARN in the
631
+ * mount's region.
632
+ */
633
+ kms_key: string;
634
+ }
635
+
606
636
  export interface Gcs {
607
637
  bucket: string;
608
638
 
@@ -633,6 +663,8 @@ export namespace BoxCreateParams {
633
663
 
634
664
  cache?: SandboxapiContextHubRepoMountSpec.Cache;
635
665
 
666
+ encryption?: SandboxapiContextHubRepoMountSpec.Encryption;
667
+
636
668
  gcs?: SandboxapiContextHubRepoMountSpec.Gcs;
637
669
 
638
670
  git?: SandboxapiContextHubRepoMountSpec.Git;
@@ -664,6 +696,14 @@ export namespace BoxCreateParams {
664
696
  writeback_seconds?: number;
665
697
  }
666
698
 
699
+ export interface Encryption {
700
+ /**
701
+ * KMSKey is the key to encrypt uploads with. S3 mounts take a KMS key ARN in the
702
+ * mount's region.
703
+ */
704
+ kms_key: string;
705
+ }
706
+
667
707
  export interface Gcs {
668
708
  bucket: string;
669
709