langsmith 0.8.9 → 0.8.11
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/client.cjs +33 -4
- package/dist/client.d.ts +10 -6
- package/dist/client.js +33 -4
- package/dist/experimental/vercel/_agent_type.cjs +30 -0
- package/dist/experimental/vercel/_agent_type.d.ts +5 -0
- package/dist/experimental/vercel/_agent_type.js +26 -0
- package/dist/experimental/vercel/telemetry.cjs +2 -7
- package/dist/experimental/vercel/telemetry.js +2 -7
- package/dist/experimental/vercel/wrap.cjs +5 -11
- package/dist/experimental/vercel/wrap.js +6 -12
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/sandbox/client.cjs +11 -5
- package/dist/sandbox/client.d.ts +4 -4
- package/dist/sandbox/client.js +11 -5
- package/dist/sandbox/index.cjs +2 -1
- package/dist/sandbox/index.d.ts +2 -2
- package/dist/sandbox/index.js +1 -1
- package/dist/sandbox/mounts.cjs +25 -2
- package/dist/sandbox/mounts.d.ts +12 -1
- package/dist/sandbox/mounts.js +24 -2
- package/dist/sandbox/proxy_config.cjs +28 -4
- package/dist/sandbox/proxy_config.d.ts +4 -2
- package/dist/sandbox/proxy_config.js +28 -4
- package/dist/sandbox/types.d.ts +36 -1
- package/dist/utils/_git.cjs +28 -1
- package/dist/utils/_git.js +28 -1
- package/dist/utils/ls_agent_type.cjs +31 -0
- package/dist/utils/ls_agent_type.d.ts +9 -0
- package/dist/utils/ls_agent_type.js +25 -0
- package/dist/utils/profiles.cjs +125 -1
- package/dist/utils/profiles.d.ts +6 -0
- package/dist/utils/profiles.js +124 -1
- package/dist/wrappers/anthropic.cjs +39 -6
- package/dist/wrappers/anthropic.js +39 -6
- package/dist/wrappers/openai.cjs +4 -0
- package/dist/wrappers/openai.js +4 -0
- package/dist/wrappers/openai_agents.cjs +15 -12
- package/dist/wrappers/openai_agents.js +15 -12
- package/package.json +12 -2
package/dist/utils/profiles.js
CHANGED
|
@@ -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
|
|
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",
|
|
@@ -5,7 +5,36 @@ exports.createUsageMetadata = createUsageMetadata;
|
|
|
5
5
|
const anthropic_managed_js_1 = require("./utils/anthropic_managed.cjs");
|
|
6
6
|
const traceable_js_1 = require("../traceable.cjs");
|
|
7
7
|
const usage_js_1 = require("../utils/usage.cjs");
|
|
8
|
+
const index_js_1 = require("../anonymizer/index.cjs");
|
|
8
9
|
const TRACED_INVOCATION_KEYS = ["top_k", "top_p", "stream", "thinking"];
|
|
10
|
+
/** Keys of an MCP server definition that are safe to trace. */
|
|
11
|
+
const MCP_SERVER_SAFE_KEYS = new Set([
|
|
12
|
+
"name",
|
|
13
|
+
"type",
|
|
14
|
+
"url",
|
|
15
|
+
"tool_configuration",
|
|
16
|
+
]);
|
|
17
|
+
/**
|
|
18
|
+
* Mask credentials in `mcp_servers` before tracing. Anything outside
|
|
19
|
+
* {@link MCP_SERVER_SAFE_KEYS} keeps its name but gets
|
|
20
|
+
* {@link SECRET_PLACEHOLDER} as its value, so the trace shows the field was set
|
|
21
|
+
* without exposing it, and fields the API adds later are masked by default.
|
|
22
|
+
*
|
|
23
|
+
* Returns new objects; the caller's are also sent to Anthropic.
|
|
24
|
+
*/
|
|
25
|
+
function redactMcpServers(servers) {
|
|
26
|
+
if (!Array.isArray(servers))
|
|
27
|
+
return servers;
|
|
28
|
+
return servers.map((server) => {
|
|
29
|
+
if (typeof server !== "object" || server == null || Array.isArray(server)) {
|
|
30
|
+
return server;
|
|
31
|
+
}
|
|
32
|
+
return Object.fromEntries(Object.entries(server).map(([key, value]) => [
|
|
33
|
+
key,
|
|
34
|
+
MCP_SERVER_SAFE_KEYS.has(key) ? value : index_js_1.SECRET_PLACEHOLDER,
|
|
35
|
+
]));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
9
38
|
/**
|
|
10
39
|
* Create usage metadata from Anthropic's token usage format.
|
|
11
40
|
*/
|
|
@@ -222,11 +251,15 @@ const wrapAnthropic = (anthropic, options) => {
|
|
|
222
251
|
* This provides parity with the Python SDK behavior and enables system prompts
|
|
223
252
|
* to be viewed and edited in the LangSmith playground.
|
|
224
253
|
*/
|
|
225
|
-
function
|
|
254
|
+
function processTracedInputs(params) {
|
|
255
|
+
// Copy first: `params` also goes to the API and must keep its real values.
|
|
256
|
+
const processed = { ...params };
|
|
257
|
+
if (processed.mcp_servers != null) {
|
|
258
|
+
processed.mcp_servers = redactMcpServers(processed.mcp_servers);
|
|
259
|
+
}
|
|
226
260
|
if (!params.system) {
|
|
227
|
-
return
|
|
261
|
+
return processed;
|
|
228
262
|
}
|
|
229
|
-
const processed = { ...params };
|
|
230
263
|
// Handle both string and ContentBlock[] formats
|
|
231
264
|
const systemContent = Array.isArray(params.system)
|
|
232
265
|
? params.system
|
|
@@ -248,7 +281,7 @@ const wrapAnthropic = (anthropic, options) => {
|
|
|
248
281
|
run_type: "llm",
|
|
249
282
|
aggregator: messageAggregator,
|
|
250
283
|
argsConfigPath: [1, "langsmithExtra"],
|
|
251
|
-
processInputs:
|
|
284
|
+
processInputs: processTracedInputs,
|
|
252
285
|
getInvocationParams: (payload) => {
|
|
253
286
|
if (typeof payload !== "object" || payload == null)
|
|
254
287
|
return undefined;
|
|
@@ -315,7 +348,7 @@ const wrapAnthropic = (anthropic, options) => {
|
|
|
315
348
|
run_type: "llm",
|
|
316
349
|
aggregator: messageAggregator,
|
|
317
350
|
argsConfigPath: [1, "langsmithExtra"],
|
|
318
|
-
processInputs:
|
|
351
|
+
processInputs: processTracedInputs,
|
|
319
352
|
getInvocationParams: messagesCreateConfig.getInvocationParams,
|
|
320
353
|
processOutputs: processMessageOutput,
|
|
321
354
|
...cleanedOptions,
|
|
@@ -341,7 +374,7 @@ const wrapAnthropic = (anthropic, options) => {
|
|
|
341
374
|
run_type: "llm",
|
|
342
375
|
aggregator: messageAggregator,
|
|
343
376
|
argsConfigPath: [1, "langsmithExtra"],
|
|
344
|
-
processInputs:
|
|
377
|
+
processInputs: processTracedInputs,
|
|
345
378
|
getInvocationParams: messagesCreateConfig.getInvocationParams,
|
|
346
379
|
processOutputs: processMessageOutput,
|
|
347
380
|
...cleanedOptions,
|
|
@@ -1,7 +1,36 @@
|
|
|
1
1
|
import { wrapManagedAgentSessionEvents } from "./utils/anthropic_managed.js";
|
|
2
2
|
import { isTraceableFunction, traceable, } from "../traceable.js";
|
|
3
3
|
import { convertAnthropicUsageToInputTokenDetails } from "../utils/usage.js";
|
|
4
|
+
import { SECRET_PLACEHOLDER } from "../anonymizer/index.js";
|
|
4
5
|
const TRACED_INVOCATION_KEYS = ["top_k", "top_p", "stream", "thinking"];
|
|
6
|
+
/** Keys of an MCP server definition that are safe to trace. */
|
|
7
|
+
const MCP_SERVER_SAFE_KEYS = new Set([
|
|
8
|
+
"name",
|
|
9
|
+
"type",
|
|
10
|
+
"url",
|
|
11
|
+
"tool_configuration",
|
|
12
|
+
]);
|
|
13
|
+
/**
|
|
14
|
+
* Mask credentials in `mcp_servers` before tracing. Anything outside
|
|
15
|
+
* {@link MCP_SERVER_SAFE_KEYS} keeps its name but gets
|
|
16
|
+
* {@link SECRET_PLACEHOLDER} as its value, so the trace shows the field was set
|
|
17
|
+
* without exposing it, and fields the API adds later are masked by default.
|
|
18
|
+
*
|
|
19
|
+
* Returns new objects; the caller's are also sent to Anthropic.
|
|
20
|
+
*/
|
|
21
|
+
function redactMcpServers(servers) {
|
|
22
|
+
if (!Array.isArray(servers))
|
|
23
|
+
return servers;
|
|
24
|
+
return servers.map((server) => {
|
|
25
|
+
if (typeof server !== "object" || server == null || Array.isArray(server)) {
|
|
26
|
+
return server;
|
|
27
|
+
}
|
|
28
|
+
return Object.fromEntries(Object.entries(server).map(([key, value]) => [
|
|
29
|
+
key,
|
|
30
|
+
MCP_SERVER_SAFE_KEYS.has(key) ? value : SECRET_PLACEHOLDER,
|
|
31
|
+
]));
|
|
32
|
+
});
|
|
33
|
+
}
|
|
5
34
|
/**
|
|
6
35
|
* Create usage metadata from Anthropic's token usage format.
|
|
7
36
|
*/
|
|
@@ -218,11 +247,15 @@ export const wrapAnthropic = (anthropic, options) => {
|
|
|
218
247
|
* This provides parity with the Python SDK behavior and enables system prompts
|
|
219
248
|
* to be viewed and edited in the LangSmith playground.
|
|
220
249
|
*/
|
|
221
|
-
function
|
|
250
|
+
function processTracedInputs(params) {
|
|
251
|
+
// Copy first: `params` also goes to the API and must keep its real values.
|
|
252
|
+
const processed = { ...params };
|
|
253
|
+
if (processed.mcp_servers != null) {
|
|
254
|
+
processed.mcp_servers = redactMcpServers(processed.mcp_servers);
|
|
255
|
+
}
|
|
222
256
|
if (!params.system) {
|
|
223
|
-
return
|
|
257
|
+
return processed;
|
|
224
258
|
}
|
|
225
|
-
const processed = { ...params };
|
|
226
259
|
// Handle both string and ContentBlock[] formats
|
|
227
260
|
const systemContent = Array.isArray(params.system)
|
|
228
261
|
? params.system
|
|
@@ -244,7 +277,7 @@ export const wrapAnthropic = (anthropic, options) => {
|
|
|
244
277
|
run_type: "llm",
|
|
245
278
|
aggregator: messageAggregator,
|
|
246
279
|
argsConfigPath: [1, "langsmithExtra"],
|
|
247
|
-
processInputs:
|
|
280
|
+
processInputs: processTracedInputs,
|
|
248
281
|
getInvocationParams: (payload) => {
|
|
249
282
|
if (typeof payload !== "object" || payload == null)
|
|
250
283
|
return undefined;
|
|
@@ -311,7 +344,7 @@ export const wrapAnthropic = (anthropic, options) => {
|
|
|
311
344
|
run_type: "llm",
|
|
312
345
|
aggregator: messageAggregator,
|
|
313
346
|
argsConfigPath: [1, "langsmithExtra"],
|
|
314
|
-
processInputs:
|
|
347
|
+
processInputs: processTracedInputs,
|
|
315
348
|
getInvocationParams: messagesCreateConfig.getInvocationParams,
|
|
316
349
|
processOutputs: processMessageOutput,
|
|
317
350
|
...cleanedOptions,
|
|
@@ -337,7 +370,7 @@ export const wrapAnthropic = (anthropic, options) => {
|
|
|
337
370
|
run_type: "llm",
|
|
338
371
|
aggregator: messageAggregator,
|
|
339
372
|
argsConfigPath: [1, "langsmithExtra"],
|
|
340
|
-
processInputs:
|
|
373
|
+
processInputs: processTracedInputs,
|
|
341
374
|
getInvocationParams: messagesCreateConfig.getInvocationParams,
|
|
342
375
|
processOutputs: processMessageOutput,
|
|
343
376
|
...cleanedOptions,
|
package/dist/wrappers/openai.cjs
CHANGED
|
@@ -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,
|
package/dist/wrappers/openai.js
CHANGED
|
@@ -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
|
-
//
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
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
|
-
|
|
700
|
-
ls_agent_type
|
|
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
|
-
//
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
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
|
-
|
|
697
|
-
ls_agent_type
|
|
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.
|
|
3
|
+
"version": "0.8.11",
|
|
4
4
|
"description": "Client library to connect to the LangSmith Observability and Evaluation Platform.",
|
|
5
5
|
"packageManager": "pnpm@10.33.0",
|
|
6
6
|
"files": [
|
|
@@ -481,7 +481,17 @@
|
|
|
481
481
|
},
|
|
482
482
|
"pnpm": {
|
|
483
483
|
"overrides": {
|
|
484
|
-
"
|
|
484
|
+
"@hono/node-server": "2.0.10",
|
|
485
|
+
"brace-expansion@<1.1.16": "1.1.16",
|
|
486
|
+
"brace-expansion@>=2.0.0 <2.1.2": "2.1.2",
|
|
487
|
+
"brace-expansion@>=3.0.0 <5.0.7": "5.0.7",
|
|
488
|
+
"fast-uri": "3.1.5",
|
|
489
|
+
"postcss": "8.5.23",
|
|
490
|
+
"js-yaml": "4.3.1",
|
|
491
|
+
"hono": "4.12.34",
|
|
492
|
+
"ip-address": "10.3.1",
|
|
493
|
+
"undici@>=7.0.0 <8.0.0": "7.29.0",
|
|
494
|
+
"undici@>=8.0.0 <9.0.0": "8.9.0",
|
|
485
495
|
"vite": "^7.3.2",
|
|
486
496
|
"form-data": "4.0.6",
|
|
487
497
|
"langsmith": "0.6.0",
|