langsmith 0.10.6 → 0.10.8

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/address.cjs CHANGED
@@ -1,31 +1,40 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EnvAddressError = void 0;
4
- exports.normalizeAddress = normalizeAddress;
5
- exports.wireKeys = wireKeys;
3
+ exports.address = exports.EnvAddressError = void 0;
4
+ exports.agent = agent;
5
+ exports.parse = parse;
6
+ exports.fromEnv = fromEnv;
6
7
  exports.envNames = envNames;
7
- exports.toWire = toWire;
8
- exports.fromWire = fromWire;
9
- exports.addressFromEnv = addressFromEnv;
10
- exports.seed = seed;
11
- exports.sameAddress = sameAddress;
12
- // Wire key per field; env var is `LANGSMITH_<WIRE KEY>`.
13
- const FIELDS = {
14
- agentId: "agent_id",
15
- agentEnvironment: "agent_environment",
16
- };
8
+ /**
9
+ * (beta) Addresses that name where runs are sent instead of a project.
10
+ * Enabled per workspace; a workspace without it rejects the runs.
11
+ *
12
+ * An address is a plain string, `lrn:agents/{id}/environments/{environment}`,
13
+ * typed as a template literal so a literal is checked at compile time. A
14
+ * dynamic `string` goes through `address.parse`, which validates it at
15
+ * runtime (JS callers are validated the same way). The environment is always
16
+ * rendered lowercase.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { address, traceable } from "langsmith";
21
+ *
22
+ * const support = address.agent("customer-support", "production");
23
+ * const handle = traceable(fn, { address: support });
24
+ * // or a literal: { address: "lrn:agents/customer-support/environments/staging" }
25
+ * ```
26
+ */
27
+ const env_js_1 = require("./utils/env.cjs");
17
28
  // The server's agent id rule: a DNS label, so a hostname can carry the id.
18
29
  const AGENT_ID_PATTERN = /^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$/;
19
- // Not `utils/env`: it imports the package index, which imports this module.
20
- function getEnv(name) {
21
- try {
22
- // eslint-disable-next-line no-process-env
23
- return typeof process !== "undefined" ? process.env?.[name] : undefined;
24
- }
25
- catch {
26
- return undefined;
27
- }
28
- }
30
+ const ENVIRONMENTS = [
31
+ "local",
32
+ "development",
33
+ "staging",
34
+ "production",
35
+ ];
36
+ const ADDRESS_PATTERN = /^lrn:agents\/([^/]*)\/environments\/([^/]*)$/;
37
+ const ENV_NAMES = ["LANGSMITH_AGENT_ID", "LANGSMITH_AGENT_ENVIRONMENT"];
29
38
  /** The `LANGSMITH_AGENT_*` / project env vars name half an address, or both. */
30
39
  class EnvAddressError extends Error {
31
40
  constructor(message) {
@@ -35,85 +44,66 @@ class EnvAddressError extends Error {
35
44
  }
36
45
  exports.EnvAddressError = EnvAddressError;
37
46
  /**
38
- * @internal Validate `value` and return a frozen copy of its fields.
39
- * @throws If it isn't an object with exactly the address fields, or a value is invalid.
47
+ * (beta) Build the address of an agent's environment.
48
+ * @param agentId 1 to 63 lowercase ASCII letters, digits or hyphens, starting
49
+ * with a letter and ending with a letter or digit.
50
+ * @param agentEnvironment One of `local`, `development`, `staging` or
51
+ * `production`, in any case.
52
+ * @throws If a value is invalid.
40
53
  */
41
- function normalizeAddress(value) {
42
- if (value == null || typeof value !== "object" || Array.isArray(value)) {
43
- throw new Error("`address` must be an object: { agentId, agentEnvironment }.");
44
- }
45
- const fields = value;
46
- const unknown = Object.keys(fields).filter((key) => !(key in FIELDS));
47
- if (unknown.length > 0) {
48
- throw new Error(`Unknown address fields: ${unknown.join(", ")}.`);
49
- }
50
- for (const name of Object.keys(FIELDS)) {
51
- const field = fields[name];
52
- if (typeof field !== "string" || field === "") {
53
- throw new Error(`Address ${name} must be a non-empty string.`);
54
- }
55
- }
56
- const { agentId, agentEnvironment } = fields;
57
- if (!AGENT_ID_PATTERN.test(agentId)) {
58
- throw new Error("Address agentId must be 1 to 63 lowercase ASCII letters, digits, or " +
54
+ function agent(agentId, agentEnvironment) {
55
+ if (typeof agentId !== "string" || !AGENT_ID_PATTERN.test(agentId)) {
56
+ throw new Error("Address agent id must be 1 to 63 lowercase ASCII letters, digits, or " +
59
57
  "hyphens, start with a letter, and end with a letter or digit, got " +
60
58
  `${JSON.stringify(agentId)}. Use an id such as "support-agent".`);
61
59
  }
62
- return Object.freeze({ agentId, agentEnvironment });
63
- }
64
- /** @internal */
65
- function wireKeys() {
66
- return Object.values(FIELDS);
67
- }
68
- /** @internal */
69
- function envNames() {
70
- return wireKeys().map((key) => `LANGSMITH_${key.toUpperCase()}`);
71
- }
72
- /** @internal */
73
- function toWire(address) {
74
- return {
75
- [FIELDS.agentId]: address.agentId,
76
- [FIELDS.agentEnvironment]: address.agentEnvironment,
77
- };
78
- }
79
- /** @internal `undefined` if no field is set; throws if only some are. */
80
- function fromWire(values) {
81
- const fields = Object.fromEntries(Object.entries(FIELDS).map(([name, key]) => [
82
- name,
83
- values[key] ?? undefined,
84
- ]));
85
- const missing = Object.entries(FIELDS)
86
- .filter(([name]) => fields[name] === undefined)
87
- .map(([, key]) => key);
88
- if (missing.length === Object.keys(FIELDS).length) {
89
- return undefined;
60
+ const environment = typeof agentEnvironment === "string"
61
+ ? agentEnvironment.toLowerCase()
62
+ : undefined;
63
+ if (environment === undefined || !ENVIRONMENTS.includes(environment)) {
64
+ throw new Error(`Address environment must be one of ${ENVIRONMENTS.join(", ")}, got ` +
65
+ `${JSON.stringify(agentEnvironment)}.`);
90
66
  }
91
- if (missing.length > 0) {
92
- throw new Error(`An address needs ${missing.join(" and ")} as well.`);
67
+ return `lrn:agents/${agentId}/environments/${environment}`;
68
+ }
69
+ /**
70
+ * (beta) Validate an address string, lowercasing its environment.
71
+ * Only agent addresses, `lrn:agents/{id}/environments/{environment}`, exist.
72
+ * @throws If `value` is not a valid agent address.
73
+ */
74
+ function parse(value) {
75
+ const match = typeof value === "string" ? ADDRESS_PATTERN.exec(value) : undefined;
76
+ if (!match) {
77
+ throw new Error("An address must be a string like " +
78
+ `"lrn:agents/{id}/environments/{environment}", got ${JSON.stringify(value)}.`);
93
79
  }
94
- return normalizeAddress(fields);
80
+ return agent(match[1], match[2]);
95
81
  }
96
82
  /**
97
- * @internal
98
- * @throws {EnvAddressError} If only some `LANGSMITH_AGENT_*` vars are set, or one is invalid.
83
+ * (beta) Read the address named by `LANGSMITH_AGENT_ID` and
84
+ * `LANGSMITH_AGENT_ENVIRONMENT`; `undefined` if neither is set.
85
+ * @throws {EnvAddressError} If only one is set, or a value is invalid.
99
86
  */
100
- function addressFromEnv() {
101
- const values = Object.fromEntries(wireKeys().map((key, i) => [key, getEnv(envNames()[i]) || undefined]));
87
+ function fromEnv() {
88
+ const values = ENV_NAMES.map((name) => (0, env_js_1.getEnvironmentVariable)(name));
89
+ if (!values.some(Boolean)) {
90
+ return undefined;
91
+ }
102
92
  try {
103
- return fromWire(values);
93
+ const missing = ENV_NAMES.filter((_, i) => !values[i]);
94
+ if (missing.length > 0) {
95
+ throw new Error(`An address needs ${missing.join(" and ")} as well.`);
96
+ }
97
+ return agent(values[0], values[1]);
104
98
  }
105
99
  catch (e) {
106
- throw new EnvAddressError(`The LANGSMITH_AGENT_* env vars can't address a run: ${e.message}`);
100
+ const present = ENV_NAMES.flatMap((name, i) => values[i] ? [`${name}=${JSON.stringify(values[i])}`] : []).join(", ");
101
+ throw new EnvAddressError(`The LANGSMITH_AGENT_* env vars can't address a run (${present}): ${e.message}`);
107
102
  }
108
103
  }
109
- /** @internal Replica id derivation seed. */
110
- function seed(address) {
111
- return ["agent", ...Object.values(toWire(address))].join("/");
112
- }
113
- /** @internal */
114
- function sameAddress(a, b) {
115
- if (!a || !b) {
116
- return a === b;
117
- }
118
- return a.agentId === b.agentId && a.agentEnvironment === b.agentEnvironment;
104
+ /** (beta) Build, validate and read addresses. */
105
+ exports.address = { agent, parse, fromEnv };
106
+ /** @internal The `LANGSMITH_AGENT_*` env var names an address reads. */
107
+ function envNames() {
108
+ return ENV_NAMES;
119
109
  }
package/dist/address.d.ts CHANGED
@@ -1,13 +1,35 @@
1
- /**
2
- * (beta) An address that runs are sent to instead of a project.
3
- * Enabled per workspace; a workspace without it rejects the runs.
4
- */
5
- export interface Address {
6
- /** 1 to 63 lowercase ASCII letters, digits or hyphens; starts with a letter. */
7
- agentId: string;
8
- agentEnvironment: string;
9
- }
1
+ /** (beta) An agent environment. */
2
+ export type Environment = "local" | "development" | "staging" | "production";
3
+ /** (beta) An address string, `lrn:agents/{id}/environments/{environment}`. */
4
+ export type Address = `lrn:agents/${string}/environments/${Environment}`;
10
5
  /** The `LANGSMITH_AGENT_*` / project env vars name half an address, or both. */
11
6
  export declare class EnvAddressError extends Error {
12
7
  constructor(message: string);
13
8
  }
9
+ /**
10
+ * (beta) Build the address of an agent's environment.
11
+ * @param agentId 1 to 63 lowercase ASCII letters, digits or hyphens, starting
12
+ * with a letter and ending with a letter or digit.
13
+ * @param agentEnvironment One of `local`, `development`, `staging` or
14
+ * `production`, in any case.
15
+ * @throws If a value is invalid.
16
+ */
17
+ export declare function agent(agentId: string, agentEnvironment: Environment | (string & {})): Address;
18
+ /**
19
+ * (beta) Validate an address string, lowercasing its environment.
20
+ * Only agent addresses, `lrn:agents/{id}/environments/{environment}`, exist.
21
+ * @throws If `value` is not a valid agent address.
22
+ */
23
+ export declare function parse(value: string): Address;
24
+ /**
25
+ * (beta) Read the address named by `LANGSMITH_AGENT_ID` and
26
+ * `LANGSMITH_AGENT_ENVIRONMENT`; `undefined` if neither is set.
27
+ * @throws {EnvAddressError} If only one is set, or a value is invalid.
28
+ */
29
+ export declare function fromEnv(): Address | undefined;
30
+ /** (beta) Build, validate and read addresses. */
31
+ export declare const address: {
32
+ agent: typeof agent;
33
+ parse: typeof parse;
34
+ fromEnv: typeof fromEnv;
35
+ };
package/dist/address.js CHANGED
@@ -1,20 +1,33 @@
1
- // Wire key per field; env var is `LANGSMITH_<WIRE KEY>`.
2
- const FIELDS = {
3
- agentId: "agent_id",
4
- agentEnvironment: "agent_environment",
5
- };
1
+ /**
2
+ * (beta) Addresses that name where runs are sent instead of a project.
3
+ * Enabled per workspace; a workspace without it rejects the runs.
4
+ *
5
+ * An address is a plain string, `lrn:agents/{id}/environments/{environment}`,
6
+ * typed as a template literal so a literal is checked at compile time. A
7
+ * dynamic `string` goes through `address.parse`, which validates it at
8
+ * runtime (JS callers are validated the same way). The environment is always
9
+ * rendered lowercase.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { address, traceable } from "langsmith";
14
+ *
15
+ * const support = address.agent("customer-support", "production");
16
+ * const handle = traceable(fn, { address: support });
17
+ * // or a literal: { address: "lrn:agents/customer-support/environments/staging" }
18
+ * ```
19
+ */
20
+ import { getEnvironmentVariable } from "./utils/env.js";
6
21
  // The server's agent id rule: a DNS label, so a hostname can carry the id.
7
22
  const AGENT_ID_PATTERN = /^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$/;
8
- // Not `utils/env`: it imports the package index, which imports this module.
9
- function getEnv(name) {
10
- try {
11
- // eslint-disable-next-line no-process-env
12
- return typeof process !== "undefined" ? process.env?.[name] : undefined;
13
- }
14
- catch {
15
- return undefined;
16
- }
17
- }
23
+ const ENVIRONMENTS = [
24
+ "local",
25
+ "development",
26
+ "staging",
27
+ "production",
28
+ ];
29
+ const ADDRESS_PATTERN = /^lrn:agents\/([^/]*)\/environments\/([^/]*)$/;
30
+ const ENV_NAMES = ["LANGSMITH_AGENT_ID", "LANGSMITH_AGENT_ENVIRONMENT"];
18
31
  /** The `LANGSMITH_AGENT_*` / project env vars name half an address, or both. */
19
32
  export class EnvAddressError extends Error {
20
33
  constructor(message) {
@@ -23,85 +36,66 @@ export class EnvAddressError extends Error {
23
36
  }
24
37
  }
25
38
  /**
26
- * @internal Validate `value` and return a frozen copy of its fields.
27
- * @throws If it isn't an object with exactly the address fields, or a value is invalid.
39
+ * (beta) Build the address of an agent's environment.
40
+ * @param agentId 1 to 63 lowercase ASCII letters, digits or hyphens, starting
41
+ * with a letter and ending with a letter or digit.
42
+ * @param agentEnvironment One of `local`, `development`, `staging` or
43
+ * `production`, in any case.
44
+ * @throws If a value is invalid.
28
45
  */
29
- export function normalizeAddress(value) {
30
- if (value == null || typeof value !== "object" || Array.isArray(value)) {
31
- throw new Error("`address` must be an object: { agentId, agentEnvironment }.");
32
- }
33
- const fields = value;
34
- const unknown = Object.keys(fields).filter((key) => !(key in FIELDS));
35
- if (unknown.length > 0) {
36
- throw new Error(`Unknown address fields: ${unknown.join(", ")}.`);
37
- }
38
- for (const name of Object.keys(FIELDS)) {
39
- const field = fields[name];
40
- if (typeof field !== "string" || field === "") {
41
- throw new Error(`Address ${name} must be a non-empty string.`);
42
- }
43
- }
44
- const { agentId, agentEnvironment } = fields;
45
- if (!AGENT_ID_PATTERN.test(agentId)) {
46
- throw new Error("Address agentId must be 1 to 63 lowercase ASCII letters, digits, or " +
46
+ export function agent(agentId, agentEnvironment) {
47
+ if (typeof agentId !== "string" || !AGENT_ID_PATTERN.test(agentId)) {
48
+ throw new Error("Address agent id must be 1 to 63 lowercase ASCII letters, digits, or " +
47
49
  "hyphens, start with a letter, and end with a letter or digit, got " +
48
50
  `${JSON.stringify(agentId)}. Use an id such as "support-agent".`);
49
51
  }
50
- return Object.freeze({ agentId, agentEnvironment });
51
- }
52
- /** @internal */
53
- export function wireKeys() {
54
- return Object.values(FIELDS);
55
- }
56
- /** @internal */
57
- export function envNames() {
58
- return wireKeys().map((key) => `LANGSMITH_${key.toUpperCase()}`);
59
- }
60
- /** @internal */
61
- export function toWire(address) {
62
- return {
63
- [FIELDS.agentId]: address.agentId,
64
- [FIELDS.agentEnvironment]: address.agentEnvironment,
65
- };
66
- }
67
- /** @internal `undefined` if no field is set; throws if only some are. */
68
- export function fromWire(values) {
69
- const fields = Object.fromEntries(Object.entries(FIELDS).map(([name, key]) => [
70
- name,
71
- values[key] ?? undefined,
72
- ]));
73
- const missing = Object.entries(FIELDS)
74
- .filter(([name]) => fields[name] === undefined)
75
- .map(([, key]) => key);
76
- if (missing.length === Object.keys(FIELDS).length) {
77
- return undefined;
52
+ const environment = typeof agentEnvironment === "string"
53
+ ? agentEnvironment.toLowerCase()
54
+ : undefined;
55
+ if (environment === undefined || !ENVIRONMENTS.includes(environment)) {
56
+ throw new Error(`Address environment must be one of ${ENVIRONMENTS.join(", ")}, got ` +
57
+ `${JSON.stringify(agentEnvironment)}.`);
78
58
  }
79
- if (missing.length > 0) {
80
- throw new Error(`An address needs ${missing.join(" and ")} as well.`);
59
+ return `lrn:agents/${agentId}/environments/${environment}`;
60
+ }
61
+ /**
62
+ * (beta) Validate an address string, lowercasing its environment.
63
+ * Only agent addresses, `lrn:agents/{id}/environments/{environment}`, exist.
64
+ * @throws If `value` is not a valid agent address.
65
+ */
66
+ export function parse(value) {
67
+ const match = typeof value === "string" ? ADDRESS_PATTERN.exec(value) : undefined;
68
+ if (!match) {
69
+ throw new Error("An address must be a string like " +
70
+ `"lrn:agents/{id}/environments/{environment}", got ${JSON.stringify(value)}.`);
81
71
  }
82
- return normalizeAddress(fields);
72
+ return agent(match[1], match[2]);
83
73
  }
84
74
  /**
85
- * @internal
86
- * @throws {EnvAddressError} If only some `LANGSMITH_AGENT_*` vars are set, or one is invalid.
75
+ * (beta) Read the address named by `LANGSMITH_AGENT_ID` and
76
+ * `LANGSMITH_AGENT_ENVIRONMENT`; `undefined` if neither is set.
77
+ * @throws {EnvAddressError} If only one is set, or a value is invalid.
87
78
  */
88
- export function addressFromEnv() {
89
- const values = Object.fromEntries(wireKeys().map((key, i) => [key, getEnv(envNames()[i]) || undefined]));
79
+ export function fromEnv() {
80
+ const values = ENV_NAMES.map((name) => getEnvironmentVariable(name));
81
+ if (!values.some(Boolean)) {
82
+ return undefined;
83
+ }
90
84
  try {
91
- return fromWire(values);
85
+ const missing = ENV_NAMES.filter((_, i) => !values[i]);
86
+ if (missing.length > 0) {
87
+ throw new Error(`An address needs ${missing.join(" and ")} as well.`);
88
+ }
89
+ return agent(values[0], values[1]);
92
90
  }
93
91
  catch (e) {
94
- throw new EnvAddressError(`The LANGSMITH_AGENT_* env vars can't address a run: ${e.message}`);
92
+ const present = ENV_NAMES.flatMap((name, i) => values[i] ? [`${name}=${JSON.stringify(values[i])}`] : []).join(", ");
93
+ throw new EnvAddressError(`The LANGSMITH_AGENT_* env vars can't address a run (${present}): ${e.message}`);
95
94
  }
96
95
  }
97
- /** @internal Replica id derivation seed. */
98
- export function seed(address) {
99
- return ["agent", ...Object.values(toWire(address))].join("/");
100
- }
101
- /** @internal */
102
- export function sameAddress(a, b) {
103
- if (!a || !b) {
104
- return a === b;
105
- }
106
- return a.agentId === b.agentId && a.agentEnvironment === b.agentEnvironment;
96
+ /** (beta) Build, validate and read addresses. */
97
+ export const address = { agent, parse, fromEnv };
98
+ /** @internal The `LANGSMITH_AGENT_*` env var names an address reads. */
99
+ export function envNames() {
100
+ return ENV_NAMES;
107
101
  }
package/dist/client.cjs CHANGED
@@ -3987,7 +3987,7 @@ class Client {
3987
3987
  if (samplingId != null && !this._shouldSample(samplingId)) {
3988
3988
  return feedback;
3989
3989
  }
3990
- const body = JSON.stringify(address ? { ...feedback, ...(0, address_js_1.toWire)(address) } : feedback);
3990
+ const body = JSON.stringify(address ? { ...feedback, address } : feedback);
3991
3991
  const url = `${this.apiUrl}/feedback`;
3992
3992
  await this.caller.call(async () => {
3993
3993
  const res = await this._fetch(url, {
package/dist/client.js CHANGED
@@ -9,7 +9,7 @@ import { Langsmith as OpenAPILangsmith } from "./_openapi_client/index.js";
9
9
  import { assertUuid } from "./utils/_uuid.js";
10
10
  import { isSampledById } from "./utils/sampling.js";
11
11
  import { warnOnce } from "./utils/warn.js";
12
- import { EnvAddressError, toWire } from "./address.js";
12
+ import { EnvAddressError } from "./address.js";
13
13
  import { applyToPayload, checkAddress, logUntraced, rejectConflicting, resolveFromEnv, warnOnEnv, } from "./utils/agent_addressing.js";
14
14
  import { getQueryBackend, QueryBackend } from "./utils/v2_migration.js";
15
15
  import { parseHubIdentifier } from "./utils/prompts.js";
@@ -3948,7 +3948,7 @@ export class Client {
3948
3948
  if (samplingId != null && !this._shouldSample(samplingId)) {
3949
3949
  return feedback;
3950
3950
  }
3951
- const body = JSON.stringify(address ? { ...feedback, ...toWire(address) } : feedback);
3951
+ const body = JSON.stringify(address ? { ...feedback, address } : feedback);
3952
3952
  const url = `${this.apiUrl}/feedback`;
3953
3953
  await this.caller.call(async () => {
3954
3954
  const res = await this._fetch(url, {
@@ -39,6 +39,7 @@ const constants = __importStar(require("./constants.cjs"));
39
39
  const env_js_1 = require("../../env.cjs");
40
40
  const env_js_2 = require("../../utils/env.cjs");
41
41
  const vercel_js_1 = require("../../utils/vercel.cjs");
42
+ const warn_js_1 = require("../../utils/warn.cjs");
42
43
  /**
43
44
  * Convert headers string in format "name=value,name2=value2" to object
44
45
  */
@@ -60,8 +61,10 @@ function parseHeadersString(headersStr) {
60
61
  *
61
62
  * This exporter automatically configures itself with LangSmith endpoints and API keys,
62
63
  * based on your LANGSMITH_API_KEY and LANGSMITH_PROJECT environment variables.
63
- * Will also respect OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_HEADERS environment
64
- * variables if set.
64
+ * OTEL_EXPORTER_OTLP_TRACES_ENDPOINT is a full traces URL and takes precedence over
65
+ * OTEL_EXPORTER_OTLP_ENDPOINT, a base URL to which /v1/traces is appended unless
66
+ * it already ends in /traces for compatibility.
67
+ * Also respects OTEL_EXPORTER_OTLP_HEADERS if set.
65
68
  *
66
69
  * @param config - Optional configuration object that accepts all OTLPTraceExporter parameters.
67
70
  * If not provided, uses default LangSmith configuration:
@@ -74,8 +77,22 @@ class LangSmithOTLPTraceExporter extends exporter_trace_otlp_proto_1.OTLPTraceEx
74
77
  const defaultLsEndpoint = (0, env_js_2.getLangSmithEnvironmentVariable)("ENDPOINT") ||
75
78
  "https://api.smith.langchain.com";
76
79
  const defaultBaseUrl = defaultLsEndpoint.replace(/\/$/, "");
77
- const defaultUrl = (0, env_js_2.getEnvironmentVariable)("OTEL_EXPORTER_OTLP_ENDPOINT") ??
78
- `${defaultBaseUrl}/otel/v1/traces`;
80
+ const baseEndpoint = (0, env_js_2.getEnvironmentVariable)("OTEL_EXPORTER_OTLP_ENDPOINT") ||
81
+ `${defaultBaseUrl}/otel`;
82
+ const defaultUrl = (0, env_js_2.getEnvironmentVariable)("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT") ||
83
+ (baseEndpoint.endsWith("/traces")
84
+ ? baseEndpoint
85
+ : `${baseEndpoint.replace(/\/$/, "")}/v1/traces`);
86
+ if (config?.url === undefined &&
87
+ !(0, env_js_2.getEnvironmentVariable)("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT") &&
88
+ baseEndpoint.endsWith("/traces")) {
89
+ (0, warn_js_1.warnOnce)("LangSmith now treats OTEL_EXPORTER_OTLP_ENDPOINT as a base URL and " +
90
+ "appends /v1/traces. Your value ends in /traces, so it is being " +
91
+ "preserved unchanged for compatibility. This fallback will be " +
92
+ "removed in the v1 release of the SDK. Move this full URL to " +
93
+ "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT to use standard OpenTelemetry " +
94
+ "configuration.");
95
+ }
79
96
  // Configure headers with API key and project if available
80
97
  let headers = config?.headers;
81
98
  if (headers === undefined) {
@@ -43,8 +43,10 @@ export type LangSmithOTLPTraceExporterConfig = ConstructorParameters<typeof OTLP
43
43
  *
44
44
  * This exporter automatically configures itself with LangSmith endpoints and API keys,
45
45
  * based on your LANGSMITH_API_KEY and LANGSMITH_PROJECT environment variables.
46
- * Will also respect OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_HEADERS environment
47
- * variables if set.
46
+ * OTEL_EXPORTER_OTLP_TRACES_ENDPOINT is a full traces URL and takes precedence over
47
+ * OTEL_EXPORTER_OTLP_ENDPOINT, a base URL to which /v1/traces is appended unless
48
+ * it already ends in /traces for compatibility.
49
+ * Also respects OTEL_EXPORTER_OTLP_HEADERS if set.
48
50
  *
49
51
  * @param config - Optional configuration object that accepts all OTLPTraceExporter parameters.
50
52
  * If not provided, uses default LangSmith configuration:
@@ -3,6 +3,7 @@ import * as constants from "./constants.js";
3
3
  import { isEnvTracingEnabled } from "../../env.js";
4
4
  import { getEnvironmentVariable, getLangSmithEnvironmentVariable, } from "../../utils/env.js";
5
5
  import { extractUsageMetadata } from "../../utils/vercel.js";
6
+ import { warnOnce } from "../../utils/warn.js";
6
7
  /**
7
8
  * Convert headers string in format "name=value,name2=value2" to object
8
9
  */
@@ -24,8 +25,10 @@ function parseHeadersString(headersStr) {
24
25
  *
25
26
  * This exporter automatically configures itself with LangSmith endpoints and API keys,
26
27
  * based on your LANGSMITH_API_KEY and LANGSMITH_PROJECT environment variables.
27
- * Will also respect OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_HEADERS environment
28
- * variables if set.
28
+ * OTEL_EXPORTER_OTLP_TRACES_ENDPOINT is a full traces URL and takes precedence over
29
+ * OTEL_EXPORTER_OTLP_ENDPOINT, a base URL to which /v1/traces is appended unless
30
+ * it already ends in /traces for compatibility.
31
+ * Also respects OTEL_EXPORTER_OTLP_HEADERS if set.
29
32
  *
30
33
  * @param config - Optional configuration object that accepts all OTLPTraceExporter parameters.
31
34
  * If not provided, uses default LangSmith configuration:
@@ -38,8 +41,22 @@ export class LangSmithOTLPTraceExporter extends OTLPTraceExporter {
38
41
  const defaultLsEndpoint = getLangSmithEnvironmentVariable("ENDPOINT") ||
39
42
  "https://api.smith.langchain.com";
40
43
  const defaultBaseUrl = defaultLsEndpoint.replace(/\/$/, "");
41
- const defaultUrl = getEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT") ??
42
- `${defaultBaseUrl}/otel/v1/traces`;
44
+ const baseEndpoint = getEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT") ||
45
+ `${defaultBaseUrl}/otel`;
46
+ const defaultUrl = getEnvironmentVariable("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT") ||
47
+ (baseEndpoint.endsWith("/traces")
48
+ ? baseEndpoint
49
+ : `${baseEndpoint.replace(/\/$/, "")}/v1/traces`);
50
+ if (config?.url === undefined &&
51
+ !getEnvironmentVariable("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT") &&
52
+ baseEndpoint.endsWith("/traces")) {
53
+ warnOnce("LangSmith now treats OTEL_EXPORTER_OTLP_ENDPOINT as a base URL and " +
54
+ "appends /v1/traces. Your value ends in /traces, so it is being " +
55
+ "preserved unchanged for compatibility. This fallback will be " +
56
+ "removed in the v1 release of the SDK. Move this full URL to " +
57
+ "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT to use standard OpenTelemetry " +
58
+ "configuration.");
59
+ }
43
60
  // Configure headers with API key and project if available
44
61
  let headers = config?.headers;
45
62
  if (headers === undefined) {
package/dist/index.cjs CHANGED
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LS_MESSAGE_VIEW_EXCLUDE = exports.__version__ = exports.InternalServerError = exports.RateLimitError = exports.UnprocessableEntityError = exports.ConflictError = exports.NotFoundError = exports.PermissionDeniedError = exports.AuthenticationError = exports.BadRequestError = exports.APIConnectionTimeoutError = exports.APIConnectionError = exports.APIUserAbortError = exports.APIError = exports.LangsmithError = exports.promptCacheSingleton = exports.configureGlobalPromptCache = exports.PromptCache = exports.Cache = exports.isTracingEnabled = exports.uuid7FromTime = exports.uuid7 = exports.computeRunIdForSecondaryReplica = exports.getDefaultProjectName = exports.overrideFetchImplementation = exports.EnvAddressError = exports.RunTree = exports.Client = void 0;
3
+ exports.LS_MESSAGE_VIEW_EXCLUDE = exports.__version__ = exports.InternalServerError = exports.RateLimitError = exports.UnprocessableEntityError = exports.ConflictError = exports.NotFoundError = exports.PermissionDeniedError = exports.AuthenticationError = exports.BadRequestError = exports.APIConnectionTimeoutError = exports.APIConnectionError = exports.APIUserAbortError = exports.APIError = exports.LangsmithError = exports.promptCacheSingleton = exports.configureGlobalPromptCache = exports.PromptCache = exports.Cache = exports.isTracingEnabled = exports.uuid7FromTime = exports.uuid7 = exports.computeRunIdForSecondaryReplica = exports.getDefaultProjectName = exports.overrideFetchImplementation = exports.EnvAddressError = exports.address = exports.RunTree = exports.Client = void 0;
4
4
  var client_js_1 = require("./client.cjs");
5
5
  Object.defineProperty(exports, "Client", { enumerable: true, get: function () { return client_js_1.Client; } });
6
6
  var run_trees_js_1 = require("./run_trees.cjs");
7
7
  Object.defineProperty(exports, "RunTree", { enumerable: true, get: function () { return run_trees_js_1.RunTree; } });
8
8
  var address_js_1 = require("./address.cjs");
9
+ Object.defineProperty(exports, "address", { enumerable: true, get: function () { return address_js_1.address; } });
9
10
  Object.defineProperty(exports, "EnvAddressError", { enumerable: true, get: function () { return address_js_1.EnvAddressError; } });
10
11
  var fetch_js_1 = require("./singletons/fetch.cjs");
11
12
  Object.defineProperty(exports, "overrideFetchImplementation", { enumerable: true, get: function () { return fetch_js_1.overrideFetchImplementation; } });
@@ -37,6 +38,6 @@ Object.defineProperty(exports, "UnprocessableEntityError", { enumerable: true, g
37
38
  Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return error_js_1.RateLimitError; } });
38
39
  Object.defineProperty(exports, "InternalServerError", { enumerable: true, get: function () { return error_js_1.InternalServerError; } });
39
40
  // Update using pnpm bump-version
40
- exports.__version__ = "0.10.6";
41
+ exports.__version__ = "0.10.8";
41
42
  // Metadata key to hide a traced run from LangSmith's Messages View.
42
43
  exports.LS_MESSAGE_VIEW_EXCLUDE = "ls_message_view_exclude";
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  export { Client, type ClientConfig, type LangSmithTracingClientInterface, } from "./client.js";
2
2
  export type { Dataset, Example, TracerSession, Run, Feedback, FeedbackConfigSchema, RetrieverOutput, } from "./schemas.js";
3
3
  export { RunTree, type RunTreeConfig, type WriteReplica } from "./run_trees.js";
4
- export { type Address, EnvAddressError } from "./address.js";
4
+ export { address, type Address, type Environment, EnvAddressError, } from "./address.js";
5
5
  export { overrideFetchImplementation } from "./singletons/fetch.js";
6
6
  export { getDefaultProjectName } from "./utils/project.js";
7
7
  export { computeRunIdForSecondaryReplica, uuid7, uuid7FromTime, } from "./uuid.js";
8
8
  export { isTracingEnabled } from "./utils/guard.js";
9
9
  export { Cache, PromptCache, type CacheConfig, type CacheMetrics, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
10
10
  export { LangsmithError, APIError, APIUserAbortError, APIConnectionError, APIConnectionTimeoutError, BadRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, } from "./_openapi_client/core/error.js";
11
- export declare const __version__ = "0.10.6";
11
+ export declare const __version__ = "0.10.8";
12
12
  export declare const LS_MESSAGE_VIEW_EXCLUDE: "ls_message_view_exclude";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { Client, } from "./client.js";
2
2
  export { RunTree } from "./run_trees.js";
3
- export { EnvAddressError } from "./address.js";
3
+ export { address, EnvAddressError, } from "./address.js";
4
4
  export { overrideFetchImplementation } from "./singletons/fetch.js";
5
5
  export { getDefaultProjectName } from "./utils/project.js";
6
6
  export { computeRunIdForSecondaryReplica, uuid7, uuid7FromTime, } from "./uuid.js";
@@ -8,6 +8,6 @@ export { isTracingEnabled } from "./utils/guard.js";
8
8
  export { Cache, PromptCache, configureGlobalPromptCache, promptCacheSingleton, } from "./utils/prompt_cache/index.js";
9
9
  export { LangsmithError, APIError, APIUserAbortError, APIConnectionError, APIConnectionTimeoutError, BadRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, } from "./_openapi_client/core/error.js";
10
10
  // Update using pnpm bump-version
11
- export const __version__ = "0.10.6";
11
+ export const __version__ = "0.10.8";
12
12
  // Metadata key to hide a traced run from LangSmith's Messages View.
13
13
  export const LS_MESSAGE_VIEW_EXCLUDE = "ls_message_view_exclude";
@@ -50,29 +50,22 @@ const HEADER_SAFE_REPLICA_FIELDS = new Set([
50
50
  "primary",
51
51
  "updates",
52
52
  "reroot",
53
- ...(0, address_js_1.wireKeys)(),
53
+ "address",
54
54
  ]);
55
- // URL-encoded JSON of the address's wire fields.
55
+ // The address string, URL-encoded.
56
56
  const LANGSMITH_ADDRESS = "langsmith-address";
57
- /** Pops the address wire keys off untrusted `values`; never throws. */
58
- function takeHeaderAddress(values) {
59
- const wire = {};
60
- for (const key of (0, address_js_1.wireKeys)()) {
61
- if (key in values) {
62
- wire[key] = values[key];
63
- delete values[key];
64
- }
57
+ /** Validates an untrusted header address; `undefined` if unusable. */
58
+ function addressFromHeader(value) {
59
+ if (value == null) {
60
+ return undefined;
65
61
  }
66
62
  try {
67
- return {
68
- named: Object.keys(wire).length > 0,
69
- address: (0, address_js_1.fromWire)(wire),
70
- };
63
+ return (0, address_js_1.parse)(value);
71
64
  }
72
65
  catch {
73
66
  // Values are untrusted, so not logged.
74
- console.warn("Ignoring an invalid address in a `baggage` header.");
75
- return { named: true };
67
+ console.warn("Ignoring an unusable address in a `baggage` header.");
68
+ return undefined;
76
69
  }
77
70
  }
78
71
  function filterReplicaForHeaders(replica) {
@@ -148,16 +141,7 @@ class Baggage {
148
141
  project_name = value;
149
142
  }
150
143
  else if (key === LANGSMITH_ADDRESS) {
151
- let parsed;
152
- try {
153
- parsed = JSON.parse(value);
154
- }
155
- catch {
156
- parsed = undefined;
157
- }
158
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
159
- address = takeHeaderAddress({ ...parsed }).address;
160
- }
144
+ address = addressFromHeader(value);
161
145
  }
162
146
  else if (key === "langsmith-replicas") {
163
147
  const parsed = JSON.parse(value);
@@ -166,10 +150,12 @@ class Baggage {
166
150
  return [replica];
167
151
  }
168
152
  const filtered = filterReplicaForHeaders(replica);
169
- const { named, address } = takeHeaderAddress(filtered);
153
+ const raw = filtered.address;
154
+ delete filtered.address;
155
+ const address = addressFromHeader(raw);
170
156
  // A project wins over an address; a replica with an invalid
171
157
  // address and no project is dropped.
172
- if (filtered.projectName || !named) {
158
+ if (filtered.projectName || raw == null) {
173
159
  return [filtered];
174
160
  }
175
161
  return address ? [{ ...filtered, address }] : [];
@@ -190,7 +176,7 @@ class Baggage {
190
176
  items.push(`langsmith-project=${encodeURIComponent(this.project_name)}`);
191
177
  }
192
178
  if (this.address) {
193
- items.push(`${LANGSMITH_ADDRESS}=${encodeURIComponent(JSON.stringify((0, address_js_1.toWire)(this.address)))}`);
179
+ items.push(`${LANGSMITH_ADDRESS}=${encodeURIComponent(this.address)}`);
194
180
  }
195
181
  return items.join(",");
196
182
  }
@@ -683,14 +669,14 @@ class RunTree {
683
669
  if (primary === undefined &&
684
670
  !this.replicas?.some((r) => r.primary === true) &&
685
671
  projectName === this.project_name &&
686
- (0, address_js_1.sameAddress)(address, this.address)) {
672
+ address === this.address) {
687
673
  return {
688
674
  ...baseRun,
689
675
  session_name: projectName,
690
676
  address,
691
677
  };
692
678
  }
693
- const seed = projectName ?? (address ? (0, address_js_1.seed)(address) : undefined) ?? "agent//";
679
+ const seed = projectName ?? address ?? "agent//";
694
680
  // Apply reroot logic before ID remapping
695
681
  if (reroot) {
696
682
  if (distributedParentId) {
package/dist/run_trees.js CHANGED
@@ -9,7 +9,7 @@ import { warnOnce } from "./utils/warn.js";
9
9
  import { uuid7FromTime, nonCryptographicUuid7Deterministic, } from "./utils/_uuid.js";
10
10
  import { v5 as uuidv5 } from "./utils/uuid/src/index.js";
11
11
  import { checkAddress, logUntraced, rejectConflicting, resolveFromEnv, } from "./utils/agent_addressing.js";
12
- import { EnvAddressError, fromWire, sameAddress, seed as addressSeed, toWire, wireKeys, } from "./address.js";
12
+ import { EnvAddressError, parse as parseAddress, } from "./address.js";
13
13
  const TIMESTAMP_LENGTH = 36;
14
14
  // DNS namespace for UUID v5 (same as Python's uuid.NAMESPACE_DNS)
15
15
  const UUID_NAMESPACE_DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
@@ -44,29 +44,22 @@ const HEADER_SAFE_REPLICA_FIELDS = new Set([
44
44
  "primary",
45
45
  "updates",
46
46
  "reroot",
47
- ...wireKeys(),
47
+ "address",
48
48
  ]);
49
- // URL-encoded JSON of the address's wire fields.
49
+ // The address string, URL-encoded.
50
50
  const LANGSMITH_ADDRESS = "langsmith-address";
51
- /** Pops the address wire keys off untrusted `values`; never throws. */
52
- function takeHeaderAddress(values) {
53
- const wire = {};
54
- for (const key of wireKeys()) {
55
- if (key in values) {
56
- wire[key] = values[key];
57
- delete values[key];
58
- }
51
+ /** Validates an untrusted header address; `undefined` if unusable. */
52
+ function addressFromHeader(value) {
53
+ if (value == null) {
54
+ return undefined;
59
55
  }
60
56
  try {
61
- return {
62
- named: Object.keys(wire).length > 0,
63
- address: fromWire(wire),
64
- };
57
+ return parseAddress(value);
65
58
  }
66
59
  catch {
67
60
  // Values are untrusted, so not logged.
68
- console.warn("Ignoring an invalid address in a `baggage` header.");
69
- return { named: true };
61
+ console.warn("Ignoring an unusable address in a `baggage` header.");
62
+ return undefined;
70
63
  }
71
64
  }
72
65
  function filterReplicaForHeaders(replica) {
@@ -142,16 +135,7 @@ class Baggage {
142
135
  project_name = value;
143
136
  }
144
137
  else if (key === LANGSMITH_ADDRESS) {
145
- let parsed;
146
- try {
147
- parsed = JSON.parse(value);
148
- }
149
- catch {
150
- parsed = undefined;
151
- }
152
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
153
- address = takeHeaderAddress({ ...parsed }).address;
154
- }
138
+ address = addressFromHeader(value);
155
139
  }
156
140
  else if (key === "langsmith-replicas") {
157
141
  const parsed = JSON.parse(value);
@@ -160,10 +144,12 @@ class Baggage {
160
144
  return [replica];
161
145
  }
162
146
  const filtered = filterReplicaForHeaders(replica);
163
- const { named, address } = takeHeaderAddress(filtered);
147
+ const raw = filtered.address;
148
+ delete filtered.address;
149
+ const address = addressFromHeader(raw);
164
150
  // A project wins over an address; a replica with an invalid
165
151
  // address and no project is dropped.
166
- if (filtered.projectName || !named) {
152
+ if (filtered.projectName || raw == null) {
167
153
  return [filtered];
168
154
  }
169
155
  return address ? [{ ...filtered, address }] : [];
@@ -184,7 +170,7 @@ class Baggage {
184
170
  items.push(`langsmith-project=${encodeURIComponent(this.project_name)}`);
185
171
  }
186
172
  if (this.address) {
187
- items.push(`${LANGSMITH_ADDRESS}=${encodeURIComponent(JSON.stringify(toWire(this.address)))}`);
173
+ items.push(`${LANGSMITH_ADDRESS}=${encodeURIComponent(this.address)}`);
188
174
  }
189
175
  return items.join(",");
190
176
  }
@@ -677,14 +663,14 @@ export class RunTree {
677
663
  if (primary === undefined &&
678
664
  !this.replicas?.some((r) => r.primary === true) &&
679
665
  projectName === this.project_name &&
680
- sameAddress(address, this.address)) {
666
+ address === this.address) {
681
667
  return {
682
668
  ...baseRun,
683
669
  session_name: projectName,
684
670
  address,
685
671
  };
686
672
  }
687
- const seed = projectName ?? (address ? addressSeed(address) : undefined) ?? "agent//";
673
+ const seed = projectName ?? address ?? "agent//";
688
674
  // Apply reroot logic before ID remapping
689
675
  if (reroot) {
690
676
  if (distributedParentId) {
package/dist/schemas.d.ts CHANGED
@@ -150,7 +150,6 @@ export interface RunCreate extends BaseRun {
150
150
  revision_id?: string;
151
151
  child_runs?: this[];
152
152
  session_name?: string;
153
- /** (beta) Sent as `agent_id` / `agent_environment`. */
154
153
  address?: Address;
155
154
  }
156
155
  export interface RunUpdate {
@@ -170,7 +169,6 @@ export interface RunUpdate {
170
169
  events?: KVMap[];
171
170
  session_id?: string;
172
171
  session_name?: string;
173
- /** (beta) Sent as `agent_id` / `agent_environment`. */
174
172
  address?: Address;
175
173
  /** Unique ID assigned to every run within this nested trace. **/
176
174
  trace_id?: string;
@@ -526,7 +526,7 @@ function traceable(wrappedFunc, config) {
526
526
  runtimeConfig = undefined;
527
527
  }
528
528
  // Runtime config outranks decorator config, whichever mode each names.
529
- [ensuredConfig.project_name, ensuredConfig.address] = (0, agent_addressing_js_1.firstNamed)([runtimeConfig?.project_name, runtimeConfig?.address], [runTreeConfig.project_name, runTreeConfig.address]);
529
+ [ensuredConfig.project_name, ensuredConfig.address] = (0, agent_addressing_js_1.firstNamed)([runtimeConfig?.project_name, (0, agent_addressing_js_1.checkAddress)(runtimeConfig?.address)], [runTreeConfig.project_name, runTreeConfig.address]);
530
530
  let runEndedPromiseResolver;
531
531
  const runEndedPromise = new Promise((resolve) => {
532
532
  runEndedPromiseResolver = resolve;
@@ -651,9 +651,28 @@ function traceable(wrappedFunc, config) {
651
651
  async start(controller) {
652
652
  // eslint-disable-next-line no-constant-condition
653
653
  while (true) {
654
- const result = await (snapshot
655
- ? snapshot(() => otel_context.with(capturedOtelContext, () => reader.read()))
656
- : otel_context.with(capturedOtelContext, () => reader.read()));
654
+ let result;
655
+ try {
656
+ result = await (snapshot
657
+ ? snapshot(() => otel_context.with(capturedOtelContext, () => reader.read()))
658
+ : otel_context.with(capturedOtelContext, () => reader.read()));
659
+ }
660
+ catch (e) {
661
+ // The source stream errored: end the run with the error and the
662
+ // chunks received so far instead of leaving it pending.
663
+ finished = true;
664
+ await currentRunTree?.end(undefined, String(e));
665
+ await handleRunOutputs({
666
+ runTree: currentRunTree,
667
+ rawOutputs: await handleChunks(chunks),
668
+ processOutputsFn,
669
+ on_end,
670
+ postRunPromise,
671
+ deferredInputs,
672
+ skipChildPromiseDelay: true,
673
+ });
674
+ throw e;
675
+ }
657
676
  if (result.done) {
658
677
  finished = true;
659
678
  await handleRunOutputs({
package/dist/traceable.js CHANGED
@@ -522,7 +522,7 @@ export function traceable(wrappedFunc, config) {
522
522
  runtimeConfig = undefined;
523
523
  }
524
524
  // Runtime config outranks decorator config, whichever mode each names.
525
- [ensuredConfig.project_name, ensuredConfig.address] = firstNamed([runtimeConfig?.project_name, runtimeConfig?.address], [runTreeConfig.project_name, runTreeConfig.address]);
525
+ [ensuredConfig.project_name, ensuredConfig.address] = firstNamed([runtimeConfig?.project_name, checkAddress(runtimeConfig?.address)], [runTreeConfig.project_name, runTreeConfig.address]);
526
526
  let runEndedPromiseResolver;
527
527
  const runEndedPromise = new Promise((resolve) => {
528
528
  runEndedPromiseResolver = resolve;
@@ -647,9 +647,28 @@ export function traceable(wrappedFunc, config) {
647
647
  async start(controller) {
648
648
  // eslint-disable-next-line no-constant-condition
649
649
  while (true) {
650
- const result = await (snapshot
651
- ? snapshot(() => otel_context.with(capturedOtelContext, () => reader.read()))
652
- : otel_context.with(capturedOtelContext, () => reader.read()));
650
+ let result;
651
+ try {
652
+ result = await (snapshot
653
+ ? snapshot(() => otel_context.with(capturedOtelContext, () => reader.read()))
654
+ : otel_context.with(capturedOtelContext, () => reader.read()));
655
+ }
656
+ catch (e) {
657
+ // The source stream errored: end the run with the error and the
658
+ // chunks received so far instead of leaving it pending.
659
+ finished = true;
660
+ await currentRunTree?.end(undefined, String(e));
661
+ await handleRunOutputs({
662
+ runTree: currentRunTree,
663
+ rawOutputs: await handleChunks(chunks),
664
+ processOutputsFn,
665
+ on_end,
666
+ postRunPromise,
667
+ deferredInputs,
668
+ skipChildPromiseDelay: true,
669
+ });
670
+ throw e;
671
+ }
653
672
  if (result.done) {
654
673
  finished = true;
655
674
  await handleRunOutputs({
@@ -10,9 +10,9 @@ exports.applyToPayload = applyToPayload;
10
10
  const address_js_1 = require("../address.cjs");
11
11
  const env_js_1 = require("./env.cjs");
12
12
  const warn_js_1 = require("./warn.cjs");
13
- /** Validate an address at an entry point; the SDK carries the frozen copy. */
13
+ /** Validate and normalise an address at an entry point; the SDK carries the result. */
14
14
  function checkAddress(address) {
15
- return address == null ? undefined : (0, address_js_1.normalizeAddress)(address);
15
+ return address == null ? undefined : (0, address_js_1.parse)(address);
16
16
  }
17
17
  function rejectConflicting(project, address) {
18
18
  if (project && address) {
@@ -41,7 +41,7 @@ function getEnvProject() {
41
41
  */
42
42
  function resolveFromEnv() {
43
43
  const project = getEnvProject();
44
- const address = (0, address_js_1.addressFromEnv)();
44
+ const address = (0, address_js_1.fromEnv)();
45
45
  if (project && address) {
46
46
  throw new address_js_1.EnvAddressError("LANGSMITH_AGENT_* and a project are both set in the environment.");
47
47
  }
@@ -64,9 +64,8 @@ function warnOnEnv() {
64
64
  }
65
65
  }
66
66
  /**
67
- * Render `address` into its wire fields, in place. Without one, a create
68
- * naming no project takes the env address. Already-rendered payloads (runs
69
- * re-prepared when batched) are left alone.
67
+ * Put the run's address in its payload field, as one lowercase string.
68
+ * Without one, a create naming no project takes the env address.
70
69
  *
71
70
  * @throws {EnvAddressError} If the env names half an address.
72
71
  */
@@ -75,16 +74,15 @@ function applyToPayload(run, { update = false } = {}) {
75
74
  let address = checkAddress(payload.address);
76
75
  delete payload.address;
77
76
  const namedProject = payload.session_id != null || payload.session_name != null;
78
- const rendered = (0, address_js_1.wireKeys)().some((key) => payload[key] != null);
79
- if (!address && !update && !namedProject && !rendered) {
80
- address = (0, address_js_1.addressFromEnv)();
77
+ if (!address && !update && !namedProject) {
78
+ address = (0, address_js_1.fromEnv)();
81
79
  }
82
80
  if (!address) {
83
81
  return;
84
82
  }
85
83
  (0, warn_js_1.warnOnce)("Sending runs to an `address` is in beta and enabled per workspace; a " +
86
84
  "workspace without it rejects the runs.");
87
- Object.assign(payload, (0, address_js_1.toWire)(address));
85
+ payload.address = address;
88
86
  if (!namedProject) {
89
87
  delete payload.session_name;
90
88
  delete payload.session_id;
@@ -1,8 +1,8 @@
1
1
  import { type Address, EnvAddressError } from "../address.js";
2
2
  /** One precedence level: the `[project, address]` it names. */
3
3
  export type Tier = [string | undefined, Address | undefined];
4
- /** Validate an address at an entry point; the SDK carries the frozen copy. */
5
- export declare function checkAddress(address: unknown): Readonly<Address> | undefined;
4
+ /** Validate and normalise an address at an entry point; the SDK carries the result. */
5
+ export declare function checkAddress(address: unknown): Address | undefined;
6
6
  export declare function rejectConflicting(project: unknown, address: unknown): void;
7
7
  /** The highest level naming a project or an address, whichever it names. */
8
8
  export declare function firstNamed(...tiers: Tier[]): Tier;
@@ -15,9 +15,8 @@ export declare function logUntraced(error: EnvAddressError): void;
15
15
  /** Warn once, at client construction, if the env can't address runs. */
16
16
  export declare function warnOnEnv(): void;
17
17
  /**
18
- * Render `address` into its wire fields, in place. Without one, a create
19
- * naming no project takes the env address. Already-rendered payloads (runs
20
- * re-prepared when batched) are left alone.
18
+ * Put the run's address in its payload field, as one lowercase string.
19
+ * Without one, a create naming no project takes the env address.
21
20
  *
22
21
  * @throws {EnvAddressError} If the env names half an address.
23
22
  */
@@ -1,9 +1,9 @@
1
- import { EnvAddressError, addressFromEnv, envNames, normalizeAddress, toWire, wireKeys, } from "../address.js";
1
+ import { EnvAddressError, envNames, fromEnv as addressFromEnv, parse, } from "../address.js";
2
2
  import { getEnvironmentVariable, getLangSmithEnvironmentVariable, } from "./env.js";
3
3
  import { warnOnce } from "./warn.js";
4
- /** Validate an address at an entry point; the SDK carries the frozen copy. */
4
+ /** Validate and normalise an address at an entry point; the SDK carries the result. */
5
5
  export function checkAddress(address) {
6
- return address == null ? undefined : normalizeAddress(address);
6
+ return address == null ? undefined : parse(address);
7
7
  }
8
8
  export function rejectConflicting(project, address) {
9
9
  if (project && address) {
@@ -55,9 +55,8 @@ export function warnOnEnv() {
55
55
  }
56
56
  }
57
57
  /**
58
- * Render `address` into its wire fields, in place. Without one, a create
59
- * naming no project takes the env address. Already-rendered payloads (runs
60
- * re-prepared when batched) are left alone.
58
+ * Put the run's address in its payload field, as one lowercase string.
59
+ * Without one, a create naming no project takes the env address.
61
60
  *
62
61
  * @throws {EnvAddressError} If the env names half an address.
63
62
  */
@@ -66,8 +65,7 @@ export function applyToPayload(run, { update = false } = {}) {
66
65
  let address = checkAddress(payload.address);
67
66
  delete payload.address;
68
67
  const namedProject = payload.session_id != null || payload.session_name != null;
69
- const rendered = wireKeys().some((key) => payload[key] != null);
70
- if (!address && !update && !namedProject && !rendered) {
68
+ if (!address && !update && !namedProject) {
71
69
  address = addressFromEnv();
72
70
  }
73
71
  if (!address) {
@@ -75,7 +73,7 @@ export function applyToPayload(run, { update = false } = {}) {
75
73
  }
76
74
  warnOnce("Sending runs to an `address` is in beta and enabled per workspace; a " +
77
75
  "workspace without it rejects the runs.");
78
- Object.assign(payload, toWire(address));
76
+ payload.address = address;
79
77
  if (!namedProject) {
80
78
  delete payload.session_name;
81
79
  delete payload.session_id;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.10.6",
3
+ "version": "0.10.8",
4
4
  "description": "Client library to connect to the LangSmith Observability and Evaluation Platform.",
5
5
  "packageManager": "pnpm@10.33.0",
6
6
  "files": [