langsmith 0.4.2 → 0.4.3-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,23 +47,40 @@ const _getModelId = (model) => {
47
47
  }
48
48
  return typeof model.modelId === "string" ? model.modelId : undefined;
49
49
  };
50
- const _formatTracedInputs = (params) => {
51
- const { prompt, messages, model, tools, ...rest } = params;
50
+ const _formatTracedInputs = async (params) => {
51
+ const { prompt, messages, model, tools, output, ...rest } = params;
52
+ let processedInputs = {};
52
53
  if (Array.isArray(prompt)) {
53
- return {
54
+ processedInputs = {
54
55
  ...rest,
55
56
  messages: prompt.map((message) => (0, utils_js_1.convertMessageToTracedFormat)(message)),
56
57
  };
57
58
  }
58
59
  else if (Array.isArray(messages)) {
59
- return {
60
+ processedInputs = {
60
61
  ...rest,
61
62
  messages: messages.map((message) => (0, utils_js_1.convertMessageToTracedFormat)(message)),
62
63
  };
63
64
  }
64
65
  else {
65
- return { ...rest, prompt, messages };
66
+ processedInputs = { ...rest, prompt, messages };
66
67
  }
68
+ try {
69
+ if (output != null &&
70
+ typeof output === "object" &&
71
+ "responseFormat" in output) {
72
+ const responseFormat = await output.responseFormat;
73
+ processedInputs.output = responseFormat;
74
+ }
75
+ else {
76
+ processedInputs.output = output;
77
+ }
78
+ }
79
+ catch {
80
+ // Could not extract response format from output for tracing
81
+ processedInputs.output = output;
82
+ }
83
+ return processedInputs;
67
84
  };
68
85
  const _mergeConfig = (baseConfig, runtimeConfig) => {
69
86
  return {
@@ -132,7 +149,7 @@ const createLangSmithProviderOptions = (lsConfig) => {
132
149
  };
133
150
  exports.createLangSmithProviderOptions = createLangSmithProviderOptions;
134
151
  /**
135
- * Wraps Vercel AI SDK 5 functions with LangSmith tracing capabilities.
152
+ * Wraps Vercel AI SDK 6 or AI SDK 5 functions with LangSmith tracing capabilities.
136
153
  *
137
154
  * @param methods - Object containing AI SDK methods to wrap
138
155
  * @param methods.wrapLanguageModel - AI SDK's wrapLanguageModel function
@@ -149,7 +166,7 @@ exports.createLangSmithProviderOptions = createLangSmithProviderOptions;
149
166
  */
150
167
  const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject, generateObject, }, baseLsConfig) => {
151
168
  /**
152
- * Wrapped version of AI SDK 5's generateText with LangSmith tracing.
169
+ * Wrapped version of AI SDK's generateText with LangSmith tracing.
153
170
  *
154
171
  * This function has the same signature and behavior as the original generateText,
155
172
  * but adds automatic tracing to LangSmith for observability.
@@ -170,6 +187,8 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
170
187
  const params = args[0];
171
188
  const { langsmith: runtimeLsConfig, ...providerOptions } = params.providerOptions ?? {};
172
189
  const { resolvedLsConfig, resolvedChildLLMRunConfig, resolvedToolConfig } = _resolveConfigs(baseLsConfig, runtimeLsConfig);
190
+ const hasExplicitOutput = "output" in params;
191
+ const hasExplicitExperimentalOutput = "experimental_output" in params;
173
192
  const traceableFunc = (0, traceable_js_1.traceable)(async (...args) => {
174
193
  const [params, ...rest] = args;
175
194
  const wrappedModel = wrapLanguageModel({
@@ -194,7 +213,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
194
213
  ai_sdk_method: "ai.generateText",
195
214
  ...resolvedLsConfig?.metadata,
196
215
  },
197
- processInputs: (inputs) => {
216
+ processInputs: async (inputs) => {
198
217
  const inputFormatter = resolvedLsConfig?.processInputs ?? _formatTracedInputs;
199
218
  return inputFormatter(inputs);
200
219
  },
@@ -209,18 +228,37 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
209
228
  if (outputs.outputs == null || typeof outputs.outputs !== "object") {
210
229
  return outputs;
211
230
  }
212
- // If experimental_output is present, return it directly at top level (like generateObject)
213
- // Note: accessing experimental_output throws if not specified, so wrap in try-catch
214
- try {
215
- if ("experimental_output" in outputs.outputs) {
216
- const experimentalOutput = outputs.outputs.experimental_output;
217
- if (experimentalOutput != null) {
218
- return experimentalOutput;
231
+ // If output or experimental_output (legacy) was explicitly provided, return it directly at top level (like generateObject)
232
+ // Note: In AI SDK 6, experimental_output/output is always available as a getter, so we need to check if it was explicitly provided
233
+ if (hasExplicitOutput) {
234
+ try {
235
+ // Try new 'output' property first, then fall back to 'experimental_output' for backwards compatibility
236
+ if ("output" in outputs.outputs) {
237
+ const output = outputs.outputs.output;
238
+ if (output != null && typeof output === "object") {
239
+ if (Array.isArray(output)) {
240
+ return { outputs: output };
241
+ }
242
+ return output;
243
+ }
219
244
  }
220
245
  }
246
+ catch {
247
+ // output not accessible, continue with normal processing
248
+ }
221
249
  }
222
- catch (e) {
223
- // experimental_output not specified, continue with normal processing
250
+ else if (hasExplicitExperimentalOutput) {
251
+ try {
252
+ if ("experimental_output" in outputs.outputs) {
253
+ const experimentalOutput = outputs.outputs.experimental_output;
254
+ if (experimentalOutput != null) {
255
+ return experimentalOutput;
256
+ }
257
+ }
258
+ }
259
+ catch {
260
+ // experimental_output not accessible, continue with normal processing
261
+ }
224
262
  }
225
263
  const { steps } = outputs.outputs;
226
264
  if (Array.isArray(steps)) {
@@ -242,7 +280,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
242
280
  return traceableFunc(...args);
243
281
  };
244
282
  /**
245
- * Wrapped version of AI SDK 5's generateObject with LangSmith tracing.
283
+ * Wrapped version of AI SDK's generateObject with LangSmith tracing.
246
284
  *
247
285
  * This function has the same signature and behavior as the original generateObject,
248
286
  * but adds automatic tracing to LangSmith for observability.
@@ -286,7 +324,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
286
324
  ai_sdk_method: "ai.generateObject",
287
325
  ...resolvedLsConfig?.metadata,
288
326
  },
289
- processInputs: (inputs) => {
327
+ processInputs: async (inputs) => {
290
328
  const inputFormatter = resolvedLsConfig?.processInputs ?? _formatTracedInputs;
291
329
  return inputFormatter(inputs);
292
330
  },
@@ -307,7 +345,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
307
345
  return traceableFunc(...args);
308
346
  };
309
347
  /**
310
- * Wrapped version of AI SDK 5's streamText with LangSmith tracing.
348
+ * Wrapped version of AI SDK's streamText with LangSmith tracing.
311
349
  *
312
350
  * Must be called with `await`, but otherwise behaves the same as the
313
351
  * original streamText and adds adds automatic tracing to LangSmith
@@ -329,6 +367,8 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
329
367
  const params = args[0];
330
368
  const { langsmith: runtimeLsConfig, ...providerOptions } = params.providerOptions ?? {};
331
369
  const { resolvedLsConfig, resolvedChildLLMRunConfig, resolvedToolConfig } = _resolveConfigs(baseLsConfig, runtimeLsConfig);
370
+ const hasExplicitOutput = "output" in params;
371
+ const hasExplicitExperimentalOutput = "experimental_output" in params;
332
372
  const traceableFunc = (0, traceable_js_1.traceable)((...args) => {
333
373
  const [params, ...rest] = args;
334
374
  const wrappedModel = wrapLanguageModel({
@@ -353,7 +393,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
353
393
  ai_sdk_method: "ai.streamText",
354
394
  ...resolvedLsConfig?.metadata,
355
395
  },
356
- processInputs: (inputs) => {
396
+ processInputs: async (inputs) => {
357
397
  const inputFormatter = resolvedLsConfig?.processInputs ?? _formatTracedInputs;
358
398
  return inputFormatter(inputs);
359
399
  },
@@ -382,8 +422,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
382
422
  return outputs;
383
423
  }
384
424
  try {
385
- if ("experimental_partialOutputStream" in outputs.outputs &&
386
- outputs.outputs.experimental_partialOutputStream != null) {
425
+ if (hasExplicitOutput || hasExplicitExperimentalOutput) {
387
426
  const textContent = await outputs.outputs.text;
388
427
  return JSON.parse(textContent);
389
428
  }
@@ -397,7 +436,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
397
436
  const steps = await outputs.outputs.steps;
398
437
  responseMetadata = { steps };
399
438
  }
400
- catch (e) {
439
+ catch {
401
440
  // Do nothing if step parsing fails
402
441
  }
403
442
  }
@@ -406,7 +445,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
406
445
  role: "assistant",
407
446
  }, responseMetadata);
408
447
  }
409
- catch (e) {
448
+ catch {
410
449
  // Handle parsing failures without a log
411
450
  return outputs;
412
451
  }
@@ -415,7 +454,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
415
454
  return traceableFunc(...args);
416
455
  };
417
456
  /**
418
- * Wrapped version of AI SDK 5's streamObject with LangSmith tracing.
457
+ * Wrapped version of AI SDK's streamObject with LangSmith tracing.
419
458
  *
420
459
  * Must be called with `await`, but otherwise behaves the same as the
421
460
  * original streamObject and adds adds automatic tracing to LangSmith
@@ -460,7 +499,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
460
499
  ai_sdk_method: "ai.streamObject",
461
500
  ...resolvedLsConfig?.metadata,
462
501
  },
463
- processInputs: (inputs) => {
502
+ processInputs: async (inputs) => {
464
503
  const inputFormatter = resolvedLsConfig?.processInputs ?? _formatTracedInputs;
465
504
  return inputFormatter(inputs);
466
505
  },
@@ -483,7 +522,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
483
522
  }
484
523
  return object;
485
524
  }
486
- catch (e) {
525
+ catch {
487
526
  // Handle parsing failures without a log
488
527
  return outputs;
489
528
  }
@@ -230,7 +230,7 @@ export type WrapAISDKConfig<T extends (...args: any[]) => any = (...args: any[])
230
230
  */
231
231
  export declare const createLangSmithProviderOptions: <T extends (...args: any[]) => any>(lsConfig?: WrapAISDKConfig<T>) => Record<string, JSONValue>;
232
232
  /**
233
- * Wraps Vercel AI SDK 5 functions with LangSmith tracing capabilities.
233
+ * Wraps Vercel AI SDK 6 or AI SDK 5 functions with LangSmith tracing capabilities.
234
234
  *
235
235
  * @param methods - Object containing AI SDK methods to wrap
236
236
  * @param methods.wrapLanguageModel - AI SDK's wrapLanguageModel function
@@ -43,23 +43,40 @@ const _getModelId = (model) => {
43
43
  }
44
44
  return typeof model.modelId === "string" ? model.modelId : undefined;
45
45
  };
46
- const _formatTracedInputs = (params) => {
47
- const { prompt, messages, model, tools, ...rest } = params;
46
+ const _formatTracedInputs = async (params) => {
47
+ const { prompt, messages, model, tools, output, ...rest } = params;
48
+ let processedInputs = {};
48
49
  if (Array.isArray(prompt)) {
49
- return {
50
+ processedInputs = {
50
51
  ...rest,
51
52
  messages: prompt.map((message) => convertMessageToTracedFormat(message)),
52
53
  };
53
54
  }
54
55
  else if (Array.isArray(messages)) {
55
- return {
56
+ processedInputs = {
56
57
  ...rest,
57
58
  messages: messages.map((message) => convertMessageToTracedFormat(message)),
58
59
  };
59
60
  }
60
61
  else {
61
- return { ...rest, prompt, messages };
62
+ processedInputs = { ...rest, prompt, messages };
62
63
  }
64
+ try {
65
+ if (output != null &&
66
+ typeof output === "object" &&
67
+ "responseFormat" in output) {
68
+ const responseFormat = await output.responseFormat;
69
+ processedInputs.output = responseFormat;
70
+ }
71
+ else {
72
+ processedInputs.output = output;
73
+ }
74
+ }
75
+ catch {
76
+ // Could not extract response format from output for tracing
77
+ processedInputs.output = output;
78
+ }
79
+ return processedInputs;
63
80
  };
64
81
  const _mergeConfig = (baseConfig, runtimeConfig) => {
65
82
  return {
@@ -127,7 +144,7 @@ export const createLangSmithProviderOptions = (lsConfig) => {
127
144
  return (lsConfig ?? {});
128
145
  };
129
146
  /**
130
- * Wraps Vercel AI SDK 5 functions with LangSmith tracing capabilities.
147
+ * Wraps Vercel AI SDK 6 or AI SDK 5 functions with LangSmith tracing capabilities.
131
148
  *
132
149
  * @param methods - Object containing AI SDK methods to wrap
133
150
  * @param methods.wrapLanguageModel - AI SDK's wrapLanguageModel function
@@ -144,7 +161,7 @@ export const createLangSmithProviderOptions = (lsConfig) => {
144
161
  */
145
162
  const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject, generateObject, }, baseLsConfig) => {
146
163
  /**
147
- * Wrapped version of AI SDK 5's generateText with LangSmith tracing.
164
+ * Wrapped version of AI SDK's generateText with LangSmith tracing.
148
165
  *
149
166
  * This function has the same signature and behavior as the original generateText,
150
167
  * but adds automatic tracing to LangSmith for observability.
@@ -165,6 +182,8 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
165
182
  const params = args[0];
166
183
  const { langsmith: runtimeLsConfig, ...providerOptions } = params.providerOptions ?? {};
167
184
  const { resolvedLsConfig, resolvedChildLLMRunConfig, resolvedToolConfig } = _resolveConfigs(baseLsConfig, runtimeLsConfig);
185
+ const hasExplicitOutput = "output" in params;
186
+ const hasExplicitExperimentalOutput = "experimental_output" in params;
168
187
  const traceableFunc = traceable(async (...args) => {
169
188
  const [params, ...rest] = args;
170
189
  const wrappedModel = wrapLanguageModel({
@@ -189,7 +208,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
189
208
  ai_sdk_method: "ai.generateText",
190
209
  ...resolvedLsConfig?.metadata,
191
210
  },
192
- processInputs: (inputs) => {
211
+ processInputs: async (inputs) => {
193
212
  const inputFormatter = resolvedLsConfig?.processInputs ?? _formatTracedInputs;
194
213
  return inputFormatter(inputs);
195
214
  },
@@ -204,18 +223,37 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
204
223
  if (outputs.outputs == null || typeof outputs.outputs !== "object") {
205
224
  return outputs;
206
225
  }
207
- // If experimental_output is present, return it directly at top level (like generateObject)
208
- // Note: accessing experimental_output throws if not specified, so wrap in try-catch
209
- try {
210
- if ("experimental_output" in outputs.outputs) {
211
- const experimentalOutput = outputs.outputs.experimental_output;
212
- if (experimentalOutput != null) {
213
- return experimentalOutput;
226
+ // If output or experimental_output (legacy) was explicitly provided, return it directly at top level (like generateObject)
227
+ // Note: In AI SDK 6, experimental_output/output is always available as a getter, so we need to check if it was explicitly provided
228
+ if (hasExplicitOutput) {
229
+ try {
230
+ // Try new 'output' property first, then fall back to 'experimental_output' for backwards compatibility
231
+ if ("output" in outputs.outputs) {
232
+ const output = outputs.outputs.output;
233
+ if (output != null && typeof output === "object") {
234
+ if (Array.isArray(output)) {
235
+ return { outputs: output };
236
+ }
237
+ return output;
238
+ }
214
239
  }
215
240
  }
241
+ catch {
242
+ // output not accessible, continue with normal processing
243
+ }
216
244
  }
217
- catch (e) {
218
- // experimental_output not specified, continue with normal processing
245
+ else if (hasExplicitExperimentalOutput) {
246
+ try {
247
+ if ("experimental_output" in outputs.outputs) {
248
+ const experimentalOutput = outputs.outputs.experimental_output;
249
+ if (experimentalOutput != null) {
250
+ return experimentalOutput;
251
+ }
252
+ }
253
+ }
254
+ catch {
255
+ // experimental_output not accessible, continue with normal processing
256
+ }
219
257
  }
220
258
  const { steps } = outputs.outputs;
221
259
  if (Array.isArray(steps)) {
@@ -237,7 +275,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
237
275
  return traceableFunc(...args);
238
276
  };
239
277
  /**
240
- * Wrapped version of AI SDK 5's generateObject with LangSmith tracing.
278
+ * Wrapped version of AI SDK's generateObject with LangSmith tracing.
241
279
  *
242
280
  * This function has the same signature and behavior as the original generateObject,
243
281
  * but adds automatic tracing to LangSmith for observability.
@@ -281,7 +319,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
281
319
  ai_sdk_method: "ai.generateObject",
282
320
  ...resolvedLsConfig?.metadata,
283
321
  },
284
- processInputs: (inputs) => {
322
+ processInputs: async (inputs) => {
285
323
  const inputFormatter = resolvedLsConfig?.processInputs ?? _formatTracedInputs;
286
324
  return inputFormatter(inputs);
287
325
  },
@@ -302,7 +340,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
302
340
  return traceableFunc(...args);
303
341
  };
304
342
  /**
305
- * Wrapped version of AI SDK 5's streamText with LangSmith tracing.
343
+ * Wrapped version of AI SDK's streamText with LangSmith tracing.
306
344
  *
307
345
  * Must be called with `await`, but otherwise behaves the same as the
308
346
  * original streamText and adds adds automatic tracing to LangSmith
@@ -324,6 +362,8 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
324
362
  const params = args[0];
325
363
  const { langsmith: runtimeLsConfig, ...providerOptions } = params.providerOptions ?? {};
326
364
  const { resolvedLsConfig, resolvedChildLLMRunConfig, resolvedToolConfig } = _resolveConfigs(baseLsConfig, runtimeLsConfig);
365
+ const hasExplicitOutput = "output" in params;
366
+ const hasExplicitExperimentalOutput = "experimental_output" in params;
327
367
  const traceableFunc = traceable((...args) => {
328
368
  const [params, ...rest] = args;
329
369
  const wrappedModel = wrapLanguageModel({
@@ -348,7 +388,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
348
388
  ai_sdk_method: "ai.streamText",
349
389
  ...resolvedLsConfig?.metadata,
350
390
  },
351
- processInputs: (inputs) => {
391
+ processInputs: async (inputs) => {
352
392
  const inputFormatter = resolvedLsConfig?.processInputs ?? _formatTracedInputs;
353
393
  return inputFormatter(inputs);
354
394
  },
@@ -377,8 +417,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
377
417
  return outputs;
378
418
  }
379
419
  try {
380
- if ("experimental_partialOutputStream" in outputs.outputs &&
381
- outputs.outputs.experimental_partialOutputStream != null) {
420
+ if (hasExplicitOutput || hasExplicitExperimentalOutput) {
382
421
  const textContent = await outputs.outputs.text;
383
422
  return JSON.parse(textContent);
384
423
  }
@@ -392,7 +431,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
392
431
  const steps = await outputs.outputs.steps;
393
432
  responseMetadata = { steps };
394
433
  }
395
- catch (e) {
434
+ catch {
396
435
  // Do nothing if step parsing fails
397
436
  }
398
437
  }
@@ -401,7 +440,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
401
440
  role: "assistant",
402
441
  }, responseMetadata);
403
442
  }
404
- catch (e) {
443
+ catch {
405
444
  // Handle parsing failures without a log
406
445
  return outputs;
407
446
  }
@@ -410,7 +449,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
410
449
  return traceableFunc(...args);
411
450
  };
412
451
  /**
413
- * Wrapped version of AI SDK 5's streamObject with LangSmith tracing.
452
+ * Wrapped version of AI SDK's streamObject with LangSmith tracing.
414
453
  *
415
454
  * Must be called with `await`, but otherwise behaves the same as the
416
455
  * original streamObject and adds adds automatic tracing to LangSmith
@@ -455,7 +494,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
455
494
  ai_sdk_method: "ai.streamObject",
456
495
  ...resolvedLsConfig?.metadata,
457
496
  },
458
- processInputs: (inputs) => {
497
+ processInputs: async (inputs) => {
459
498
  const inputFormatter = resolvedLsConfig?.processInputs ?? _formatTracedInputs;
460
499
  return inputFormatter(inputs);
461
500
  },
@@ -478,7 +517,7 @@ const wrapAISDK = ({ wrapLanguageModel, generateText, streamText, streamObject,
478
517
  }
479
518
  return object;
480
519
  }
481
- catch (e) {
520
+ catch {
482
521
  // Handle parsing failures without a log
483
522
  return outputs;
484
523
  }
@@ -38,16 +38,53 @@ const setUsageMetadataOnRunTree = (result, runTree) => {
38
38
  if (result.usage == null || typeof result.usage !== "object") {
39
39
  return;
40
40
  }
41
- // Shim for AI SDK 4
42
- const inputTokens = result.usage?.inputTokens ??
43
- result.usage?.promptTokens;
44
- const outputTokens = result.usage?.outputTokens ??
45
- result.usage?.completionTokens;
46
- let totalTokens = result.usage?.totalTokens;
47
- if (typeof totalTokens !== "number" &&
48
- typeof inputTokens === "number" &&
49
- typeof outputTokens === "number") {
50
- totalTokens = inputTokens + outputTokens;
41
+ const usage = result.usage;
42
+ let inputTokens;
43
+ let outputTokens;
44
+ let totalTokens;
45
+ // AI SDK 6: Check for object-based token structures first
46
+ if (typeof usage.inputTokens === "object" &&
47
+ usage.inputTokens?.total != null) {
48
+ // AI SDK 6 detected
49
+ inputTokens = usage.inputTokens.total;
50
+ if (typeof usage.outputTokens === "object" &&
51
+ usage.outputTokens?.total != null) {
52
+ outputTokens = usage.outputTokens.total;
53
+ }
54
+ totalTokens = result.usage?.totalTokens;
55
+ if (typeof totalTokens !== "number" &&
56
+ typeof inputTokens === "number" &&
57
+ typeof outputTokens === "number") {
58
+ totalTokens = inputTokens + outputTokens;
59
+ }
60
+ }
61
+ else if (typeof usage.inputTokens === "number") {
62
+ // AI SDK 5 detected
63
+ inputTokens = usage.inputTokens;
64
+ if (typeof usage.outputTokens === "number") {
65
+ outputTokens = usage.outputTokens;
66
+ }
67
+ totalTokens = result.usage?.totalTokens;
68
+ if (typeof totalTokens !== "number" &&
69
+ typeof inputTokens === "number" &&
70
+ typeof outputTokens === "number") {
71
+ totalTokens = inputTokens + outputTokens;
72
+ }
73
+ }
74
+ else {
75
+ // AI SDK 4 fallback
76
+ if (typeof usage.promptTokens === "number") {
77
+ inputTokens = usage.promptTokens;
78
+ }
79
+ if (typeof usage.completionTokens === "number") {
80
+ outputTokens = usage.completionTokens;
81
+ }
82
+ totalTokens = result.usage?.totalTokens;
83
+ if (typeof totalTokens !== "number" &&
84
+ typeof inputTokens === "number" &&
85
+ typeof outputTokens === "number") {
86
+ totalTokens = inputTokens + outputTokens;
87
+ }
51
88
  }
52
89
  const langsmithUsage = {
53
90
  input_tokens: inputTokens,
@@ -73,7 +110,7 @@ const setUsageMetadataOnRunTree = (result, runTree) => {
73
110
  };
74
111
  };
75
112
  /**
76
- * AI SDK middleware that wraps an AI SDK 5 model and adds LangSmith tracing.
113
+ * AI SDK middleware that wraps an AI SDK 6 or 5 model and adds LangSmith tracing.
77
114
  */
78
115
  function LangSmithMiddleware(config) {
79
116
  const { name, modelId, lsConfig } = config ?? {};
@@ -15,7 +15,7 @@ export type AggregatedDoStreamOutput = {
15
15
  finishReason?: LanguageModelV2FinishReason;
16
16
  };
17
17
  /**
18
- * AI SDK middleware that wraps an AI SDK 5 model and adds LangSmith tracing.
18
+ * AI SDK middleware that wraps an AI SDK 6 or 5 model and adds LangSmith tracing.
19
19
  */
20
20
  export declare function LangSmithMiddleware(config?: {
21
21
  name: string;
@@ -35,16 +35,53 @@ const setUsageMetadataOnRunTree = (result, runTree) => {
35
35
  if (result.usage == null || typeof result.usage !== "object") {
36
36
  return;
37
37
  }
38
- // Shim for AI SDK 4
39
- const inputTokens = result.usage?.inputTokens ??
40
- result.usage?.promptTokens;
41
- const outputTokens = result.usage?.outputTokens ??
42
- result.usage?.completionTokens;
43
- let totalTokens = result.usage?.totalTokens;
44
- if (typeof totalTokens !== "number" &&
45
- typeof inputTokens === "number" &&
46
- typeof outputTokens === "number") {
47
- totalTokens = inputTokens + outputTokens;
38
+ const usage = result.usage;
39
+ let inputTokens;
40
+ let outputTokens;
41
+ let totalTokens;
42
+ // AI SDK 6: Check for object-based token structures first
43
+ if (typeof usage.inputTokens === "object" &&
44
+ usage.inputTokens?.total != null) {
45
+ // AI SDK 6 detected
46
+ inputTokens = usage.inputTokens.total;
47
+ if (typeof usage.outputTokens === "object" &&
48
+ usage.outputTokens?.total != null) {
49
+ outputTokens = usage.outputTokens.total;
50
+ }
51
+ totalTokens = result.usage?.totalTokens;
52
+ if (typeof totalTokens !== "number" &&
53
+ typeof inputTokens === "number" &&
54
+ typeof outputTokens === "number") {
55
+ totalTokens = inputTokens + outputTokens;
56
+ }
57
+ }
58
+ else if (typeof usage.inputTokens === "number") {
59
+ // AI SDK 5 detected
60
+ inputTokens = usage.inputTokens;
61
+ if (typeof usage.outputTokens === "number") {
62
+ outputTokens = usage.outputTokens;
63
+ }
64
+ totalTokens = result.usage?.totalTokens;
65
+ if (typeof totalTokens !== "number" &&
66
+ typeof inputTokens === "number" &&
67
+ typeof outputTokens === "number") {
68
+ totalTokens = inputTokens + outputTokens;
69
+ }
70
+ }
71
+ else {
72
+ // AI SDK 4 fallback
73
+ if (typeof usage.promptTokens === "number") {
74
+ inputTokens = usage.promptTokens;
75
+ }
76
+ if (typeof usage.completionTokens === "number") {
77
+ outputTokens = usage.completionTokens;
78
+ }
79
+ totalTokens = result.usage?.totalTokens;
80
+ if (typeof totalTokens !== "number" &&
81
+ typeof inputTokens === "number" &&
82
+ typeof outputTokens === "number") {
83
+ totalTokens = inputTokens + outputTokens;
84
+ }
48
85
  }
49
86
  const langsmithUsage = {
50
87
  input_tokens: inputTokens,
@@ -70,7 +107,7 @@ const setUsageMetadataOnRunTree = (result, runTree) => {
70
107
  };
71
108
  };
72
109
  /**
73
- * AI SDK middleware that wraps an AI SDK 5 model and adds LangSmith tracing.
110
+ * AI SDK middleware that wraps an AI SDK 6 or 5 model and adds LangSmith tracing.
74
111
  */
75
112
  export function LangSmithMiddleware(config) {
76
113
  const { name, modelId, lsConfig } = config ?? {};
package/dist/index.cjs CHANGED
@@ -13,4 +13,4 @@ var uuid_js_1 = require("./uuid.cjs");
13
13
  Object.defineProperty(exports, "uuid7", { enumerable: true, get: function () { return uuid_js_1.uuid7; } });
14
14
  Object.defineProperty(exports, "uuid7FromTime", { enumerable: true, get: function () { return uuid_js_1.uuid7FromTime; } });
15
15
  // Update using yarn bump-version
16
- exports.__version__ = "0.4.2";
16
+ exports.__version__ = "0.4.3-rc.0";
package/dist/index.d.ts CHANGED
@@ -4,4 +4,4 @@ export { RunTree, type RunTreeConfig } from "./run_trees.js";
4
4
  export { overrideFetchImplementation } from "./singletons/fetch.js";
5
5
  export { getDefaultProjectName } from "./utils/project.js";
6
6
  export { uuid7, uuid7FromTime } from "./uuid.js";
7
- export declare const __version__ = "0.4.2";
7
+ export declare const __version__ = "0.4.3-rc.0";
package/dist/index.js CHANGED
@@ -4,4 +4,4 @@ export { overrideFetchImplementation } from "./singletons/fetch.js";
4
4
  export { getDefaultProjectName } from "./utils/project.js";
5
5
  export { uuid7, uuid7FromTime } from "./uuid.js";
6
6
  // Update using yarn bump-version
7
- export const __version__ = "0.4.2";
7
+ export const __version__ = "0.4.3-rc.0";
@@ -287,6 +287,12 @@ class RunTree {
287
287
  writable: true,
288
288
  value: void 0
289
289
  });
290
+ Object.defineProperty(this, "_awaitInputsOnPost", {
291
+ enumerable: true,
292
+ configurable: true,
293
+ writable: true,
294
+ value: void 0
295
+ });
290
296
  // If you pass in a run tree directly, return a shallow clone
291
297
  if (isRunTree(originalConfig)) {
292
298
  Object.assign(this, { ...originalConfig });
@@ -644,6 +650,9 @@ class RunTree {
644
650
  };
645
651
  }
646
652
  async postRun(excludeChildRuns = true) {
653
+ if (this._awaitInputsOnPost) {
654
+ this.inputs = await this.inputs;
655
+ }
647
656
  try {
648
657
  const runtimeEnv = (0, env_js_2.getRuntimeEnvironment)();
649
658
  if (this.replicas && this.replicas.length > 0) {
@@ -101,6 +101,7 @@ export declare class RunTree implements BaseRun {
101
101
  replicas?: WriteReplica[];
102
102
  distributedParentId?: string;
103
103
  private _serialized_start_time;
104
+ _awaitInputsOnPost?: boolean;
104
105
  constructor(originalConfig: RunTreeConfig | RunTree);
105
106
  set metadata(metadata: KVMap);
106
107
  get metadata(): KVMap;
package/dist/run_trees.js CHANGED
@@ -281,6 +281,12 @@ export class RunTree {
281
281
  writable: true,
282
282
  value: void 0
283
283
  });
284
+ Object.defineProperty(this, "_awaitInputsOnPost", {
285
+ enumerable: true,
286
+ configurable: true,
287
+ writable: true,
288
+ value: void 0
289
+ });
284
290
  // If you pass in a run tree directly, return a shallow clone
285
291
  if (isRunTree(originalConfig)) {
286
292
  Object.assign(this, { ...originalConfig });
@@ -638,6 +644,9 @@ export class RunTree {
638
644
  };
639
645
  }
640
646
  async postRun(excludeChildRuns = true) {
647
+ if (this._awaitInputsOnPost) {
648
+ this.inputs = await this.inputs;
649
+ }
641
650
  try {
642
651
  const runtimeEnv = getRuntimeEnvironment();
643
652
  if (this.replicas && this.replicas.length > 0) {
@@ -108,14 +108,12 @@ const _extractUsage = (runData) => {
108
108
  return runData.outputs?.usage_metadata ?? usageMetadataFromMetadata;
109
109
  };
110
110
  async function handleEnd(params) {
111
- const { runTree, on_end, postRunPromise, deferredInputs, skipChildPromiseDelay, } = params;
111
+ const { runTree, on_end, postRunPromise, deferredInputs } = params;
112
112
  const onEnd = on_end;
113
113
  if (onEnd) {
114
114
  onEnd(runTree);
115
115
  }
116
- if (!skipChildPromiseDelay) {
117
- await postRunPromise;
118
- }
116
+ await postRunPromise;
119
117
  if (deferredInputs) {
120
118
  await runTree?.postRun();
121
119
  }
@@ -240,7 +238,11 @@ const getTracingRunTree = (runTree, inputs, getInvocationParams, processInputs,
240
238
  }
241
239
  const [attached, args] = handleRunAttachments(inputs, extractAttachments);
242
240
  runTree.attachments = attached;
243
- runTree.inputs = handleRunInputs(args, processInputs);
241
+ const processedInputs = handleRunInputs(args, processInputs);
242
+ if (isAsyncFn(processInputs)) {
243
+ runTree._awaitInputsOnPost = true;
244
+ }
245
+ runTree.inputs = processedInputs;
244
246
  const invocationParams = getInvocationParams?.(...inputs);
245
247
  if (invocationParams != null) {
246
248
  runTree.extra ??= {};
@@ -777,7 +779,6 @@ function traceable(wrappedFunc, config) {
777
779
  postRunPromise,
778
780
  on_end,
779
781
  deferredInputs,
780
- skipChildPromiseDelay: true,
781
782
  });
782
783
  throw error;
783
784
  })
@@ -49,7 +49,7 @@ export type TraceableConfig<Func extends (...args: any[]) => any> = Partial<Omit
49
49
  * @param inputs Key-value map of the function inputs.
50
50
  * @returns Transformed key-value map
51
51
  */
52
- processInputs?: (inputs: Readonly<ProcessInputs<Parameters<Func>>>) => KVMap;
52
+ processInputs?: (inputs: Readonly<ProcessInputs<Parameters<Func>>>) => KVMap | Promise<KVMap>;
53
53
  /**
54
54
  * Apply transformations to the outputs before logging.
55
55
  * This function should NOT mutate the outputs.
package/dist/traceable.js CHANGED
@@ -104,14 +104,12 @@ const _extractUsage = (runData) => {
104
104
  return runData.outputs?.usage_metadata ?? usageMetadataFromMetadata;
105
105
  };
106
106
  async function handleEnd(params) {
107
- const { runTree, on_end, postRunPromise, deferredInputs, skipChildPromiseDelay, } = params;
107
+ const { runTree, on_end, postRunPromise, deferredInputs } = params;
108
108
  const onEnd = on_end;
109
109
  if (onEnd) {
110
110
  onEnd(runTree);
111
111
  }
112
- if (!skipChildPromiseDelay) {
113
- await postRunPromise;
114
- }
112
+ await postRunPromise;
115
113
  if (deferredInputs) {
116
114
  await runTree?.postRun();
117
115
  }
@@ -236,7 +234,11 @@ const getTracingRunTree = (runTree, inputs, getInvocationParams, processInputs,
236
234
  }
237
235
  const [attached, args] = handleRunAttachments(inputs, extractAttachments);
238
236
  runTree.attachments = attached;
239
- runTree.inputs = handleRunInputs(args, processInputs);
237
+ const processedInputs = handleRunInputs(args, processInputs);
238
+ if (isAsyncFn(processInputs)) {
239
+ runTree._awaitInputsOnPost = true;
240
+ }
241
+ runTree.inputs = processedInputs;
240
242
  const invocationParams = getInvocationParams?.(...inputs);
241
243
  if (invocationParams != null) {
242
244
  runTree.extra ??= {};
@@ -773,7 +775,6 @@ export function traceable(wrappedFunc, config) {
773
775
  postRunPromise,
774
776
  on_end,
775
777
  deferredInputs,
776
- skipChildPromiseDelay: true,
777
778
  });
778
779
  throw error;
779
780
  })
@@ -16,7 +16,41 @@ function extractTraceableServiceTier(providerMetadata) {
16
16
  }
17
17
  return undefined;
18
18
  }
19
+ function isLanguageModelV3Usage(usage) {
20
+ return usage.inputTokens != null && typeof usage.inputTokens === "object";
21
+ }
22
+ function extractAISDK6OutputTokenDetails(usage, providerMetadata) {
23
+ const openAIServiceTier = extractTraceableServiceTier(providerMetadata ?? {});
24
+ const outputTokenDetailsKeyPrefix = openAIServiceTier
25
+ ? `${openAIServiceTier}_`
26
+ : "";
27
+ const outputTokens = usage.outputTokens;
28
+ const outputTokenDetails = {};
29
+ // Extract reasoning tokens from AI SDK 6
30
+ if (typeof outputTokens?.reasoning === "number" &&
31
+ outputTokens?.reasoning > 0) {
32
+ outputTokenDetails[`${outputTokenDetailsKeyPrefix}reasoning`] =
33
+ outputTokens.reasoning;
34
+ }
35
+ // Apply service tier logic for AI SDK 6
36
+ if (openAIServiceTier && typeof outputTokens?.total === "number") {
37
+ // Avoid counting reasoning tokens towards the output token count
38
+ // since service tier tokens are already priced differently
39
+ outputTokenDetails[openAIServiceTier] =
40
+ outputTokens.total -
41
+ (outputTokenDetails[`${outputTokenDetailsKeyPrefix}reasoning`] ?? 0);
42
+ }
43
+ return outputTokenDetails;
44
+ }
19
45
  function extractOutputTokenDetails(usage, providerMetadata) {
46
+ if (usage == null) {
47
+ return {};
48
+ }
49
+ // AI SDK 6: Check for built-in outputTokens breakdown first
50
+ if (isLanguageModelV3Usage(usage)) {
51
+ // Return AI SDK 6 results (even if empty, to prevent falling through to SDK 5 logic)
52
+ return extractAISDK6OutputTokenDetails(usage, providerMetadata);
53
+ }
20
54
  const openAIServiceTier = extractTraceableServiceTier(providerMetadata ?? {});
21
55
  const outputTokenDetailsKeyPrefix = openAIServiceTier
22
56
  ? `${openAIServiceTier}_`
@@ -35,7 +69,62 @@ function extractOutputTokenDetails(usage, providerMetadata) {
35
69
  }
36
70
  return outputTokenDetails;
37
71
  }
72
+ function extractAISDK6InputTokenDetails(usage, providerMetadata) {
73
+ let inputTokenDetails = {};
74
+ const inputTokens = usage.inputTokens;
75
+ // Extract standard AI SDK 6 input token breakdowns
76
+ // Map AI SDK 6 fields to LangSmith token detail fields:
77
+ // - cacheRead -> cache_read
78
+ // - cacheWrite -> cache_creation
79
+ if (providerMetadata?.anthropic != null &&
80
+ typeof providerMetadata?.anthropic === "object") {
81
+ const anthropic = providerMetadata.anthropic;
82
+ if (anthropic.usage != null && typeof anthropic.usage === "object") {
83
+ // Raw usage from Anthropic returned in AI SDK 5
84
+ const usage = anthropic.usage;
85
+ inputTokenDetails = (0, usage_js_1.convertAnthropicUsageToInputTokenDetails)(usage);
86
+ }
87
+ }
88
+ else {
89
+ if (typeof inputTokens?.cacheRead === "number" &&
90
+ inputTokens.cacheRead > 0) {
91
+ inputTokenDetails.cache_read = inputTokens.cacheRead;
92
+ }
93
+ if (typeof inputTokens?.cacheWrite === "number" &&
94
+ inputTokens?.cacheWrite > 0) {
95
+ inputTokenDetails.cache_creation = inputTokens?.cacheWrite;
96
+ }
97
+ }
98
+ // Handle OpenAI service tier for AI SDK 6
99
+ const openAIServiceTier = extractTraceableServiceTier(providerMetadata ?? {});
100
+ if (openAIServiceTier) {
101
+ const serviceTierPrefix = `${openAIServiceTier}_`;
102
+ // Add cache_read with service tier prefix if we have cached tokens
103
+ if (typeof inputTokens?.cacheRead === "number" &&
104
+ inputTokens?.cacheRead > 0) {
105
+ inputTokenDetails[`${serviceTierPrefix}cache_read`] =
106
+ inputTokens.cacheRead;
107
+ // Remove the non-prefixed version since we're using service tier
108
+ delete inputTokenDetails.cache_read;
109
+ }
110
+ // Calculate service tier tokens (total minus cached)
111
+ if (typeof inputTokens?.total === "number") {
112
+ inputTokenDetails[openAIServiceTier] =
113
+ inputTokens.total -
114
+ (inputTokenDetails[`${serviceTierPrefix}cache_read`] ?? 0);
115
+ }
116
+ }
117
+ return inputTokenDetails;
118
+ }
38
119
  function extractInputTokenDetails(usage, providerMetadata) {
120
+ if (usage == null) {
121
+ return {};
122
+ }
123
+ // AI SDK 6: Check for built-in inputTokens breakdown first
124
+ if (isLanguageModelV3Usage(usage)) {
125
+ // Return AI SDK 6 results (even if empty, to prevent falling through to SDK 5 logic)
126
+ return extractAISDK6InputTokenDetails(usage, providerMetadata);
127
+ }
39
128
  let inputTokenDetails = {};
40
129
  if (providerMetadata?.anthropic != null &&
41
130
  typeof providerMetadata?.anthropic === "object") {
@@ -1,7 +1,7 @@
1
- import type { LanguageModelV2Usage } from "@ai-sdk/provider";
1
+ import type { LanguageModelV2Usage, LanguageModelV3Usage } from "@ai-sdk/provider";
2
2
  import { KVMap } from "../schemas.js";
3
- export declare function extractOutputTokenDetails(usage?: Partial<LanguageModelV2Usage>, providerMetadata?: Record<string, unknown>): Record<string, number>;
4
- export declare function extractInputTokenDetails(usage?: Partial<LanguageModelV2Usage>, providerMetadata?: Record<string, unknown>): Record<string, number>;
3
+ export declare function extractOutputTokenDetails(usage?: Partial<LanguageModelV2Usage> | Partial<LanguageModelV3Usage>, providerMetadata?: Record<string, unknown>): Record<string, number>;
4
+ export declare function extractInputTokenDetails(usage?: Partial<LanguageModelV2Usage> | Partial<LanguageModelV3Usage>, providerMetadata?: Record<string, unknown>): Record<string, number>;
5
5
  export declare function extractUsageMetadata(span?: {
6
6
  status?: {
7
7
  code: number;
@@ -11,7 +11,41 @@ function extractTraceableServiceTier(providerMetadata) {
11
11
  }
12
12
  return undefined;
13
13
  }
14
+ function isLanguageModelV3Usage(usage) {
15
+ return usage.inputTokens != null && typeof usage.inputTokens === "object";
16
+ }
17
+ function extractAISDK6OutputTokenDetails(usage, providerMetadata) {
18
+ const openAIServiceTier = extractTraceableServiceTier(providerMetadata ?? {});
19
+ const outputTokenDetailsKeyPrefix = openAIServiceTier
20
+ ? `${openAIServiceTier}_`
21
+ : "";
22
+ const outputTokens = usage.outputTokens;
23
+ const outputTokenDetails = {};
24
+ // Extract reasoning tokens from AI SDK 6
25
+ if (typeof outputTokens?.reasoning === "number" &&
26
+ outputTokens?.reasoning > 0) {
27
+ outputTokenDetails[`${outputTokenDetailsKeyPrefix}reasoning`] =
28
+ outputTokens.reasoning;
29
+ }
30
+ // Apply service tier logic for AI SDK 6
31
+ if (openAIServiceTier && typeof outputTokens?.total === "number") {
32
+ // Avoid counting reasoning tokens towards the output token count
33
+ // since service tier tokens are already priced differently
34
+ outputTokenDetails[openAIServiceTier] =
35
+ outputTokens.total -
36
+ (outputTokenDetails[`${outputTokenDetailsKeyPrefix}reasoning`] ?? 0);
37
+ }
38
+ return outputTokenDetails;
39
+ }
14
40
  export function extractOutputTokenDetails(usage, providerMetadata) {
41
+ if (usage == null) {
42
+ return {};
43
+ }
44
+ // AI SDK 6: Check for built-in outputTokens breakdown first
45
+ if (isLanguageModelV3Usage(usage)) {
46
+ // Return AI SDK 6 results (even if empty, to prevent falling through to SDK 5 logic)
47
+ return extractAISDK6OutputTokenDetails(usage, providerMetadata);
48
+ }
15
49
  const openAIServiceTier = extractTraceableServiceTier(providerMetadata ?? {});
16
50
  const outputTokenDetailsKeyPrefix = openAIServiceTier
17
51
  ? `${openAIServiceTier}_`
@@ -30,7 +64,62 @@ export function extractOutputTokenDetails(usage, providerMetadata) {
30
64
  }
31
65
  return outputTokenDetails;
32
66
  }
67
+ function extractAISDK6InputTokenDetails(usage, providerMetadata) {
68
+ let inputTokenDetails = {};
69
+ const inputTokens = usage.inputTokens;
70
+ // Extract standard AI SDK 6 input token breakdowns
71
+ // Map AI SDK 6 fields to LangSmith token detail fields:
72
+ // - cacheRead -> cache_read
73
+ // - cacheWrite -> cache_creation
74
+ if (providerMetadata?.anthropic != null &&
75
+ typeof providerMetadata?.anthropic === "object") {
76
+ const anthropic = providerMetadata.anthropic;
77
+ if (anthropic.usage != null && typeof anthropic.usage === "object") {
78
+ // Raw usage from Anthropic returned in AI SDK 5
79
+ const usage = anthropic.usage;
80
+ inputTokenDetails = convertAnthropicUsageToInputTokenDetails(usage);
81
+ }
82
+ }
83
+ else {
84
+ if (typeof inputTokens?.cacheRead === "number" &&
85
+ inputTokens.cacheRead > 0) {
86
+ inputTokenDetails.cache_read = inputTokens.cacheRead;
87
+ }
88
+ if (typeof inputTokens?.cacheWrite === "number" &&
89
+ inputTokens?.cacheWrite > 0) {
90
+ inputTokenDetails.cache_creation = inputTokens?.cacheWrite;
91
+ }
92
+ }
93
+ // Handle OpenAI service tier for AI SDK 6
94
+ const openAIServiceTier = extractTraceableServiceTier(providerMetadata ?? {});
95
+ if (openAIServiceTier) {
96
+ const serviceTierPrefix = `${openAIServiceTier}_`;
97
+ // Add cache_read with service tier prefix if we have cached tokens
98
+ if (typeof inputTokens?.cacheRead === "number" &&
99
+ inputTokens?.cacheRead > 0) {
100
+ inputTokenDetails[`${serviceTierPrefix}cache_read`] =
101
+ inputTokens.cacheRead;
102
+ // Remove the non-prefixed version since we're using service tier
103
+ delete inputTokenDetails.cache_read;
104
+ }
105
+ // Calculate service tier tokens (total minus cached)
106
+ if (typeof inputTokens?.total === "number") {
107
+ inputTokenDetails[openAIServiceTier] =
108
+ inputTokens.total -
109
+ (inputTokenDetails[`${serviceTierPrefix}cache_read`] ?? 0);
110
+ }
111
+ }
112
+ return inputTokenDetails;
113
+ }
33
114
  export function extractInputTokenDetails(usage, providerMetadata) {
115
+ if (usage == null) {
116
+ return {};
117
+ }
118
+ // AI SDK 6: Check for built-in inputTokens breakdown first
119
+ if (isLanguageModelV3Usage(usage)) {
120
+ // Return AI SDK 6 results (even if empty, to prevent falling through to SDK 5 logic)
121
+ return extractAISDK6InputTokenDetails(usage, providerMetadata);
122
+ }
34
123
  let inputTokenDetails = {};
35
124
  if (providerMetadata?.anthropic != null &&
36
125
  typeof providerMetadata?.anthropic === "object") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langsmith",
3
- "version": "0.4.2",
3
+ "version": "0.4.3-rc.0",
4
4
  "description": "Client library to connect to the LangSmith Observability and Evaluation Platform.",
5
5
  "packageManager": "yarn@1.22.19",
6
6
  "files": [
@@ -140,8 +140,9 @@
140
140
  "uuid": "^10.0.0"
141
141
  },
142
142
  "devDependencies": {
143
- "@ai-sdk/anthropic": "^2.0.17",
144
- "@ai-sdk/openai": "^2.0.23",
143
+ "@ai-sdk/anthropic": "^3.0.0",
144
+ "@ai-sdk/openai": "^3.0.0",
145
+ "@ai-sdk/provider": "^3.0.0",
145
146
  "@anthropic-ai/sdk": "^0.71.2",
146
147
  "@babel/preset-env": "^7.22.4",
147
148
  "@faker-js/faker": "^8.4.1",
@@ -160,7 +161,7 @@
160
161
  "@types/node-fetch": "^2.6.12",
161
162
  "@typescript-eslint/eslint-plugin": "^5.59.8",
162
163
  "@typescript-eslint/parser": "^5.59.8",
163
- "ai": "^5.0.44",
164
+ "ai": "^6.0.1",
164
165
  "babel-jest": "^29.5.0",
165
166
  "cross-env": "^7.0.3",
166
167
  "dotenv": "^16.1.3",