langsmith 0.5.26 → 0.6.0
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 +44 -18
- package/dist/client.d.ts +40 -3
- package/dist/client.js +44 -18
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/utils/serialize_worker.cjs +1 -2
- package/dist/utils/serialize_worker.d.ts +1 -2
- package/dist/utils/serialize_worker.js +1 -2
- package/package.json +1 -1
package/dist/client.cjs
CHANGED
|
@@ -51,6 +51,12 @@ const fsUtils = __importStar(require("./utils/fs.cjs"));
|
|
|
51
51
|
const fetch_js_1 = require("./singletons/fetch.cjs");
|
|
52
52
|
const index_js_3 = require("./utils/fast-safe-stringify/index.cjs");
|
|
53
53
|
const serialize_worker_js_1 = require("./utils/serialize_worker.cjs");
|
|
54
|
+
function assertPullPublicPromptAllowed(promptIdentifier, dangerouslyPullPublicPrompt) {
|
|
55
|
+
const [owner] = (0, prompts_js_1.parseHubIdentifier)(promptIdentifier);
|
|
56
|
+
if (owner !== "-" && !dangerouslyPullPublicPrompt) {
|
|
57
|
+
throw new Error("Pulling a public prompt by owner/name is disabled by default because prompts may contain untrusted serialized LangChain objects. If you trust this prompt, set `dangerouslyPullPublicPrompt: true` to acknowledge the risk.");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
54
60
|
/**
|
|
55
61
|
* Catches timestamps without a timezone suffix.
|
|
56
62
|
*/
|
|
@@ -190,19 +196,11 @@ class AutoBatchQueue {
|
|
|
190
196
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
|
|
191
197
|
itemPromiseResolve = resolve;
|
|
192
198
|
});
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
// structural estimate instead. The estimate is only used for soft
|
|
199
|
-
// memory accounting (queue size limit and downstream async caller
|
|
200
|
-
// memory tracking), never for anything correctness-critical -- the
|
|
201
|
-
// real serialization still happens later, off the hot path, when the
|
|
202
|
-
// batch is assembled for sending.
|
|
203
|
-
const size = (0, env_js_1.getLangSmithEnvironmentVariable)("PERF_OPTIMIZATION") === "true"
|
|
204
|
-
? (0, index_js_3.estimateSerializedSize)(item.item).size
|
|
205
|
-
: (0, index_js_3.serialize)(item.item, `Serializing run with id: ${item.item.id}`).length;
|
|
199
|
+
// Use a cheap structural estimate for soft memory accounting (queue size
|
|
200
|
+
// limit and downstream async caller memory tracking). The exact
|
|
201
|
+
// serialization still happens later, off the hot path, when the batch is
|
|
202
|
+
// assembled for sending.
|
|
203
|
+
const size = (0, index_js_3.estimateSerializedSize)(item.item).size;
|
|
206
204
|
// Check if adding this item would exceed the size limit
|
|
207
205
|
// Allow the run if the queue is empty (to support large single traces)
|
|
208
206
|
if (this.sizeBytes + size > this.maxSizeBytes && this.items.length > 0) {
|
|
@@ -274,11 +272,9 @@ class Client {
|
|
|
274
272
|
}
|
|
275
273
|
/**
|
|
276
274
|
* Serialize a payload for tracing, optionally offloading the work to a
|
|
277
|
-
* Node worker thread when
|
|
278
|
-
* supports worker_threads.
|
|
275
|
+
* Node worker thread when the runtime supports worker_threads.
|
|
279
276
|
*
|
|
280
277
|
* Falls back to synchronous serialization when:
|
|
281
|
-
* - the perf flag is off
|
|
282
278
|
* - manualFlushMode is enabled (serverless: worker boot cost > benefit)
|
|
283
279
|
* - worker_threads is unavailable (non-Node runtimes)
|
|
284
280
|
* - the payload contains values that can't be structured-cloned across
|
|
@@ -294,8 +290,7 @@ class Client {
|
|
|
294
290
|
});
|
|
295
291
|
}
|
|
296
292
|
async _serializeBody(payload, errorContext) {
|
|
297
|
-
|
|
298
|
-
if (!perfOptIn || this.manualFlushMode) {
|
|
293
|
+
if (this.manualFlushMode) {
|
|
299
294
|
return (0, index_js_3.serialize)(payload, errorContext);
|
|
300
295
|
}
|
|
301
296
|
// Shape-aware gate: worker offload pays for itself only when the
|
|
@@ -4498,7 +4493,24 @@ class Client {
|
|
|
4498
4493
|
hub_model_provider: result.model_provider,
|
|
4499
4494
|
};
|
|
4500
4495
|
}
|
|
4496
|
+
/**
|
|
4497
|
+
* Pull a prompt commit from the LangSmith API.
|
|
4498
|
+
*
|
|
4499
|
+
* Public prompts referenced by owner/name cross a trust boundary because the
|
|
4500
|
+
* prompt manifest may contain serialized LangChain objects and configuration
|
|
4501
|
+
* that affect runtime behavior. For example, a prompt can intentionally
|
|
4502
|
+
* configure a model with a custom base URL, headers, model name, or other
|
|
4503
|
+
* constructor arguments. These are supported features, but they also mean the
|
|
4504
|
+
* prompt contents should be treated as executable configuration rather than
|
|
4505
|
+
* plain text.
|
|
4506
|
+
*
|
|
4507
|
+
* Set `dangerouslyPullPublicPrompt: true` only after reviewing and trusting
|
|
4508
|
+
* the prompt contents, not merely the publishing account. Prompts from your
|
|
4509
|
+
* own or your organization's account can still be unsafe if that account or
|
|
4510
|
+
* prompt was compromised.
|
|
4511
|
+
*/
|
|
4501
4512
|
async pullPromptCommit(promptIdentifier, options) {
|
|
4513
|
+
assertPullPublicPromptAllowed(promptIdentifier, options?.dangerouslyPullPublicPrompt);
|
|
4502
4514
|
// Check cache first if not skipped
|
|
4503
4515
|
const refreshFunc = this._fetchPromptFromApi.bind(this, promptIdentifier, options);
|
|
4504
4516
|
if (!options?.skipCache && this._promptCache) {
|
|
@@ -4518,12 +4530,26 @@ class Client {
|
|
|
4518
4530
|
/**
|
|
4519
4531
|
* This method should not be used directly, use `import { pull } from "langchain/hub"` instead.
|
|
4520
4532
|
* Using this method directly returns the JSON string of the prompt rather than a LangChain object.
|
|
4533
|
+
*
|
|
4534
|
+
* Public prompts referenced by owner/name cross a trust boundary because the
|
|
4535
|
+
* prompt manifest may contain serialized LangChain objects and configuration
|
|
4536
|
+
* that affect runtime behavior. For example, a prompt can intentionally
|
|
4537
|
+
* configure a model with a custom base URL, headers, model name, or other
|
|
4538
|
+
* constructor arguments. These are supported features, but they also mean the
|
|
4539
|
+
* prompt contents should be treated as executable configuration rather than
|
|
4540
|
+
* plain text.
|
|
4541
|
+
*
|
|
4542
|
+
* Set `dangerouslyPullPublicPrompt: true` only after reviewing and trusting
|
|
4543
|
+
* the prompt contents, not merely the publishing account. Prompts from your
|
|
4544
|
+
* own or your organization's account can still be unsafe if that account or
|
|
4545
|
+
* prompt was compromised.
|
|
4521
4546
|
* @private
|
|
4522
4547
|
*/
|
|
4523
4548
|
async _pullPrompt(promptIdentifier, options) {
|
|
4524
4549
|
const promptObject = await this.pullPromptCommit(promptIdentifier, {
|
|
4525
4550
|
includeModel: options?.includeModel,
|
|
4526
4551
|
skipCache: options?.skipCache,
|
|
4552
|
+
dangerouslyPullPublicPrompt: options?.dangerouslyPullPublicPrompt,
|
|
4527
4553
|
});
|
|
4528
4554
|
const prompt = JSON.stringify(promptObject.manifest);
|
|
4529
4555
|
return prompt;
|
package/dist/client.d.ts
CHANGED
|
@@ -442,11 +442,9 @@ export declare class Client implements LangSmithTracingClientInterface {
|
|
|
442
442
|
private get _fetch();
|
|
443
443
|
/**
|
|
444
444
|
* Serialize a payload for tracing, optionally offloading the work to a
|
|
445
|
-
* Node worker thread when
|
|
446
|
-
* supports worker_threads.
|
|
445
|
+
* Node worker thread when the runtime supports worker_threads.
|
|
447
446
|
*
|
|
448
447
|
* Falls back to synchronous serialization when:
|
|
449
|
-
* - the perf flag is off
|
|
450
448
|
* - manualFlushMode is enabled (serverless: worker boot cost > benefit)
|
|
451
449
|
* - worker_threads is unavailable (non-Node runtimes)
|
|
452
450
|
* - the payload contains values that can't be structured-cloned across
|
|
@@ -1322,18 +1320,57 @@ export declare class Client implements LangSmithTracingClientInterface {
|
|
|
1322
1320
|
* Fetch a prompt commit directly from the API (bypassing cache).
|
|
1323
1321
|
*/
|
|
1324
1322
|
private _fetchPromptFromApi;
|
|
1323
|
+
/**
|
|
1324
|
+
* Pull a prompt commit from the LangSmith API.
|
|
1325
|
+
*
|
|
1326
|
+
* Public prompts referenced by owner/name cross a trust boundary because the
|
|
1327
|
+
* prompt manifest may contain serialized LangChain objects and configuration
|
|
1328
|
+
* that affect runtime behavior. For example, a prompt can intentionally
|
|
1329
|
+
* configure a model with a custom base URL, headers, model name, or other
|
|
1330
|
+
* constructor arguments. These are supported features, but they also mean the
|
|
1331
|
+
* prompt contents should be treated as executable configuration rather than
|
|
1332
|
+
* plain text.
|
|
1333
|
+
*
|
|
1334
|
+
* Set `dangerouslyPullPublicPrompt: true` only after reviewing and trusting
|
|
1335
|
+
* the prompt contents, not merely the publishing account. Prompts from your
|
|
1336
|
+
* own or your organization's account can still be unsafe if that account or
|
|
1337
|
+
* prompt was compromised.
|
|
1338
|
+
*/
|
|
1325
1339
|
pullPromptCommit(promptIdentifier: string, options?: {
|
|
1326
1340
|
includeModel?: boolean;
|
|
1327
1341
|
skipCache?: boolean;
|
|
1342
|
+
/**
|
|
1343
|
+
* Set to `true` to allow pulling a public prompt by owner/name, for
|
|
1344
|
+
* example `username/promptname`. Defaults to `false`.
|
|
1345
|
+
*/
|
|
1346
|
+
dangerouslyPullPublicPrompt?: boolean;
|
|
1328
1347
|
}): Promise<PromptCommit>;
|
|
1329
1348
|
/**
|
|
1330
1349
|
* This method should not be used directly, use `import { pull } from "langchain/hub"` instead.
|
|
1331
1350
|
* Using this method directly returns the JSON string of the prompt rather than a LangChain object.
|
|
1351
|
+
*
|
|
1352
|
+
* Public prompts referenced by owner/name cross a trust boundary because the
|
|
1353
|
+
* prompt manifest may contain serialized LangChain objects and configuration
|
|
1354
|
+
* that affect runtime behavior. For example, a prompt can intentionally
|
|
1355
|
+
* configure a model with a custom base URL, headers, model name, or other
|
|
1356
|
+
* constructor arguments. These are supported features, but they also mean the
|
|
1357
|
+
* prompt contents should be treated as executable configuration rather than
|
|
1358
|
+
* plain text.
|
|
1359
|
+
*
|
|
1360
|
+
* Set `dangerouslyPullPublicPrompt: true` only after reviewing and trusting
|
|
1361
|
+
* the prompt contents, not merely the publishing account. Prompts from your
|
|
1362
|
+
* own or your organization's account can still be unsafe if that account or
|
|
1363
|
+
* prompt was compromised.
|
|
1332
1364
|
* @private
|
|
1333
1365
|
*/
|
|
1334
1366
|
_pullPrompt(promptIdentifier: string, options?: {
|
|
1335
1367
|
includeModel?: boolean;
|
|
1336
1368
|
skipCache?: boolean;
|
|
1369
|
+
/**
|
|
1370
|
+
* Set to `true` to allow pulling a public prompt by owner/name, for
|
|
1371
|
+
* example `username/promptname`. Defaults to `false`.
|
|
1372
|
+
*/
|
|
1373
|
+
dangerouslyPullPublicPrompt?: boolean;
|
|
1337
1374
|
}): Promise<any>;
|
|
1338
1375
|
pushPrompt(promptIdentifier: string, options?: {
|
|
1339
1376
|
object?: any;
|
package/dist/client.js
CHANGED
|
@@ -14,6 +14,12 @@ import * as fsUtils from "./utils/fs.js";
|
|
|
14
14
|
import { _shouldStreamForGlobalFetchImplementation, _getFetchImplementation, } from "./singletons/fetch.js";
|
|
15
15
|
import { serialize as serializePayloadForTracing, estimateSerializedSize, } from "./utils/fast-safe-stringify/index.js";
|
|
16
16
|
import { getSharedSerializeWorker, hasLargeString, } from "./utils/serialize_worker.js";
|
|
17
|
+
function assertPullPublicPromptAllowed(promptIdentifier, dangerouslyPullPublicPrompt) {
|
|
18
|
+
const [owner] = parseHubIdentifier(promptIdentifier);
|
|
19
|
+
if (owner !== "-" && !dangerouslyPullPublicPrompt) {
|
|
20
|
+
throw new Error("Pulling a public prompt by owner/name is disabled by default because prompts may contain untrusted serialized LangChain objects. If you trust this prompt, set `dangerouslyPullPublicPrompt: true` to acknowledge the risk.");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
17
23
|
/**
|
|
18
24
|
* Catches timestamps without a timezone suffix.
|
|
19
25
|
*/
|
|
@@ -153,19 +159,11 @@ export class AutoBatchQueue {
|
|
|
153
159
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
|
|
154
160
|
itemPromiseResolve = resolve;
|
|
155
161
|
});
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
// structural estimate instead. The estimate is only used for soft
|
|
162
|
-
// memory accounting (queue size limit and downstream async caller
|
|
163
|
-
// memory tracking), never for anything correctness-critical -- the
|
|
164
|
-
// real serialization still happens later, off the hot path, when the
|
|
165
|
-
// batch is assembled for sending.
|
|
166
|
-
const size = getLangSmithEnvironmentVariable("PERF_OPTIMIZATION") === "true"
|
|
167
|
-
? estimateSerializedSize(item.item).size
|
|
168
|
-
: serializePayloadForTracing(item.item, `Serializing run with id: ${item.item.id}`).length;
|
|
162
|
+
// Use a cheap structural estimate for soft memory accounting (queue size
|
|
163
|
+
// limit and downstream async caller memory tracking). The exact
|
|
164
|
+
// serialization still happens later, off the hot path, when the batch is
|
|
165
|
+
// assembled for sending.
|
|
166
|
+
const size = estimateSerializedSize(item.item).size;
|
|
169
167
|
// Check if adding this item would exceed the size limit
|
|
170
168
|
// Allow the run if the queue is empty (to support large single traces)
|
|
171
169
|
if (this.sizeBytes + size > this.maxSizeBytes && this.items.length > 0) {
|
|
@@ -236,11 +234,9 @@ export class Client {
|
|
|
236
234
|
}
|
|
237
235
|
/**
|
|
238
236
|
* Serialize a payload for tracing, optionally offloading the work to a
|
|
239
|
-
* Node worker thread when
|
|
240
|
-
* supports worker_threads.
|
|
237
|
+
* Node worker thread when the runtime supports worker_threads.
|
|
241
238
|
*
|
|
242
239
|
* Falls back to synchronous serialization when:
|
|
243
|
-
* - the perf flag is off
|
|
244
240
|
* - manualFlushMode is enabled (serverless: worker boot cost > benefit)
|
|
245
241
|
* - worker_threads is unavailable (non-Node runtimes)
|
|
246
242
|
* - the payload contains values that can't be structured-cloned across
|
|
@@ -256,8 +252,7 @@ export class Client {
|
|
|
256
252
|
});
|
|
257
253
|
}
|
|
258
254
|
async _serializeBody(payload, errorContext) {
|
|
259
|
-
|
|
260
|
-
if (!perfOptIn || this.manualFlushMode) {
|
|
255
|
+
if (this.manualFlushMode) {
|
|
261
256
|
return serializePayloadForTracing(payload, errorContext);
|
|
262
257
|
}
|
|
263
258
|
// Shape-aware gate: worker offload pays for itself only when the
|
|
@@ -4460,7 +4455,24 @@ export class Client {
|
|
|
4460
4455
|
hub_model_provider: result.model_provider,
|
|
4461
4456
|
};
|
|
4462
4457
|
}
|
|
4458
|
+
/**
|
|
4459
|
+
* Pull a prompt commit from the LangSmith API.
|
|
4460
|
+
*
|
|
4461
|
+
* Public prompts referenced by owner/name cross a trust boundary because the
|
|
4462
|
+
* prompt manifest may contain serialized LangChain objects and configuration
|
|
4463
|
+
* that affect runtime behavior. For example, a prompt can intentionally
|
|
4464
|
+
* configure a model with a custom base URL, headers, model name, or other
|
|
4465
|
+
* constructor arguments. These are supported features, but they also mean the
|
|
4466
|
+
* prompt contents should be treated as executable configuration rather than
|
|
4467
|
+
* plain text.
|
|
4468
|
+
*
|
|
4469
|
+
* Set `dangerouslyPullPublicPrompt: true` only after reviewing and trusting
|
|
4470
|
+
* the prompt contents, not merely the publishing account. Prompts from your
|
|
4471
|
+
* own or your organization's account can still be unsafe if that account or
|
|
4472
|
+
* prompt was compromised.
|
|
4473
|
+
*/
|
|
4463
4474
|
async pullPromptCommit(promptIdentifier, options) {
|
|
4475
|
+
assertPullPublicPromptAllowed(promptIdentifier, options?.dangerouslyPullPublicPrompt);
|
|
4464
4476
|
// Check cache first if not skipped
|
|
4465
4477
|
const refreshFunc = this._fetchPromptFromApi.bind(this, promptIdentifier, options);
|
|
4466
4478
|
if (!options?.skipCache && this._promptCache) {
|
|
@@ -4480,12 +4492,26 @@ export class Client {
|
|
|
4480
4492
|
/**
|
|
4481
4493
|
* This method should not be used directly, use `import { pull } from "langchain/hub"` instead.
|
|
4482
4494
|
* Using this method directly returns the JSON string of the prompt rather than a LangChain object.
|
|
4495
|
+
*
|
|
4496
|
+
* Public prompts referenced by owner/name cross a trust boundary because the
|
|
4497
|
+
* prompt manifest may contain serialized LangChain objects and configuration
|
|
4498
|
+
* that affect runtime behavior. For example, a prompt can intentionally
|
|
4499
|
+
* configure a model with a custom base URL, headers, model name, or other
|
|
4500
|
+
* constructor arguments. These are supported features, but they also mean the
|
|
4501
|
+
* prompt contents should be treated as executable configuration rather than
|
|
4502
|
+
* plain text.
|
|
4503
|
+
*
|
|
4504
|
+
* Set `dangerouslyPullPublicPrompt: true` only after reviewing and trusting
|
|
4505
|
+
* the prompt contents, not merely the publishing account. Prompts from your
|
|
4506
|
+
* own or your organization's account can still be unsafe if that account or
|
|
4507
|
+
* prompt was compromised.
|
|
4483
4508
|
* @private
|
|
4484
4509
|
*/
|
|
4485
4510
|
async _pullPrompt(promptIdentifier, options) {
|
|
4486
4511
|
const promptObject = await this.pullPromptCommit(promptIdentifier, {
|
|
4487
4512
|
includeModel: options?.includeModel,
|
|
4488
4513
|
skipCache: options?.skipCache,
|
|
4514
|
+
dangerouslyPullPublicPrompt: options?.dangerouslyPullPublicPrompt,
|
|
4489
4515
|
});
|
|
4490
4516
|
const prompt = JSON.stringify(promptObject.manifest);
|
|
4491
4517
|
return prompt;
|
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 pnpm bump-version
|
|
21
|
-
exports.__version__ = "0.
|
|
21
|
+
exports.__version__ = "0.6.0";
|
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.
|
|
8
|
+
export declare const __version__ = "0.6.0";
|
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 pnpm bump-version
|
|
8
|
-
export const __version__ = "0.
|
|
8
|
+
export const __version__ = "0.6.0";
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Off-thread serialization using Node worker_threads.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* synchronous serialize() when:
|
|
5
|
+
* Falls back silently to synchronous serialize() when:
|
|
7
6
|
* - worker_threads is unavailable (browsers, Deno, Bun without compat,
|
|
8
7
|
* Cloudflare Workers, Vercel Edge, React Native)
|
|
9
8
|
* - the worker cannot be constructed (bundler/runtime constraints)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Off-thread serialization using Node worker_threads.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* synchronous serialize() when:
|
|
4
|
+
* Falls back silently to synchronous serialize() when:
|
|
6
5
|
* - worker_threads is unavailable (browsers, Deno, Bun without compat,
|
|
7
6
|
* Cloudflare Workers, Vercel Edge, React Native)
|
|
8
7
|
* - the worker cannot be constructed (bundler/runtime constraints)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Off-thread serialization using Node worker_threads.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* synchronous serialize() when:
|
|
4
|
+
* Falls back silently to synchronous serialize() when:
|
|
6
5
|
* - worker_threads is unavailable (browsers, Deno, Bun without compat,
|
|
7
6
|
* Cloudflare Workers, Vercel Edge, React Native)
|
|
8
7
|
* - the worker cannot be constructed (bundler/runtime constraints)
|