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.
Files changed (56) hide show
  1. package/dist/_openapi_client/client.cjs +1 -1
  2. package/dist/_openapi_client/client.d.ts +2 -2
  3. package/dist/_openapi_client/client.js +1 -1
  4. package/dist/_openapi_client/internal/detect-platform.cjs +1 -1
  5. package/dist/_openapi_client/internal/detect-platform.js +1 -1
  6. package/dist/_openapi_client/resources/annotation-queues/annotation-queues.d.ts +1 -0
  7. package/dist/_openapi_client/resources/index.d.ts +1 -1
  8. package/dist/_openapi_client/resources/issues.cjs +1 -1
  9. package/dist/_openapi_client/resources/issues.d.ts +18 -1
  10. package/dist/_openapi_client/resources/issues.js +1 -1
  11. package/dist/_openapi_client/resources/online-evaluators.d.ts +2 -2
  12. package/dist/_openapi_client/resources/sandboxes/boxes.cjs +20 -3
  13. package/dist/_openapi_client/resources/sandboxes/boxes.d.ts +40 -9
  14. package/dist/_openapi_client/resources/sandboxes/boxes.js +20 -3
  15. package/dist/_openapi_client/resources/sandboxes/sandboxes.d.ts +46 -3
  16. package/dist/_openapi_client/resources/sandboxes/snapshots.cjs +6 -2
  17. package/dist/_openapi_client/resources/sandboxes/snapshots.d.ts +16 -6
  18. package/dist/_openapi_client/resources/sandboxes/snapshots.js +6 -2
  19. package/dist/client.cjs +56 -83
  20. package/dist/client.d.ts +16 -14
  21. package/dist/client.js +56 -83
  22. package/dist/env.cjs +14 -1
  23. package/dist/env.d.ts +9 -0
  24. package/dist/env.js +12 -0
  25. package/dist/evaluation/evaluate_comparative.cjs +2 -0
  26. package/dist/evaluation/evaluate_comparative.js +2 -0
  27. package/dist/experimental/vercel/telemetry.cjs +19 -6
  28. package/dist/experimental/vercel/telemetry.js +17 -4
  29. package/dist/index.cjs +1 -1
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.js +1 -1
  32. package/dist/run_trees.cjs +19 -2
  33. package/dist/run_trees.d.ts +12 -0
  34. package/dist/run_trees.js +19 -2
  35. package/dist/schemas.d.ts +2 -0
  36. package/dist/singletons/constants.cjs +7 -1
  37. package/dist/singletons/constants.d.ts +3 -0
  38. package/dist/singletons/constants.js +5 -0
  39. package/dist/traceable.cjs +46 -15
  40. package/dist/traceable.js +48 -17
  41. package/dist/utils/_uuid.cjs +11 -19
  42. package/dist/utils/_uuid.d.ts +7 -7
  43. package/dist/utils/_uuid.js +11 -19
  44. package/dist/utils/env.cjs +18 -7
  45. package/dist/utils/env.js +18 -7
  46. package/dist/utils/redaction.cjs +38 -0
  47. package/dist/utils/redaction.d.ts +10 -0
  48. package/dist/utils/redaction.js +33 -0
  49. package/dist/utils/sampling.cjs +34 -0
  50. package/dist/utils/sampling.d.ts +10 -0
  51. package/dist/utils/sampling.js +30 -0
  52. package/dist/wrappers/anthropic.cjs +21 -24
  53. package/dist/wrappers/anthropic.js +21 -24
  54. package/dist/wrappers/openai_agents.cjs +2 -1
  55. package/dist/wrappers/openai_agents.js +2 -1
  56. 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 index_js_1 = require("../anonymizer/index.cjs");
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
- * Transform system parameter into visible message for playground editability.
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 { SECRET_PLACEHOLDER } from "../anonymizer/index.js";
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
- * Transform system parameter into visible message for playground editability.
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(span.spanData.type === "agent" ? undefined : { excludeInputs: true });
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(span.spanData.type === "agent" ? undefined : { excludeInputs: true });
819
+ await run.patchRun({ excludeInputs: true });
819
820
  }
820
821
  }
821
822
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.8.12",
3
+ "version": "0.10.0",
4
4
  "description": "Client library to connect to the LangSmith Observability and Evaluation Platform.",
5
5
  "packageManager": "pnpm@10.33.0",
6
6
  "files": [