langsmith 0.7.0 → 0.7.2
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 +1 -1
- package/dist/client.js +1 -1
- package/dist/experimental/vercel/index.cjs +18 -637
- package/dist/experimental/vercel/index.d.ts +3 -257
- package/dist/experimental/vercel/index.js +2 -635
- package/dist/experimental/vercel/middleware.cjs +2 -78
- package/dist/experimental/vercel/middleware.js +1 -77
- package/dist/experimental/vercel/telemetry.cjs +462 -0
- package/dist/experimental/vercel/telemetry.d.ts +89 -0
- package/dist/experimental/vercel/telemetry.js +459 -0
- package/dist/experimental/vercel/utils.cjs +142 -35
- package/dist/experimental/vercel/utils.d.ts +28 -3
- package/dist/experimental/vercel/utils.js +140 -34
- package/dist/experimental/vercel/wrap.cjs +639 -0
- package/dist/experimental/vercel/wrap.d.ts +257 -0
- package/dist/experimental/vercel/wrap.js +635 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/sandbox/client.cjs +21 -0
- package/dist/sandbox/client.d.ts +1 -0
- package/dist/sandbox/client.js +21 -0
- package/dist/sandbox/sandbox.cjs +12 -1
- package/dist/sandbox/sandbox.js +12 -1
- package/dist/sandbox/types.d.ts +12 -0
- package/dist/sandbox/ws_execute.cjs +11 -7
- package/dist/sandbox/ws_execute.d.ts +2 -1
- package/dist/sandbox/ws_execute.js +11 -7
- package/dist/utils/types.cjs +13 -0
- package/dist/utils/types.d.ts +2 -0
- package/dist/utils/types.js +8 -0
- package/dist/utils/vercel.cjs +68 -10
- package/dist/utils/vercel.d.ts +17 -2
- package/dist/utils/vercel.js +68 -10
- package/experimental/sandbox.cjs +1 -0
- package/experimental/sandbox.d.cts +1 -0
- package/experimental/sandbox.d.ts +1 -0
- package/experimental/sandbox.js +1 -0
- package/package.json +22 -7
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.convertMessageToTracedFormat = exports.normalizeFileDataAsDataURL = void 0;
|
|
3
|
+
exports.setUsageMetadataOnRunTree = exports.convertMessageToTracedFormat = exports.normalizeFileDataAsDataURL = void 0;
|
|
4
|
+
const types_js_1 = require("../../utils/types.cjs");
|
|
5
|
+
const vercel_js_1 = require("../../utils/vercel.cjs");
|
|
4
6
|
const guessMimetypeFromBase64 = (data) => {
|
|
5
7
|
// Check magic bytes from base64 data
|
|
6
8
|
const bytes = atob(data.substring(0, 20)); // Decode first few bytes
|
|
@@ -42,62 +44,89 @@ const guessMimetypeFromBase64 = (data) => {
|
|
|
42
44
|
}
|
|
43
45
|
return undefined;
|
|
44
46
|
};
|
|
47
|
+
function _isAISDKFileData(input) {
|
|
48
|
+
if (!(0, types_js_1.isRecord)(input))
|
|
49
|
+
return false;
|
|
50
|
+
if (input.type === "data" && "data" in input)
|
|
51
|
+
return true;
|
|
52
|
+
if (input.type === "url" && "url" in input)
|
|
53
|
+
return true;
|
|
54
|
+
if (input.type === "reference" && "reference" in input)
|
|
55
|
+
return true;
|
|
56
|
+
if (input.type === "text" && "text" in input)
|
|
57
|
+
return true;
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
function _toUint8Array(fileData) {
|
|
61
|
+
// Covers `fileData: ArrayBuffer | Buffer | Uint8Array`
|
|
62
|
+
if (fileData instanceof Uint8Array) {
|
|
63
|
+
return fileData;
|
|
64
|
+
}
|
|
65
|
+
if (fileData != null &&
|
|
66
|
+
typeof fileData === "object" &&
|
|
67
|
+
"type" in fileData &&
|
|
68
|
+
"data" in fileData &&
|
|
69
|
+
typeof fileData.data === "object" &&
|
|
70
|
+
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
71
|
+
fileData.data instanceof Uint8Array) {
|
|
72
|
+
return fileData.data;
|
|
73
|
+
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
74
|
+
}
|
|
75
|
+
if (fileData instanceof ArrayBuffer) {
|
|
76
|
+
return new Uint8Array(fileData);
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
45
80
|
const normalizeFileDataAsDataURL = (fileData, mimeType) => {
|
|
46
|
-
|
|
81
|
+
if (_isAISDKFileData(fileData)) {
|
|
82
|
+
if (fileData.type === "data") {
|
|
83
|
+
return (0, exports.normalizeFileDataAsDataURL)(fileData.data, mimeType);
|
|
84
|
+
}
|
|
85
|
+
if (fileData.type === "url") {
|
|
86
|
+
return fileData.url.toString();
|
|
87
|
+
}
|
|
88
|
+
if (fileData.type === "reference") {
|
|
89
|
+
// TODO: figure out if we can store the reference in a more reasonable format
|
|
90
|
+
return `data:application/octet-stream;base64,${btoa(JSON.stringify(fileData.reference))}`;
|
|
91
|
+
}
|
|
92
|
+
if (fileData.type === "text") {
|
|
93
|
+
return `data:text/plain;base64,${btoa(fileData.text)}`;
|
|
94
|
+
}
|
|
95
|
+
throw new Error("AISDKFileData is not supported");
|
|
96
|
+
}
|
|
47
97
|
if (fileData instanceof URL) {
|
|
48
98
|
return fileData.toString();
|
|
49
99
|
}
|
|
50
|
-
let normalizedFileData;
|
|
51
100
|
if (typeof fileData !== "string") {
|
|
52
|
-
|
|
53
|
-
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
54
|
-
if (fileData instanceof Uint8Array) {
|
|
55
|
-
uint8Array = fileData;
|
|
56
|
-
}
|
|
57
|
-
else if (fileData != null &&
|
|
58
|
-
typeof fileData === "object" &&
|
|
59
|
-
"type" in fileData &&
|
|
60
|
-
"data" in fileData &&
|
|
61
|
-
typeof fileData.data === "object" &&
|
|
62
|
-
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
63
|
-
fileData.data instanceof Uint8Array) {
|
|
64
|
-
uint8Array = fileData.data;
|
|
65
|
-
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
66
|
-
}
|
|
67
|
-
else if (fileData instanceof ArrayBuffer) {
|
|
68
|
-
uint8Array = new Uint8Array(fileData);
|
|
69
|
-
}
|
|
101
|
+
const uint8Array = _toUint8Array(fileData);
|
|
70
102
|
if (uint8Array) {
|
|
71
103
|
let binary = "";
|
|
72
104
|
for (let i = 0; i < uint8Array.length; i++) {
|
|
73
105
|
binary += String.fromCharCode(uint8Array[i]);
|
|
74
106
|
}
|
|
75
107
|
const base64 = btoa(binary);
|
|
76
|
-
|
|
108
|
+
const dataType = mimeType ??
|
|
77
109
|
guessMimetypeFromBase64(base64) ??
|
|
78
|
-
"application/octet-stream"
|
|
79
|
-
|
|
80
|
-
else {
|
|
81
|
-
normalizedFileData = "";
|
|
110
|
+
"application/octet-stream";
|
|
111
|
+
return `data:${dataType};base64,${base64}`;
|
|
82
112
|
}
|
|
83
113
|
}
|
|
84
|
-
|
|
114
|
+
if (typeof fileData === "string") {
|
|
85
115
|
if (fileData.startsWith("http://") || fileData.startsWith("https://")) {
|
|
86
|
-
|
|
116
|
+
return fileData;
|
|
87
117
|
}
|
|
88
|
-
|
|
89
|
-
|
|
118
|
+
if (!fileData.startsWith("data:")) {
|
|
119
|
+
return `data:${mimeType ??
|
|
90
120
|
guessMimetypeFromBase64(fileData) ??
|
|
91
121
|
"application/octet-stream"};base64,${fileData}`;
|
|
92
122
|
}
|
|
93
|
-
|
|
94
|
-
normalizedFileData = fileData;
|
|
95
|
-
}
|
|
123
|
+
return fileData;
|
|
96
124
|
}
|
|
97
|
-
return
|
|
125
|
+
return "";
|
|
98
126
|
};
|
|
99
127
|
exports.normalizeFileDataAsDataURL = normalizeFileDataAsDataURL;
|
|
100
|
-
const convertMessageToTracedFormat = (
|
|
128
|
+
const convertMessageToTracedFormat = (rawMessage, responseMetadata) => {
|
|
129
|
+
const message = rawMessage;
|
|
101
130
|
const formattedMessage = {
|
|
102
131
|
...message,
|
|
103
132
|
};
|
|
@@ -179,3 +208,81 @@ const convertMessageToTracedFormat = (message, responseMetadata) => {
|
|
|
179
208
|
return formattedMessage;
|
|
180
209
|
};
|
|
181
210
|
exports.convertMessageToTracedFormat = convertMessageToTracedFormat;
|
|
211
|
+
const setUsageMetadataOnRunTree = (result, runTree) => {
|
|
212
|
+
if (result.usage == null || typeof result.usage !== "object") {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const usage = result.usage;
|
|
216
|
+
let inputTokens;
|
|
217
|
+
let outputTokens;
|
|
218
|
+
let totalTokens;
|
|
219
|
+
// AI SDK 6: Check for object-based token structures first
|
|
220
|
+
if ((0, types_js_1.isRecord)(usage.inputTokens) &&
|
|
221
|
+
usage.inputTokens?.total != null &&
|
|
222
|
+
typeof usage.inputTokens.total === "number") {
|
|
223
|
+
// AI SDK 6 detected
|
|
224
|
+
inputTokens = usage.inputTokens.total;
|
|
225
|
+
if ((0, types_js_1.isRecord)(usage.outputTokens) &&
|
|
226
|
+
usage.outputTokens?.total != null &&
|
|
227
|
+
typeof usage.outputTokens.total === "number") {
|
|
228
|
+
outputTokens = usage.outputTokens.total;
|
|
229
|
+
}
|
|
230
|
+
totalTokens = result.usage?.totalTokens;
|
|
231
|
+
if (typeof totalTokens !== "number" &&
|
|
232
|
+
typeof inputTokens === "number" &&
|
|
233
|
+
typeof outputTokens === "number") {
|
|
234
|
+
totalTokens = inputTokens + outputTokens;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else if (typeof usage.inputTokens === "number") {
|
|
238
|
+
// AI SDK 5 detected
|
|
239
|
+
inputTokens = usage.inputTokens;
|
|
240
|
+
if (typeof usage.outputTokens === "number") {
|
|
241
|
+
outputTokens = usage.outputTokens;
|
|
242
|
+
}
|
|
243
|
+
totalTokens = result.usage?.totalTokens;
|
|
244
|
+
if (typeof totalTokens !== "number" &&
|
|
245
|
+
typeof inputTokens === "number" &&
|
|
246
|
+
typeof outputTokens === "number") {
|
|
247
|
+
totalTokens = inputTokens + outputTokens;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
// AI SDK 4 fallback
|
|
252
|
+
if (typeof usage.promptTokens === "number") {
|
|
253
|
+
inputTokens = usage.promptTokens;
|
|
254
|
+
}
|
|
255
|
+
if (typeof usage.completionTokens === "number") {
|
|
256
|
+
outputTokens = usage.completionTokens;
|
|
257
|
+
}
|
|
258
|
+
totalTokens = result.usage?.totalTokens;
|
|
259
|
+
if (typeof totalTokens !== "number" &&
|
|
260
|
+
typeof inputTokens === "number" &&
|
|
261
|
+
typeof outputTokens === "number") {
|
|
262
|
+
totalTokens = inputTokens + outputTokens;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const langsmithUsage = {
|
|
266
|
+
input_tokens: inputTokens,
|
|
267
|
+
output_tokens: outputTokens,
|
|
268
|
+
total_tokens: totalTokens,
|
|
269
|
+
};
|
|
270
|
+
const inputTokenDetails = (0, vercel_js_1.extractInputTokenDetails)(result.usage, result.providerMetadata);
|
|
271
|
+
const outputTokenDetails = (0, vercel_js_1.extractOutputTokenDetails)(result.usage, result.providerMetadata);
|
|
272
|
+
runTree.extra = {
|
|
273
|
+
...runTree.extra,
|
|
274
|
+
metadata: {
|
|
275
|
+
...runTree.extra?.metadata,
|
|
276
|
+
usage_metadata: {
|
|
277
|
+
...langsmithUsage,
|
|
278
|
+
input_token_details: {
|
|
279
|
+
...inputTokenDetails,
|
|
280
|
+
},
|
|
281
|
+
output_token_details: {
|
|
282
|
+
...outputTokenDetails,
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
exports.setUsageMetadataOnRunTree = setUsageMetadataOnRunTree;
|
|
@@ -1,3 +1,28 @@
|
|
|
1
|
-
import type { LanguageModelV2DataContent } from "@ai-sdk/provider";
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { LanguageModelV2DataContent, LanguageModelV2Usage, SharedV2ProviderMetadata } from "@ai-sdk/provider";
|
|
2
|
+
import { RunTree } from "../../run_trees.js";
|
|
3
|
+
type AISDKDataContent = string | Uint8Array | ArrayBuffer | Buffer;
|
|
4
|
+
type AISDKProviderReference = {
|
|
5
|
+
[provider: string]: string;
|
|
6
|
+
} & {
|
|
7
|
+
type?: never;
|
|
8
|
+
};
|
|
9
|
+
type AISDKFileData = {
|
|
10
|
+
type: "data";
|
|
11
|
+
data: AISDKDataContent;
|
|
12
|
+
} | {
|
|
13
|
+
type: "url";
|
|
14
|
+
url: URL;
|
|
15
|
+
} | {
|
|
16
|
+
type: "reference";
|
|
17
|
+
reference: AISDKProviderReference;
|
|
18
|
+
} | {
|
|
19
|
+
type: "text";
|
|
20
|
+
text: string;
|
|
21
|
+
};
|
|
22
|
+
export declare const normalizeFileDataAsDataURL: (fileData: AISDKFileData | AISDKDataContent | LanguageModelV2DataContent | AISDKProviderReference | URL, mimeType: string | undefined) => string;
|
|
23
|
+
export declare const convertMessageToTracedFormat: (rawMessage: Record<string, unknown>, responseMetadata?: Record<string, unknown>) => Record<string, unknown>;
|
|
24
|
+
export declare const setUsageMetadataOnRunTree: (result: {
|
|
25
|
+
usage?: LanguageModelV2Usage;
|
|
26
|
+
providerMetadata?: SharedV2ProviderMetadata;
|
|
27
|
+
}, runTree: RunTree) => void;
|
|
28
|
+
export {};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isRecord } from "../../utils/types.js";
|
|
2
|
+
import { extractInputTokenDetails, extractOutputTokenDetails, } from "../../utils/vercel.js";
|
|
1
3
|
const guessMimetypeFromBase64 = (data) => {
|
|
2
4
|
// Check magic bytes from base64 data
|
|
3
5
|
const bytes = atob(data.substring(0, 20)); // Decode first few bytes
|
|
@@ -39,61 +41,88 @@ const guessMimetypeFromBase64 = (data) => {
|
|
|
39
41
|
}
|
|
40
42
|
return undefined;
|
|
41
43
|
};
|
|
44
|
+
function _isAISDKFileData(input) {
|
|
45
|
+
if (!isRecord(input))
|
|
46
|
+
return false;
|
|
47
|
+
if (input.type === "data" && "data" in input)
|
|
48
|
+
return true;
|
|
49
|
+
if (input.type === "url" && "url" in input)
|
|
50
|
+
return true;
|
|
51
|
+
if (input.type === "reference" && "reference" in input)
|
|
52
|
+
return true;
|
|
53
|
+
if (input.type === "text" && "text" in input)
|
|
54
|
+
return true;
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
function _toUint8Array(fileData) {
|
|
58
|
+
// Covers `fileData: ArrayBuffer | Buffer | Uint8Array`
|
|
59
|
+
if (fileData instanceof Uint8Array) {
|
|
60
|
+
return fileData;
|
|
61
|
+
}
|
|
62
|
+
if (fileData != null &&
|
|
63
|
+
typeof fileData === "object" &&
|
|
64
|
+
"type" in fileData &&
|
|
65
|
+
"data" in fileData &&
|
|
66
|
+
typeof fileData.data === "object" &&
|
|
67
|
+
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
68
|
+
fileData.data instanceof Uint8Array) {
|
|
69
|
+
return fileData.data;
|
|
70
|
+
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
71
|
+
}
|
|
72
|
+
if (fileData instanceof ArrayBuffer) {
|
|
73
|
+
return new Uint8Array(fileData);
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
42
77
|
export const normalizeFileDataAsDataURL = (fileData, mimeType) => {
|
|
43
|
-
|
|
78
|
+
if (_isAISDKFileData(fileData)) {
|
|
79
|
+
if (fileData.type === "data") {
|
|
80
|
+
return normalizeFileDataAsDataURL(fileData.data, mimeType);
|
|
81
|
+
}
|
|
82
|
+
if (fileData.type === "url") {
|
|
83
|
+
return fileData.url.toString();
|
|
84
|
+
}
|
|
85
|
+
if (fileData.type === "reference") {
|
|
86
|
+
// TODO: figure out if we can store the reference in a more reasonable format
|
|
87
|
+
return `data:application/octet-stream;base64,${btoa(JSON.stringify(fileData.reference))}`;
|
|
88
|
+
}
|
|
89
|
+
if (fileData.type === "text") {
|
|
90
|
+
return `data:text/plain;base64,${btoa(fileData.text)}`;
|
|
91
|
+
}
|
|
92
|
+
throw new Error("AISDKFileData is not supported");
|
|
93
|
+
}
|
|
44
94
|
if (fileData instanceof URL) {
|
|
45
95
|
return fileData.toString();
|
|
46
96
|
}
|
|
47
|
-
let normalizedFileData;
|
|
48
97
|
if (typeof fileData !== "string") {
|
|
49
|
-
|
|
50
|
-
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
51
|
-
if (fileData instanceof Uint8Array) {
|
|
52
|
-
uint8Array = fileData;
|
|
53
|
-
}
|
|
54
|
-
else if (fileData != null &&
|
|
55
|
-
typeof fileData === "object" &&
|
|
56
|
-
"type" in fileData &&
|
|
57
|
-
"data" in fileData &&
|
|
58
|
-
typeof fileData.data === "object" &&
|
|
59
|
-
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
60
|
-
fileData.data instanceof Uint8Array) {
|
|
61
|
-
uint8Array = fileData.data;
|
|
62
|
-
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
63
|
-
}
|
|
64
|
-
else if (fileData instanceof ArrayBuffer) {
|
|
65
|
-
uint8Array = new Uint8Array(fileData);
|
|
66
|
-
}
|
|
98
|
+
const uint8Array = _toUint8Array(fileData);
|
|
67
99
|
if (uint8Array) {
|
|
68
100
|
let binary = "";
|
|
69
101
|
for (let i = 0; i < uint8Array.length; i++) {
|
|
70
102
|
binary += String.fromCharCode(uint8Array[i]);
|
|
71
103
|
}
|
|
72
104
|
const base64 = btoa(binary);
|
|
73
|
-
|
|
105
|
+
const dataType = mimeType ??
|
|
74
106
|
guessMimetypeFromBase64(base64) ??
|
|
75
|
-
"application/octet-stream"
|
|
76
|
-
|
|
77
|
-
else {
|
|
78
|
-
normalizedFileData = "";
|
|
107
|
+
"application/octet-stream";
|
|
108
|
+
return `data:${dataType};base64,${base64}`;
|
|
79
109
|
}
|
|
80
110
|
}
|
|
81
|
-
|
|
111
|
+
if (typeof fileData === "string") {
|
|
82
112
|
if (fileData.startsWith("http://") || fileData.startsWith("https://")) {
|
|
83
|
-
|
|
113
|
+
return fileData;
|
|
84
114
|
}
|
|
85
|
-
|
|
86
|
-
|
|
115
|
+
if (!fileData.startsWith("data:")) {
|
|
116
|
+
return `data:${mimeType ??
|
|
87
117
|
guessMimetypeFromBase64(fileData) ??
|
|
88
118
|
"application/octet-stream"};base64,${fileData}`;
|
|
89
119
|
}
|
|
90
|
-
|
|
91
|
-
normalizedFileData = fileData;
|
|
92
|
-
}
|
|
120
|
+
return fileData;
|
|
93
121
|
}
|
|
94
|
-
return
|
|
122
|
+
return "";
|
|
95
123
|
};
|
|
96
|
-
export const convertMessageToTracedFormat = (
|
|
124
|
+
export const convertMessageToTracedFormat = (rawMessage, responseMetadata) => {
|
|
125
|
+
const message = rawMessage;
|
|
97
126
|
const formattedMessage = {
|
|
98
127
|
...message,
|
|
99
128
|
};
|
|
@@ -174,3 +203,80 @@ export const convertMessageToTracedFormat = (message, responseMetadata) => {
|
|
|
174
203
|
}
|
|
175
204
|
return formattedMessage;
|
|
176
205
|
};
|
|
206
|
+
export const setUsageMetadataOnRunTree = (result, runTree) => {
|
|
207
|
+
if (result.usage == null || typeof result.usage !== "object") {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const usage = result.usage;
|
|
211
|
+
let inputTokens;
|
|
212
|
+
let outputTokens;
|
|
213
|
+
let totalTokens;
|
|
214
|
+
// AI SDK 6: Check for object-based token structures first
|
|
215
|
+
if (isRecord(usage.inputTokens) &&
|
|
216
|
+
usage.inputTokens?.total != null &&
|
|
217
|
+
typeof usage.inputTokens.total === "number") {
|
|
218
|
+
// AI SDK 6 detected
|
|
219
|
+
inputTokens = usage.inputTokens.total;
|
|
220
|
+
if (isRecord(usage.outputTokens) &&
|
|
221
|
+
usage.outputTokens?.total != null &&
|
|
222
|
+
typeof usage.outputTokens.total === "number") {
|
|
223
|
+
outputTokens = usage.outputTokens.total;
|
|
224
|
+
}
|
|
225
|
+
totalTokens = result.usage?.totalTokens;
|
|
226
|
+
if (typeof totalTokens !== "number" &&
|
|
227
|
+
typeof inputTokens === "number" &&
|
|
228
|
+
typeof outputTokens === "number") {
|
|
229
|
+
totalTokens = inputTokens + outputTokens;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
else if (typeof usage.inputTokens === "number") {
|
|
233
|
+
// AI SDK 5 detected
|
|
234
|
+
inputTokens = usage.inputTokens;
|
|
235
|
+
if (typeof usage.outputTokens === "number") {
|
|
236
|
+
outputTokens = usage.outputTokens;
|
|
237
|
+
}
|
|
238
|
+
totalTokens = result.usage?.totalTokens;
|
|
239
|
+
if (typeof totalTokens !== "number" &&
|
|
240
|
+
typeof inputTokens === "number" &&
|
|
241
|
+
typeof outputTokens === "number") {
|
|
242
|
+
totalTokens = inputTokens + outputTokens;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
// AI SDK 4 fallback
|
|
247
|
+
if (typeof usage.promptTokens === "number") {
|
|
248
|
+
inputTokens = usage.promptTokens;
|
|
249
|
+
}
|
|
250
|
+
if (typeof usage.completionTokens === "number") {
|
|
251
|
+
outputTokens = usage.completionTokens;
|
|
252
|
+
}
|
|
253
|
+
totalTokens = result.usage?.totalTokens;
|
|
254
|
+
if (typeof totalTokens !== "number" &&
|
|
255
|
+
typeof inputTokens === "number" &&
|
|
256
|
+
typeof outputTokens === "number") {
|
|
257
|
+
totalTokens = inputTokens + outputTokens;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const langsmithUsage = {
|
|
261
|
+
input_tokens: inputTokens,
|
|
262
|
+
output_tokens: outputTokens,
|
|
263
|
+
total_tokens: totalTokens,
|
|
264
|
+
};
|
|
265
|
+
const inputTokenDetails = extractInputTokenDetails(result.usage, result.providerMetadata);
|
|
266
|
+
const outputTokenDetails = extractOutputTokenDetails(result.usage, result.providerMetadata);
|
|
267
|
+
runTree.extra = {
|
|
268
|
+
...runTree.extra,
|
|
269
|
+
metadata: {
|
|
270
|
+
...runTree.extra?.metadata,
|
|
271
|
+
usage_metadata: {
|
|
272
|
+
...langsmithUsage,
|
|
273
|
+
input_token_details: {
|
|
274
|
+
...inputTokenDetails,
|
|
275
|
+
},
|
|
276
|
+
output_token_details: {
|
|
277
|
+
...outputTokenDetails,
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
};
|