langsmith 0.10.12 → 0.10.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { AgentAddress, EnvAddressError, ensureAgent, envNames, } from "../address.mjs";
1
+ import { addressFromEnv, addressFromLrn, addressToLrn, EnvAddressError, ensureAgent, envNames, } from "../address.mjs";
2
2
  import { getEnvironmentVariable, getLangSmithEnvironmentVariable, } from "./env.mjs";
3
3
  import { warnOnce } from "./warn.mjs";
4
4
  export function rejectConflicting(project, address) {
@@ -28,7 +28,7 @@ function getEnvProject() {
28
28
  */
29
29
  export function resolveFromEnv() {
30
30
  const project = getEnvProject();
31
- const address = AgentAddress.fromEnv();
31
+ const address = addressFromEnv();
32
32
  if (project && address) {
33
33
  throw new EnvAddressError("LANGSMITH_AGENT_* and a project are both set in the environment.");
34
34
  }
@@ -64,7 +64,7 @@ export function applyToPayload(run, { update = false } = {}) {
64
64
  // is sent. It is parsed again, so a malformed one cannot fail the whole
65
65
  // batch in the backend.
66
66
  try {
67
- address = AgentAddress._fromLrn(payload.address);
67
+ address = addressFromLrn(payload.address);
68
68
  }
69
69
  catch {
70
70
  throw new Error("The run's `address` is not a valid agent address.");
@@ -76,14 +76,14 @@ export function applyToPayload(run, { update = false } = {}) {
76
76
  delete payload.address;
77
77
  const namedProject = payload.session_id != null || payload.session_name != null;
78
78
  if (!address && !update && !namedProject) {
79
- address = AgentAddress.fromEnv();
79
+ address = addressFromEnv();
80
80
  }
81
81
  if (!address) {
82
82
  return;
83
83
  }
84
84
  warnOnce("Sending runs to an `address` is in beta and enabled per workspace; a " +
85
85
  "workspace without it rejects the runs.");
86
- payload.address = address._toLrn();
86
+ payload.address = addressToLrn(address);
87
87
  if (!namedProject) {
88
88
  delete payload.session_name;
89
89
  delete payload.session_id;
@@ -1 +1 @@
1
- {"version":3,"file":"addressing.mjs","sourceRoot":"","sources":["../../src/lib/utils/addressing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"addressing.mjs","sourceRoot":"","sources":["../../src/lib/utils/addressing.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EACd,cAAc,EACd,YAAY,EACZ,eAAe,EACf,WAAW,EACX,QAAQ,GACT,uBAAsB;AACvB,OAAO,EACL,sBAAsB,EACtB,+BAA+B,GAChC,kBAAiB;AAClB,OAAO,EAAE,QAAQ,EAAE,mBAAkB;AAKrC,MAAM,UAAU,iBAAiB,CAAC,OAAgB,EAAE,OAAgB;IAClE,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,+BAA+B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,aAAa;YACjE,oBAAoB,CACvB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,UAAU,CAAC,GAAG,KAAa;IACzC,KAAK,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,EAAE,CAAC;QACvC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACpC,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;YACvB,OAAO,CAAC,OAAO,IAAI,SAAS,EAAE,OAAO,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IACD,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,aAAa;IACpB,OAAO,CACL,+BAA+B,CAAC,SAAS,CAAC;QAC1C,sBAAsB,CAAC,mBAAmB,CAAC;QAC3C,SAAS,CACV,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IACjC,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,eAAe,CACvB,kEAAkE,CACnE,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,SAAS,EAAE,SAAS,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAsB;IAChD,QAAQ,CAAC,uCAAuC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;AACnE,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAC7D,OAAO;IACT,CAAC;IACD,IAAI,CAAC;QACH,cAAc,EAAE,CAAC;IACnB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,QAAQ,CACN,GAAI,CAAW,CAAC,OAAO,6CAA6C;YAClE,aAAa,CAChB,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,GAA2E,EAC3E,EAAE,MAAM,GAAG,KAAK,KAA2B,EAAE;IAE7C,MAAM,OAAO,GAAG,GAA8B,CAAC;IAC/C,IAAI,OAAiC,CAAC;IACtC,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACxC,0EAA0E;QAC1E,wEAAwE;QACxE,wBAAwB;QACxB,IAAI,CAAC;YACH,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,CAAC;IACvB,MAAM,YAAY,GAChB,OAAO,CAAC,UAAU,IAAI,IAAI,IAAI,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC;IAC7D,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QACzC,OAAO,GAAG,cAAc,EAAE,CAAC;IAC7B,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IACD,QAAQ,CACN,uEAAuE;QACrE,wCAAwC,CAC3C,CAAC;IACF,OAAO,CAAC,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,OAAO,CAAC,YAAY,CAAC;QAC5B,OAAO,OAAO,CAAC,UAAU,CAAC;IAC5B,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.10.12",
3
+ "version": "0.10.13",
4
4
  "description": "Client library to connect to the LangSmith Observability and Evaluation Platform.",
5
5
  "author": "LangChain <>",
6
6
  "types": "./index.d.ts",
@@ -34,12 +34,13 @@
34
34
  "overrides": {
35
35
  "minimatch": "^9.0.7",
36
36
  "@hono/node-server": "2.0.10",
37
- "brace-expansion@<1.1.18": "1.1.18",
37
+ "brace-expansion@<1.1.21": "1.1.21",
38
38
  "brace-expansion@>=2.0.0 <2.1.7": "2.1.7",
39
39
  "source-map-js": "1.2.2",
40
40
  "@modelcontextprotocol/sdk": "1.31.0",
41
41
  "handlebars": "4.7.10",
42
- "brace-expansion@>=3.0.0 <5.0.7": "5.0.7",
42
+ "brace-expansion@>=3.0.0 <3.0.9": "3.0.9",
43
+ "brace-expansion@>=4.0.0 <5.0.12": "5.0.12",
43
44
  "fast-uri": "3.1.8",
44
45
  "postcss": "8.5.23",
45
46
  "js-yaml": "4.3.2",
@@ -59,12 +60,13 @@
59
60
  "overrides": {
60
61
  "minimatch": "^9.0.7",
61
62
  "@hono/node-server": "2.0.10",
62
- "brace-expansion@<1.1.18": "1.1.18",
63
+ "brace-expansion@<1.1.21": "1.1.21",
63
64
  "brace-expansion@>=2.0.0 <2.1.7": "2.1.7",
64
65
  "source-map-js": "1.2.2",
65
66
  "@modelcontextprotocol/sdk": "1.31.0",
66
67
  "handlebars": "4.7.10",
67
- "brace-expansion@>=3.0.0 <5.0.7": "5.0.7",
68
+ "brace-expansion@>=3.0.0 <3.0.9": "3.0.9",
69
+ "brace-expansion@>=4.0.0 <5.0.12": "5.0.12",
68
70
  "fast-uri": "3.1.8",
69
71
  "postcss": "8.5.23",
70
72
  "js-yaml": "4.3.2",
@@ -84,12 +86,13 @@
84
86
  "resolutions": {
85
87
  "minimatch": "^9.0.7",
86
88
  "@hono/node-server": "2.0.10",
87
- "brace-expansion@<1.1.18": "1.1.18",
89
+ "brace-expansion@<1.1.21": "1.1.21",
88
90
  "brace-expansion@>=2.0.0 <2.1.7": "2.1.7",
89
91
  "source-map-js": "1.2.2",
90
92
  "@modelcontextprotocol/sdk": "1.31.0",
91
93
  "handlebars": "4.7.10",
92
- "brace-expansion@>=3.0.0 <5.0.7": "5.0.7",
94
+ "brace-expansion@>=3.0.0 <3.0.9": "3.0.9",
95
+ "brace-expansion@>=4.0.0 <5.0.12": "5.0.12",
93
96
  "fast-uri": "3.1.8",
94
97
  "postcss": "8.5.23",
95
98
  "js-yaml": "4.3.2",
@@ -26,32 +26,67 @@ export type Environment = "local" | "development" | "staging" | "production";
26
26
  */
27
27
  export type Lrn = `lrn:agents/${string}/environments/${Environment}`;
28
28
 
29
- /** (beta) The backend's form of an address, as the resolve endpoint takes it. */
30
- export type ApiAddress = {
31
- kind: "AGENT" | "EXPERIMENT" | "EVALUATOR";
32
- id?: string;
33
- environment?: Uppercase<Environment>;
34
- };
29
+ /** (beta) The address of an agent's environment. */
30
+ export interface AgentAddress {
31
+ kind: "AGENT";
32
+ id: string;
33
+ environment: Uppercase<Environment>;
34
+ }
35
35
 
36
- /** (beta) A feature that holds traces in a tracing project. */
37
- export interface Address {
38
- /** The address in the backend's form. */
39
- toApiAddress(): ApiAddress;
36
+ /** (beta) Construct and validate an agent address; plain objects are also accepted. */
37
+ export class AgentAddress {
38
+ constructor(id: string, environment: Environment | (string & {})) {
39
+ const address = ensureAgent({ kind: "AGENT", id, environment });
40
+ this.kind = address.kind;
41
+ this.id = address.id;
42
+ this.environment = address.environment;
43
+ Object.freeze(this);
44
+ }
45
+ }
46
+
47
+ /** (beta) The address of an experiment's tracing project. */
48
+ export interface ExperimentAddress {
49
+ kind: "EXPERIMENT";
50
+ id: string;
51
+ }
52
+
53
+ /** (beta) Construct and validate an experiment address. */
54
+ export class ExperimentAddress {
55
+ constructor(id: string) {
56
+ const address = ensureAddress({ kind: "EXPERIMENT", id });
57
+ this.kind = address.kind;
58
+ this.id = address.id;
59
+ Object.freeze(this);
60
+ }
61
+ }
62
+
63
+ /** (beta) The address of the workspace's shared evaluators project. */
64
+ export interface EvaluatorAddress {
65
+ kind: "EVALUATOR";
40
66
  }
41
67
 
68
+ /** (beta) Construct the workspace's evaluators address. */
69
+ export class EvaluatorAddress {
70
+ constructor() {
71
+ this.kind = "EVALUATOR";
72
+ Object.freeze(this);
73
+ }
74
+ }
75
+
76
+ /** (beta) A feature that holds traces in a tracing project. */
77
+ export type Address = AgentAddress | ExperimentAddress | EvaluatorAddress;
78
+
79
+ /** (beta) An address as the resolve endpoint takes it. */
80
+ export type ApiAddress = Address;
81
+
42
82
  const UUID_PATTERN =
43
83
  /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
44
84
 
45
85
  // The server's agent id rule: a DNS label, so a hostname can carry the id.
46
86
  const AGENT_ID_PATTERN = /^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$/;
47
- const ENVIRONMENTS: string[] = [
48
- "local",
49
- "development",
50
- "staging",
51
- "production",
52
- ];
53
-
54
- // The wire form of an agent address. The parts are validated by `AgentAddress`.
87
+ const ENVIRONMENTS = ["local", "development", "staging", "production"];
88
+
89
+ // The wire form of an agent address. The parts are validated at entrypoints.
55
90
  const LRN_PATTERN = /^lrn:agents\/([^/]+)\/environments\/([^/]+)$/;
56
91
 
57
92
  const ENV_NAMES = ["LANGSMITH_AGENT_ID", "LANGSMITH_AGENT_ENVIRONMENT"];
@@ -64,189 +99,112 @@ export class EnvAddressError extends Error {
64
99
  }
65
100
  }
66
101
 
67
- /**
68
- * (beta) The address of an agent's environment.
69
- *
70
- * @example
71
- * ```ts
72
- * new AgentAddress("customer-support", "production");
73
- * ```
74
- */
75
- export class AgentAddress implements Address {
76
- readonly id: string;
77
-
78
- /** Always lowercase. */
79
- readonly environment: Environment;
80
-
81
- /**
82
- * @param id 1 to 63 lowercase ASCII letters, digits or hyphens, starting
83
- * with a letter and ending with a letter or digit. The server creates the
84
- * agent on first use.
85
- * @param environment One of `local`, `development`, `staging` or `production`, in
86
- * any case.
87
- * @throws If a value is invalid.
88
- */
89
- constructor(id: string, environment: Environment | (string & {})) {
90
- if (typeof id !== "string" || !AGENT_ID_PATTERN.test(id)) {
91
- throw new Error(
92
- "Address agent id must be 1 to 63 lowercase ASCII letters, digits, or " +
93
- "hyphens, start with a letter, and end with a letter or digit, got " +
94
- `${JSON.stringify(id)}. Use an id such as "support-agent".`,
95
- );
96
- }
97
- const normalized =
98
- typeof environment === "string" ? environment.toLowerCase() : undefined;
99
- if (normalized === undefined || !ENVIRONMENTS.includes(normalized)) {
100
- throw new Error(
101
- `Address environment must be one of ${ENVIRONMENTS.join(", ")}, got ` +
102
- `${JSON.stringify(environment)}.`,
103
- );
104
- }
105
- this.id = id;
106
- this.environment = normalized as Environment;
107
- Object.freeze(this);
108
- }
109
-
110
- toApiAddress(): ApiAddress {
111
- return {
112
- kind: "AGENT",
113
- id: this.id,
114
- environment: this.environment.toUpperCase() as Uppercase<Environment>,
115
- };
116
- }
117
-
118
- /** @internal */
119
- _toLrn(): Lrn {
120
- return `lrn:agents/${this.id}/environments/${this.environment}`;
121
- }
122
-
123
- /**
124
- * @internal Parse an LRN read from the wire, such as a `baggage` header. The
125
- * value is untrusted, so it is not echoed in the error.
126
- * @throws If `value` is not an agent LRN, or names an invalid id or environment.
127
- */
128
- static _fromLrn(value: unknown): AgentAddress {
129
- const match = typeof value === "string" ? LRN_PATTERN.exec(value) : null;
130
- if (match === null) {
131
- throw new Error("Not an agent address.");
132
- }
133
- return new AgentAddress(match[1], match[2]);
134
- }
135
-
136
- /**
137
- * Read the agent named by `LANGSMITH_AGENT_ID` and
138
- * `LANGSMITH_AGENT_ENVIRONMENT`; `undefined` if neither is set.
139
- * @throws {EnvAddressError} If only one is set, or a value is invalid.
140
- */
141
- static fromEnv(): AgentAddress | undefined {
142
- const values = ENV_NAMES.map((name) => getEnvironmentVariable(name));
143
- if (!values.some(Boolean)) {
144
- return undefined;
145
- }
146
- try {
147
- const missing = ENV_NAMES.filter((_, i) => !values[i]);
148
- if (missing.length > 0) {
149
- throw new Error(`An address needs ${missing.join(" and ")} as well.`);
150
- }
151
- return new AgentAddress(values[0] as string, values[1] as string);
152
- } catch (e) {
153
- const present = ENV_NAMES.flatMap((name, i) =>
154
- values[i] ? [`${name}=${JSON.stringify(values[i])}`] : [],
155
- ).join(", ");
156
- throw new EnvAddressError(
157
- `The LANGSMITH_AGENT_* env vars can't address a run (${present}): ${
158
- (e as Error).message
159
- }`,
160
- );
161
- }
102
+ /** Validate an address at an SDK entrypoint and return a normalized copy. */
103
+ export function ensureAddress<K extends Address["kind"]>(value: {
104
+ kind: K;
105
+ id?: unknown;
106
+ environment?: unknown;
107
+ }): Extract<Address, { kind: K }>;
108
+ export function ensureAddress(value: unknown): Address | undefined;
109
+ export function ensureAddress(value: unknown): Address | undefined {
110
+ if (value == null) return undefined;
111
+ if (typeof value !== "object") {
112
+ throw new Error(
113
+ "address must be an AgentAddress, ExperimentAddress or EvaluatorAddress object.",
114
+ );
162
115
  }
163
- }
164
-
165
- /** (beta) The address of an experiment's tracing project. */
166
- export class ExperimentAddress implements Address {
167
- /** Always lowercase. */
168
- readonly id: string;
169
-
170
- /**
171
- * @param id The experiment's UUID.
172
- * @throws If `id` is not a UUID.
173
- */
174
- constructor(id: string) {
116
+ const { kind, id, environment } = value as Record<string, unknown>;
117
+ if (kind === "EVALUATOR") return { kind };
118
+ if (kind === "EXPERIMENT") {
175
119
  if (typeof id !== "string" || !UUID_PATTERN.test(id)) {
176
120
  throw new Error(
177
121
  `Experiment id must be a UUID, got ${JSON.stringify(id)}.`,
178
122
  );
179
123
  }
180
- this.id = id.toLowerCase();
181
- Object.freeze(this);
124
+ return { kind, id: id.toLowerCase() };
182
125
  }
183
-
184
- toApiAddress(): ApiAddress {
185
- return { kind: "EXPERIMENT", id: this.id };
126
+ if (kind !== "AGENT") {
127
+ throw new Error(
128
+ "address must be an AgentAddress, ExperimentAddress or EvaluatorAddress object.",
129
+ );
186
130
  }
187
- }
188
-
189
- /** (beta) The address of the workspace's shared evaluators project. */
190
- export class EvaluatorAddress implements Address {
191
- constructor() {
192
- Object.freeze(this);
131
+ if (typeof id !== "string" || !AGENT_ID_PATTERN.test(id)) {
132
+ throw new Error(
133
+ "Address agent id must be 1 to 63 lowercase ASCII letters, digits, or " +
134
+ "hyphens, start with a letter, and end with a letter or digit, got " +
135
+ `${JSON.stringify(id)}. Use an id such as "support-agent".`,
136
+ );
193
137
  }
194
-
195
- toApiAddress(): ApiAddress {
196
- return { kind: "EVALUATOR" };
138
+ const normalized =
139
+ typeof environment === "string" ? environment.toLowerCase() : undefined;
140
+ if (normalized === undefined || !ENVIRONMENTS.includes(normalized)) {
141
+ throw new Error(
142
+ `Address environment must be one of ${ENVIRONMENTS.join(
143
+ ", ",
144
+ )}, got ${JSON.stringify(environment)}.`,
145
+ );
197
146
  }
147
+ return {
148
+ kind,
149
+ id,
150
+ environment: normalized.toUpperCase() as Uppercase<Environment>,
151
+ };
198
152
  }
199
153
 
200
- /**
201
- * @internal The ingestion entry-point guard: `value` must be an `AgentAddress` (or
202
- * absent), and is returned as is. Other addresses and strings are rejected.
203
- * @throws If `value` is not an `AgentAddress`.
204
- */
154
+ /** @internal Only agent addresses can receive traces. */
155
+ export function ensureAgent(value: {
156
+ kind: "AGENT";
157
+ id?: unknown;
158
+ environment?: unknown;
159
+ }): AgentAddress;
160
+ export function ensureAgent(value: unknown): AgentAddress | undefined;
205
161
  export function ensureAgent(value: unknown): AgentAddress | undefined {
206
- if (value == null) {
207
- return undefined;
208
- }
209
- if (value instanceof AgentAddress) {
210
- return value;
211
- }
212
- if (
213
- typeof value === "object" &&
214
- typeof (value as Address).toApiAddress === "function"
215
- ) {
162
+ const address = ensureAddress(value);
163
+ if (address && address.kind !== "AGENT") {
216
164
  throw new Error(
217
- `Only an AgentAddress can receive traces, got ${
218
- (value as object).constructor?.name ?? "an unknown address"
219
- }.`,
165
+ `Only an AgentAddress can receive traces, got ${address.kind}.`,
220
166
  );
221
167
  }
222
- throw new Error(
223
- "address must be an AgentAddress such as `new AgentAddress(id, environment)`, got " +
224
- `${typeof value === "string" ? JSON.stringify(value) : typeof value}.`,
225
- );
168
+ return address;
226
169
  }
227
170
 
228
- /**
229
- * Return `value` if it is an `Address` of any kind, as a lookup takes it.
230
- * For the calls that only resolve an address to its project, such as
231
- * `getRunUrl`. Whatever receives traces takes `ensureAgent`.
232
- */
233
- export function ensureAddress(value: unknown): Address | undefined {
234
- if (value == null) {
235
- return undefined;
236
- }
237
- if (
238
- typeof value === "object" &&
239
- typeof (value as Address).toApiAddress === "function"
240
- ) {
241
- return value as Address;
171
+ /** @internal Convert a validated address to the ingestion wire format. */
172
+ export function addressToLrn(address: AgentAddress): Lrn {
173
+ return `lrn:agents/${address.id}/environments/${
174
+ address.environment.toLowerCase() as Environment
175
+ }`;
176
+ }
177
+
178
+ /** @internal Parse and validate an address from untrusted wire data. */
179
+ export function addressFromLrn(value: unknown): AgentAddress {
180
+ const match = typeof value === "string" ? LRN_PATTERN.exec(value) : null;
181
+ if (!match) throw new Error("Not an agent address.");
182
+ return ensureAgent({ kind: "AGENT", id: match[1], environment: match[2] });
183
+ }
184
+
185
+ /** @internal Read and validate the address named by environment variables. */
186
+ export function addressFromEnv(): AgentAddress | undefined {
187
+ const values = ENV_NAMES.map((name) => getEnvironmentVariable(name));
188
+ if (!values.some(Boolean)) return undefined;
189
+ try {
190
+ const missing = ENV_NAMES.filter((_, i) => !values[i]);
191
+ if (missing.length)
192
+ throw new Error(`An address needs ${missing.join(" and ")} as well.`);
193
+ return ensureAgent({
194
+ kind: "AGENT",
195
+ id: values[0],
196
+ environment: values[1],
197
+ });
198
+ } catch (e) {
199
+ throw new EnvAddressError(
200
+ `The LANGSMITH_AGENT_* env vars can't address a run: ${
201
+ (e as Error).message
202
+ }`,
203
+ );
242
204
  }
243
- throw new Error(
244
- "address must be an AgentAddress, ExperimentAddress or EvaluatorAddress, got " +
245
- `${typeof value === "string" ? JSON.stringify(value) : typeof value}.`,
246
- );
247
205
  }
248
206
 
249
- /** @internal The `LANGSMITH_AGENT_*` env var names an address reads. */
207
+ /** @internal The environment variable names an address reads. */
250
208
  export function envNames(): string[] {
251
209
  return ENV_NAMES;
252
210
  }
package/src/lib/client.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { addressToLrn } from "./address.js";
1
2
  import * as uuid from "./utils/uuid/src/index.js";
2
3
  import { getOpenAPIBaseUrl } from "./utils/api_url.js";
3
4
  import type { OTELContext } from "./experimental/otel/types.js";
@@ -1861,7 +1862,7 @@ export class Client implements LangSmithTracingClientInterface {
1861
1862
 
1862
1863
  /**
1863
1864
  * (beta) Access the sessions resource, which resolves an address to the
1864
- * project its traces go to: `client.sessions.resolve(address.toApiAddress())`.
1865
+ * project its traces go to: `client.sessions.resolve(address)`.
1865
1866
  */
1866
1867
  public get sessions(): Sessions {
1867
1868
  this._checkStainlessVersion("0.18.0");
@@ -3359,9 +3360,7 @@ export class Client implements LangSmithTracingClientInterface {
3359
3360
 
3360
3361
  /** The ID of the project an address names, with one request. */
3361
3362
  private async _resolveAddress(address: Address): Promise<string> {
3362
- const { session_id: sessionId } = await this.sessions.resolve(
3363
- address.toApiAddress(),
3364
- );
3363
+ const { session_id: sessionId } = await this.sessions.resolve(address);
3365
3364
  assertUuid(sessionId);
3366
3365
  return sessionId;
3367
3366
  }
@@ -5672,7 +5671,7 @@ export class Client implements LangSmithTracingClientInterface {
5672
5671
  return feedback as Feedback;
5673
5672
  }
5674
5673
  const body = JSON.stringify(
5675
- address ? { ...feedback, address: address._toLrn() } : feedback,
5674
+ address ? { ...feedback, address: addressToLrn(address) } : feedback,
5676
5675
  );
5677
5676
  const url = `${this.apiUrl}/feedback`;
5678
5677
  await this.caller.call(async () => {
@@ -1,3 +1,4 @@
1
+ import { addressToLrn, addressFromLrn } from "./address.js";
1
2
  import { Client } from "./client.js";
2
3
  import { isEnvTracingEnabled } from "./env.js";
3
4
  import {
@@ -33,7 +34,7 @@ import {
33
34
  rejectConflicting,
34
35
  resolveFromEnv,
35
36
  } from "./utils/addressing.js";
36
- import { AgentAddress, EnvAddressError, ensureAgent } from "./address.js";
37
+ import { type AgentAddress, EnvAddressError, ensureAgent } from "./address.js";
37
38
 
38
39
  const TIMESTAMP_LENGTH = 36;
39
40
  // DNS namespace for UUID v5 (same as Python's uuid.NAMESPACE_DNS)
@@ -197,7 +198,7 @@ const HEADER_SAFE_REPLICA_FIELDS = new Set([
197
198
  /** Rebuilds an untrusted header address; `undefined` if unusable. */
198
199
  function addressFromHeader(value: unknown): AgentAddress | undefined {
199
200
  try {
200
- return AgentAddress._fromLrn(value);
201
+ return addressFromLrn(value);
201
202
  } catch {
202
203
  // Values are untrusted, so not logged.
203
204
  console.warn("Ignoring an unusable address in a `baggage` header.");
@@ -301,7 +302,7 @@ class Baggage {
301
302
  }
302
303
  if (this.address) {
303
304
  items.push(
304
- `langsmith-address=${encodeURIComponent(this.address._toLrn())}`,
305
+ `langsmith-address=${encodeURIComponent(addressToLrn(this.address))}`,
305
306
  );
306
307
  }
307
308
 
@@ -752,7 +753,8 @@ export class RunTree implements BaseRun {
752
753
  primary === undefined &&
753
754
  !this.replicas?.some((r) => r.primary === true) &&
754
755
  projectName === this.project_name &&
755
- address?._toLrn() === this.address?._toLrn()
756
+ (address ? addressToLrn(address) : undefined) ===
757
+ (this.address ? addressToLrn(this.address) : undefined)
756
758
  ) {
757
759
  return {
758
760
  ...baseRun,
@@ -760,7 +762,8 @@ export class RunTree implements BaseRun {
760
762
  address,
761
763
  };
762
764
  }
763
- const seed = projectName ?? address?._toLrn() ?? "agent//";
765
+ const seed =
766
+ projectName ?? (address ? addressToLrn(address) : undefined) ?? "agent//";
764
767
 
765
768
  // Apply reroot logic before ID remapping
766
769
  if (reroot) {
@@ -1,5 +1,8 @@
1
1
  import {
2
- AgentAddress,
2
+ type AgentAddress,
3
+ addressFromEnv,
4
+ addressFromLrn,
5
+ addressToLrn,
3
6
  EnvAddressError,
4
7
  ensureAgent,
5
8
  envNames,
@@ -47,7 +50,7 @@ function getEnvProject(): string | undefined {
47
50
  */
48
51
  export function resolveFromEnv(): Tier {
49
52
  const project = getEnvProject();
50
- const address = AgentAddress.fromEnv();
53
+ const address = addressFromEnv();
51
54
  if (project && address) {
52
55
  throw new EnvAddressError(
53
56
  "LANGSMITH_AGENT_* and a project are both set in the environment.",
@@ -92,7 +95,7 @@ export function applyToPayload(
92
95
  // is sent. It is parsed again, so a malformed one cannot fail the whole
93
96
  // batch in the backend.
94
97
  try {
95
- address = AgentAddress._fromLrn(payload.address);
98
+ address = addressFromLrn(payload.address);
96
99
  } catch {
97
100
  throw new Error("The run's `address` is not a valid agent address.");
98
101
  }
@@ -103,7 +106,7 @@ export function applyToPayload(
103
106
  const namedProject =
104
107
  payload.session_id != null || payload.session_name != null;
105
108
  if (!address && !update && !namedProject) {
106
- address = AgentAddress.fromEnv();
109
+ address = addressFromEnv();
107
110
  }
108
111
  if (!address) {
109
112
  return;
@@ -112,7 +115,7 @@ export function applyToPayload(
112
115
  "Sending runs to an `address` is in beta and enabled per workspace; a " +
113
116
  "workspace without it rejects the runs.",
114
117
  );
115
- payload.address = address._toLrn();
118
+ payload.address = addressToLrn(address);
116
119
  if (!namedProject) {
117
120
  delete payload.session_name;
118
121
  delete payload.session_id;
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = '0.10.12'; // x-release-please-version
1
+ export const VERSION = '0.10.13'; // x-release-please-version
package/version.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.10.12";
1
+ export declare const VERSION = "0.10.13";
2
2
  //# sourceMappingURL=version.d.mts.map
package/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.10.12";
1
+ export declare const VERSION = "0.10.13";
2
2
  //# sourceMappingURL=version.d.ts.map
package/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
- exports.VERSION = '0.10.12'; // x-release-please-version
4
+ exports.VERSION = '0.10.13'; // x-release-please-version
5
5
  //# sourceMappingURL=version.js.map
package/version.mjs CHANGED
@@ -1,2 +1,2 @@
1
- export const VERSION = '0.10.12'; // x-release-please-version
1
+ export const VERSION = '0.10.13'; // x-release-please-version
2
2
  //# sourceMappingURL=version.mjs.map