langsmith 0.8.8 → 0.8.10

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 (65) hide show
  1. package/dist/_openapi_client/resources/annotation-queues/annotation-queues.cjs +10 -0
  2. package/dist/_openapi_client/resources/annotation-queues/annotation-queues.d.ts +10 -0
  3. package/dist/_openapi_client/resources/annotation-queues/annotation-queues.js +10 -0
  4. package/dist/_openapi_client/resources/annotation-queues/runs.cjs +13 -1
  5. package/dist/_openapi_client/resources/annotation-queues/runs.d.ts +13 -1
  6. package/dist/_openapi_client/resources/annotation-queues/runs.js +13 -1
  7. package/dist/_openapi_client/resources/datasets/experiment-runs.cjs +2 -0
  8. package/dist/_openapi_client/resources/datasets/experiment-runs.d.ts +2 -0
  9. package/dist/_openapi_client/resources/datasets/experiment-runs.js +2 -0
  10. package/dist/_openapi_client/resources/issues.d.ts +1 -1
  11. package/dist/_openapi_client/resources/public/runs.cjs +9 -7
  12. package/dist/_openapi_client/resources/public/runs.d.ts +8 -6
  13. package/dist/_openapi_client/resources/public/runs.js +9 -7
  14. package/dist/_openapi_client/resources/runs/runs.cjs +11 -6
  15. package/dist/_openapi_client/resources/runs/runs.d.ts +11 -6
  16. package/dist/_openapi_client/resources/runs/runs.js +11 -6
  17. package/dist/_openapi_client/resources/runs/share.cjs +4 -0
  18. package/dist/_openapi_client/resources/runs/share.d.ts +4 -0
  19. package/dist/_openapi_client/resources/runs/share.js +4 -0
  20. package/dist/_openapi_client/resources/threads.cjs +11 -8
  21. package/dist/_openapi_client/resources/threads.d.ts +11 -8
  22. package/dist/_openapi_client/resources/threads.js +11 -8
  23. package/dist/_openapi_client/resources/traces.cjs +6 -3
  24. package/dist/_openapi_client/resources/traces.d.ts +6 -3
  25. package/dist/_openapi_client/resources/traces.js +6 -3
  26. package/dist/client.cjs +295 -24
  27. package/dist/client.d.ts +63 -9
  28. package/dist/client.js +295 -24
  29. package/dist/evaluation/evaluate_comparative.cjs +7 -4
  30. package/dist/evaluation/evaluate_comparative.js +7 -4
  31. package/dist/experimental/vercel/_agent_type.cjs +30 -0
  32. package/dist/experimental/vercel/_agent_type.d.ts +5 -0
  33. package/dist/experimental/vercel/_agent_type.js +26 -0
  34. package/dist/experimental/vercel/telemetry.cjs +2 -7
  35. package/dist/experimental/vercel/telemetry.js +2 -7
  36. package/dist/experimental/vercel/wrap.cjs +5 -11
  37. package/dist/experimental/vercel/wrap.js +6 -12
  38. package/dist/index.cjs +1 -1
  39. package/dist/index.d.ts +1 -1
  40. package/dist/index.js +1 -1
  41. package/dist/sandbox/command_handle.cjs +34 -7
  42. package/dist/sandbox/command_handle.d.ts +1 -0
  43. package/dist/sandbox/command_handle.js +34 -7
  44. package/dist/sandbox/ws_execute.cjs +7 -3
  45. package/dist/sandbox/ws_execute.d.ts +4 -2
  46. package/dist/sandbox/ws_execute.js +7 -3
  47. package/dist/utils/_git.cjs +28 -1
  48. package/dist/utils/_git.js +28 -1
  49. package/dist/utils/ls_agent_type.cjs +31 -0
  50. package/dist/utils/ls_agent_type.d.ts +9 -0
  51. package/dist/utils/ls_agent_type.js +25 -0
  52. package/dist/utils/profiles.cjs +125 -1
  53. package/dist/utils/profiles.d.ts +6 -0
  54. package/dist/utils/profiles.js +124 -1
  55. package/dist/utils/v2_migration.cjs +18 -0
  56. package/dist/utils/v2_migration.d.ts +8 -0
  57. package/dist/utils/v2_migration.js +16 -0
  58. package/dist/utils/warn.cjs +30 -4
  59. package/dist/utils/warn.d.ts +4 -1
  60. package/dist/utils/warn.js +29 -4
  61. package/dist/wrappers/openai.cjs +4 -0
  62. package/dist/wrappers/openai.js +4 -0
  63. package/dist/wrappers/openai_agents.cjs +15 -12
  64. package/dist/wrappers/openai_agents.js +15 -12
  65. package/package.json +1 -1
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.ProfileAuth = exports.DEFAULT_API_URL = void 0;
37
37
  exports.hasValue = hasValue;
38
+ exports.resolveTokenEndpoint = resolveTokenEndpoint;
38
39
  exports.loadProfileClientConfig = loadProfileClientConfig;
39
40
  const env_js_1 = require("./env.cjs");
40
41
  const fsUtils = __importStar(require("./fs.cjs"));
@@ -43,6 +44,8 @@ exports.DEFAULT_API_URL = "https://api.smith.langchain.com";
43
44
  const OAUTH_CLIENT_ID = "langsmith-cli";
44
45
  const TOKEN_REFRESH_LEEWAY_MS = 60_000;
45
46
  const TOKEN_REFRESH_TIMEOUT_MS = 10_000;
47
+ const OAUTH_DISCOVERY_TIMEOUT_MS = 5_000;
48
+ const WELL_KNOWN_OAUTH_PATH = "/.well-known/oauth-authorization-server";
46
49
  function isBrowserLikeRuntime() {
47
50
  const env = (0, env_js_1.getEnv)();
48
51
  return env === "browser" || env === "webworker";
@@ -125,6 +128,126 @@ function normalizeConfigUrl(apiUrl) {
125
128
  ? normalized.slice(0, -apiV1Suffix.length)
126
129
  : normalized;
127
130
  }
131
+ /**
132
+ * Metadata base URLs to probe, most specific first: the configured mount point,
133
+ * then the self-hosted and SaaS locations, so both a bare origin and an
134
+ * explicit `/api` resolve.
135
+ */
136
+ function oauthDiscoveryCandidates(apiUrl) {
137
+ const given = normalizeConfigUrl(apiUrl);
138
+ const origin = given.endsWith("/api")
139
+ ? given.slice(0, -"/api".length)
140
+ : given;
141
+ const candidates = [];
142
+ for (const candidate of [given, `${origin}/api`, origin]) {
143
+ if (candidate && candidate !== "/api" && !candidates.includes(candidate)) {
144
+ candidates.push(candidate);
145
+ }
146
+ }
147
+ return candidates;
148
+ }
149
+ /**
150
+ * Check the document describes the deployment we probed. RFC 8414 requires the
151
+ * issuer to match the URL the well-known path was built from, and every
152
+ * endpoint must share the issuer's origin. Refresh tokens are posted to these
153
+ * endpoints, so an unvalidated document could redirect credentials elsewhere.
154
+ */
155
+ function isTrustedOAuthMetadata(doc, base) {
156
+ const { issuer } = doc;
157
+ if (typeof issuer !== "string" ||
158
+ issuer.replace(/\/+$/, "") !== base.replace(/\/+$/, "")) {
159
+ return false;
160
+ }
161
+ let issuerUrl;
162
+ try {
163
+ issuerUrl = new URL(issuer);
164
+ }
165
+ catch {
166
+ return false;
167
+ }
168
+ for (const endpoint of [
169
+ doc.device_authorization_endpoint,
170
+ doc.token_endpoint,
171
+ ]) {
172
+ if (typeof endpoint !== "string" || !endpoint) {
173
+ return false;
174
+ }
175
+ try {
176
+ const url = new URL(endpoint);
177
+ if (url.protocol !== issuerUrl.protocol || url.host !== issuerUrl.host) {
178
+ return false;
179
+ }
180
+ }
181
+ catch {
182
+ return false;
183
+ }
184
+ }
185
+ return true;
186
+ }
187
+ /**
188
+ * Metadata URLs for an issuer, RFC 8414 form first. RFC 8414 inserts the
189
+ * well-known segment between the origin and the issuer path, so
190
+ * `https://host/api` is described at
191
+ * `https://host/.well-known/oauth-authorization-server/api`. Deployments
192
+ * commonly also serve the appended form, and for a path-less issuer the two are
193
+ * identical.
194
+ */
195
+ function oauthMetadataUrls(base) {
196
+ const appended = `${base}${WELL_KNOWN_OAUTH_PATH}`;
197
+ let inserted;
198
+ try {
199
+ const url = new URL(base);
200
+ inserted = `${url.origin}${WELL_KNOWN_OAUTH_PATH}${url.pathname === "/" ? "" : url.pathname}`;
201
+ }
202
+ catch {
203
+ return [appended];
204
+ }
205
+ return inserted === appended ? [inserted] : [inserted, appended];
206
+ }
207
+ async function fetchOAuthMetadata(url, base, fetchImplementation) {
208
+ let response;
209
+ try {
210
+ response = await fetchImplementation(url, {
211
+ method: "GET",
212
+ headers: { Accept: "application/json" },
213
+ signal: AbortSignal.timeout(OAUTH_DISCOVERY_TIMEOUT_MS),
214
+ });
215
+ }
216
+ catch {
217
+ return undefined;
218
+ }
219
+ if (!response.ok) {
220
+ return undefined;
221
+ }
222
+ let doc;
223
+ try {
224
+ // Self-hosted answers unknown paths with an HTML 200 from the SPA.
225
+ doc = (await response.json());
226
+ }
227
+ catch {
228
+ return undefined;
229
+ }
230
+ if (!doc || typeof doc !== "object" || !isTrustedOAuthMetadata(doc, base)) {
231
+ return undefined;
232
+ }
233
+ return doc;
234
+ }
235
+ /**
236
+ * Resolve the token endpoint, preferring the deployment's metadata document.
237
+ * Falls back to `<mount>/oauth/token`, keeping a trailing `/api` because
238
+ * self-hosted mounts the authorization server under it.
239
+ */
240
+ async function resolveTokenEndpoint(apiUrl, fetchImplementation) {
241
+ for (const base of oauthDiscoveryCandidates(apiUrl)) {
242
+ for (const url of oauthMetadataUrls(base)) {
243
+ const doc = await fetchOAuthMetadata(url, base, fetchImplementation);
244
+ if (doc) {
245
+ return doc.token_endpoint;
246
+ }
247
+ }
248
+ }
249
+ return `${normalizeConfigUrl(apiUrl)}/oauth/token`;
250
+ }
128
251
  function applyTokenResponse(profile, token) {
129
252
  profile.oauth ??= {};
130
253
  if (token.access_token) {
@@ -262,7 +385,8 @@ class ProfileAuth {
262
385
  client_id: OAUTH_CLIENT_ID,
263
386
  refresh_token: this.state.profile.oauth?.refresh_token ?? refreshToken,
264
387
  });
265
- const response = await fetchImplementation(`${normalizeConfigUrl(refreshApiUrl)}/oauth/token`, {
388
+ const tokenEndpoint = await resolveTokenEndpoint(refreshApiUrl, fetchImplementation);
389
+ const response = await fetchImplementation(tokenEndpoint, {
266
390
  method: "POST",
267
391
  headers: {
268
392
  "Content-Type": "application/x-www-form-urlencoded",
@@ -33,6 +33,12 @@ export type ProfileClientConfig = {
33
33
  profileAuth?: ProfileAuth;
34
34
  };
35
35
  export declare function hasValue(value?: string | null): boolean;
36
+ /**
37
+ * Resolve the token endpoint, preferring the deployment's metadata document.
38
+ * Falls back to `<mount>/oauth/token`, keeping a trailing `/api` because
39
+ * self-hosted mounts the authorization server under it.
40
+ */
41
+ export declare function resolveTokenEndpoint(apiUrl: string, fetchImplementation: typeof fetch): Promise<string>;
36
42
  export declare function loadProfileClientConfig(): ProfileClientConfig;
37
43
  export declare class ProfileAuth {
38
44
  private state;
@@ -5,6 +5,8 @@ export const DEFAULT_API_URL = "https://api.smith.langchain.com";
5
5
  const OAUTH_CLIENT_ID = "langsmith-cli";
6
6
  const TOKEN_REFRESH_LEEWAY_MS = 60_000;
7
7
  const TOKEN_REFRESH_TIMEOUT_MS = 10_000;
8
+ const OAUTH_DISCOVERY_TIMEOUT_MS = 5_000;
9
+ const WELL_KNOWN_OAUTH_PATH = "/.well-known/oauth-authorization-server";
8
10
  function isBrowserLikeRuntime() {
9
11
  const env = getEnv();
10
12
  return env === "browser" || env === "webworker";
@@ -87,6 +89,126 @@ function normalizeConfigUrl(apiUrl) {
87
89
  ? normalized.slice(0, -apiV1Suffix.length)
88
90
  : normalized;
89
91
  }
92
+ /**
93
+ * Metadata base URLs to probe, most specific first: the configured mount point,
94
+ * then the self-hosted and SaaS locations, so both a bare origin and an
95
+ * explicit `/api` resolve.
96
+ */
97
+ function oauthDiscoveryCandidates(apiUrl) {
98
+ const given = normalizeConfigUrl(apiUrl);
99
+ const origin = given.endsWith("/api")
100
+ ? given.slice(0, -"/api".length)
101
+ : given;
102
+ const candidates = [];
103
+ for (const candidate of [given, `${origin}/api`, origin]) {
104
+ if (candidate && candidate !== "/api" && !candidates.includes(candidate)) {
105
+ candidates.push(candidate);
106
+ }
107
+ }
108
+ return candidates;
109
+ }
110
+ /**
111
+ * Check the document describes the deployment we probed. RFC 8414 requires the
112
+ * issuer to match the URL the well-known path was built from, and every
113
+ * endpoint must share the issuer's origin. Refresh tokens are posted to these
114
+ * endpoints, so an unvalidated document could redirect credentials elsewhere.
115
+ */
116
+ function isTrustedOAuthMetadata(doc, base) {
117
+ const { issuer } = doc;
118
+ if (typeof issuer !== "string" ||
119
+ issuer.replace(/\/+$/, "") !== base.replace(/\/+$/, "")) {
120
+ return false;
121
+ }
122
+ let issuerUrl;
123
+ try {
124
+ issuerUrl = new URL(issuer);
125
+ }
126
+ catch {
127
+ return false;
128
+ }
129
+ for (const endpoint of [
130
+ doc.device_authorization_endpoint,
131
+ doc.token_endpoint,
132
+ ]) {
133
+ if (typeof endpoint !== "string" || !endpoint) {
134
+ return false;
135
+ }
136
+ try {
137
+ const url = new URL(endpoint);
138
+ if (url.protocol !== issuerUrl.protocol || url.host !== issuerUrl.host) {
139
+ return false;
140
+ }
141
+ }
142
+ catch {
143
+ return false;
144
+ }
145
+ }
146
+ return true;
147
+ }
148
+ /**
149
+ * Metadata URLs for an issuer, RFC 8414 form first. RFC 8414 inserts the
150
+ * well-known segment between the origin and the issuer path, so
151
+ * `https://host/api` is described at
152
+ * `https://host/.well-known/oauth-authorization-server/api`. Deployments
153
+ * commonly also serve the appended form, and for a path-less issuer the two are
154
+ * identical.
155
+ */
156
+ function oauthMetadataUrls(base) {
157
+ const appended = `${base}${WELL_KNOWN_OAUTH_PATH}`;
158
+ let inserted;
159
+ try {
160
+ const url = new URL(base);
161
+ inserted = `${url.origin}${WELL_KNOWN_OAUTH_PATH}${url.pathname === "/" ? "" : url.pathname}`;
162
+ }
163
+ catch {
164
+ return [appended];
165
+ }
166
+ return inserted === appended ? [inserted] : [inserted, appended];
167
+ }
168
+ async function fetchOAuthMetadata(url, base, fetchImplementation) {
169
+ let response;
170
+ try {
171
+ response = await fetchImplementation(url, {
172
+ method: "GET",
173
+ headers: { Accept: "application/json" },
174
+ signal: AbortSignal.timeout(OAUTH_DISCOVERY_TIMEOUT_MS),
175
+ });
176
+ }
177
+ catch {
178
+ return undefined;
179
+ }
180
+ if (!response.ok) {
181
+ return undefined;
182
+ }
183
+ let doc;
184
+ try {
185
+ // Self-hosted answers unknown paths with an HTML 200 from the SPA.
186
+ doc = (await response.json());
187
+ }
188
+ catch {
189
+ return undefined;
190
+ }
191
+ if (!doc || typeof doc !== "object" || !isTrustedOAuthMetadata(doc, base)) {
192
+ return undefined;
193
+ }
194
+ return doc;
195
+ }
196
+ /**
197
+ * Resolve the token endpoint, preferring the deployment's metadata document.
198
+ * Falls back to `<mount>/oauth/token`, keeping a trailing `/api` because
199
+ * self-hosted mounts the authorization server under it.
200
+ */
201
+ export async function resolveTokenEndpoint(apiUrl, fetchImplementation) {
202
+ for (const base of oauthDiscoveryCandidates(apiUrl)) {
203
+ for (const url of oauthMetadataUrls(base)) {
204
+ const doc = await fetchOAuthMetadata(url, base, fetchImplementation);
205
+ if (doc) {
206
+ return doc.token_endpoint;
207
+ }
208
+ }
209
+ }
210
+ return `${normalizeConfigUrl(apiUrl)}/oauth/token`;
211
+ }
90
212
  function applyTokenResponse(profile, token) {
91
213
  profile.oauth ??= {};
92
214
  if (token.access_token) {
@@ -224,7 +346,8 @@ export class ProfileAuth {
224
346
  client_id: OAUTH_CLIENT_ID,
225
347
  refresh_token: this.state.profile.oauth?.refresh_token ?? refreshToken,
226
348
  });
227
- const response = await fetchImplementation(`${normalizeConfigUrl(refreshApiUrl)}/oauth/token`, {
349
+ const tokenEndpoint = await resolveTokenEndpoint(refreshApiUrl, fetchImplementation);
350
+ const response = await fetchImplementation(tokenEndpoint, {
228
351
  method: "POST",
229
352
  headers: {
230
353
  "Content-Type": "application/x-www-form-urlencoded",
@@ -1,7 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QueryBackend = void 0;
4
+ exports.getQueryBackend = getQueryBackend;
3
5
  exports.v2RunToRun = v2RunToRun;
4
6
  exports.loadTracesV2 = loadTracesV2;
7
+ exports.QueryBackend = {
8
+ CLICKHOUSE_ONLY: "clickhouse_only",
9
+ SMITHDB_ONLY: "smithdb_only",
10
+ DUAL: "dual",
11
+ };
12
+ /** Which backend(s) `/info`'s `instance_flags` indicate for run/trace queries. */
13
+ function getQueryBackend(instanceFlags) {
14
+ const flags = instanceFlags ?? {};
15
+ const chEnabled = Boolean(flags.ch_query_enabled ?? true);
16
+ const sdbEnabled = Boolean(flags.sdb_query_enabled ?? false);
17
+ if (!chEnabled && sdbEnabled)
18
+ return exports.QueryBackend.SMITHDB_ONLY;
19
+ if (chEnabled && sdbEnabled)
20
+ return exports.QueryBackend.DUAL;
21
+ return exports.QueryBackend.CLICKHOUSE_ONLY;
22
+ }
5
23
  // Omitting selects from `/v2/runs/query` returns only the run ID.
6
24
  const V2_RUN_SELECTS = [
7
25
  "ID",
@@ -1,6 +1,14 @@
1
1
  import type { Run as V2Run } from "../_openapi_client/resources/runs/runs.js";
2
2
  import type { Client } from "../client.js";
3
3
  import type { Run, TracerSession } from "../schemas.js";
4
+ export declare const QueryBackend: {
5
+ readonly CLICKHOUSE_ONLY: "clickhouse_only";
6
+ readonly SMITHDB_ONLY: "smithdb_only";
7
+ readonly DUAL: "dual";
8
+ };
9
+ export type QueryBackend = (typeof QueryBackend)[keyof typeof QueryBackend];
10
+ /** Which backend(s) `/info`'s `instance_flags` indicate for run/trace queries. */
11
+ export declare function getQueryBackend(instanceFlags?: Record<string, unknown> | null): QueryBackend;
4
12
  export declare function v2RunToRun(run: V2Run): Run;
5
13
  export declare function loadTracesV2(client: Client, project: TracerSession, options: {
6
14
  isRoot?: boolean;
@@ -1,3 +1,19 @@
1
+ export const QueryBackend = {
2
+ CLICKHOUSE_ONLY: "clickhouse_only",
3
+ SMITHDB_ONLY: "smithdb_only",
4
+ DUAL: "dual",
5
+ };
6
+ /** Which backend(s) `/info`'s `instance_flags` indicate for run/trace queries. */
7
+ export function getQueryBackend(instanceFlags) {
8
+ const flags = instanceFlags ?? {};
9
+ const chEnabled = Boolean(flags.ch_query_enabled ?? true);
10
+ const sdbEnabled = Boolean(flags.sdb_query_enabled ?? false);
11
+ if (!chEnabled && sdbEnabled)
12
+ return QueryBackend.SMITHDB_ONLY;
13
+ if (chEnabled && sdbEnabled)
14
+ return QueryBackend.DUAL;
15
+ return QueryBackend.CLICKHOUSE_ONLY;
16
+ }
1
17
  // Omitting selects from `/v2/runs/query` returns only the run ID.
2
18
  const V2_RUN_SELECTS = [
3
19
  "ID",
@@ -1,10 +1,36 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports._resetWarnedMessages = _resetWarnedMessages;
3
4
  exports.warnOnce = warnOnce;
4
5
  const warnedMessages = {};
5
- function warnOnce(message) {
6
- if (!warnedMessages[message]) {
7
- console.warn(message);
8
- warnedMessages[message] = true;
6
+ /**
7
+ * Clear the warn-once record so a later call warns again.
8
+ *
9
+ * Test-only. `warnedMessages` is module-global and never otherwise reset, so
10
+ * without this a test asserting "warning X was (not) emitted" depends on whether
11
+ * an earlier test in the same file already consumed X.
12
+ *
13
+ * @internal
14
+ */
15
+ function _resetWarnedMessages() {
16
+ for (const key of Object.keys(warnedMessages)) {
17
+ delete warnedMessages[key];
18
+ }
19
+ }
20
+ function warnOnce(message, options) {
21
+ const key = options?.code ?? message;
22
+ if (!warnedMessages[key]) {
23
+ warnedMessages[key] = true;
24
+ if (options?.type &&
25
+ typeof process !== "undefined" &&
26
+ typeof process.emitWarning === "function") {
27
+ process.emitWarning(message, { type: options.type, code: options.code });
28
+ }
29
+ else if (options?.type && options?.code) {
30
+ console.warn(`${options.type} [${options.code}]: ${message}`);
31
+ }
32
+ else {
33
+ console.warn(message);
34
+ }
9
35
  }
10
36
  }
@@ -1 +1,4 @@
1
- export declare function warnOnce(message: string): void;
1
+ export declare function warnOnce(message: string, options?: {
2
+ type?: string;
3
+ code?: string;
4
+ }): void;
@@ -1,7 +1,32 @@
1
1
  const warnedMessages = {};
2
- export function warnOnce(message) {
3
- if (!warnedMessages[message]) {
4
- console.warn(message);
5
- warnedMessages[message] = true;
2
+ /**
3
+ * Clear the warn-once record so a later call warns again.
4
+ *
5
+ * Test-only. `warnedMessages` is module-global and never otherwise reset, so
6
+ * without this a test asserting "warning X was (not) emitted" depends on whether
7
+ * an earlier test in the same file already consumed X.
8
+ *
9
+ * @internal
10
+ */
11
+ export function _resetWarnedMessages() {
12
+ for (const key of Object.keys(warnedMessages)) {
13
+ delete warnedMessages[key];
14
+ }
15
+ }
16
+ export function warnOnce(message, options) {
17
+ const key = options?.code ?? message;
18
+ if (!warnedMessages[key]) {
19
+ warnedMessages[key] = true;
20
+ if (options?.type &&
21
+ typeof process !== "undefined" &&
22
+ typeof process.emitWarning === "function") {
23
+ process.emitWarning(message, { type: options.type, code: options.code });
24
+ }
25
+ else if (options?.type && options?.code) {
26
+ console.warn(`${options.type} [${options.code}]: ${message}`);
27
+ }
28
+ else {
29
+ console.warn(message);
30
+ }
6
31
  }
7
32
  }
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.wrapOpenAI = void 0;
4
4
  const traceable_js_1 = require("../traceable.cjs");
5
+ const traceable_js_2 = require("../singletons/traceable.cjs");
6
+ const ls_agent_type_js_1 = require("../utils/ls_agent_type.cjs");
5
7
  const TRACED_INVOCATION_KEYS = [
6
8
  "frequency_penalty",
7
9
  "n",
@@ -261,6 +263,7 @@ const getChatModelInvocationParamsFn = (provider, prepopulatedInvocationParams,
261
263
  ...prepopulatedInvocationParams,
262
264
  ...ls_invocation_params,
263
265
  },
266
+ ...(0, ls_agent_type_js_1.defaultLsAgentTypeMetadata)(requestMetadata, (0, traceable_js_2.getCurrentRunTree)(true)),
264
267
  };
265
268
  };
266
269
  };
@@ -416,6 +419,7 @@ const wrapOpenAI = (openai, options) => {
416
419
  ...prepopulatedInvocationParams,
417
420
  ...ls_invocation_params,
418
421
  },
422
+ ...(0, ls_agent_type_js_1.defaultLsAgentTypeMetadata)({}, (0, traceable_js_2.getCurrentRunTree)(true)),
419
423
  };
420
424
  },
421
425
  ...cleanedOptions,
@@ -1,4 +1,6 @@
1
1
  import { isTraceableFunction, traceable, } from "../traceable.js";
2
+ import { getCurrentRunTree } from "../singletons/traceable.js";
3
+ import { defaultLsAgentTypeMetadata } from "../utils/ls_agent_type.js";
2
4
  const TRACED_INVOCATION_KEYS = [
3
5
  "frequency_penalty",
4
6
  "n",
@@ -258,6 +260,7 @@ const getChatModelInvocationParamsFn = (provider, prepopulatedInvocationParams,
258
260
  ...prepopulatedInvocationParams,
259
261
  ...ls_invocation_params,
260
262
  },
263
+ ...defaultLsAgentTypeMetadata(requestMetadata, getCurrentRunTree(true)),
261
264
  };
262
265
  };
263
266
  };
@@ -413,6 +416,7 @@ export const wrapOpenAI = (openai, options) => {
413
416
  ...prepopulatedInvocationParams,
414
417
  ...ls_invocation_params,
415
418
  },
419
+ ...defaultLsAgentTypeMetadata({}, getCurrentRunTree(true)),
416
420
  };
417
421
  },
418
422
  ...cleanedOptions,
@@ -10,6 +10,7 @@ const node_async_hooks_1 = require("node:async_hooks");
10
10
  const run_trees_js_1 = require("../run_trees.cjs");
11
11
  const client_js_1 = require("../client.cjs");
12
12
  const traceable_js_1 = require("../singletons/traceable.cjs");
13
+ const ls_agent_type_js_1 = require("../utils/ls_agent_type.cjs");
13
14
  traceable_js_1.AsyncLocalStorageProviderSingleton.initializeGlobalInstance(new node_async_hooks_1.AsyncLocalStorage());
14
15
  /**
15
16
  * Set the current AsyncLocalStorage store to the given RunTree without a
@@ -521,14 +522,15 @@ class OpenAIAgentsTracingProcessor {
521
522
  else {
522
523
  runName = "Agent workflow";
523
524
  }
524
- // Build metadata
525
- const runExtra = {
526
- metadata: {
527
- ...this._metadata,
528
- ls_integration: "openai-agents-sdk",
529
- ls_agent_type: "root",
530
- },
525
+ // Merge three sources: processor defaults, trace.metadata (user's per-run
526
+ // ls_agent_type), and force-set ls_integration.
527
+ const mergedMetadata = {
528
+ ...this._metadata,
529
+ ...(trace.metadata ?? {}),
530
+ ls_integration: "openai-agents-sdk",
531
531
  };
532
+ Object.assign(mergedMetadata, (0, ls_agent_type_js_1.defaultLsAgentTypeMetadata)(mergedMetadata, currentRunTree));
533
+ const runExtra = { metadata: mergedMetadata };
532
534
  const traceDict = trace.toJSON() ?? {};
533
535
  const groupId = trace.groupId ??
534
536
  traceDict.groupId ??
@@ -589,9 +591,10 @@ class OpenAIAgentsTracingProcessor {
589
591
  }
590
592
  this._runs.delete(trace.traceId);
591
593
  const traceDict = trace.toJSON() ?? {};
594
+ // trace.metadata may have new keys since onTraceStart; pull them in.
592
595
  const metadata = {
593
- ...traceDict.metadata,
594
596
  ...this._metadata,
597
+ ...traceDict.metadata,
595
598
  };
596
599
  try {
597
600
  // Update run with final inputs/outputs
@@ -695,10 +698,10 @@ class OpenAIAgentsTracingProcessor {
695
698
  if (!childRun.extra.metadata) {
696
699
  childRun.extra.metadata = {};
697
700
  }
698
- childRun.extra.metadata = {
699
- ...childRun.extra.metadata,
700
- ls_agent_type: "subagent",
701
- };
701
+ const meta = childRun.extra.metadata;
702
+ if (!ls_agent_type_js_1.NON_ROOT_LS_AGENT_TYPES.has(meta.ls_agent_type)) {
703
+ meta.ls_agent_type = "subagent";
704
+ }
702
705
  }
703
706
  }
704
707
  // Track span data type for parent lookups
@@ -7,6 +7,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
7
7
  import { RunTree } from "../run_trees.js";
8
8
  import { Client } from "../client.js";
9
9
  import { AsyncLocalStorageProviderSingleton, getCurrentRunTree, } from "../singletons/traceable.js";
10
+ import { NON_ROOT_LS_AGENT_TYPES, defaultLsAgentTypeMetadata, } from "../utils/ls_agent_type.js";
10
11
  AsyncLocalStorageProviderSingleton.initializeGlobalInstance(new AsyncLocalStorage());
11
12
  /**
12
13
  * Set the current AsyncLocalStorage store to the given RunTree without a
@@ -518,14 +519,15 @@ export class OpenAIAgentsTracingProcessor {
518
519
  else {
519
520
  runName = "Agent workflow";
520
521
  }
521
- // Build metadata
522
- const runExtra = {
523
- metadata: {
524
- ...this._metadata,
525
- ls_integration: "openai-agents-sdk",
526
- ls_agent_type: "root",
527
- },
522
+ // Merge three sources: processor defaults, trace.metadata (user's per-run
523
+ // ls_agent_type), and force-set ls_integration.
524
+ const mergedMetadata = {
525
+ ...this._metadata,
526
+ ...(trace.metadata ?? {}),
527
+ ls_integration: "openai-agents-sdk",
528
528
  };
529
+ Object.assign(mergedMetadata, defaultLsAgentTypeMetadata(mergedMetadata, currentRunTree));
530
+ const runExtra = { metadata: mergedMetadata };
529
531
  const traceDict = trace.toJSON() ?? {};
530
532
  const groupId = trace.groupId ??
531
533
  traceDict.groupId ??
@@ -586,9 +588,10 @@ export class OpenAIAgentsTracingProcessor {
586
588
  }
587
589
  this._runs.delete(trace.traceId);
588
590
  const traceDict = trace.toJSON() ?? {};
591
+ // trace.metadata may have new keys since onTraceStart; pull them in.
589
592
  const metadata = {
590
- ...traceDict.metadata,
591
593
  ...this._metadata,
594
+ ...traceDict.metadata,
592
595
  };
593
596
  try {
594
597
  // Update run with final inputs/outputs
@@ -692,10 +695,10 @@ export class OpenAIAgentsTracingProcessor {
692
695
  if (!childRun.extra.metadata) {
693
696
  childRun.extra.metadata = {};
694
697
  }
695
- childRun.extra.metadata = {
696
- ...childRun.extra.metadata,
697
- ls_agent_type: "subagent",
698
- };
698
+ const meta = childRun.extra.metadata;
699
+ if (!NON_ROOT_LS_AGENT_TYPES.has(meta.ls_agent_type)) {
700
+ meta.ls_agent_type = "subagent";
701
+ }
699
702
  }
700
703
  }
701
704
  // Track span data type for parent lookups
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.8.8",
3
+ "version": "0.8.10",
4
4
  "description": "Client library to connect to the LangSmith Observability and Evaluation Platform.",
5
5
  "packageManager": "pnpm@10.33.0",
6
6
  "files": [