langsmith 0.8.12 → 0.10.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/_openapi_client/client.cjs +1 -1
- package/dist/_openapi_client/client.d.ts +2 -2
- package/dist/_openapi_client/client.js +1 -1
- package/dist/_openapi_client/internal/detect-platform.cjs +1 -1
- package/dist/_openapi_client/internal/detect-platform.js +1 -1
- package/dist/_openapi_client/resources/annotation-queues/annotation-queues.d.ts +1 -0
- package/dist/_openapi_client/resources/index.d.ts +1 -1
- package/dist/_openapi_client/resources/issues.cjs +1 -1
- package/dist/_openapi_client/resources/issues.d.ts +18 -1
- package/dist/_openapi_client/resources/issues.js +1 -1
- package/dist/_openapi_client/resources/online-evaluators.d.ts +2 -2
- package/dist/_openapi_client/resources/sandboxes/boxes.cjs +20 -3
- package/dist/_openapi_client/resources/sandboxes/boxes.d.ts +40 -9
- package/dist/_openapi_client/resources/sandboxes/boxes.js +20 -3
- package/dist/_openapi_client/resources/sandboxes/sandboxes.d.ts +46 -3
- package/dist/_openapi_client/resources/sandboxes/snapshots.cjs +6 -2
- package/dist/_openapi_client/resources/sandboxes/snapshots.d.ts +16 -6
- package/dist/_openapi_client/resources/sandboxes/snapshots.js +6 -2
- package/dist/client.cjs +56 -83
- package/dist/client.d.ts +16 -14
- package/dist/client.js +56 -83
- package/dist/env.cjs +14 -1
- package/dist/env.d.ts +9 -0
- package/dist/env.js +12 -0
- package/dist/evaluation/evaluate_comparative.cjs +2 -0
- package/dist/evaluation/evaluate_comparative.js +2 -0
- package/dist/experimental/vercel/telemetry.cjs +19 -6
- package/dist/experimental/vercel/telemetry.js +17 -4
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/run_trees.cjs +19 -2
- package/dist/run_trees.d.ts +12 -0
- package/dist/run_trees.js +19 -2
- package/dist/schemas.d.ts +2 -0
- package/dist/singletons/constants.cjs +7 -1
- package/dist/singletons/constants.d.ts +3 -0
- package/dist/singletons/constants.js +5 -0
- package/dist/traceable.cjs +46 -15
- package/dist/traceable.js +48 -17
- package/dist/utils/_uuid.cjs +11 -19
- package/dist/utils/_uuid.d.ts +7 -7
- package/dist/utils/_uuid.js +11 -19
- package/dist/utils/env.cjs +18 -7
- package/dist/utils/env.js +18 -7
- package/dist/utils/redaction.cjs +38 -0
- package/dist/utils/redaction.d.ts +10 -0
- package/dist/utils/redaction.js +33 -0
- package/dist/utils/sampling.cjs +34 -0
- package/dist/utils/sampling.d.ts +10 -0
- package/dist/utils/sampling.js +30 -0
- package/dist/wrappers/anthropic.cjs +21 -24
- package/dist/wrappers/anthropic.js +21 -24
- package/dist/wrappers/openai_agents.cjs +2 -1
- package/dist/wrappers/openai_agents.js +2 -1
- package/package.json +1 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic trace sampling, kept consistent across LangSmith SDKs.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Decide whether `identifier` is sampled in at `samplingRate`.
|
|
6
|
+
*
|
|
7
|
+
* The decision is a pure function of the identifier, so every process and
|
|
8
|
+
* every SDK agrees on it, and a run's create and patch never disagree.
|
|
9
|
+
*/
|
|
10
|
+
export declare const isSampledById: (identifier: string | null | undefined, samplingRate: number | undefined) => boolean;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic trace sampling, kept consistent across LangSmith SDKs.
|
|
3
|
+
*/
|
|
4
|
+
import { XXH3_128 } from "./xxhash/xxhash.js";
|
|
5
|
+
const SAMPLING_HASH_MODULUS = 1000000n;
|
|
6
|
+
// Reused across calls: constructing a TextEncoder per hash costs more than the
|
|
7
|
+
// hash itself.
|
|
8
|
+
const encoder = new TextEncoder();
|
|
9
|
+
/**
|
|
10
|
+
* Decide whether `identifier` is sampled in at `samplingRate`.
|
|
11
|
+
*
|
|
12
|
+
* The decision is a pure function of the identifier, so every process and
|
|
13
|
+
* every SDK agrees on it, and a run's create and patch never disagree.
|
|
14
|
+
*/
|
|
15
|
+
export const isSampledById = (identifier, samplingRate) => {
|
|
16
|
+
if (samplingRate === undefined || samplingRate >= 1) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
if (samplingRate <= 0) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (identifier == null) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
// XXH3-128 over the UTF-8 bytes, matching the Python SDK's `xxhash.xxh3_128`.
|
|
26
|
+
// The identifier is sampled in when its fraction of the modulus falls below
|
|
27
|
+
// the rate, which is also expressed in [0, 1).
|
|
28
|
+
const bucket = XXH3_128(encoder.encode(identifier.toLowerCase())) % SAMPLING_HASH_MODULUS;
|
|
29
|
+
return Number(bucket) / Number(SAMPLING_HASH_MODULUS) < samplingRate;
|
|
30
|
+
};
|
|
@@ -5,7 +5,7 @@ exports.createUsageMetadata = createUsageMetadata;
|
|
|
5
5
|
const anthropic_managed_js_1 = require("./utils/anthropic_managed.cjs");
|
|
6
6
|
const traceable_js_1 = require("../traceable.cjs");
|
|
7
7
|
const usage_js_1 = require("../utils/usage.cjs");
|
|
8
|
-
const
|
|
8
|
+
const redaction_js_1 = require("../utils/redaction.cjs");
|
|
9
9
|
const TRACED_INVOCATION_KEYS = ["top_k", "top_p", "stream", "thinking"];
|
|
10
10
|
/** Keys of an MCP server definition that are safe to trace. */
|
|
11
11
|
const MCP_SERVER_SAFE_KEYS = new Set([
|
|
@@ -14,27 +14,20 @@ const MCP_SERVER_SAFE_KEYS = new Set([
|
|
|
14
14
|
"url",
|
|
15
15
|
"tool_configuration",
|
|
16
16
|
]);
|
|
17
|
-
/**
|
|
18
|
-
* Mask credentials in `mcp_servers` before tracing. Anything outside
|
|
19
|
-
* {@link MCP_SERVER_SAFE_KEYS} keeps its name but gets
|
|
20
|
-
* {@link SECRET_PLACEHOLDER} as its value, so the trace shows the field was set
|
|
21
|
-
* without exposing it, and fields the API adds later are masked by default.
|
|
22
|
-
*
|
|
23
|
-
* Returns new objects; the caller's are also sent to Anthropic.
|
|
24
|
-
*/
|
|
17
|
+
/** Mask `mcp_servers` credentials outside {@link MCP_SERVER_SAFE_KEYS}. */
|
|
25
18
|
function redactMcpServers(servers) {
|
|
26
19
|
if (!Array.isArray(servers))
|
|
27
20
|
return servers;
|
|
28
|
-
return servers.map((server) =>
|
|
29
|
-
if (typeof server !== "object" || server == null || Array.isArray(server)) {
|
|
30
|
-
return server;
|
|
31
|
-
}
|
|
32
|
-
return Object.fromEntries(Object.entries(server).map(([key, value]) => [
|
|
33
|
-
key,
|
|
34
|
-
MCP_SERVER_SAFE_KEYS.has(key) ? value : index_js_1.SECRET_PLACEHOLDER,
|
|
35
|
-
]));
|
|
36
|
-
});
|
|
21
|
+
return servers.map((server) => (0, redaction_js_1.redactOutside)(server, MCP_SERVER_SAFE_KEYS));
|
|
37
22
|
}
|
|
23
|
+
/** Request-transport keys that are credentials by construction. */
|
|
24
|
+
const TRANSPORT_SECRET_KEYS = new Set([
|
|
25
|
+
"headers",
|
|
26
|
+
"query",
|
|
27
|
+
"extra_headers",
|
|
28
|
+
"extra_body",
|
|
29
|
+
"extra_query",
|
|
30
|
+
]);
|
|
38
31
|
/**
|
|
39
32
|
* Create usage metadata from Anthropic's token usage format.
|
|
40
33
|
*/
|
|
@@ -246,17 +239,18 @@ const wrapAnthropic = (anthropic, options) => {
|
|
|
246
239
|
...options,
|
|
247
240
|
metadata: restMetadata,
|
|
248
241
|
};
|
|
249
|
-
/**
|
|
250
|
-
|
|
251
|
-
* This provides parity with the Python SDK behavior and enables system prompts
|
|
252
|
-
* to be viewed and edited in the LangSmith playground.
|
|
253
|
-
*/
|
|
254
|
-
function processTracedInputs(params) {
|
|
242
|
+
/** Mask credentials and surface `system` as a message the playground can edit. */
|
|
243
|
+
function redactAnthropicParams(params) {
|
|
255
244
|
// Copy first: `params` also goes to the API and must keep its real values.
|
|
256
245
|
const processed = { ...params };
|
|
257
246
|
if (processed.mcp_servers != null) {
|
|
258
247
|
processed.mcp_servers = redactMcpServers(processed.mcp_servers);
|
|
259
248
|
}
|
|
249
|
+
for (const key of TRANSPORT_SECRET_KEYS) {
|
|
250
|
+
if (processed[key] != null) {
|
|
251
|
+
processed[key] = (0, redaction_js_1.mask)(processed[key]);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
260
254
|
if (!params.system) {
|
|
261
255
|
return processed;
|
|
262
256
|
}
|
|
@@ -275,6 +269,9 @@ const wrapAnthropic = (anthropic, options) => {
|
|
|
275
269
|
delete processed.system;
|
|
276
270
|
return processed;
|
|
277
271
|
}
|
|
272
|
+
function processTracedInputs(inputs) {
|
|
273
|
+
return (0, redaction_js_1.overParams)(inputs, redactAnthropicParams);
|
|
274
|
+
}
|
|
278
275
|
// Common configuration for messages.create
|
|
279
276
|
const messagesCreateConfig = {
|
|
280
277
|
name: "ChatAnthropic",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { wrapManagedAgentSessionEvents } from "./utils/anthropic_managed.js";
|
|
2
2
|
import { isTraceableFunction, traceable, } from "../traceable.js";
|
|
3
3
|
import { convertAnthropicUsageToInputTokenDetails } from "../utils/usage.js";
|
|
4
|
-
import {
|
|
4
|
+
import { mask, overParams, redactOutside } from "../utils/redaction.js";
|
|
5
5
|
const TRACED_INVOCATION_KEYS = ["top_k", "top_p", "stream", "thinking"];
|
|
6
6
|
/** Keys of an MCP server definition that are safe to trace. */
|
|
7
7
|
const MCP_SERVER_SAFE_KEYS = new Set([
|
|
@@ -10,27 +10,20 @@ const MCP_SERVER_SAFE_KEYS = new Set([
|
|
|
10
10
|
"url",
|
|
11
11
|
"tool_configuration",
|
|
12
12
|
]);
|
|
13
|
-
/**
|
|
14
|
-
* Mask credentials in `mcp_servers` before tracing. Anything outside
|
|
15
|
-
* {@link MCP_SERVER_SAFE_KEYS} keeps its name but gets
|
|
16
|
-
* {@link SECRET_PLACEHOLDER} as its value, so the trace shows the field was set
|
|
17
|
-
* without exposing it, and fields the API adds later are masked by default.
|
|
18
|
-
*
|
|
19
|
-
* Returns new objects; the caller's are also sent to Anthropic.
|
|
20
|
-
*/
|
|
13
|
+
/** Mask `mcp_servers` credentials outside {@link MCP_SERVER_SAFE_KEYS}. */
|
|
21
14
|
function redactMcpServers(servers) {
|
|
22
15
|
if (!Array.isArray(servers))
|
|
23
16
|
return servers;
|
|
24
|
-
return servers.map((server) =>
|
|
25
|
-
if (typeof server !== "object" || server == null || Array.isArray(server)) {
|
|
26
|
-
return server;
|
|
27
|
-
}
|
|
28
|
-
return Object.fromEntries(Object.entries(server).map(([key, value]) => [
|
|
29
|
-
key,
|
|
30
|
-
MCP_SERVER_SAFE_KEYS.has(key) ? value : SECRET_PLACEHOLDER,
|
|
31
|
-
]));
|
|
32
|
-
});
|
|
17
|
+
return servers.map((server) => redactOutside(server, MCP_SERVER_SAFE_KEYS));
|
|
33
18
|
}
|
|
19
|
+
/** Request-transport keys that are credentials by construction. */
|
|
20
|
+
const TRANSPORT_SECRET_KEYS = new Set([
|
|
21
|
+
"headers",
|
|
22
|
+
"query",
|
|
23
|
+
"extra_headers",
|
|
24
|
+
"extra_body",
|
|
25
|
+
"extra_query",
|
|
26
|
+
]);
|
|
34
27
|
/**
|
|
35
28
|
* Create usage metadata from Anthropic's token usage format.
|
|
36
29
|
*/
|
|
@@ -242,17 +235,18 @@ export const wrapAnthropic = (anthropic, options) => {
|
|
|
242
235
|
...options,
|
|
243
236
|
metadata: restMetadata,
|
|
244
237
|
};
|
|
245
|
-
/**
|
|
246
|
-
|
|
247
|
-
* This provides parity with the Python SDK behavior and enables system prompts
|
|
248
|
-
* to be viewed and edited in the LangSmith playground.
|
|
249
|
-
*/
|
|
250
|
-
function processTracedInputs(params) {
|
|
238
|
+
/** Mask credentials and surface `system` as a message the playground can edit. */
|
|
239
|
+
function redactAnthropicParams(params) {
|
|
251
240
|
// Copy first: `params` also goes to the API and must keep its real values.
|
|
252
241
|
const processed = { ...params };
|
|
253
242
|
if (processed.mcp_servers != null) {
|
|
254
243
|
processed.mcp_servers = redactMcpServers(processed.mcp_servers);
|
|
255
244
|
}
|
|
245
|
+
for (const key of TRANSPORT_SECRET_KEYS) {
|
|
246
|
+
if (processed[key] != null) {
|
|
247
|
+
processed[key] = mask(processed[key]);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
256
250
|
if (!params.system) {
|
|
257
251
|
return processed;
|
|
258
252
|
}
|
|
@@ -271,6 +265,9 @@ export const wrapAnthropic = (anthropic, options) => {
|
|
|
271
265
|
delete processed.system;
|
|
272
266
|
return processed;
|
|
273
267
|
}
|
|
268
|
+
function processTracedInputs(inputs) {
|
|
269
|
+
return overParams(inputs, redactAnthropicParams);
|
|
270
|
+
}
|
|
274
271
|
// Common configuration for messages.create
|
|
275
272
|
const messagesCreateConfig = {
|
|
276
273
|
name: "ChatAnthropic",
|
|
@@ -717,6 +717,7 @@ class OpenAIAgentsTracingProcessor {
|
|
|
717
717
|
// available at start.
|
|
718
718
|
if (spanData.type === "generation" ||
|
|
719
719
|
spanData.type === "response" ||
|
|
720
|
+
spanData.type === "agent" ||
|
|
720
721
|
spanData.type === "function" ||
|
|
721
722
|
spanData.type === "handoff") {
|
|
722
723
|
this._unpostedSpans.add(span.spanId);
|
|
@@ -818,7 +819,7 @@ class OpenAIAgentsTracingProcessor {
|
|
|
818
819
|
await run.postRun();
|
|
819
820
|
}
|
|
820
821
|
else {
|
|
821
|
-
await run.patchRun(
|
|
822
|
+
await run.patchRun({ excludeInputs: true });
|
|
822
823
|
}
|
|
823
824
|
}
|
|
824
825
|
catch (e) {
|
|
@@ -714,6 +714,7 @@ export class OpenAIAgentsTracingProcessor {
|
|
|
714
714
|
// available at start.
|
|
715
715
|
if (spanData.type === "generation" ||
|
|
716
716
|
spanData.type === "response" ||
|
|
717
|
+
spanData.type === "agent" ||
|
|
717
718
|
spanData.type === "function" ||
|
|
718
719
|
spanData.type === "handoff") {
|
|
719
720
|
this._unpostedSpans.add(span.spanId);
|
|
@@ -815,7 +816,7 @@ export class OpenAIAgentsTracingProcessor {
|
|
|
815
816
|
await run.postRun();
|
|
816
817
|
}
|
|
817
818
|
else {
|
|
818
|
-
await run.patchRun(
|
|
819
|
+
await run.patchRun({ excludeInputs: true });
|
|
819
820
|
}
|
|
820
821
|
}
|
|
821
822
|
catch (e) {
|