braintrust 3.3.0 → 3.5.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.
- package/README.md +52 -67
- package/dev/dist/index.d.mts +98 -14
- package/dev/dist/index.d.ts +98 -14
- package/dev/dist/index.js +2751 -1463
- package/dev/dist/index.mjs +2383 -1095
- package/dist/auto-instrumentations/bundler/esbuild.cjs +476 -31
- package/dist/auto-instrumentations/bundler/esbuild.d.mts +2 -2
- package/dist/auto-instrumentations/bundler/esbuild.d.ts +2 -2
- package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
- package/dist/auto-instrumentations/bundler/rollup.cjs +476 -31
- package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
- package/dist/auto-instrumentations/bundler/vite.cjs +476 -31
- package/dist/auto-instrumentations/bundler/vite.d.mts +2 -2
- package/dist/auto-instrumentations/bundler/vite.d.ts +2 -2
- package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
- package/dist/auto-instrumentations/bundler/webpack.cjs +476 -31
- package/dist/auto-instrumentations/bundler/webpack.d.mts +2 -2
- package/dist/auto-instrumentations/bundler/webpack.d.ts +2 -2
- package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
- package/dist/auto-instrumentations/chunk-DQTPSXJB.mjs +733 -0
- package/dist/auto-instrumentations/chunk-EVUKFMHG.mjs +41 -0
- package/dist/auto-instrumentations/{chunk-OLOPGWTJ.mjs → chunk-F3TJZ3Z2.mjs} +1 -1
- package/dist/auto-instrumentations/chunk-VLEJ5AEK.mjs +41 -0
- package/dist/auto-instrumentations/hook.mjs +540 -37
- package/dist/auto-instrumentations/index.cjs +476 -31
- package/dist/auto-instrumentations/index.d.mts +5 -5
- package/dist/auto-instrumentations/index.d.ts +5 -5
- package/dist/auto-instrumentations/index.mjs +1 -1
- package/dist/auto-instrumentations/loader/cjs-patch.cjs +32 -10
- package/dist/auto-instrumentations/loader/cjs-patch.mjs +10 -5
- package/dist/auto-instrumentations/loader/esm-hook.mjs +11 -12
- package/dist/auto-instrumentations/loader/get-package-version.cjs +28 -8
- package/dist/auto-instrumentations/loader/get-package-version.d.mts +2 -1
- package/dist/auto-instrumentations/loader/get-package-version.d.ts +2 -1
- package/dist/auto-instrumentations/loader/get-package-version.mjs +3 -1
- package/dist/browser.d.mts +806 -306
- package/dist/browser.d.ts +806 -306
- package/dist/browser.js +3235 -2317
- package/dist/browser.mjs +3235 -2317
- package/dist/cli.js +2672 -1347
- package/dist/edge-light.d.mts +1 -1
- package/dist/edge-light.d.ts +1 -1
- package/dist/edge-light.js +3035 -2087
- package/dist/edge-light.mjs +3035 -2087
- package/dist/index.d.mts +806 -306
- package/dist/index.d.ts +806 -306
- package/dist/index.js +3570 -2654
- package/dist/index.mjs +3235 -2319
- package/dist/instrumentation/index.d.mts +16 -22
- package/dist/instrumentation/index.d.ts +16 -22
- package/dist/instrumentation/index.js +2241 -1077
- package/dist/instrumentation/index.mjs +2241 -1077
- package/dist/workerd.d.mts +1 -1
- package/dist/workerd.d.ts +1 -1
- package/dist/workerd.js +3035 -2087
- package/dist/workerd.mjs +3035 -2087
- package/package.json +26 -7
- package/dist/auto-instrumentations/chunk-KVX7OFPD.mjs +0 -288
- package/dist/auto-instrumentations/chunk-XDBPUTVE.mjs +0 -22
- package/dist/auto-instrumentations/chunk-ZEC7BCL4.mjs +0 -22
|
@@ -1,5 +1,98 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
1
|
+
// src/isomorph.ts
|
|
2
|
+
var DefaultAsyncLocalStorage = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
}
|
|
5
|
+
enterWith(_) {
|
|
6
|
+
}
|
|
7
|
+
run(_, callback) {
|
|
8
|
+
return callback();
|
|
9
|
+
}
|
|
10
|
+
getStore() {
|
|
11
|
+
return void 0;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var DefaultChannel = class {
|
|
15
|
+
constructor(name) {
|
|
16
|
+
this.name = name;
|
|
17
|
+
}
|
|
18
|
+
hasSubscribers = false;
|
|
19
|
+
subscribe(_subscription) {
|
|
20
|
+
}
|
|
21
|
+
unsubscribe(_subscription) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
bindStore(_store, _transform) {
|
|
25
|
+
}
|
|
26
|
+
unbindStore(_store) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
publish(_message) {
|
|
30
|
+
}
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
+
runStores(_message, fn, thisArg, ...args) {
|
|
33
|
+
return fn.apply(thisArg, args);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var DefaultTracingChannel = class {
|
|
37
|
+
start;
|
|
38
|
+
end;
|
|
39
|
+
asyncStart;
|
|
40
|
+
asyncEnd;
|
|
41
|
+
error;
|
|
42
|
+
constructor(nameOrChannels) {
|
|
43
|
+
if (typeof nameOrChannels === "string") {
|
|
44
|
+
this.start = new DefaultChannel(`tracing:${nameOrChannels}:start`);
|
|
45
|
+
this.end = new DefaultChannel(`tracing:${nameOrChannels}:end`);
|
|
46
|
+
this.asyncStart = new DefaultChannel(
|
|
47
|
+
`tracing:${nameOrChannels}:asyncStart`
|
|
48
|
+
);
|
|
49
|
+
this.asyncEnd = new DefaultChannel(`tracing:${nameOrChannels}:asyncEnd`);
|
|
50
|
+
this.error = new DefaultChannel(`tracing:${nameOrChannels}:error`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
this.start = nameOrChannels.start ?? new DefaultChannel("tracing:start");
|
|
54
|
+
this.end = nameOrChannels.end ?? new DefaultChannel("tracing:end");
|
|
55
|
+
this.asyncStart = nameOrChannels.asyncStart ?? new DefaultChannel("tracing:asyncStart");
|
|
56
|
+
this.asyncEnd = nameOrChannels.asyncEnd ?? new DefaultChannel("tracing:asyncEnd");
|
|
57
|
+
this.error = nameOrChannels.error ?? new DefaultChannel("tracing:error");
|
|
58
|
+
}
|
|
59
|
+
get hasSubscribers() {
|
|
60
|
+
return this.start.hasSubscribers || this.end.hasSubscribers || this.asyncStart.hasSubscribers || this.asyncEnd.hasSubscribers || this.error.hasSubscribers;
|
|
61
|
+
}
|
|
62
|
+
subscribe(_handlers) {
|
|
63
|
+
}
|
|
64
|
+
unsubscribe(_handlers) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
68
|
+
traceSync(fn, _message, thisArg, ...args) {
|
|
69
|
+
return fn.apply(thisArg, args);
|
|
70
|
+
}
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
|
+
tracePromise(fn, _message, thisArg, ...args) {
|
|
73
|
+
return Promise.resolve(fn.apply(thisArg, args));
|
|
74
|
+
}
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
76
|
+
traceCallback(fn, _position, _message, thisArg, ...args) {
|
|
77
|
+
return fn.apply(thisArg, args);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
var iso = {
|
|
81
|
+
buildType: "unknown",
|
|
82
|
+
// Will be set by configureBrowser() or configureNode()
|
|
83
|
+
getRepoInfo: async (_settings) => void 0,
|
|
84
|
+
getPastNAncestors: async () => [],
|
|
85
|
+
getEnv: (_name) => void 0,
|
|
86
|
+
getCallerLocation: () => void 0,
|
|
87
|
+
newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
|
+
newTracingChannel: (nameOrChannels) => new DefaultTracingChannel(nameOrChannels),
|
|
90
|
+
processOn: (_0, _1) => {
|
|
91
|
+
},
|
|
92
|
+
basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
|
|
93
|
+
writeln: (text) => console.log(text)
|
|
94
|
+
};
|
|
95
|
+
var isomorph_default = iso;
|
|
3
96
|
|
|
4
97
|
// src/instrumentation/core/stream-patcher.ts
|
|
5
98
|
function isAsyncIterable(value) {
|
|
@@ -16,7 +109,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
16
109
|
return stream;
|
|
17
110
|
}
|
|
18
111
|
const originalIteratorFn = stream[Symbol.asyncIterator];
|
|
19
|
-
if (originalIteratorFn
|
|
112
|
+
if ("__braintrust_patched" in originalIteratorFn && originalIteratorFn["__braintrust_patched"]) {
|
|
20
113
|
return stream;
|
|
21
114
|
}
|
|
22
115
|
try {
|
|
@@ -57,7 +150,10 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
57
150
|
completed = true;
|
|
58
151
|
if (options.onError) {
|
|
59
152
|
try {
|
|
60
|
-
options.onError(
|
|
153
|
+
options.onError(
|
|
154
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
155
|
+
chunks
|
|
156
|
+
);
|
|
61
157
|
} catch (handlerError) {
|
|
62
158
|
console.error("Error in stream onError handler:", handlerError);
|
|
63
159
|
}
|
|
@@ -85,7 +181,8 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
85
181
|
iterator.throw = async function(...args) {
|
|
86
182
|
if (!completed) {
|
|
87
183
|
completed = true;
|
|
88
|
-
const
|
|
184
|
+
const rawError = args[0];
|
|
185
|
+
const error = rawError instanceof Error ? rawError : new Error(String(rawError));
|
|
89
186
|
if (options.onError) {
|
|
90
187
|
try {
|
|
91
188
|
options.onError(error, chunks);
|
|
@@ -99,7 +196,9 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
99
196
|
}
|
|
100
197
|
return iterator;
|
|
101
198
|
};
|
|
102
|
-
patchedIteratorFn
|
|
199
|
+
Object.defineProperty(patchedIteratorFn, "__braintrust_patched", {
|
|
200
|
+
value: true
|
|
201
|
+
});
|
|
103
202
|
stream[Symbol.asyncIterator] = patchedIteratorFn;
|
|
104
203
|
return stream;
|
|
105
204
|
} catch (error) {
|
|
@@ -111,6 +210,111 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
111
210
|
// src/logger.ts
|
|
112
211
|
import { v4 as uuidv42 } from "uuid";
|
|
113
212
|
|
|
213
|
+
// src/debug-logger.ts
|
|
214
|
+
var PREFIX = "[braintrust]";
|
|
215
|
+
var DEBUG_LOG_LEVEL_SYMBOL = Symbol.for("braintrust-debug-log-level");
|
|
216
|
+
var LOG_LEVEL_PRIORITY = {
|
|
217
|
+
error: 0,
|
|
218
|
+
warn: 1,
|
|
219
|
+
info: 2,
|
|
220
|
+
debug: 3
|
|
221
|
+
};
|
|
222
|
+
var hasWarnedAboutInvalidEnvValue = false;
|
|
223
|
+
var debugLogStateResolver = void 0;
|
|
224
|
+
function warnInvalidEnvValue(value) {
|
|
225
|
+
if (hasWarnedAboutInvalidEnvValue) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
hasWarnedAboutInvalidEnvValue = true;
|
|
229
|
+
console.warn(
|
|
230
|
+
PREFIX,
|
|
231
|
+
`Invalid BRAINTRUST_DEBUG_LOG_LEVEL value "${value}". Expected "error", "warn", "info", or "debug".`
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
function normalizeDebugLogLevelOption(option) {
|
|
235
|
+
if (option === false) {
|
|
236
|
+
return void 0;
|
|
237
|
+
}
|
|
238
|
+
if (option === "error" || option === "warn" || option === "info" || option === "debug") {
|
|
239
|
+
return option;
|
|
240
|
+
}
|
|
241
|
+
throw new Error(
|
|
242
|
+
`Invalid debugLogLevel value "${option}". Expected false, "error", "warn", "info", or "debug".`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
function parseDebugLogLevelEnv(value) {
|
|
246
|
+
if (!value) {
|
|
247
|
+
return void 0;
|
|
248
|
+
}
|
|
249
|
+
if (value === "error" || value === "warn" || value === "info" || value === "debug") {
|
|
250
|
+
return value;
|
|
251
|
+
}
|
|
252
|
+
warnInvalidEnvValue(value);
|
|
253
|
+
return void 0;
|
|
254
|
+
}
|
|
255
|
+
function getEnvDebugLogLevel() {
|
|
256
|
+
return parseDebugLogLevelEnv(isomorph_default.getEnv("BRAINTRUST_DEBUG_LOG_LEVEL"));
|
|
257
|
+
}
|
|
258
|
+
function setGlobalDebugLogLevel(level) {
|
|
259
|
+
globalThis[DEBUG_LOG_LEVEL_SYMBOL] = level;
|
|
260
|
+
}
|
|
261
|
+
function setDebugLogStateResolver(resolver) {
|
|
262
|
+
debugLogStateResolver = resolver;
|
|
263
|
+
}
|
|
264
|
+
function resolveDebugLogLevel(state) {
|
|
265
|
+
const stateLevel = state?.getDebugLogLevel?.();
|
|
266
|
+
const hasStateOverride = state?.hasDebugLogLevelOverride?.() ?? false;
|
|
267
|
+
if (hasStateOverride) {
|
|
268
|
+
return stateLevel;
|
|
269
|
+
}
|
|
270
|
+
const globalLevel = (
|
|
271
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
272
|
+
globalThis[DEBUG_LOG_LEVEL_SYMBOL]
|
|
273
|
+
);
|
|
274
|
+
if (globalLevel !== void 0) {
|
|
275
|
+
return globalLevel === false ? void 0 : globalLevel;
|
|
276
|
+
}
|
|
277
|
+
return getEnvDebugLogLevel();
|
|
278
|
+
}
|
|
279
|
+
function emit(method, state, args) {
|
|
280
|
+
const level = resolveDebugLogLevel(state);
|
|
281
|
+
if (!level || LOG_LEVEL_PRIORITY[method] > LOG_LEVEL_PRIORITY[level]) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (method === "info") {
|
|
285
|
+
console.log(PREFIX, ...args);
|
|
286
|
+
} else if (method === "debug") {
|
|
287
|
+
console.debug(PREFIX, ...args);
|
|
288
|
+
} else if (method === "warn") {
|
|
289
|
+
console.warn(PREFIX, ...args);
|
|
290
|
+
} else {
|
|
291
|
+
console.error(PREFIX, ...args);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function createDebugLogger(state) {
|
|
295
|
+
const resolveState = () => state ?? debugLogStateResolver?.();
|
|
296
|
+
return {
|
|
297
|
+
info(...args) {
|
|
298
|
+
emit("info", resolveState(), args);
|
|
299
|
+
},
|
|
300
|
+
debug(...args) {
|
|
301
|
+
emit("debug", resolveState(), args);
|
|
302
|
+
},
|
|
303
|
+
warn(...args) {
|
|
304
|
+
emit("warn", resolveState(), args);
|
|
305
|
+
},
|
|
306
|
+
error(...args) {
|
|
307
|
+
emit("error", resolveState(), args);
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
var debugLogger = {
|
|
312
|
+
...createDebugLogger(),
|
|
313
|
+
forState(state) {
|
|
314
|
+
return createDebugLogger(state);
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
|
|
114
318
|
// src/queue.ts
|
|
115
319
|
var DEFAULT_QUEUE_SIZE = 15e3;
|
|
116
320
|
var Queue = class {
|
|
@@ -119,7 +323,7 @@ var Queue = class {
|
|
|
119
323
|
enforceSizeLimit = false;
|
|
120
324
|
constructor(maxSize) {
|
|
121
325
|
if (maxSize < 1) {
|
|
122
|
-
|
|
326
|
+
debugLogger.warn(
|
|
123
327
|
`maxSize ${maxSize} is <1, using default ${DEFAULT_QUEUE_SIZE}`
|
|
124
328
|
);
|
|
125
329
|
maxSize = DEFAULT_QUEUE_SIZE;
|
|
@@ -1916,6 +2120,8 @@ var Experiment = z6.object({
|
|
|
1916
2120
|
deleted_at: z6.union([z6.string(), z6.null()]).optional(),
|
|
1917
2121
|
dataset_id: z6.union([z6.string(), z6.null()]).optional(),
|
|
1918
2122
|
dataset_version: z6.union([z6.string(), z6.null()]).optional(),
|
|
2123
|
+
parameters_id: z6.union([z6.string(), z6.null()]).optional(),
|
|
2124
|
+
parameters_version: z6.union([z6.string(), z6.null()]).optional(),
|
|
1919
2125
|
public: z6.boolean(),
|
|
1920
2126
|
user_id: z6.union([z6.string(), z6.null()]).optional(),
|
|
1921
2127
|
metadata: z6.union([z6.object({}).partial().passthrough(), z6.null()]).optional(),
|
|
@@ -1938,7 +2144,11 @@ var SpanType = z6.union([
|
|
|
1938
2144
|
z6.null()
|
|
1939
2145
|
]);
|
|
1940
2146
|
var SpanAttributes = z6.union([
|
|
1941
|
-
z6.object({
|
|
2147
|
+
z6.object({
|
|
2148
|
+
name: z6.union([z6.string(), z6.null()]),
|
|
2149
|
+
type: SpanType,
|
|
2150
|
+
purpose: z6.union([z6.literal("scorer"), z6.null()])
|
|
2151
|
+
}).partial().passthrough(),
|
|
1942
2152
|
z6.null()
|
|
1943
2153
|
]);
|
|
1944
2154
|
var ExperimentEvent = z6.object({
|
|
@@ -2378,6 +2588,7 @@ var FunctionId = z6.union([
|
|
|
2378
2588
|
version: z6.string()
|
|
2379
2589
|
}),
|
|
2380
2590
|
code: z6.string(),
|
|
2591
|
+
function_type: FunctionTypeEnum.and(z6.unknown()).optional(),
|
|
2381
2592
|
name: z6.union([z6.string(), z6.null()]).optional()
|
|
2382
2593
|
}),
|
|
2383
2594
|
z6.object({
|
|
@@ -2607,7 +2818,12 @@ var TopicAutomationConfig = z6.object({
|
|
|
2607
2818
|
topic_map_functions: z6.array(TopicMapFunctionAutomation),
|
|
2608
2819
|
scope: z6.union([SpanScope, TraceScope, GroupScope, z6.null()]).optional(),
|
|
2609
2820
|
data_scope: TopicAutomationDataScope.optional(),
|
|
2610
|
-
btql_filter: z6.union([z6.string(), z6.null()]).optional()
|
|
2821
|
+
btql_filter: z6.union([z6.string(), z6.null()]).optional(),
|
|
2822
|
+
backfill_time_range: z6.union([
|
|
2823
|
+
z6.string(),
|
|
2824
|
+
z6.object({ from: z6.string(), to: z6.string() }),
|
|
2825
|
+
z6.null()
|
|
2826
|
+
]).optional()
|
|
2611
2827
|
});
|
|
2612
2828
|
var ProjectAutomation = z6.object({
|
|
2613
2829
|
id: z6.string().uuid(),
|
|
@@ -3461,34 +3677,6 @@ function devNullWritableStream() {
|
|
|
3461
3677
|
});
|
|
3462
3678
|
}
|
|
3463
3679
|
|
|
3464
|
-
// src/isomorph.ts
|
|
3465
|
-
var DefaultAsyncLocalStorage = class {
|
|
3466
|
-
constructor() {
|
|
3467
|
-
}
|
|
3468
|
-
enterWith(_) {
|
|
3469
|
-
}
|
|
3470
|
-
run(_, callback) {
|
|
3471
|
-
return callback();
|
|
3472
|
-
}
|
|
3473
|
-
getStore() {
|
|
3474
|
-
return void 0;
|
|
3475
|
-
}
|
|
3476
|
-
};
|
|
3477
|
-
var iso = {
|
|
3478
|
-
buildType: "unknown",
|
|
3479
|
-
// Will be set by configureBrowser() or configureNode()
|
|
3480
|
-
getRepoInfo: async (_settings) => void 0,
|
|
3481
|
-
getPastNAncestors: async () => [],
|
|
3482
|
-
getEnv: (_name) => void 0,
|
|
3483
|
-
getCallerLocation: () => void 0,
|
|
3484
|
-
newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
|
|
3485
|
-
processOn: (_0, _1) => {
|
|
3486
|
-
},
|
|
3487
|
-
basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
|
|
3488
|
-
writeln: (text) => console.log(text)
|
|
3489
|
-
};
|
|
3490
|
-
var isomorph_default = iso;
|
|
3491
|
-
|
|
3492
3680
|
// src/prompt-cache/disk-cache.ts
|
|
3493
3681
|
function canUseDiskCache() {
|
|
3494
3682
|
return !!(isomorph_default.hash && isomorph_default.gunzip && isomorph_default.gzip && isomorph_default.stat && isomorph_default.readFile && isomorph_default.writeFile && isomorph_default.utimes && isomorph_default.readdir && isomorph_default.mkdir && isomorph_default.unlink && isomorph_default.homedir);
|
|
@@ -4046,6 +4234,12 @@ var parametersRowSchema = z8.object({
|
|
|
4046
4234
|
}),
|
|
4047
4235
|
metadata: z8.union([z8.object({}).partial().passthrough(), z8.null()]).optional()
|
|
4048
4236
|
});
|
|
4237
|
+
var InlineAttachmentReferenceSchema = z8.object({
|
|
4238
|
+
type: z8.literal("inline_attachment"),
|
|
4239
|
+
src: z8.string().min(1),
|
|
4240
|
+
content_type: z8.string().optional(),
|
|
4241
|
+
filename: z8.string().optional()
|
|
4242
|
+
});
|
|
4049
4243
|
var LoginInvalidOrgError = class extends Error {
|
|
4050
4244
|
constructor(message) {
|
|
4051
4245
|
super(message);
|
|
@@ -4192,7 +4386,10 @@ var loginSchema = z8.strictObject({
|
|
|
4192
4386
|
proxyUrl: z8.string(),
|
|
4193
4387
|
loginToken: z8.string(),
|
|
4194
4388
|
orgId: z8.string().nullish(),
|
|
4195
|
-
gitMetadataSettings: GitMetadataSettings.nullish()
|
|
4389
|
+
gitMetadataSettings: GitMetadataSettings.nullish(),
|
|
4390
|
+
debugLogLevel: z8.enum(["error", "warn", "info", "debug"]).optional(),
|
|
4391
|
+
// Distinguishes explicit false from unset so env fallback stays disabled after deserialization.
|
|
4392
|
+
debugLogLevelDisabled: z8.boolean().optional()
|
|
4196
4393
|
});
|
|
4197
4394
|
var stateNonce = 0;
|
|
4198
4395
|
var BraintrustState = class _BraintrustState {
|
|
@@ -4213,6 +4410,16 @@ var BraintrustState = class _BraintrustState {
|
|
|
4213
4410
|
this._bgLogger = new SyncLazyValue(
|
|
4214
4411
|
() => new HTTPBackgroundLogger(new LazyValue(defaultGetLogConn), loginParams)
|
|
4215
4412
|
);
|
|
4413
|
+
if (loginParams.debugLogLevel !== void 0) {
|
|
4414
|
+
this.debugLogLevelConfigured = true;
|
|
4415
|
+
this.debugLogLevel = normalizeDebugLogLevelOption(
|
|
4416
|
+
loginParams.debugLogLevel
|
|
4417
|
+
);
|
|
4418
|
+
setGlobalDebugLogLevel(this.debugLogLevel ?? false);
|
|
4419
|
+
} else {
|
|
4420
|
+
this.debugLogLevel = getEnvDebugLogLevel();
|
|
4421
|
+
setGlobalDebugLogLevel(void 0);
|
|
4422
|
+
}
|
|
4216
4423
|
this.resetLoginInfo();
|
|
4217
4424
|
const memoryCache = new LRUCache({
|
|
4218
4425
|
max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_MEMORY_MAX")) ?? 1 << 10
|
|
@@ -4257,6 +4464,8 @@ var BraintrustState = class _BraintrustState {
|
|
|
4257
4464
|
proxyUrl = null;
|
|
4258
4465
|
loggedIn = false;
|
|
4259
4466
|
gitMetadataSettings;
|
|
4467
|
+
debugLogLevel;
|
|
4468
|
+
debugLogLevelConfigured = false;
|
|
4260
4469
|
fetch = globalThis.fetch;
|
|
4261
4470
|
_appConn = null;
|
|
4262
4471
|
_apiConn = null;
|
|
@@ -4322,6 +4531,11 @@ var BraintrustState = class _BraintrustState {
|
|
|
4322
4531
|
this.proxyUrl = other.proxyUrl;
|
|
4323
4532
|
this.loggedIn = other.loggedIn;
|
|
4324
4533
|
this.gitMetadataSettings = other.gitMetadataSettings;
|
|
4534
|
+
this.debugLogLevel = other.debugLogLevel;
|
|
4535
|
+
this.debugLogLevelConfigured = other.debugLogLevelConfigured;
|
|
4536
|
+
setGlobalDebugLogLevel(
|
|
4537
|
+
this.debugLogLevelConfigured ? this.debugLogLevel ?? false : void 0
|
|
4538
|
+
);
|
|
4325
4539
|
this._appConn = other._appConn;
|
|
4326
4540
|
this._apiConn = other._apiConn;
|
|
4327
4541
|
this.loginReplaceApiConn(this.apiConn());
|
|
@@ -4346,7 +4560,9 @@ var BraintrustState = class _BraintrustState {
|
|
|
4346
4560
|
orgName: this.orgName,
|
|
4347
4561
|
apiUrl: this.apiUrl,
|
|
4348
4562
|
proxyUrl: this.proxyUrl,
|
|
4349
|
-
gitMetadataSettings: this.gitMetadataSettings
|
|
4563
|
+
gitMetadataSettings: this.gitMetadataSettings,
|
|
4564
|
+
...this.debugLogLevel ? { debugLogLevel: this.debugLogLevel } : {},
|
|
4565
|
+
...this.debugLogLevelConfigured && !this.debugLogLevel ? { debugLogLevelDisabled: true } : {}
|
|
4350
4566
|
};
|
|
4351
4567
|
}
|
|
4352
4568
|
static deserialize(serialized, opts) {
|
|
@@ -4373,6 +4589,10 @@ var BraintrustState = class _BraintrustState {
|
|
|
4373
4589
|
state.proxyConn().set_token(state.loginToken);
|
|
4374
4590
|
}
|
|
4375
4591
|
state.loggedIn = true;
|
|
4592
|
+
state.debugLogLevelConfigured = "debugLogLevel" in serializedParsed.data || !!serializedParsed.data.debugLogLevelDisabled;
|
|
4593
|
+
setGlobalDebugLogLevel(
|
|
4594
|
+
state.debugLogLevelConfigured ? state.debugLogLevel ?? false : void 0
|
|
4595
|
+
);
|
|
4376
4596
|
state.loginReplaceApiConn(state.apiConn());
|
|
4377
4597
|
return state;
|
|
4378
4598
|
}
|
|
@@ -4385,7 +4605,22 @@ var BraintrustState = class _BraintrustState {
|
|
|
4385
4605
|
setMaskingFunction(maskingFunction) {
|
|
4386
4606
|
this.bgLogger().setMaskingFunction(maskingFunction);
|
|
4387
4607
|
}
|
|
4608
|
+
setDebugLogLevel(option) {
|
|
4609
|
+
if (option === void 0) {
|
|
4610
|
+
return;
|
|
4611
|
+
}
|
|
4612
|
+
this.debugLogLevelConfigured = true;
|
|
4613
|
+
this.debugLogLevel = normalizeDebugLogLevelOption(option);
|
|
4614
|
+
setGlobalDebugLogLevel(this.debugLogLevel ?? false);
|
|
4615
|
+
}
|
|
4616
|
+
getDebugLogLevel() {
|
|
4617
|
+
return this.debugLogLevel;
|
|
4618
|
+
}
|
|
4619
|
+
hasDebugLogLevelOverride() {
|
|
4620
|
+
return this.debugLogLevelConfigured;
|
|
4621
|
+
}
|
|
4388
4622
|
async login(loginParams) {
|
|
4623
|
+
this.setDebugLogLevel(loginParams.debugLogLevel);
|
|
4389
4624
|
if (this.apiUrl && !loginParams.forceLogin) {
|
|
4390
4625
|
return;
|
|
4391
4626
|
}
|
|
@@ -4483,6 +4718,7 @@ var BraintrustState = class _BraintrustState {
|
|
|
4483
4718
|
};
|
|
4484
4719
|
var _globalState;
|
|
4485
4720
|
var _internalGetGlobalState = () => _globalState;
|
|
4721
|
+
setDebugLogStateResolver(() => _internalGetGlobalState());
|
|
4486
4722
|
var FailedHTTPResponse = class extends Error {
|
|
4487
4723
|
status;
|
|
4488
4724
|
text;
|
|
@@ -4597,7 +4833,7 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
4597
4833
|
return await resp.json();
|
|
4598
4834
|
} catch (e) {
|
|
4599
4835
|
if (i < tries - 1) {
|
|
4600
|
-
|
|
4836
|
+
debugLogger.debug(
|
|
4601
4837
|
`Retrying API request ${object_type} ${JSON.stringify(args)} ${e.status} ${e.text}`
|
|
4602
4838
|
);
|
|
4603
4839
|
continue;
|
|
@@ -4809,7 +5045,7 @@ with a Blob/ArrayBuffer, or run the program on Node.js.`
|
|
|
4809
5045
|
try {
|
|
4810
5046
|
statSync(data);
|
|
4811
5047
|
} catch (e) {
|
|
4812
|
-
|
|
5048
|
+
debugLogger.warn(`Failed to read file: ${e}`);
|
|
4813
5049
|
}
|
|
4814
5050
|
}
|
|
4815
5051
|
};
|
|
@@ -5521,7 +5757,7 @@ var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
|
|
|
5521
5757
|
this.queueDropLoggingPeriod = queueDropLoggingPeriodEnv;
|
|
5522
5758
|
}
|
|
5523
5759
|
if (isomorph_default.getEnv("BRAINTRUST_LOG_FLUSH_CHUNK_SIZE")) {
|
|
5524
|
-
|
|
5760
|
+
debugLogger.warn(
|
|
5525
5761
|
"BRAINTRUST_LOG_FLUSH_CHUNK_SIZE is deprecated and no longer has any effect. Log flushing now sends all items at once and batches them automatically. This environment variable will be removed in a future major release."
|
|
5526
5762
|
);
|
|
5527
5763
|
}
|
|
@@ -5583,7 +5819,10 @@ var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
|
|
|
5583
5819
|
const versionInfo = await conn.get_json("version");
|
|
5584
5820
|
serverLimit = z8.object({ logs3_payload_max_bytes: z8.number().nullish() }).parse(versionInfo).logs3_payload_max_bytes ?? null;
|
|
5585
5821
|
} catch (e) {
|
|
5586
|
-
|
|
5822
|
+
debugLogger.warn(
|
|
5823
|
+
"Failed to fetch version info for payload limit:",
|
|
5824
|
+
e
|
|
5825
|
+
);
|
|
5587
5826
|
}
|
|
5588
5827
|
const validServerLimit = serverLimit !== null && serverLimit > 0 ? serverLimit : null;
|
|
5589
5828
|
const canUseOverflow = validServerLimit !== null;
|
|
@@ -5727,16 +5966,16 @@ var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
|
|
|
5727
5966
|
if (isRetrying) {
|
|
5728
5967
|
errmsg += ". Retrying";
|
|
5729
5968
|
}
|
|
5730
|
-
|
|
5969
|
+
debugLogger.warn(errmsg);
|
|
5731
5970
|
if (!isRetrying) {
|
|
5732
|
-
|
|
5971
|
+
debugLogger.warn(
|
|
5733
5972
|
`Failed to construct log records to flush after ${this.numTries} attempts. Dropping batch`
|
|
5734
5973
|
);
|
|
5735
5974
|
throw e;
|
|
5736
5975
|
} else {
|
|
5737
|
-
|
|
5976
|
+
debugLogger.warn(e);
|
|
5738
5977
|
const sleepTimeS = BACKGROUND_LOGGER_BASE_SLEEP_TIME_S * 2 ** i;
|
|
5739
|
-
|
|
5978
|
+
debugLogger.info(`Sleeping for ${sleepTimeS}s`);
|
|
5740
5979
|
await new Promise(
|
|
5741
5980
|
(resolve) => setTimeout(resolve, sleepTimeS * 1e3)
|
|
5742
5981
|
);
|
|
@@ -5837,15 +6076,15 @@ Error: ${errorText}`;
|
|
|
5837
6076
|
this.logFailedPayloadsDir();
|
|
5838
6077
|
}
|
|
5839
6078
|
if (!isRetrying) {
|
|
5840
|
-
|
|
6079
|
+
debugLogger.warn(
|
|
5841
6080
|
`log request failed after ${this.numTries} retries. Dropping batch`
|
|
5842
6081
|
);
|
|
5843
6082
|
throw new Error(errMsg);
|
|
5844
6083
|
} else {
|
|
5845
|
-
|
|
6084
|
+
debugLogger.warn(errMsg);
|
|
5846
6085
|
if (isRetrying) {
|
|
5847
6086
|
const sleepTimeS = BACKGROUND_LOGGER_BASE_SLEEP_TIME_S * 2 ** i;
|
|
5848
|
-
|
|
6087
|
+
debugLogger.info(`Sleeping for ${sleepTimeS}s`);
|
|
5849
6088
|
await new Promise(
|
|
5850
6089
|
(resolve) => setTimeout(resolve, sleepTimeS * 1e3)
|
|
5851
6090
|
);
|
|
@@ -5860,7 +6099,7 @@ Error: ${errorText}`;
|
|
|
5860
6099
|
this.queueDropLoggingState.numDropped += numItems;
|
|
5861
6100
|
const timeNow = getCurrentUnixTimestamp();
|
|
5862
6101
|
if (timeNow - this.queueDropLoggingState.lastLoggedTimestamp > this.queueDropLoggingPeriod) {
|
|
5863
|
-
|
|
6102
|
+
debugLogger.warn(
|
|
5864
6103
|
`Dropped ${this.queueDropLoggingState.numDropped} elements due to full queue`
|
|
5865
6104
|
);
|
|
5866
6105
|
if (this.failedPublishPayloadsDir) {
|
|
@@ -5892,7 +6131,7 @@ Error: ${errorText}`;
|
|
|
5892
6131
|
await _HTTPBackgroundLogger.writePayloadToDir({ payloadDir, payload });
|
|
5893
6132
|
}
|
|
5894
6133
|
} catch (e) {
|
|
5895
|
-
|
|
6134
|
+
debugLogger.error(e);
|
|
5896
6135
|
}
|
|
5897
6136
|
}
|
|
5898
6137
|
static async writePayloadToDir({
|
|
@@ -5900,7 +6139,7 @@ Error: ${errorText}`;
|
|
|
5900
6139
|
payload
|
|
5901
6140
|
}) {
|
|
5902
6141
|
if (!(isomorph_default.pathJoin && isomorph_default.mkdir && isomorph_default.writeFile)) {
|
|
5903
|
-
|
|
6142
|
+
debugLogger.warn(
|
|
5904
6143
|
"Cannot dump payloads: filesystem-operations not supported on this platform"
|
|
5905
6144
|
);
|
|
5906
6145
|
return;
|
|
@@ -5913,7 +6152,7 @@ Error: ${errorText}`;
|
|
|
5913
6152
|
await isomorph_default.mkdir(payloadDir, { recursive: true });
|
|
5914
6153
|
await isomorph_default.writeFile(payloadFile, payload);
|
|
5915
6154
|
} catch (e) {
|
|
5916
|
-
|
|
6155
|
+
debugLogger.error(
|
|
5917
6156
|
`Failed to write failed payload to output file ${payloadFile}:
|
|
5918
6157
|
`,
|
|
5919
6158
|
e
|
|
@@ -5944,7 +6183,9 @@ Error: ${errorText}`;
|
|
|
5944
6183
|
}
|
|
5945
6184
|
}
|
|
5946
6185
|
logFailedPayloadsDir() {
|
|
5947
|
-
|
|
6186
|
+
debugLogger.warn(
|
|
6187
|
+
`Logging failed payloads to ${this.failedPublishPayloadsDir}`
|
|
6188
|
+
);
|
|
5948
6189
|
}
|
|
5949
6190
|
// Should only be called by BraintrustState.
|
|
5950
6191
|
internalReplaceApiConn(apiConn) {
|
|
@@ -6355,7 +6596,14 @@ var ObjectFetcher = class {
|
|
|
6355
6596
|
async *fetchRecordsFromApi(batchSize) {
|
|
6356
6597
|
const state = await this.getState();
|
|
6357
6598
|
const objectId = await this.id;
|
|
6358
|
-
const
|
|
6599
|
+
const batchLimit = batchSize ?? DEFAULT_FETCH_BATCH_SIZE;
|
|
6600
|
+
const internalLimit = this._internal_btql?.limit;
|
|
6601
|
+
const limit = batchSize !== void 0 ? batchSize : internalLimit ?? batchLimit;
|
|
6602
|
+
const internalBtqlWithoutReservedQueryKeys = Object.fromEntries(
|
|
6603
|
+
Object.entries(this._internal_btql ?? {}).filter(
|
|
6604
|
+
([key]) => key !== "cursor" && key !== "limit" && key !== "select" && key !== "from"
|
|
6605
|
+
)
|
|
6606
|
+
);
|
|
6359
6607
|
let cursor = void 0;
|
|
6360
6608
|
let iterations = 0;
|
|
6361
6609
|
while (true) {
|
|
@@ -6363,7 +6611,6 @@ var ObjectFetcher = class {
|
|
|
6363
6611
|
`btql`,
|
|
6364
6612
|
{
|
|
6365
6613
|
query: {
|
|
6366
|
-
...this._internal_btql,
|
|
6367
6614
|
select: [
|
|
6368
6615
|
{
|
|
6369
6616
|
op: "star"
|
|
@@ -6383,7 +6630,8 @@ var ObjectFetcher = class {
|
|
|
6383
6630
|
]
|
|
6384
6631
|
},
|
|
6385
6632
|
cursor,
|
|
6386
|
-
limit
|
|
6633
|
+
limit,
|
|
6634
|
+
...internalBtqlWithoutReservedQueryKeys
|
|
6387
6635
|
},
|
|
6388
6636
|
use_columnstore: false,
|
|
6389
6637
|
brainstore_realtime: true,
|
|
@@ -6656,7 +6904,7 @@ var Experiment2 = class extends ObjectFetcher {
|
|
|
6656
6904
|
scores = results["scores"];
|
|
6657
6905
|
metrics = results["metrics"];
|
|
6658
6906
|
} catch (e) {
|
|
6659
|
-
|
|
6907
|
+
debugLogger.forState(state).warn(
|
|
6660
6908
|
`Failed to fetch experiment scores and metrics: ${e}
|
|
6661
6909
|
|
|
6662
6910
|
View complete results in Braintrust or run experiment.summarize() again.`
|
|
@@ -6733,7 +6981,7 @@ View complete results in Braintrust or run experiment.summarize() again.`
|
|
|
6733
6981
|
* @deprecated This function is deprecated. You can simply remove it from your code.
|
|
6734
6982
|
*/
|
|
6735
6983
|
async close() {
|
|
6736
|
-
|
|
6984
|
+
debugLogger.forState(this.state).warn(
|
|
6737
6985
|
"close is deprecated and will be removed in a future version of braintrust. It is now a no-op and can be removed"
|
|
6738
6986
|
);
|
|
6739
6987
|
return this.id;
|
|
@@ -6890,8 +7138,8 @@ var SpanImpl = class _SpanImpl {
|
|
|
6890
7138
|
...serializableInternalData,
|
|
6891
7139
|
[IS_MERGE_FIELD]: this.isMerge
|
|
6892
7140
|
});
|
|
6893
|
-
if (partialRecord.metrics?.end) {
|
|
6894
|
-
this.loggedEndTime = partialRecord.metrics
|
|
7141
|
+
if (typeof partialRecord.metrics?.end === "number") {
|
|
7142
|
+
this.loggedEndTime = partialRecord.metrics.end;
|
|
6895
7143
|
}
|
|
6896
7144
|
if (this.parentObjectType === 1 /* EXPERIMENT */) {
|
|
6897
7145
|
const cachedSpan = {
|
|
@@ -7126,7 +7374,7 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
7126
7374
|
constructor(state, lazyMetadata, pinnedVersion, legacy, _internal_btql) {
|
|
7127
7375
|
const isLegacyDataset = legacy ?? DEFAULT_IS_LEGACY_DATASET;
|
|
7128
7376
|
if (isLegacyDataset) {
|
|
7129
|
-
|
|
7377
|
+
debugLogger.forState(state).warn(
|
|
7130
7378
|
`Records will be fetched from this dataset in the legacy format, with the "expected" field renamed to "output". Please update your code to use "expected", and use \`braintrust.initDataset()\` with \`{ useOutput: false }\`, which will become the default in a future version of Braintrust.`
|
|
7131
7379
|
);
|
|
7132
7380
|
}
|
|
@@ -7357,7 +7605,7 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
7357
7605
|
* @deprecated This function is deprecated. You can simply remove it from your code.
|
|
7358
7606
|
*/
|
|
7359
7607
|
async close() {
|
|
7360
|
-
|
|
7608
|
+
debugLogger.forState(this.state).warn(
|
|
7361
7609
|
"close is deprecated and will be removed in a future version of braintrust. It is now a no-op and can be removed"
|
|
7362
7610
|
);
|
|
7363
7611
|
return this.id;
|
|
@@ -7368,6 +7616,49 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
7368
7616
|
};
|
|
7369
7617
|
var TEST_API_KEY = "___TEST_API_KEY__THIS_IS_NOT_REAL___";
|
|
7370
7618
|
|
|
7619
|
+
// src/instrumentation/core/channel-tracing-utils.ts
|
|
7620
|
+
function hasChannelSpanInfo(value) {
|
|
7621
|
+
return isObject(value) && isObject(value.span_info);
|
|
7622
|
+
}
|
|
7623
|
+
function getChannelSpanInfo(event) {
|
|
7624
|
+
if (isObject(event.span_info)) {
|
|
7625
|
+
return event.span_info;
|
|
7626
|
+
}
|
|
7627
|
+
const firstArg = event.arguments?.[0];
|
|
7628
|
+
if (hasChannelSpanInfo(firstArg)) {
|
|
7629
|
+
return firstArg.span_info;
|
|
7630
|
+
}
|
|
7631
|
+
return void 0;
|
|
7632
|
+
}
|
|
7633
|
+
function buildStartSpanArgs(config, event) {
|
|
7634
|
+
const spanInfo = getChannelSpanInfo(event);
|
|
7635
|
+
const spanAttributes = {
|
|
7636
|
+
type: config.type
|
|
7637
|
+
};
|
|
7638
|
+
if (isObject(spanInfo?.spanAttributes)) {
|
|
7639
|
+
mergeDicts(spanAttributes, spanInfo.spanAttributes);
|
|
7640
|
+
}
|
|
7641
|
+
return {
|
|
7642
|
+
name: typeof spanInfo?.name === "string" && spanInfo.name ? spanInfo.name : config.name,
|
|
7643
|
+
spanAttributes,
|
|
7644
|
+
spanInfoMetadata: isObject(spanInfo?.metadata) ? spanInfo.metadata : void 0
|
|
7645
|
+
};
|
|
7646
|
+
}
|
|
7647
|
+
function mergeInputMetadata(metadata, spanInfoMetadata) {
|
|
7648
|
+
if (!spanInfoMetadata) {
|
|
7649
|
+
return isObject(metadata) ? (
|
|
7650
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
7651
|
+
metadata
|
|
7652
|
+
) : void 0;
|
|
7653
|
+
}
|
|
7654
|
+
const mergedMetadata = {};
|
|
7655
|
+
mergeDicts(mergedMetadata, spanInfoMetadata);
|
|
7656
|
+
if (isObject(metadata)) {
|
|
7657
|
+
mergeDicts(mergedMetadata, metadata);
|
|
7658
|
+
}
|
|
7659
|
+
return mergedMetadata;
|
|
7660
|
+
}
|
|
7661
|
+
|
|
7371
7662
|
// src/instrumentation/core/plugin.ts
|
|
7372
7663
|
var BasePlugin = class {
|
|
7373
7664
|
enabled = false;
|
|
@@ -7399,23 +7690,25 @@ var BasePlugin = class {
|
|
|
7399
7690
|
* @param handlers - Event handlers
|
|
7400
7691
|
*/
|
|
7401
7692
|
subscribe(channelName, handlers) {
|
|
7402
|
-
const
|
|
7403
|
-
|
|
7693
|
+
const channel2 = isomorph_default.newTracingChannel(channelName);
|
|
7694
|
+
channel2.subscribe(handlers);
|
|
7404
7695
|
}
|
|
7405
7696
|
/**
|
|
7406
7697
|
* Subscribe to a channel for async methods (non-streaming).
|
|
7407
7698
|
* Creates a span and logs input/output/metrics.
|
|
7408
7699
|
*/
|
|
7409
7700
|
subscribeToChannel(channelName, config) {
|
|
7410
|
-
const
|
|
7701
|
+
const channel2 = isomorph_default.newTracingChannel(channelName);
|
|
7411
7702
|
const spans = /* @__PURE__ */ new WeakMap();
|
|
7412
7703
|
const handlers = {
|
|
7413
7704
|
start: (event) => {
|
|
7705
|
+
const { name, spanAttributes, spanInfoMetadata } = buildStartSpanArgs(
|
|
7706
|
+
config,
|
|
7707
|
+
event
|
|
7708
|
+
);
|
|
7414
7709
|
const span = startSpan({
|
|
7415
|
-
name
|
|
7416
|
-
spanAttributes
|
|
7417
|
-
type: config.type
|
|
7418
|
-
}
|
|
7710
|
+
name,
|
|
7711
|
+
spanAttributes
|
|
7419
7712
|
});
|
|
7420
7713
|
const startTime = getCurrentUnixTimestamp();
|
|
7421
7714
|
spans.set(event, { span, startTime });
|
|
@@ -7423,7 +7716,7 @@ var BasePlugin = class {
|
|
|
7423
7716
|
const { input, metadata } = config.extractInput(event.arguments);
|
|
7424
7717
|
span.log({
|
|
7425
7718
|
input,
|
|
7426
|
-
metadata
|
|
7719
|
+
metadata: mergeInputMetadata(metadata, spanInfoMetadata)
|
|
7427
7720
|
});
|
|
7428
7721
|
} catch (error) {
|
|
7429
7722
|
console.error(`Error extracting input for ${channelName}:`, error);
|
|
@@ -7436,10 +7729,12 @@ var BasePlugin = class {
|
|
|
7436
7729
|
}
|
|
7437
7730
|
const { span, startTime } = spanData;
|
|
7438
7731
|
try {
|
|
7439
|
-
const output = config.extractOutput(event.result);
|
|
7440
|
-
const metrics = config.extractMetrics(event.result, startTime);
|
|
7732
|
+
const output = config.extractOutput(event.result, event);
|
|
7733
|
+
const metrics = config.extractMetrics(event.result, startTime, event);
|
|
7734
|
+
const metadata = config.extractMetadata?.(event.result, event);
|
|
7441
7735
|
span.log({
|
|
7442
7736
|
output,
|
|
7737
|
+
...metadata !== void 0 ? { metadata } : {},
|
|
7443
7738
|
metrics
|
|
7444
7739
|
});
|
|
7445
7740
|
} catch (error) {
|
|
@@ -7462,9 +7757,9 @@ var BasePlugin = class {
|
|
|
7462
7757
|
spans.delete(event);
|
|
7463
7758
|
}
|
|
7464
7759
|
};
|
|
7465
|
-
|
|
7760
|
+
channel2.subscribe(handlers);
|
|
7466
7761
|
this.unsubscribers.push(() => {
|
|
7467
|
-
|
|
7762
|
+
channel2.unsubscribe(handlers);
|
|
7468
7763
|
});
|
|
7469
7764
|
}
|
|
7470
7765
|
/**
|
|
@@ -7472,15 +7767,17 @@ var BasePlugin = class {
|
|
|
7472
7767
|
* Handles both streaming and non-streaming responses.
|
|
7473
7768
|
*/
|
|
7474
7769
|
subscribeToStreamingChannel(channelName, config) {
|
|
7475
|
-
const
|
|
7770
|
+
const channel2 = isomorph_default.newTracingChannel(channelName);
|
|
7476
7771
|
const spans = /* @__PURE__ */ new WeakMap();
|
|
7477
7772
|
const handlers = {
|
|
7478
7773
|
start: (event) => {
|
|
7774
|
+
const { name, spanAttributes, spanInfoMetadata } = buildStartSpanArgs(
|
|
7775
|
+
config,
|
|
7776
|
+
event
|
|
7777
|
+
);
|
|
7479
7778
|
const span = startSpan({
|
|
7480
|
-
name
|
|
7481
|
-
spanAttributes
|
|
7482
|
-
type: config.type
|
|
7483
|
-
}
|
|
7779
|
+
name,
|
|
7780
|
+
spanAttributes
|
|
7484
7781
|
});
|
|
7485
7782
|
const startTime = getCurrentUnixTimestamp();
|
|
7486
7783
|
spans.set(event, { span, startTime });
|
|
@@ -7488,7 +7785,7 @@ var BasePlugin = class {
|
|
|
7488
7785
|
const { input, metadata } = config.extractInput(event.arguments);
|
|
7489
7786
|
span.log({
|
|
7490
7787
|
input,
|
|
7491
|
-
metadata
|
|
7788
|
+
metadata: mergeInputMetadata(metadata, spanInfoMetadata)
|
|
7492
7789
|
});
|
|
7493
7790
|
} catch (error) {
|
|
7494
7791
|
console.error(`Error extracting input for ${channelName}:`, error);
|
|
@@ -7501,24 +7798,39 @@ var BasePlugin = class {
|
|
|
7501
7798
|
}
|
|
7502
7799
|
const { span, startTime } = spanData;
|
|
7503
7800
|
if (isAsyncIterable(event.result)) {
|
|
7801
|
+
let firstChunkTime;
|
|
7504
7802
|
patchStreamIfNeeded(event.result, {
|
|
7803
|
+
onChunk: () => {
|
|
7804
|
+
if (firstChunkTime === void 0) {
|
|
7805
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
7806
|
+
}
|
|
7807
|
+
},
|
|
7505
7808
|
onComplete: (chunks) => {
|
|
7506
7809
|
try {
|
|
7507
7810
|
let output;
|
|
7508
7811
|
let metrics;
|
|
7812
|
+
let metadata;
|
|
7509
7813
|
if (config.aggregateChunks) {
|
|
7510
|
-
const aggregated = config.aggregateChunks(
|
|
7814
|
+
const aggregated = config.aggregateChunks(
|
|
7815
|
+
chunks,
|
|
7816
|
+
event.result,
|
|
7817
|
+
event
|
|
7818
|
+
);
|
|
7511
7819
|
output = aggregated.output;
|
|
7512
7820
|
metrics = aggregated.metrics;
|
|
7821
|
+
metadata = aggregated.metadata;
|
|
7513
7822
|
} else {
|
|
7514
|
-
output = config.extractOutput(chunks);
|
|
7515
|
-
metrics = config.extractMetrics(chunks, startTime);
|
|
7823
|
+
output = config.extractOutput(chunks, event);
|
|
7824
|
+
metrics = config.extractMetrics(chunks, startTime, event);
|
|
7516
7825
|
}
|
|
7517
|
-
if (
|
|
7826
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
7827
|
+
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
7828
|
+
} else if (metrics.time_to_first_token === void 0 && chunks.length > 0) {
|
|
7518
7829
|
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
7519
7830
|
}
|
|
7520
7831
|
span.log({
|
|
7521
7832
|
output,
|
|
7833
|
+
...metadata !== void 0 ? { metadata } : {},
|
|
7522
7834
|
metrics
|
|
7523
7835
|
});
|
|
7524
7836
|
} catch (error) {
|
|
@@ -7539,10 +7851,16 @@ var BasePlugin = class {
|
|
|
7539
7851
|
});
|
|
7540
7852
|
} else {
|
|
7541
7853
|
try {
|
|
7542
|
-
const output = config.extractOutput(event.result);
|
|
7543
|
-
const
|
|
7854
|
+
const output = config.extractOutput(event.result, event);
|
|
7855
|
+
const metadata = config.extractMetadata ? config.extractMetadata(event.result, event) : void 0;
|
|
7856
|
+
const metrics = config.extractMetrics(
|
|
7857
|
+
event.result,
|
|
7858
|
+
startTime,
|
|
7859
|
+
event
|
|
7860
|
+
);
|
|
7544
7861
|
span.log({
|
|
7545
7862
|
output,
|
|
7863
|
+
...metadata !== void 0 ? { metadata } : {},
|
|
7546
7864
|
metrics
|
|
7547
7865
|
});
|
|
7548
7866
|
} catch (error) {
|
|
@@ -7566,9 +7884,9 @@ var BasePlugin = class {
|
|
|
7566
7884
|
spans.delete(event);
|
|
7567
7885
|
}
|
|
7568
7886
|
};
|
|
7569
|
-
|
|
7887
|
+
channel2.subscribe(handlers);
|
|
7570
7888
|
this.unsubscribers.push(() => {
|
|
7571
|
-
|
|
7889
|
+
channel2.unsubscribe(handlers);
|
|
7572
7890
|
});
|
|
7573
7891
|
}
|
|
7574
7892
|
/**
|
|
@@ -7576,15 +7894,17 @@ var BasePlugin = class {
|
|
|
7576
7894
|
* Used for methods like beta.chat.completions.stream() and responses.stream().
|
|
7577
7895
|
*/
|
|
7578
7896
|
subscribeToSyncStreamChannel(channelName, config) {
|
|
7579
|
-
const
|
|
7897
|
+
const channel2 = isomorph_default.newTracingChannel(channelName);
|
|
7580
7898
|
const spans = /* @__PURE__ */ new WeakMap();
|
|
7581
7899
|
const handlers = {
|
|
7582
7900
|
start: (event) => {
|
|
7901
|
+
const { name, spanAttributes, spanInfoMetadata } = buildStartSpanArgs(
|
|
7902
|
+
config,
|
|
7903
|
+
event
|
|
7904
|
+
);
|
|
7583
7905
|
const span = startSpan({
|
|
7584
|
-
name
|
|
7585
|
-
spanAttributes
|
|
7586
|
-
type: config.type
|
|
7587
|
-
}
|
|
7906
|
+
name,
|
|
7907
|
+
spanAttributes
|
|
7588
7908
|
});
|
|
7589
7909
|
const startTime = getCurrentUnixTimestamp();
|
|
7590
7910
|
spans.set(event, { span, startTime });
|
|
@@ -7592,7 +7912,7 @@ var BasePlugin = class {
|
|
|
7592
7912
|
const { input, metadata } = config.extractInput(event.arguments);
|
|
7593
7913
|
span.log({
|
|
7594
7914
|
input,
|
|
7595
|
-
metadata
|
|
7915
|
+
metadata: mergeInputMetadata(metadata, spanInfoMetadata)
|
|
7596
7916
|
});
|
|
7597
7917
|
} catch (error) {
|
|
7598
7918
|
console.error(`Error extracting input for ${channelName}:`, error);
|
|
@@ -7676,9 +7996,9 @@ var BasePlugin = class {
|
|
|
7676
7996
|
spans.delete(event);
|
|
7677
7997
|
}
|
|
7678
7998
|
};
|
|
7679
|
-
|
|
7999
|
+
channel2.subscribe(handlers);
|
|
7680
8000
|
this.unsubscribers.push(() => {
|
|
7681
|
-
|
|
8001
|
+
channel2.unsubscribe(handlers);
|
|
7682
8002
|
});
|
|
7683
8003
|
}
|
|
7684
8004
|
};
|
|
@@ -7701,134 +8021,645 @@ function isValidChannelName(channelName) {
|
|
|
7701
8021
|
return /^braintrust:[^:]+:.+$/.test(channelName);
|
|
7702
8022
|
}
|
|
7703
8023
|
|
|
7704
|
-
// src/
|
|
7705
|
-
function
|
|
7706
|
-
|
|
7707
|
-
"image/png": "png",
|
|
7708
|
-
"image/jpeg": "jpg",
|
|
7709
|
-
"image/gif": "gif",
|
|
7710
|
-
"image/webp": "webp",
|
|
7711
|
-
"image/svg+xml": "svg",
|
|
7712
|
-
"audio/mpeg": "mp3",
|
|
7713
|
-
"audio/wav": "wav",
|
|
7714
|
-
"audio/ogg": "ogg",
|
|
7715
|
-
"video/mp4": "mp4",
|
|
7716
|
-
"video/webm": "webm",
|
|
7717
|
-
"application/pdf": "pdf",
|
|
7718
|
-
"application/json": "json",
|
|
7719
|
-
"text/plain": "txt",
|
|
7720
|
-
"text/html": "html",
|
|
7721
|
-
"text/csv": "csv"
|
|
7722
|
-
};
|
|
7723
|
-
return extensionMap[mediaType] || "bin";
|
|
8024
|
+
// src/instrumentation/core/channel-tracing.ts
|
|
8025
|
+
function isSyncStreamLike(value) {
|
|
8026
|
+
return !!value && typeof value === "object" && typeof value.on === "function";
|
|
7724
8027
|
}
|
|
7725
|
-
function
|
|
8028
|
+
function hasChoices(value) {
|
|
8029
|
+
return !!value && typeof value === "object" && "choices" in value;
|
|
8030
|
+
}
|
|
8031
|
+
function normalizeMetadata(metadata) {
|
|
8032
|
+
return isObject(metadata) ? metadata : void 0;
|
|
8033
|
+
}
|
|
8034
|
+
function startSpanForEvent(config, event, channelName) {
|
|
8035
|
+
const { name, spanAttributes, spanInfoMetadata } = buildStartSpanArgs(
|
|
8036
|
+
config,
|
|
8037
|
+
event
|
|
8038
|
+
);
|
|
8039
|
+
const span = startSpan({
|
|
8040
|
+
name,
|
|
8041
|
+
spanAttributes
|
|
8042
|
+
});
|
|
8043
|
+
const startTime = getCurrentUnixTimestamp();
|
|
7726
8044
|
try {
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
}
|
|
7739
|
-
} else if (data.startsWith("http://") || data.startsWith("https://")) {
|
|
7740
|
-
return null;
|
|
7741
|
-
} else {
|
|
7742
|
-
const binaryString = atob(data);
|
|
7743
|
-
const bytes = new Uint8Array(binaryString.length);
|
|
7744
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
7745
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
7746
|
-
}
|
|
7747
|
-
return new Blob([bytes], { type: mediaType });
|
|
7748
|
-
}
|
|
7749
|
-
} else if (data instanceof Uint8Array) {
|
|
7750
|
-
return new Blob([data], { type: mediaType });
|
|
7751
|
-
} else if (data instanceof ArrayBuffer) {
|
|
7752
|
-
return new Blob([data], { type: mediaType });
|
|
7753
|
-
} else if (typeof Buffer !== "undefined" && data instanceof Buffer) {
|
|
7754
|
-
return new Blob([data], { type: mediaType });
|
|
7755
|
-
}
|
|
7756
|
-
} catch {
|
|
7757
|
-
return null;
|
|
8045
|
+
const { input, metadata } = config.extractInput(
|
|
8046
|
+
event.arguments,
|
|
8047
|
+
event,
|
|
8048
|
+
span
|
|
8049
|
+
);
|
|
8050
|
+
span.log({
|
|
8051
|
+
input,
|
|
8052
|
+
metadata: mergeInputMetadata(metadata, spanInfoMetadata)
|
|
8053
|
+
});
|
|
8054
|
+
} catch (error) {
|
|
8055
|
+
console.error(`Error extracting input for ${channelName}:`, error);
|
|
7758
8056
|
}
|
|
7759
|
-
return
|
|
8057
|
+
return { span, startTime };
|
|
7760
8058
|
}
|
|
7761
|
-
function
|
|
7762
|
-
|
|
7763
|
-
|
|
8059
|
+
function logErrorAndEnd(states, event) {
|
|
8060
|
+
const spanData = states.get(event);
|
|
8061
|
+
if (!spanData) {
|
|
8062
|
+
return;
|
|
7764
8063
|
}
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
8064
|
+
spanData.span.log({
|
|
8065
|
+
error: event.error.message
|
|
8066
|
+
});
|
|
8067
|
+
spanData.span.end();
|
|
8068
|
+
states.delete(event);
|
|
8069
|
+
}
|
|
8070
|
+
function traceAsyncChannel(channel2, config) {
|
|
8071
|
+
const tracingChannel = channel2.tracingChannel();
|
|
8072
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
8073
|
+
const channelName = channel2.channelName;
|
|
8074
|
+
const handlers = {
|
|
8075
|
+
start: (event) => {
|
|
8076
|
+
states.set(
|
|
8077
|
+
event,
|
|
8078
|
+
startSpanForEvent(
|
|
8079
|
+
config,
|
|
8080
|
+
event,
|
|
8081
|
+
channelName
|
|
8082
|
+
)
|
|
8083
|
+
);
|
|
8084
|
+
},
|
|
8085
|
+
asyncEnd: (event) => {
|
|
8086
|
+
const spanData = states.get(event);
|
|
8087
|
+
if (!spanData) {
|
|
8088
|
+
return;
|
|
7779
8089
|
}
|
|
7780
|
-
const
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
8090
|
+
const asyncEndEvent = event;
|
|
8091
|
+
const { span, startTime } = spanData;
|
|
8092
|
+
try {
|
|
8093
|
+
const output = config.extractOutput(
|
|
8094
|
+
asyncEndEvent.result,
|
|
8095
|
+
asyncEndEvent
|
|
8096
|
+
);
|
|
8097
|
+
const metrics = config.extractMetrics(
|
|
8098
|
+
asyncEndEvent.result,
|
|
8099
|
+
startTime,
|
|
8100
|
+
asyncEndEvent
|
|
8101
|
+
);
|
|
8102
|
+
const metadata = config.extractMetadata?.(
|
|
8103
|
+
asyncEndEvent.result,
|
|
8104
|
+
asyncEndEvent
|
|
8105
|
+
);
|
|
8106
|
+
span.log({
|
|
8107
|
+
output,
|
|
8108
|
+
...normalizeMetadata(metadata) !== void 0 ? { metadata: normalizeMetadata(metadata) } : {},
|
|
8109
|
+
metrics
|
|
7788
8110
|
});
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
8111
|
+
} catch (error) {
|
|
8112
|
+
console.error(`Error extracting output for ${channelName}:`, error);
|
|
8113
|
+
} finally {
|
|
8114
|
+
span.end();
|
|
8115
|
+
states.delete(event);
|
|
8116
|
+
}
|
|
8117
|
+
},
|
|
8118
|
+
error: (event) => {
|
|
8119
|
+
logErrorAndEnd(states, event);
|
|
7794
8120
|
}
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
8121
|
+
};
|
|
8122
|
+
tracingChannel.subscribe(handlers);
|
|
8123
|
+
return () => {
|
|
8124
|
+
tracingChannel.unsubscribe(handlers);
|
|
8125
|
+
};
|
|
8126
|
+
}
|
|
8127
|
+
function traceStreamingChannel(channel2, config) {
|
|
8128
|
+
const tracingChannel = channel2.tracingChannel();
|
|
8129
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
8130
|
+
const channelName = channel2.channelName;
|
|
8131
|
+
const handlers = {
|
|
8132
|
+
start: (event) => {
|
|
8133
|
+
states.set(
|
|
8134
|
+
event,
|
|
8135
|
+
startSpanForEvent(
|
|
8136
|
+
config,
|
|
8137
|
+
event,
|
|
8138
|
+
channelName
|
|
8139
|
+
)
|
|
8140
|
+
);
|
|
8141
|
+
},
|
|
8142
|
+
asyncEnd: (event) => {
|
|
8143
|
+
const spanData = states.get(event);
|
|
8144
|
+
if (!spanData) {
|
|
8145
|
+
return;
|
|
8146
|
+
}
|
|
8147
|
+
const asyncEndEvent = event;
|
|
8148
|
+
const { span, startTime } = spanData;
|
|
8149
|
+
if (isAsyncIterable(asyncEndEvent.result)) {
|
|
8150
|
+
let firstChunkTime;
|
|
8151
|
+
patchStreamIfNeeded(asyncEndEvent.result, {
|
|
8152
|
+
onChunk: () => {
|
|
8153
|
+
if (firstChunkTime === void 0) {
|
|
8154
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
8155
|
+
}
|
|
8156
|
+
},
|
|
8157
|
+
onComplete: (chunks) => {
|
|
8158
|
+
try {
|
|
8159
|
+
let output;
|
|
8160
|
+
let metrics;
|
|
8161
|
+
let metadata;
|
|
8162
|
+
if (config.aggregateChunks) {
|
|
8163
|
+
const aggregated = config.aggregateChunks(
|
|
8164
|
+
chunks,
|
|
8165
|
+
asyncEndEvent.result,
|
|
8166
|
+
asyncEndEvent,
|
|
8167
|
+
startTime
|
|
8168
|
+
);
|
|
8169
|
+
output = aggregated.output;
|
|
8170
|
+
metrics = aggregated.metrics;
|
|
8171
|
+
metadata = aggregated.metadata;
|
|
8172
|
+
} else {
|
|
8173
|
+
output = config.extractOutput(
|
|
8174
|
+
chunks,
|
|
8175
|
+
asyncEndEvent
|
|
8176
|
+
);
|
|
8177
|
+
metrics = config.extractMetrics(
|
|
8178
|
+
chunks,
|
|
8179
|
+
startTime,
|
|
8180
|
+
asyncEndEvent
|
|
8181
|
+
);
|
|
8182
|
+
}
|
|
8183
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
8184
|
+
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
8185
|
+
} else if (metrics.time_to_first_token === void 0 && chunks.length > 0) {
|
|
8186
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8187
|
+
}
|
|
8188
|
+
span.log({
|
|
8189
|
+
output,
|
|
8190
|
+
...metadata !== void 0 ? { metadata } : {},
|
|
8191
|
+
metrics
|
|
8192
|
+
});
|
|
8193
|
+
} catch (error) {
|
|
8194
|
+
console.error(
|
|
8195
|
+
`Error extracting output for ${channelName}:`,
|
|
8196
|
+
error
|
|
8197
|
+
);
|
|
8198
|
+
} finally {
|
|
8199
|
+
span.end();
|
|
8200
|
+
states.delete(event);
|
|
8201
|
+
}
|
|
8202
|
+
},
|
|
8203
|
+
onError: (error) => {
|
|
8204
|
+
span.log({
|
|
8205
|
+
error: error.message
|
|
8206
|
+
});
|
|
8207
|
+
span.end();
|
|
8208
|
+
states.delete(event);
|
|
8209
|
+
}
|
|
8210
|
+
});
|
|
8211
|
+
return;
|
|
8212
|
+
}
|
|
8213
|
+
if (config.patchResult?.({
|
|
8214
|
+
channelName,
|
|
8215
|
+
endEvent: asyncEndEvent,
|
|
8216
|
+
result: asyncEndEvent.result,
|
|
8217
|
+
span,
|
|
8218
|
+
startTime
|
|
8219
|
+
})) {
|
|
8220
|
+
states.delete(event);
|
|
8221
|
+
return;
|
|
8222
|
+
}
|
|
8223
|
+
try {
|
|
8224
|
+
const output = config.extractOutput(
|
|
8225
|
+
asyncEndEvent.result,
|
|
8226
|
+
asyncEndEvent
|
|
8227
|
+
);
|
|
8228
|
+
const metrics = config.extractMetrics(
|
|
8229
|
+
asyncEndEvent.result,
|
|
8230
|
+
startTime,
|
|
8231
|
+
asyncEndEvent
|
|
8232
|
+
);
|
|
8233
|
+
const metadata = config.extractMetadata?.(
|
|
8234
|
+
asyncEndEvent.result,
|
|
8235
|
+
asyncEndEvent
|
|
8236
|
+
);
|
|
8237
|
+
span.log({
|
|
8238
|
+
output,
|
|
8239
|
+
...normalizeMetadata(metadata) !== void 0 ? { metadata: normalizeMetadata(metadata) } : {},
|
|
8240
|
+
metrics
|
|
8241
|
+
});
|
|
8242
|
+
} catch (error) {
|
|
8243
|
+
console.error(`Error extracting output for ${channelName}:`, error);
|
|
8244
|
+
} finally {
|
|
8245
|
+
span.end();
|
|
8246
|
+
states.delete(event);
|
|
8247
|
+
}
|
|
8248
|
+
},
|
|
8249
|
+
error: (event) => {
|
|
8250
|
+
logErrorAndEnd(states, event);
|
|
8251
|
+
}
|
|
8252
|
+
};
|
|
8253
|
+
tracingChannel.subscribe(handlers);
|
|
8254
|
+
return () => {
|
|
8255
|
+
tracingChannel.unsubscribe(handlers);
|
|
8256
|
+
};
|
|
8257
|
+
}
|
|
8258
|
+
function traceSyncStreamChannel(channel2, config) {
|
|
8259
|
+
const tracingChannel = channel2.tracingChannel();
|
|
8260
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
8261
|
+
const channelName = channel2.channelName;
|
|
8262
|
+
const handlers = {
|
|
8263
|
+
start: (event) => {
|
|
8264
|
+
states.set(
|
|
8265
|
+
event,
|
|
8266
|
+
startSpanForEvent(
|
|
8267
|
+
config,
|
|
8268
|
+
event,
|
|
8269
|
+
channelName
|
|
8270
|
+
)
|
|
8271
|
+
);
|
|
8272
|
+
},
|
|
8273
|
+
end: (event) => {
|
|
8274
|
+
const spanData = states.get(event);
|
|
8275
|
+
if (!spanData) {
|
|
8276
|
+
return;
|
|
8277
|
+
}
|
|
8278
|
+
const { span, startTime } = spanData;
|
|
8279
|
+
const endEvent = event;
|
|
8280
|
+
if (config.patchResult?.({
|
|
8281
|
+
channelName,
|
|
8282
|
+
endEvent,
|
|
8283
|
+
result: endEvent.result,
|
|
8284
|
+
span,
|
|
8285
|
+
startTime
|
|
8286
|
+
})) {
|
|
8287
|
+
return;
|
|
8288
|
+
}
|
|
8289
|
+
const stream = endEvent.result;
|
|
8290
|
+
if (!isSyncStreamLike(stream)) {
|
|
8291
|
+
span.end();
|
|
8292
|
+
states.delete(event);
|
|
8293
|
+
return;
|
|
8294
|
+
}
|
|
8295
|
+
let first = true;
|
|
8296
|
+
stream.on("chunk", () => {
|
|
8297
|
+
if (first) {
|
|
8298
|
+
span.log({
|
|
8299
|
+
metrics: {
|
|
8300
|
+
time_to_first_token: getCurrentUnixTimestamp() - startTime
|
|
8301
|
+
}
|
|
8302
|
+
});
|
|
8303
|
+
first = false;
|
|
8304
|
+
}
|
|
8305
|
+
});
|
|
8306
|
+
stream.on("chatCompletion", (completion) => {
|
|
8307
|
+
try {
|
|
8308
|
+
if (hasChoices(completion)) {
|
|
8309
|
+
span.log({
|
|
8310
|
+
output: completion.choices
|
|
8311
|
+
});
|
|
8312
|
+
}
|
|
8313
|
+
} catch (error) {
|
|
8314
|
+
console.error(
|
|
8315
|
+
`Error extracting chatCompletion for ${channelName}:`,
|
|
8316
|
+
error
|
|
8317
|
+
);
|
|
8318
|
+
}
|
|
8319
|
+
});
|
|
8320
|
+
stream.on("event", (streamEvent) => {
|
|
8321
|
+
if (!config.extractFromEvent) {
|
|
8322
|
+
return;
|
|
8323
|
+
}
|
|
8324
|
+
try {
|
|
8325
|
+
if (first) {
|
|
8326
|
+
span.log({
|
|
8327
|
+
metrics: {
|
|
8328
|
+
time_to_first_token: getCurrentUnixTimestamp() - startTime
|
|
8329
|
+
}
|
|
8330
|
+
});
|
|
8331
|
+
first = false;
|
|
8332
|
+
}
|
|
8333
|
+
const extracted = config.extractFromEvent(streamEvent);
|
|
8334
|
+
if (extracted && Object.keys(extracted).length > 0) {
|
|
8335
|
+
span.log(extracted);
|
|
8336
|
+
}
|
|
8337
|
+
} catch (error) {
|
|
8338
|
+
console.error(`Error extracting event for ${channelName}:`, error);
|
|
8339
|
+
}
|
|
8340
|
+
});
|
|
8341
|
+
stream.on("end", () => {
|
|
8342
|
+
span.end();
|
|
8343
|
+
states.delete(event);
|
|
8344
|
+
});
|
|
8345
|
+
stream.on("error", (error) => {
|
|
8346
|
+
span.log({
|
|
8347
|
+
error: error.message
|
|
7805
8348
|
});
|
|
8349
|
+
span.end();
|
|
8350
|
+
states.delete(event);
|
|
8351
|
+
});
|
|
8352
|
+
},
|
|
8353
|
+
error: (event) => {
|
|
8354
|
+
logErrorAndEnd(states, event);
|
|
8355
|
+
}
|
|
8356
|
+
};
|
|
8357
|
+
tracingChannel.subscribe(handlers);
|
|
8358
|
+
return () => {
|
|
8359
|
+
tracingChannel.unsubscribe(handlers);
|
|
8360
|
+
};
|
|
8361
|
+
}
|
|
8362
|
+
function unsubscribeAll(unsubscribers) {
|
|
8363
|
+
for (const unsubscribe of unsubscribers) {
|
|
8364
|
+
unsubscribe();
|
|
8365
|
+
}
|
|
8366
|
+
return [];
|
|
8367
|
+
}
|
|
8368
|
+
|
|
8369
|
+
// src/wrappers/attachment-utils.ts
|
|
8370
|
+
function getExtensionFromMediaType(mediaType) {
|
|
8371
|
+
const extensionMap = {
|
|
8372
|
+
"image/png": "png",
|
|
8373
|
+
"image/jpeg": "jpg",
|
|
8374
|
+
"image/gif": "gif",
|
|
8375
|
+
"image/webp": "webp",
|
|
8376
|
+
"image/svg+xml": "svg",
|
|
8377
|
+
"audio/mpeg": "mp3",
|
|
8378
|
+
"audio/wav": "wav",
|
|
8379
|
+
"audio/ogg": "ogg",
|
|
8380
|
+
"video/mp4": "mp4",
|
|
8381
|
+
"video/webm": "webm",
|
|
8382
|
+
"application/pdf": "pdf",
|
|
8383
|
+
"application/json": "json",
|
|
8384
|
+
"text/plain": "txt",
|
|
8385
|
+
"text/html": "html",
|
|
8386
|
+
"text/csv": "csv"
|
|
8387
|
+
};
|
|
8388
|
+
return extensionMap[mediaType] || "bin";
|
|
8389
|
+
}
|
|
8390
|
+
function convertDataToBlob(data, mediaType) {
|
|
8391
|
+
try {
|
|
8392
|
+
if (typeof data === "string") {
|
|
8393
|
+
if (data.startsWith("data:")) {
|
|
8394
|
+
const base64Match = data.match(/^data:[^;]+;base64,(.+)$/);
|
|
8395
|
+
if (base64Match) {
|
|
8396
|
+
const base64 = base64Match[1];
|
|
8397
|
+
const binaryString = atob(base64);
|
|
8398
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
8399
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
8400
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
8401
|
+
}
|
|
8402
|
+
return new Blob([bytes], { type: mediaType });
|
|
8403
|
+
}
|
|
8404
|
+
} else if (data.startsWith("http://") || data.startsWith("https://")) {
|
|
8405
|
+
return null;
|
|
8406
|
+
} else {
|
|
8407
|
+
const binaryString = atob(data);
|
|
8408
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
8409
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
8410
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
8411
|
+
}
|
|
8412
|
+
return new Blob([bytes], { type: mediaType });
|
|
8413
|
+
}
|
|
8414
|
+
} else if (data instanceof Uint8Array) {
|
|
8415
|
+
return new Blob([data], { type: mediaType });
|
|
8416
|
+
} else if (data instanceof ArrayBuffer) {
|
|
8417
|
+
return new Blob([data], { type: mediaType });
|
|
8418
|
+
} else if (typeof Buffer !== "undefined" && data instanceof Buffer) {
|
|
8419
|
+
return new Blob([data], { type: mediaType });
|
|
8420
|
+
}
|
|
8421
|
+
} catch {
|
|
8422
|
+
return null;
|
|
8423
|
+
}
|
|
8424
|
+
return null;
|
|
8425
|
+
}
|
|
8426
|
+
function processInputAttachments(input) {
|
|
8427
|
+
if (!input) {
|
|
8428
|
+
return input;
|
|
8429
|
+
}
|
|
8430
|
+
let attachmentIndex = 0;
|
|
8431
|
+
const inferMediaTypeFromDataUrl = (value, fallback) => {
|
|
8432
|
+
const mediaTypeMatch = value.match(/^data:([^;]+);/);
|
|
8433
|
+
return mediaTypeMatch?.[1] || fallback;
|
|
8434
|
+
};
|
|
8435
|
+
const toAttachment = (value, mediaType, filename) => {
|
|
8436
|
+
const blob = convertDataToBlob(value, mediaType);
|
|
8437
|
+
if (!blob) {
|
|
8438
|
+
return null;
|
|
8439
|
+
}
|
|
8440
|
+
return new Attachment({
|
|
8441
|
+
data: blob,
|
|
8442
|
+
filename,
|
|
8443
|
+
contentType: mediaType
|
|
8444
|
+
});
|
|
8445
|
+
};
|
|
8446
|
+
const processNode = (node) => {
|
|
8447
|
+
if (Array.isArray(node)) {
|
|
8448
|
+
return node.map(processNode);
|
|
8449
|
+
}
|
|
8450
|
+
if (!node || typeof node !== "object") {
|
|
8451
|
+
return node;
|
|
8452
|
+
}
|
|
8453
|
+
if (node.type === "image_url" && node.image_url && typeof node.image_url === "object" && typeof node.image_url.url === "string" && node.image_url.url.startsWith("data:")) {
|
|
8454
|
+
const mediaType = inferMediaTypeFromDataUrl(
|
|
8455
|
+
node.image_url.url,
|
|
8456
|
+
"image/png"
|
|
8457
|
+
);
|
|
8458
|
+
const filename = `image.${getExtensionFromMediaType(mediaType)}`;
|
|
8459
|
+
const attachment = toAttachment(node.image_url.url, mediaType, filename);
|
|
8460
|
+
if (attachment) {
|
|
7806
8461
|
return {
|
|
7807
|
-
...
|
|
7808
|
-
|
|
8462
|
+
...node,
|
|
8463
|
+
image_url: {
|
|
8464
|
+
...node.image_url,
|
|
8465
|
+
url: attachment
|
|
8466
|
+
}
|
|
7809
8467
|
};
|
|
7810
8468
|
}
|
|
7811
8469
|
}
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
8470
|
+
if (node.type === "file" && node.file && typeof node.file === "object" && typeof node.file.file_data === "string" && node.file.file_data.startsWith("data:")) {
|
|
8471
|
+
const mediaType = inferMediaTypeFromDataUrl(
|
|
8472
|
+
node.file.file_data,
|
|
8473
|
+
"application/octet-stream"
|
|
8474
|
+
);
|
|
8475
|
+
const filename = typeof node.file.filename === "string" && node.file.filename ? node.file.filename : `document.${getExtensionFromMediaType(mediaType)}`;
|
|
8476
|
+
const attachment = toAttachment(node.file.file_data, mediaType, filename);
|
|
8477
|
+
if (attachment) {
|
|
8478
|
+
return {
|
|
8479
|
+
...node,
|
|
8480
|
+
file: {
|
|
8481
|
+
...node.file,
|
|
8482
|
+
file_data: attachment
|
|
8483
|
+
}
|
|
8484
|
+
};
|
|
8485
|
+
}
|
|
7817
8486
|
}
|
|
7818
|
-
if (
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
}
|
|
8487
|
+
if (node.type === "image" && node.image) {
|
|
8488
|
+
let mediaType = "image/png";
|
|
8489
|
+
if (typeof node.image === "string" && node.image.startsWith("data:")) {
|
|
8490
|
+
mediaType = inferMediaTypeFromDataUrl(node.image, mediaType);
|
|
8491
|
+
} else if (node.mediaType) {
|
|
8492
|
+
mediaType = node.mediaType;
|
|
8493
|
+
}
|
|
8494
|
+
const filename = `input_image_${attachmentIndex}.${getExtensionFromMediaType(mediaType)}`;
|
|
8495
|
+
const attachment = toAttachment(node.image, mediaType, filename);
|
|
8496
|
+
if (attachment) {
|
|
8497
|
+
attachmentIndex++;
|
|
8498
|
+
return {
|
|
8499
|
+
...node,
|
|
8500
|
+
image: attachment
|
|
8501
|
+
};
|
|
8502
|
+
}
|
|
8503
|
+
}
|
|
8504
|
+
if (node.type === "file" && node.data) {
|
|
8505
|
+
const mediaType = node.mediaType || "application/octet-stream";
|
|
8506
|
+
const filename = node.filename || `input_file_${attachmentIndex}.${getExtensionFromMediaType(mediaType)}`;
|
|
8507
|
+
const attachment = toAttachment(node.data, mediaType, filename);
|
|
8508
|
+
if (attachment) {
|
|
8509
|
+
attachmentIndex++;
|
|
8510
|
+
return {
|
|
8511
|
+
...node,
|
|
8512
|
+
data: attachment
|
|
8513
|
+
};
|
|
8514
|
+
}
|
|
8515
|
+
}
|
|
8516
|
+
const processed = {};
|
|
8517
|
+
for (const [key, value] of Object.entries(node)) {
|
|
8518
|
+
processed[key] = processNode(value);
|
|
7823
8519
|
}
|
|
7824
|
-
return
|
|
8520
|
+
return processed;
|
|
7825
8521
|
};
|
|
7826
8522
|
if (Array.isArray(input)) {
|
|
7827
|
-
return input.map(
|
|
7828
|
-
}
|
|
7829
|
-
|
|
8523
|
+
return input.map(processNode);
|
|
8524
|
+
}
|
|
8525
|
+
return processNode(input);
|
|
8526
|
+
}
|
|
8527
|
+
|
|
8528
|
+
// src/instrumentation/core/channel-definitions.ts
|
|
8529
|
+
function channel(spec) {
|
|
8530
|
+
return spec;
|
|
8531
|
+
}
|
|
8532
|
+
function defineChannels(pkg, channels) {
|
|
8533
|
+
return Object.fromEntries(
|
|
8534
|
+
Object.entries(channels).map(([key, spec]) => {
|
|
8535
|
+
const fullChannelName = `orchestrion:${pkg}:${spec.channelName}`;
|
|
8536
|
+
if (spec.kind === "async") {
|
|
8537
|
+
const asyncSpec = spec;
|
|
8538
|
+
const tracingChannel2 = () => isomorph_default.newTracingChannel(
|
|
8539
|
+
fullChannelName
|
|
8540
|
+
);
|
|
8541
|
+
return [
|
|
8542
|
+
key,
|
|
8543
|
+
{
|
|
8544
|
+
...asyncSpec,
|
|
8545
|
+
tracingChannel: tracingChannel2,
|
|
8546
|
+
tracePromise: (fn, context) => tracingChannel2().tracePromise(
|
|
8547
|
+
fn,
|
|
8548
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
8549
|
+
context
|
|
8550
|
+
)
|
|
8551
|
+
}
|
|
8552
|
+
];
|
|
8553
|
+
}
|
|
8554
|
+
const syncSpec = spec;
|
|
8555
|
+
const tracingChannel = () => isomorph_default.newTracingChannel(
|
|
8556
|
+
fullChannelName
|
|
8557
|
+
);
|
|
8558
|
+
return [
|
|
8559
|
+
key,
|
|
8560
|
+
{
|
|
8561
|
+
...syncSpec,
|
|
8562
|
+
tracingChannel,
|
|
8563
|
+
traceSync: (fn, context) => tracingChannel().traceSync(
|
|
8564
|
+
fn,
|
|
8565
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
8566
|
+
context
|
|
8567
|
+
)
|
|
8568
|
+
}
|
|
8569
|
+
];
|
|
8570
|
+
})
|
|
8571
|
+
);
|
|
8572
|
+
}
|
|
8573
|
+
|
|
8574
|
+
// src/instrumentation/plugins/openai-channels.ts
|
|
8575
|
+
var openAIChannels = defineChannels("openai", {
|
|
8576
|
+
chatCompletionsCreate: channel({
|
|
8577
|
+
channelName: "chat.completions.create",
|
|
8578
|
+
kind: "async"
|
|
8579
|
+
}),
|
|
8580
|
+
embeddingsCreate: channel({
|
|
8581
|
+
channelName: "embeddings.create",
|
|
8582
|
+
kind: "async"
|
|
8583
|
+
}),
|
|
8584
|
+
betaChatCompletionsParse: channel({
|
|
8585
|
+
channelName: "beta.chat.completions.parse",
|
|
8586
|
+
kind: "async"
|
|
8587
|
+
}),
|
|
8588
|
+
betaChatCompletionsStream: channel({
|
|
8589
|
+
channelName: "beta.chat.completions.stream",
|
|
8590
|
+
kind: "sync-stream"
|
|
8591
|
+
}),
|
|
8592
|
+
moderationsCreate: channel({
|
|
8593
|
+
channelName: "moderations.create",
|
|
8594
|
+
kind: "async"
|
|
8595
|
+
}),
|
|
8596
|
+
responsesCreate: channel({
|
|
8597
|
+
channelName: "responses.create",
|
|
8598
|
+
kind: "async"
|
|
8599
|
+
}),
|
|
8600
|
+
responsesStream: channel({
|
|
8601
|
+
channelName: "responses.stream",
|
|
8602
|
+
kind: "sync-stream"
|
|
8603
|
+
}),
|
|
8604
|
+
responsesParse: channel({
|
|
8605
|
+
channelName: "responses.parse",
|
|
8606
|
+
kind: "async"
|
|
8607
|
+
})
|
|
8608
|
+
});
|
|
8609
|
+
|
|
8610
|
+
// src/openai-utils.ts
|
|
8611
|
+
var BRAINTRUST_CACHED_STREAM_METRIC = "__braintrust_cached_metric";
|
|
8612
|
+
var LEGACY_CACHED_HEADER = "x-cached";
|
|
8613
|
+
var X_CACHED_HEADER = "x-bt-cached";
|
|
8614
|
+
var TOKEN_NAME_MAP = {
|
|
8615
|
+
input_tokens: "prompt_tokens",
|
|
8616
|
+
output_tokens: "completion_tokens",
|
|
8617
|
+
total_tokens: "tokens"
|
|
8618
|
+
};
|
|
8619
|
+
var TOKEN_PREFIX_MAP = {
|
|
8620
|
+
input: "prompt",
|
|
8621
|
+
output: "completion"
|
|
8622
|
+
};
|
|
8623
|
+
function parseMetricsFromUsage(usage) {
|
|
8624
|
+
if (!usage) {
|
|
8625
|
+
return {};
|
|
8626
|
+
}
|
|
8627
|
+
const metrics = {};
|
|
8628
|
+
for (const [oaiName, value] of Object.entries(usage)) {
|
|
8629
|
+
if (typeof value === "number") {
|
|
8630
|
+
const metricName = TOKEN_NAME_MAP[oaiName] || oaiName;
|
|
8631
|
+
metrics[metricName] = value;
|
|
8632
|
+
continue;
|
|
8633
|
+
}
|
|
8634
|
+
if (!oaiName.endsWith("_tokens_details") || !isObject(value)) {
|
|
8635
|
+
continue;
|
|
8636
|
+
}
|
|
8637
|
+
const rawPrefix = oaiName.slice(0, -"_tokens_details".length);
|
|
8638
|
+
const prefix = TOKEN_PREFIX_MAP[rawPrefix] || rawPrefix;
|
|
8639
|
+
for (const [key, nestedValue] of Object.entries(value)) {
|
|
8640
|
+
if (typeof nestedValue !== "number") {
|
|
8641
|
+
continue;
|
|
8642
|
+
}
|
|
8643
|
+
metrics[`${prefix}_${key}`] = nestedValue;
|
|
8644
|
+
}
|
|
8645
|
+
}
|
|
8646
|
+
return metrics;
|
|
8647
|
+
}
|
|
8648
|
+
function parseCachedHeader(value) {
|
|
8649
|
+
if (!value) {
|
|
8650
|
+
return void 0;
|
|
7830
8651
|
}
|
|
7831
|
-
return
|
|
8652
|
+
return ["true", "hit"].includes(value.toLowerCase()) ? 1 : 0;
|
|
8653
|
+
}
|
|
8654
|
+
function getCachedMetricFromHeaders(headers) {
|
|
8655
|
+
if (!headers || typeof headers.get !== "function") {
|
|
8656
|
+
return void 0;
|
|
8657
|
+
}
|
|
8658
|
+
const cachedHeader = headers.get(X_CACHED_HEADER);
|
|
8659
|
+
if (cachedHeader) {
|
|
8660
|
+
return parseCachedHeader(cachedHeader);
|
|
8661
|
+
}
|
|
8662
|
+
return parseCachedHeader(headers.get(LEGACY_CACHED_HEADER));
|
|
7832
8663
|
}
|
|
7833
8664
|
|
|
7834
8665
|
// src/instrumentation/plugins/openai-plugin.ts
|
|
@@ -7837,13 +8668,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
7837
8668
|
super();
|
|
7838
8669
|
}
|
|
7839
8670
|
onEnable() {
|
|
7840
|
-
this.
|
|
7841
|
-
|
|
7842
|
-
{
|
|
8671
|
+
this.unsubscribers.push(
|
|
8672
|
+
traceStreamingChannel(openAIChannels.chatCompletionsCreate, {
|
|
7843
8673
|
name: "Chat Completion",
|
|
7844
8674
|
type: "llm" /* LLM */,
|
|
7845
|
-
extractInput: (
|
|
7846
|
-
const params = args[0] || {};
|
|
8675
|
+
extractInput: ([params]) => {
|
|
7847
8676
|
const { messages, ...metadata } = params;
|
|
7848
8677
|
return {
|
|
7849
8678
|
input: processInputAttachments(messages),
|
|
@@ -7853,41 +8682,49 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
7853
8682
|
extractOutput: (result) => {
|
|
7854
8683
|
return result?.choices;
|
|
7855
8684
|
},
|
|
7856
|
-
extractMetrics: (result, startTime) => {
|
|
7857
|
-
const metrics =
|
|
8685
|
+
extractMetrics: (result, startTime, endEvent) => {
|
|
8686
|
+
const metrics = withCachedMetric(
|
|
8687
|
+
parseMetricsFromUsage(result?.usage),
|
|
8688
|
+
result,
|
|
8689
|
+
endEvent
|
|
8690
|
+
);
|
|
7858
8691
|
if (startTime) {
|
|
7859
8692
|
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
7860
8693
|
}
|
|
7861
8694
|
return metrics;
|
|
7862
8695
|
},
|
|
7863
8696
|
aggregateChunks: aggregateChatCompletionChunks
|
|
7864
|
-
}
|
|
8697
|
+
})
|
|
7865
8698
|
);
|
|
7866
|
-
this.
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
8699
|
+
this.unsubscribers.push(
|
|
8700
|
+
traceAsyncChannel(openAIChannels.embeddingsCreate, {
|
|
8701
|
+
name: "Embedding",
|
|
8702
|
+
type: "llm" /* LLM */,
|
|
8703
|
+
extractInput: ([params]) => {
|
|
8704
|
+
const { input, ...metadata } = params;
|
|
8705
|
+
return {
|
|
8706
|
+
input,
|
|
8707
|
+
metadata: { ...metadata, provider: "openai" }
|
|
8708
|
+
};
|
|
8709
|
+
},
|
|
8710
|
+
extractOutput: (result) => {
|
|
8711
|
+
const embedding = result?.data?.[0]?.embedding;
|
|
8712
|
+
return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
|
|
8713
|
+
},
|
|
8714
|
+
extractMetrics: (result, _startTime, endEvent) => {
|
|
8715
|
+
return withCachedMetric(
|
|
8716
|
+
parseMetricsFromUsage(result?.usage),
|
|
8717
|
+
result,
|
|
8718
|
+
endEvent
|
|
8719
|
+
);
|
|
8720
|
+
}
|
|
8721
|
+
})
|
|
8722
|
+
);
|
|
8723
|
+
this.unsubscribers.push(
|
|
8724
|
+
traceStreamingChannel(openAIChannels.betaChatCompletionsParse, {
|
|
7887
8725
|
name: "Chat Completion",
|
|
7888
8726
|
type: "llm" /* LLM */,
|
|
7889
|
-
extractInput: (
|
|
7890
|
-
const params = args[0] || {};
|
|
8727
|
+
extractInput: ([params]) => {
|
|
7891
8728
|
const { messages, ...metadata } = params;
|
|
7892
8729
|
return {
|
|
7893
8730
|
input: processInputAttachments(messages),
|
|
@@ -7897,164 +8734,196 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
7897
8734
|
extractOutput: (result) => {
|
|
7898
8735
|
return result?.choices;
|
|
7899
8736
|
},
|
|
7900
|
-
extractMetrics: (result, startTime) => {
|
|
7901
|
-
const metrics =
|
|
8737
|
+
extractMetrics: (result, startTime, endEvent) => {
|
|
8738
|
+
const metrics = withCachedMetric(
|
|
8739
|
+
parseMetricsFromUsage(result?.usage),
|
|
8740
|
+
result,
|
|
8741
|
+
endEvent
|
|
8742
|
+
);
|
|
7902
8743
|
if (startTime) {
|
|
7903
8744
|
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
7904
8745
|
}
|
|
7905
8746
|
return metrics;
|
|
7906
8747
|
},
|
|
7907
8748
|
aggregateChunks: aggregateChatCompletionChunks
|
|
7908
|
-
}
|
|
8749
|
+
})
|
|
7909
8750
|
);
|
|
7910
|
-
this.
|
|
7911
|
-
|
|
7912
|
-
{
|
|
8751
|
+
this.unsubscribers.push(
|
|
8752
|
+
traceSyncStreamChannel(openAIChannels.betaChatCompletionsStream, {
|
|
7913
8753
|
name: "Chat Completion",
|
|
7914
8754
|
type: "llm" /* LLM */,
|
|
7915
|
-
extractInput: (
|
|
7916
|
-
const params = args[0] || {};
|
|
8755
|
+
extractInput: ([params]) => {
|
|
7917
8756
|
const { messages, ...metadata } = params;
|
|
7918
8757
|
return {
|
|
7919
8758
|
input: processInputAttachments(messages),
|
|
7920
8759
|
metadata: { ...metadata, provider: "openai" }
|
|
7921
8760
|
};
|
|
7922
8761
|
}
|
|
7923
|
-
}
|
|
8762
|
+
})
|
|
7924
8763
|
);
|
|
7925
|
-
this.
|
|
7926
|
-
|
|
7927
|
-
|
|
7928
|
-
|
|
7929
|
-
|
|
7930
|
-
|
|
7931
|
-
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
|
|
7936
|
-
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
type: "llm" /* LLM */,
|
|
7946
|
-
extractInput: (args) => {
|
|
7947
|
-
const params = args[0] || {};
|
|
7948
|
-
const { input, ...metadata } = params;
|
|
7949
|
-
return {
|
|
7950
|
-
input: processInputAttachments(input),
|
|
7951
|
-
metadata: { ...metadata, provider: "openai" }
|
|
7952
|
-
};
|
|
7953
|
-
},
|
|
7954
|
-
extractOutput: (result) => {
|
|
7955
|
-
return processImagesInOutput(result?.output);
|
|
7956
|
-
},
|
|
7957
|
-
extractMetrics: (result, startTime) => {
|
|
7958
|
-
const metrics = parseMetricsFromUsage(result?.usage);
|
|
7959
|
-
if (startTime) {
|
|
7960
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
7961
|
-
}
|
|
7962
|
-
return metrics;
|
|
7963
|
-
}
|
|
7964
|
-
});
|
|
7965
|
-
this.subscribeToSyncStreamChannel("orchestrion:openai:responses.stream", {
|
|
7966
|
-
name: "openai.responses.stream",
|
|
7967
|
-
type: "llm" /* LLM */,
|
|
7968
|
-
extractInput: (args) => {
|
|
7969
|
-
const params = args[0] || {};
|
|
7970
|
-
const { input, ...metadata } = params;
|
|
7971
|
-
return {
|
|
7972
|
-
input: processInputAttachments(input),
|
|
7973
|
-
metadata: { ...metadata, provider: "openai" }
|
|
7974
|
-
};
|
|
7975
|
-
},
|
|
7976
|
-
extractFromEvent: (event) => {
|
|
7977
|
-
if (!event || !event.type || !event.response) {
|
|
7978
|
-
return {};
|
|
8764
|
+
this.unsubscribers.push(
|
|
8765
|
+
traceAsyncChannel(openAIChannels.moderationsCreate, {
|
|
8766
|
+
name: "Moderation",
|
|
8767
|
+
type: "llm" /* LLM */,
|
|
8768
|
+
extractInput: ([params]) => {
|
|
8769
|
+
const { input, ...metadata } = params;
|
|
8770
|
+
return {
|
|
8771
|
+
input,
|
|
8772
|
+
metadata: { ...metadata, provider: "openai" }
|
|
8773
|
+
};
|
|
8774
|
+
},
|
|
8775
|
+
extractOutput: (result) => {
|
|
8776
|
+
return result?.results;
|
|
8777
|
+
},
|
|
8778
|
+
extractMetrics: (result, _startTime, endEvent) => {
|
|
8779
|
+
return withCachedMetric(
|
|
8780
|
+
parseMetricsFromUsage(result?.usage),
|
|
8781
|
+
result,
|
|
8782
|
+
endEvent
|
|
8783
|
+
);
|
|
7979
8784
|
}
|
|
7980
|
-
|
|
7981
|
-
|
|
8785
|
+
})
|
|
8786
|
+
);
|
|
8787
|
+
this.unsubscribers.push(
|
|
8788
|
+
traceStreamingChannel(openAIChannels.responsesCreate, {
|
|
8789
|
+
name: "openai.responses.create",
|
|
8790
|
+
type: "llm" /* LLM */,
|
|
8791
|
+
extractInput: ([params]) => {
|
|
8792
|
+
const { input, ...metadata } = params;
|
|
8793
|
+
return {
|
|
8794
|
+
input: processInputAttachments(input),
|
|
8795
|
+
metadata: { ...metadata, provider: "openai" }
|
|
8796
|
+
};
|
|
8797
|
+
},
|
|
8798
|
+
extractOutput: (result) => {
|
|
8799
|
+
return processImagesInOutput(result?.output);
|
|
8800
|
+
},
|
|
8801
|
+
extractMetadata: (result) => {
|
|
8802
|
+
if (!result) {
|
|
8803
|
+
return void 0;
|
|
8804
|
+
}
|
|
8805
|
+
const { output: _output, usage: _usage, ...metadata } = result;
|
|
8806
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
8807
|
+
},
|
|
8808
|
+
extractMetrics: (result, startTime, endEvent) => {
|
|
8809
|
+
const metrics = withCachedMetric(
|
|
8810
|
+
parseMetricsFromUsage(result?.usage),
|
|
8811
|
+
result,
|
|
8812
|
+
endEvent
|
|
8813
|
+
);
|
|
8814
|
+
if (startTime) {
|
|
8815
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8816
|
+
}
|
|
8817
|
+
return metrics;
|
|
8818
|
+
},
|
|
8819
|
+
aggregateChunks: aggregateResponseStreamEvents
|
|
8820
|
+
})
|
|
8821
|
+
);
|
|
8822
|
+
this.unsubscribers.push(
|
|
8823
|
+
traceSyncStreamChannel(openAIChannels.responsesStream, {
|
|
8824
|
+
name: "openai.responses.create",
|
|
8825
|
+
type: "llm" /* LLM */,
|
|
8826
|
+
extractInput: ([params]) => {
|
|
8827
|
+
const { input, ...metadata } = params;
|
|
8828
|
+
return {
|
|
8829
|
+
input: processInputAttachments(input),
|
|
8830
|
+
metadata: { ...metadata, provider: "openai" }
|
|
8831
|
+
};
|
|
8832
|
+
},
|
|
8833
|
+
extractFromEvent: (event) => {
|
|
8834
|
+
if (event.type !== "response.completed" || !event.response) {
|
|
8835
|
+
return {};
|
|
8836
|
+
}
|
|
8837
|
+
const response = event.response;
|
|
7982
8838
|
const data = {};
|
|
7983
|
-
if (response
|
|
8839
|
+
if (response.output !== void 0) {
|
|
7984
8840
|
data.output = processImagesInOutput(response.output);
|
|
7985
8841
|
}
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
data.metadata = metadata;
|
|
7990
|
-
}
|
|
8842
|
+
const { usage: _usage, output: _output, ...metadata } = response;
|
|
8843
|
+
if (Object.keys(metadata).length > 0) {
|
|
8844
|
+
data.metadata = metadata;
|
|
7991
8845
|
}
|
|
7992
|
-
data.metrics = parseMetricsFromUsage(response
|
|
8846
|
+
data.metrics = parseMetricsFromUsage(response.usage);
|
|
7993
8847
|
return data;
|
|
7994
8848
|
}
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8006
|
-
|
|
8007
|
-
}
|
|
8008
|
-
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8849
|
+
})
|
|
8850
|
+
);
|
|
8851
|
+
this.unsubscribers.push(
|
|
8852
|
+
traceStreamingChannel(openAIChannels.responsesParse, {
|
|
8853
|
+
name: "openai.responses.parse",
|
|
8854
|
+
type: "llm" /* LLM */,
|
|
8855
|
+
extractInput: ([params]) => {
|
|
8856
|
+
const { input, ...metadata } = params;
|
|
8857
|
+
return {
|
|
8858
|
+
input: processInputAttachments(input),
|
|
8859
|
+
metadata: { ...metadata, provider: "openai" }
|
|
8860
|
+
};
|
|
8861
|
+
},
|
|
8862
|
+
extractOutput: (result) => {
|
|
8863
|
+
return processImagesInOutput(result?.output);
|
|
8864
|
+
},
|
|
8865
|
+
extractMetadata: (result) => {
|
|
8866
|
+
if (!result) {
|
|
8867
|
+
return void 0;
|
|
8868
|
+
}
|
|
8869
|
+
const { output: _output, usage: _usage, ...metadata } = result;
|
|
8870
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
8871
|
+
},
|
|
8872
|
+
extractMetrics: (result, startTime, endEvent) => {
|
|
8873
|
+
const metrics = withCachedMetric(
|
|
8874
|
+
parseMetricsFromUsage(result?.usage),
|
|
8875
|
+
result,
|
|
8876
|
+
endEvent
|
|
8877
|
+
);
|
|
8878
|
+
if (startTime) {
|
|
8879
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8880
|
+
}
|
|
8881
|
+
return metrics;
|
|
8882
|
+
},
|
|
8883
|
+
aggregateChunks: aggregateResponseStreamEvents
|
|
8884
|
+
})
|
|
8885
|
+
);
|
|
8020
8886
|
}
|
|
8021
8887
|
onDisable() {
|
|
8888
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
8022
8889
|
}
|
|
8023
8890
|
};
|
|
8024
|
-
|
|
8025
|
-
|
|
8026
|
-
|
|
8027
|
-
total_tokens: "tokens"
|
|
8028
|
-
};
|
|
8029
|
-
var TOKEN_PREFIX_MAP = {
|
|
8030
|
-
input: "prompt",
|
|
8031
|
-
output: "completion"
|
|
8032
|
-
};
|
|
8033
|
-
function parseMetricsFromUsage(usage) {
|
|
8034
|
-
if (!usage) {
|
|
8035
|
-
return {};
|
|
8891
|
+
function getCachedMetricFromEndEvent(endEvent) {
|
|
8892
|
+
if (!isObject(endEvent)) {
|
|
8893
|
+
return void 0;
|
|
8036
8894
|
}
|
|
8037
|
-
const
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
const metricName = TOKEN_NAME_MAP[oai_name] || oai_name;
|
|
8041
|
-
metrics[metricName] = value;
|
|
8042
|
-
} else if (oai_name.endsWith("_tokens_details")) {
|
|
8043
|
-
if (!isObject(value)) {
|
|
8044
|
-
continue;
|
|
8045
|
-
}
|
|
8046
|
-
const rawPrefix = oai_name.slice(0, -"_tokens_details".length);
|
|
8047
|
-
const prefix = TOKEN_PREFIX_MAP[rawPrefix] || rawPrefix;
|
|
8048
|
-
for (const [key, n] of Object.entries(value)) {
|
|
8049
|
-
if (typeof n !== "number") {
|
|
8050
|
-
continue;
|
|
8051
|
-
}
|
|
8052
|
-
const metricName = `${prefix}_${key}`;
|
|
8053
|
-
metrics[metricName] = n;
|
|
8054
|
-
}
|
|
8055
|
-
}
|
|
8895
|
+
const response = endEvent.response;
|
|
8896
|
+
if (!isObject(response)) {
|
|
8897
|
+
return void 0;
|
|
8056
8898
|
}
|
|
8057
|
-
|
|
8899
|
+
const headers = response.headers;
|
|
8900
|
+
if (!headers || typeof headers.get !== "function") {
|
|
8901
|
+
return void 0;
|
|
8902
|
+
}
|
|
8903
|
+
return getCachedMetricFromHeaders(headers);
|
|
8904
|
+
}
|
|
8905
|
+
function withCachedMetric(metrics, result, endEvent) {
|
|
8906
|
+
if (metrics.cached !== void 0) {
|
|
8907
|
+
return metrics;
|
|
8908
|
+
}
|
|
8909
|
+
const cachedFromEvent = getCachedMetricFromEndEvent(endEvent);
|
|
8910
|
+
if (cachedFromEvent !== void 0) {
|
|
8911
|
+
return {
|
|
8912
|
+
...metrics,
|
|
8913
|
+
cached: cachedFromEvent
|
|
8914
|
+
};
|
|
8915
|
+
}
|
|
8916
|
+
if (!isObject(result)) {
|
|
8917
|
+
return metrics;
|
|
8918
|
+
}
|
|
8919
|
+
const cached = result[BRAINTRUST_CACHED_STREAM_METRIC];
|
|
8920
|
+
if (typeof cached !== "number") {
|
|
8921
|
+
return metrics;
|
|
8922
|
+
}
|
|
8923
|
+
return {
|
|
8924
|
+
...metrics,
|
|
8925
|
+
cached
|
|
8926
|
+
};
|
|
8058
8927
|
}
|
|
8059
8928
|
function processImagesInOutput(output) {
|
|
8060
8929
|
if (Array.isArray(output)) {
|
|
@@ -8085,7 +8954,7 @@ function processImagesInOutput(output) {
|
|
|
8085
8954
|
}
|
|
8086
8955
|
return output;
|
|
8087
8956
|
}
|
|
8088
|
-
function aggregateChatCompletionChunks(chunks) {
|
|
8957
|
+
function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
|
|
8089
8958
|
let role = void 0;
|
|
8090
8959
|
let content = void 0;
|
|
8091
8960
|
let tool_calls = void 0;
|
|
@@ -8127,6 +8996,7 @@ function aggregateChatCompletionChunks(chunks) {
|
|
|
8127
8996
|
}
|
|
8128
8997
|
}
|
|
8129
8998
|
}
|
|
8999
|
+
metrics = withCachedMetric(metrics, streamResult, endEvent);
|
|
8130
9000
|
return {
|
|
8131
9001
|
metrics,
|
|
8132
9002
|
output: [
|
|
@@ -8143,9 +9013,33 @@ function aggregateChatCompletionChunks(chunks) {
|
|
|
8143
9013
|
]
|
|
8144
9014
|
};
|
|
8145
9015
|
}
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
9016
|
+
function aggregateResponseStreamEvents(chunks, _streamResult, endEvent) {
|
|
9017
|
+
let output = void 0;
|
|
9018
|
+
let metrics = {};
|
|
9019
|
+
let metadata = void 0;
|
|
9020
|
+
for (const chunk of chunks) {
|
|
9021
|
+
if (!chunk || !chunk.type || !chunk.response) {
|
|
9022
|
+
continue;
|
|
9023
|
+
}
|
|
9024
|
+
if (chunk.type !== "response.completed") {
|
|
9025
|
+
continue;
|
|
9026
|
+
}
|
|
9027
|
+
const response = chunk.response;
|
|
9028
|
+
if (response?.output !== void 0) {
|
|
9029
|
+
output = processImagesInOutput(response.output);
|
|
9030
|
+
}
|
|
9031
|
+
const { usage: _usage, output: _output, ...rest } = response || {};
|
|
9032
|
+
if (Object.keys(rest).length > 0) {
|
|
9033
|
+
metadata = rest;
|
|
9034
|
+
}
|
|
9035
|
+
metrics = parseMetricsFromUsage(response?.usage);
|
|
9036
|
+
}
|
|
9037
|
+
return {
|
|
9038
|
+
output,
|
|
9039
|
+
metrics: withCachedMetric(metrics, void 0, endEvent),
|
|
9040
|
+
...metadata !== void 0 ? { metadata } : {}
|
|
9041
|
+
};
|
|
9042
|
+
}
|
|
8149
9043
|
|
|
8150
9044
|
// src/wrappers/anthropic-tokens-util.ts
|
|
8151
9045
|
function finalizeAnthropicTokens(metrics) {
|
|
@@ -8167,215 +9061,75 @@ function extractAnthropicCacheTokens(cacheReadTokens = 0, cacheCreationTokens =
|
|
|
8167
9061
|
return cacheTokens;
|
|
8168
9062
|
}
|
|
8169
9063
|
|
|
9064
|
+
// src/instrumentation/plugins/anthropic-channels.ts
|
|
9065
|
+
var anthropicChannels = defineChannels("@anthropic-ai/sdk", {
|
|
9066
|
+
messagesCreate: channel({
|
|
9067
|
+
channelName: "messages.create",
|
|
9068
|
+
kind: "async"
|
|
9069
|
+
}),
|
|
9070
|
+
betaMessagesCreate: channel({
|
|
9071
|
+
channelName: "beta.messages.create",
|
|
9072
|
+
kind: "async"
|
|
9073
|
+
})
|
|
9074
|
+
});
|
|
9075
|
+
|
|
8170
9076
|
// src/instrumentation/plugins/anthropic-plugin.ts
|
|
8171
9077
|
var AnthropicPlugin = class extends BasePlugin {
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
this.subscribeToAnthropicChannels();
|
|
8175
|
-
}
|
|
8176
|
-
onDisable() {
|
|
8177
|
-
for (const unsubscribe of this.unsubscribers) {
|
|
8178
|
-
unsubscribe();
|
|
8179
|
-
}
|
|
8180
|
-
this.unsubscribers = [];
|
|
8181
|
-
}
|
|
8182
|
-
subscribeToAnthropicChannels() {
|
|
8183
|
-
this.subscribeToStreamingChannel("orchestrion:anthropic:messages.create", {
|
|
8184
|
-
name: "anthropic.messages.create",
|
|
8185
|
-
type: "llm" /* LLM */,
|
|
8186
|
-
extractInput: (args) => {
|
|
8187
|
-
const params = args[0] || {};
|
|
8188
|
-
const input = coalesceInput(params.messages || [], params.system);
|
|
8189
|
-
const metadata = filterFrom(params, ["messages", "system"]);
|
|
8190
|
-
return {
|
|
8191
|
-
input: processAttachmentsInInput(input),
|
|
8192
|
-
metadata: { ...metadata, provider: "anthropic" }
|
|
8193
|
-
};
|
|
8194
|
-
},
|
|
8195
|
-
extractOutput: (result) => {
|
|
8196
|
-
return result ? { role: result.role, content: result.content } : null;
|
|
8197
|
-
},
|
|
8198
|
-
extractMetrics: (result, startTime) => {
|
|
8199
|
-
const metrics = parseMetricsFromUsage2(result?.usage);
|
|
8200
|
-
if (startTime) {
|
|
8201
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8202
|
-
}
|
|
8203
|
-
const finalized = finalizeAnthropicTokens(metrics);
|
|
8204
|
-
return Object.fromEntries(
|
|
8205
|
-
Object.entries(finalized).filter(([, v]) => v !== void 0)
|
|
8206
|
-
);
|
|
8207
|
-
},
|
|
8208
|
-
extractMetadata: (result) => {
|
|
8209
|
-
const metadata = {};
|
|
8210
|
-
const metas = ["stop_reason", "stop_sequence"];
|
|
8211
|
-
for (const m of metas) {
|
|
8212
|
-
if (result?.[m] !== void 0) {
|
|
8213
|
-
metadata[m] = result[m];
|
|
8214
|
-
}
|
|
8215
|
-
}
|
|
8216
|
-
return metadata;
|
|
8217
|
-
},
|
|
8218
|
-
aggregateChunks: aggregateAnthropicStreamChunks,
|
|
8219
|
-
isStreaming: (args) => {
|
|
8220
|
-
return args[0]?.stream === true;
|
|
8221
|
-
}
|
|
8222
|
-
});
|
|
8223
|
-
this.subscribeToStreamingChannel(
|
|
8224
|
-
"orchestrion:anthropic:beta.messages.create",
|
|
8225
|
-
{
|
|
8226
|
-
name: "anthropic.beta.messages.create",
|
|
8227
|
-
type: "llm" /* LLM */,
|
|
8228
|
-
extractInput: (args) => {
|
|
8229
|
-
const params = args[0] || {};
|
|
8230
|
-
const input = coalesceInput(params.messages || [], params.system);
|
|
8231
|
-
const metadata = filterFrom(params, ["messages", "system"]);
|
|
8232
|
-
return {
|
|
8233
|
-
input: processAttachmentsInInput(input),
|
|
8234
|
-
metadata: { ...metadata, provider: "anthropic" }
|
|
8235
|
-
};
|
|
8236
|
-
},
|
|
8237
|
-
extractOutput: (result) => {
|
|
8238
|
-
return result ? { role: result.role, content: result.content } : null;
|
|
8239
|
-
},
|
|
8240
|
-
extractMetrics: (result, startTime) => {
|
|
8241
|
-
const metrics = parseMetricsFromUsage2(result?.usage);
|
|
8242
|
-
if (startTime) {
|
|
8243
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8244
|
-
}
|
|
8245
|
-
const finalized = finalizeAnthropicTokens(metrics);
|
|
8246
|
-
return Object.fromEntries(
|
|
8247
|
-
Object.entries(finalized).filter(([, v]) => v !== void 0)
|
|
8248
|
-
);
|
|
8249
|
-
},
|
|
8250
|
-
extractMetadata: (result) => {
|
|
8251
|
-
const metadata = {};
|
|
8252
|
-
const metas = ["stop_reason", "stop_sequence"];
|
|
8253
|
-
for (const m of metas) {
|
|
8254
|
-
if (result?.[m] !== void 0) {
|
|
8255
|
-
metadata[m] = result[m];
|
|
8256
|
-
}
|
|
8257
|
-
}
|
|
8258
|
-
return metadata;
|
|
8259
|
-
},
|
|
8260
|
-
aggregateChunks: aggregateAnthropicStreamChunks,
|
|
8261
|
-
isStreaming: (args) => {
|
|
8262
|
-
return args[0]?.stream === true;
|
|
8263
|
-
}
|
|
8264
|
-
}
|
|
8265
|
-
);
|
|
9078
|
+
onEnable() {
|
|
9079
|
+
this.subscribeToAnthropicChannels();
|
|
8266
9080
|
}
|
|
8267
|
-
|
|
8268
|
-
|
|
8269
|
-
|
|
8270
|
-
|
|
8271
|
-
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
const
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
}
|
|
8281
|
-
}
|
|
8282
|
-
const startTime = getCurrentUnixTimestamp();
|
|
8283
|
-
spans.set(event, { span, startTime });
|
|
8284
|
-
try {
|
|
8285
|
-
const { input, metadata } = config.extractInput(event.arguments);
|
|
8286
|
-
span.log({
|
|
8287
|
-
input,
|
|
8288
|
-
metadata
|
|
8289
|
-
});
|
|
8290
|
-
} catch (error) {
|
|
8291
|
-
console.error(`Error extracting input for ${channelName}:`, error);
|
|
8292
|
-
}
|
|
9081
|
+
onDisable() {
|
|
9082
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
9083
|
+
}
|
|
9084
|
+
subscribeToAnthropicChannels() {
|
|
9085
|
+
const anthropicConfig = {
|
|
9086
|
+
name: "anthropic.messages.create",
|
|
9087
|
+
type: "llm" /* LLM */,
|
|
9088
|
+
extractInput: (args) => {
|
|
9089
|
+
const params = args[0] || {};
|
|
9090
|
+
const input = coalesceInput(params.messages || [], params.system);
|
|
9091
|
+
const metadata = filterFrom(params, ["messages", "system"]);
|
|
9092
|
+
return {
|
|
9093
|
+
input: processAttachmentsInInput(input),
|
|
9094
|
+
metadata: { ...metadata, provider: "anthropic" }
|
|
9095
|
+
};
|
|
8293
9096
|
},
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
9097
|
+
extractOutput: (message) => {
|
|
9098
|
+
return message ? { role: message.role, content: message.content } : null;
|
|
9099
|
+
},
|
|
9100
|
+
extractMetrics: (message, startTime) => {
|
|
9101
|
+
const metrics = parseMetricsFromUsage2(message?.usage);
|
|
9102
|
+
if (startTime) {
|
|
9103
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8298
9104
|
}
|
|
8299
|
-
const
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
metadata = aggregated.metadata || {};
|
|
8313
|
-
} else {
|
|
8314
|
-
output = config.extractOutput(chunks);
|
|
8315
|
-
metrics = config.extractMetrics(chunks, startTime);
|
|
8316
|
-
if (config.extractMetadata) {
|
|
8317
|
-
metadata = config.extractMetadata(chunks);
|
|
8318
|
-
}
|
|
8319
|
-
}
|
|
8320
|
-
if (!metrics.time_to_first_token && chunks.length > 0) {
|
|
8321
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8322
|
-
}
|
|
8323
|
-
span.log({
|
|
8324
|
-
output,
|
|
8325
|
-
metrics,
|
|
8326
|
-
metadata
|
|
8327
|
-
});
|
|
8328
|
-
} catch (error) {
|
|
8329
|
-
console.error(
|
|
8330
|
-
`Error extracting output for ${channelName}:`,
|
|
8331
|
-
error
|
|
8332
|
-
);
|
|
8333
|
-
} finally {
|
|
8334
|
-
span.end();
|
|
8335
|
-
}
|
|
8336
|
-
},
|
|
8337
|
-
onError: (error) => {
|
|
8338
|
-
span.log({
|
|
8339
|
-
error: error.message
|
|
8340
|
-
});
|
|
8341
|
-
span.end();
|
|
8342
|
-
}
|
|
8343
|
-
});
|
|
8344
|
-
} else {
|
|
8345
|
-
try {
|
|
8346
|
-
const output = config.extractOutput(event.result);
|
|
8347
|
-
const metrics = config.extractMetrics(event.result, startTime);
|
|
8348
|
-
const metadata = config.extractMetadata ? config.extractMetadata(event.result) : {};
|
|
8349
|
-
span.log({
|
|
8350
|
-
output,
|
|
8351
|
-
metrics,
|
|
8352
|
-
metadata
|
|
8353
|
-
});
|
|
8354
|
-
} catch (error) {
|
|
8355
|
-
console.error(`Error extracting output for ${channelName}:`, error);
|
|
8356
|
-
} finally {
|
|
8357
|
-
span.end();
|
|
8358
|
-
spans.delete(event);
|
|
9105
|
+
const finalized = finalizeAnthropicTokens(metrics);
|
|
9106
|
+
return Object.fromEntries(
|
|
9107
|
+
Object.entries(finalized).filter(
|
|
9108
|
+
(entry) => entry[1] !== void 0
|
|
9109
|
+
)
|
|
9110
|
+
);
|
|
9111
|
+
},
|
|
9112
|
+
extractMetadata: (message) => {
|
|
9113
|
+
const metadata = {};
|
|
9114
|
+
const metas = ["stop_reason", "stop_sequence"];
|
|
9115
|
+
for (const m of metas) {
|
|
9116
|
+
if (message?.[m] !== void 0) {
|
|
9117
|
+
metadata[m] = message[m];
|
|
8359
9118
|
}
|
|
8360
9119
|
}
|
|
9120
|
+
return metadata;
|
|
8361
9121
|
},
|
|
8362
|
-
|
|
8363
|
-
const spanData = spans.get(event);
|
|
8364
|
-
if (!spanData) {
|
|
8365
|
-
return;
|
|
8366
|
-
}
|
|
8367
|
-
const { span } = spanData;
|
|
8368
|
-
span.log({
|
|
8369
|
-
error: event.error.message
|
|
8370
|
-
});
|
|
8371
|
-
span.end();
|
|
8372
|
-
spans.delete(event);
|
|
8373
|
-
}
|
|
9122
|
+
aggregateChunks: (chunks) => aggregateAnthropicStreamChunks(chunks)
|
|
8374
9123
|
};
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
9124
|
+
this.unsubscribers.push(
|
|
9125
|
+
traceStreamingChannel(anthropicChannels.messagesCreate, anthropicConfig)
|
|
9126
|
+
);
|
|
9127
|
+
this.unsubscribers.push(
|
|
9128
|
+
traceStreamingChannel(anthropicChannels.betaMessagesCreate, {
|
|
9129
|
+
...anthropicConfig,
|
|
9130
|
+
name: "anthropic.beta.messages.create"
|
|
9131
|
+
})
|
|
9132
|
+
);
|
|
8379
9133
|
}
|
|
8380
9134
|
};
|
|
8381
9135
|
function parseMetricsFromUsage2(usage) {
|
|
@@ -8399,29 +9153,29 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
8399
9153
|
const deltas = [];
|
|
8400
9154
|
let metrics = {};
|
|
8401
9155
|
let metadata = {};
|
|
8402
|
-
for (const
|
|
8403
|
-
switch (
|
|
9156
|
+
for (const event of chunks) {
|
|
9157
|
+
switch (event?.type) {
|
|
8404
9158
|
case "message_start":
|
|
8405
|
-
if (
|
|
8406
|
-
const initialMetrics = parseMetricsFromUsage2(
|
|
9159
|
+
if (event.message?.usage) {
|
|
9160
|
+
const initialMetrics = parseMetricsFromUsage2(event.message.usage);
|
|
8407
9161
|
metrics = { ...metrics, ...initialMetrics };
|
|
8408
9162
|
}
|
|
8409
9163
|
break;
|
|
8410
9164
|
case "content_block_delta":
|
|
8411
|
-
if (
|
|
8412
|
-
const text =
|
|
9165
|
+
if (event.delta?.type === "text_delta") {
|
|
9166
|
+
const text = event.delta.text;
|
|
8413
9167
|
if (text) {
|
|
8414
9168
|
deltas.push(text);
|
|
8415
9169
|
}
|
|
8416
9170
|
}
|
|
8417
9171
|
break;
|
|
8418
9172
|
case "message_delta":
|
|
8419
|
-
if (
|
|
8420
|
-
const finalMetrics = parseMetricsFromUsage2(
|
|
9173
|
+
if (event.usage) {
|
|
9174
|
+
const finalMetrics = parseMetricsFromUsage2(event.usage);
|
|
8421
9175
|
metrics = { ...metrics, ...finalMetrics };
|
|
8422
9176
|
}
|
|
8423
|
-
if (
|
|
8424
|
-
metadata = { ...metadata, ...
|
|
9177
|
+
if (event.delta) {
|
|
9178
|
+
metadata = { ...metadata, ...event.delta };
|
|
8425
9179
|
}
|
|
8426
9180
|
break;
|
|
8427
9181
|
}
|
|
@@ -8429,7 +9183,9 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
8429
9183
|
const output = deltas.join("");
|
|
8430
9184
|
const finalized = finalizeAnthropicTokens(metrics);
|
|
8431
9185
|
const filteredMetrics = Object.fromEntries(
|
|
8432
|
-
Object.entries(finalized).filter(
|
|
9186
|
+
Object.entries(finalized).filter(
|
|
9187
|
+
(entry) => entry[1] !== void 0
|
|
9188
|
+
)
|
|
8433
9189
|
);
|
|
8434
9190
|
return {
|
|
8435
9191
|
output,
|
|
@@ -8437,6 +9193,9 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
8437
9193
|
metadata
|
|
8438
9194
|
};
|
|
8439
9195
|
}
|
|
9196
|
+
function isAnthropicBase64ContentBlock(input) {
|
|
9197
|
+
return (input.type === "image" || input.type === "document") && isObject(input.source) && input.source.type === "base64";
|
|
9198
|
+
}
|
|
8440
9199
|
function convertBase64ToAttachment(source, contentType) {
|
|
8441
9200
|
const mediaType = typeof source.media_type === "string" ? source.media_type : "image/png";
|
|
8442
9201
|
const base64Data = source.data;
|
|
@@ -8460,14 +9219,14 @@ function convertBase64ToAttachment(source, contentType) {
|
|
|
8460
9219
|
data: attachment
|
|
8461
9220
|
};
|
|
8462
9221
|
}
|
|
8463
|
-
return source;
|
|
9222
|
+
return { ...source };
|
|
8464
9223
|
}
|
|
8465
9224
|
function processAttachmentsInInput(input) {
|
|
8466
9225
|
if (Array.isArray(input)) {
|
|
8467
9226
|
return input.map(processAttachmentsInInput);
|
|
8468
9227
|
}
|
|
8469
9228
|
if (isObject(input)) {
|
|
8470
|
-
if ((input
|
|
9229
|
+
if (isAnthropicBase64ContentBlock(input)) {
|
|
8471
9230
|
return {
|
|
8472
9231
|
...input,
|
|
8473
9232
|
source: convertBase64ToAttachment(input.source, input.type)
|
|
@@ -8495,306 +9254,755 @@ function filterFrom(obj, fieldsToRemove) {
|
|
|
8495
9254
|
result[key] = value;
|
|
8496
9255
|
}
|
|
8497
9256
|
}
|
|
8498
|
-
return result;
|
|
9257
|
+
return result;
|
|
9258
|
+
}
|
|
9259
|
+
|
|
9260
|
+
// src/wrappers/ai-sdk/normalize-logged-output.ts
|
|
9261
|
+
var REMOVE_NORMALIZED_VALUE = Symbol("braintrust.ai-sdk.remove-normalized");
|
|
9262
|
+
function normalizeAISDKLoggedOutput(value) {
|
|
9263
|
+
const normalized = normalizeAISDKLoggedValue(value);
|
|
9264
|
+
return normalized === REMOVE_NORMALIZED_VALUE ? {} : normalized;
|
|
9265
|
+
}
|
|
9266
|
+
function normalizeAISDKLoggedValue(value, context = {}) {
|
|
9267
|
+
if (Array.isArray(value)) {
|
|
9268
|
+
return value.map((entry) => normalizeAISDKLoggedValue(entry, context)).filter((entry) => entry !== REMOVE_NORMALIZED_VALUE);
|
|
9269
|
+
}
|
|
9270
|
+
if (!value || typeof value !== "object") {
|
|
9271
|
+
return value;
|
|
9272
|
+
}
|
|
9273
|
+
const nextInProviderMetadata = context.inProviderMetadata || context.parentKey === "providerMetadata" || context.parentKey === "experimental_providerMetadata";
|
|
9274
|
+
const normalizedEntries = [];
|
|
9275
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
9276
|
+
if (key === "cachedPromptTokens" && entry === 0) {
|
|
9277
|
+
continue;
|
|
9278
|
+
}
|
|
9279
|
+
if (context.parentKey === "request" && key === "body" && entry === "<omitted>") {
|
|
9280
|
+
continue;
|
|
9281
|
+
}
|
|
9282
|
+
const normalizedEntry = normalizeAISDKLoggedValue(entry, {
|
|
9283
|
+
inProviderMetadata: nextInProviderMetadata,
|
|
9284
|
+
parentKey: key
|
|
9285
|
+
});
|
|
9286
|
+
if (normalizedEntry === REMOVE_NORMALIZED_VALUE) {
|
|
9287
|
+
continue;
|
|
9288
|
+
}
|
|
9289
|
+
normalizedEntries.push([key, normalizedEntry]);
|
|
9290
|
+
}
|
|
9291
|
+
if (normalizedEntries.length === 0) {
|
|
9292
|
+
if (context.parentKey === "request" || nextInProviderMetadata) {
|
|
9293
|
+
return REMOVE_NORMALIZED_VALUE;
|
|
9294
|
+
}
|
|
9295
|
+
return {};
|
|
9296
|
+
}
|
|
9297
|
+
return Object.fromEntries(normalizedEntries);
|
|
9298
|
+
}
|
|
9299
|
+
|
|
9300
|
+
// src/zod/utils.ts
|
|
9301
|
+
import { zodToJsonSchema as zodToJsonSchemaV3 } from "zod-to-json-schema";
|
|
9302
|
+
import * as z42 from "zod/v4";
|
|
9303
|
+
function isZodV4(zodObject) {
|
|
9304
|
+
return typeof zodObject === "object" && zodObject !== null && "_zod" in zodObject && zodObject._zod !== void 0;
|
|
9305
|
+
}
|
|
9306
|
+
function zodToJsonSchema(schema) {
|
|
9307
|
+
if (isZodV4(schema)) {
|
|
9308
|
+
return z42.toJSONSchema(schema, {
|
|
9309
|
+
target: "draft-7"
|
|
9310
|
+
});
|
|
9311
|
+
}
|
|
9312
|
+
return zodToJsonSchemaV3(schema);
|
|
9313
|
+
}
|
|
9314
|
+
|
|
9315
|
+
// src/wrappers/ai-sdk/tool-serialization.ts
|
|
9316
|
+
function isZodSchema(value) {
|
|
9317
|
+
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
9318
|
+
}
|
|
9319
|
+
function serializeZodSchema(schema) {
|
|
9320
|
+
try {
|
|
9321
|
+
return zodToJsonSchema(schema);
|
|
9322
|
+
} catch {
|
|
9323
|
+
return {
|
|
9324
|
+
type: "object",
|
|
9325
|
+
description: "Zod schema (conversion failed)"
|
|
9326
|
+
};
|
|
9327
|
+
}
|
|
9328
|
+
}
|
|
9329
|
+
function serializeTool(tool) {
|
|
9330
|
+
if (!tool || typeof tool !== "object") {
|
|
9331
|
+
return tool;
|
|
9332
|
+
}
|
|
9333
|
+
const serialized = { ...tool };
|
|
9334
|
+
if (isZodSchema(serialized.inputSchema)) {
|
|
9335
|
+
serialized.inputSchema = serializeZodSchema(serialized.inputSchema);
|
|
9336
|
+
}
|
|
9337
|
+
if (isZodSchema(serialized.parameters)) {
|
|
9338
|
+
serialized.parameters = serializeZodSchema(serialized.parameters);
|
|
9339
|
+
}
|
|
9340
|
+
if ("execute" in serialized) {
|
|
9341
|
+
delete serialized.execute;
|
|
9342
|
+
}
|
|
9343
|
+
if ("render" in serialized) {
|
|
9344
|
+
delete serialized.render;
|
|
9345
|
+
}
|
|
9346
|
+
return serialized;
|
|
9347
|
+
}
|
|
9348
|
+
function serializeAISDKToolsForLogging(tools) {
|
|
9349
|
+
if (!tools || typeof tools !== "object") {
|
|
9350
|
+
return tools;
|
|
9351
|
+
}
|
|
9352
|
+
if (Array.isArray(tools)) {
|
|
9353
|
+
return tools.map(serializeTool);
|
|
9354
|
+
}
|
|
9355
|
+
const serialized = {};
|
|
9356
|
+
for (const [key, tool] of Object.entries(tools)) {
|
|
9357
|
+
serialized[key] = serializeTool(tool);
|
|
9358
|
+
}
|
|
9359
|
+
return serialized;
|
|
9360
|
+
}
|
|
9361
|
+
|
|
9362
|
+
// src/instrumentation/plugins/ai-sdk-channels.ts
|
|
9363
|
+
var aiSDKChannels = defineChannels("ai", {
|
|
9364
|
+
generateText: channel({
|
|
9365
|
+
channelName: "generateText",
|
|
9366
|
+
kind: "async"
|
|
9367
|
+
}),
|
|
9368
|
+
streamText: channel({
|
|
9369
|
+
channelName: "streamText",
|
|
9370
|
+
kind: "async"
|
|
9371
|
+
}),
|
|
9372
|
+
streamTextSync: channel({
|
|
9373
|
+
channelName: "streamText.sync",
|
|
9374
|
+
kind: "sync-stream"
|
|
9375
|
+
}),
|
|
9376
|
+
generateObject: channel({
|
|
9377
|
+
channelName: "generateObject",
|
|
9378
|
+
kind: "async"
|
|
9379
|
+
}),
|
|
9380
|
+
streamObject: channel({
|
|
9381
|
+
channelName: "streamObject",
|
|
9382
|
+
kind: "async"
|
|
9383
|
+
}),
|
|
9384
|
+
streamObjectSync: channel({
|
|
9385
|
+
channelName: "streamObject.sync",
|
|
9386
|
+
kind: "sync-stream"
|
|
9387
|
+
}),
|
|
9388
|
+
agentGenerate: channel({
|
|
9389
|
+
channelName: "Agent.generate",
|
|
9390
|
+
kind: "async"
|
|
9391
|
+
}),
|
|
9392
|
+
agentStream: channel({
|
|
9393
|
+
channelName: "Agent.stream",
|
|
9394
|
+
kind: "async"
|
|
9395
|
+
}),
|
|
9396
|
+
toolLoopAgentGenerate: channel({
|
|
9397
|
+
channelName: "ToolLoopAgent.generate",
|
|
9398
|
+
kind: "async"
|
|
9399
|
+
}),
|
|
9400
|
+
toolLoopAgentStream: channel({
|
|
9401
|
+
channelName: "ToolLoopAgent.stream",
|
|
9402
|
+
kind: "async"
|
|
9403
|
+
})
|
|
9404
|
+
});
|
|
9405
|
+
|
|
9406
|
+
// src/instrumentation/plugins/ai-sdk-plugin.ts
|
|
9407
|
+
var DEFAULT_DENY_OUTPUT_PATHS = [
|
|
9408
|
+
// v3
|
|
9409
|
+
"roundtrips[].request.body",
|
|
9410
|
+
"roundtrips[].response.headers",
|
|
9411
|
+
"rawResponse.headers",
|
|
9412
|
+
"responseMessages",
|
|
9413
|
+
// v5
|
|
9414
|
+
"request.body",
|
|
9415
|
+
"response.body",
|
|
9416
|
+
"response.headers",
|
|
9417
|
+
"steps[].request.body",
|
|
9418
|
+
"steps[].response.body",
|
|
9419
|
+
"steps[].response.headers"
|
|
9420
|
+
];
|
|
9421
|
+
var AUTO_PATCHED_MODEL = Symbol.for("braintrust.ai-sdk.auto-patched-model");
|
|
9422
|
+
var AUTO_PATCHED_TOOL = Symbol.for("braintrust.ai-sdk.auto-patched-tool");
|
|
9423
|
+
var AISDKPlugin = class extends BasePlugin {
|
|
9424
|
+
config;
|
|
9425
|
+
constructor(config = {}) {
|
|
9426
|
+
super();
|
|
9427
|
+
this.config = config;
|
|
9428
|
+
}
|
|
9429
|
+
onEnable() {
|
|
9430
|
+
this.subscribeToAISDK();
|
|
9431
|
+
}
|
|
9432
|
+
onDisable() {
|
|
9433
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
9434
|
+
}
|
|
9435
|
+
subscribeToAISDK() {
|
|
9436
|
+
const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
|
|
9437
|
+
this.unsubscribers.push(
|
|
9438
|
+
traceStreamingChannel(aiSDKChannels.generateText, {
|
|
9439
|
+
name: "generateText",
|
|
9440
|
+
type: "llm" /* LLM */,
|
|
9441
|
+
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9442
|
+
extractOutput: (result, endEvent) => {
|
|
9443
|
+
finalizeAISDKChildTracing(endEvent);
|
|
9444
|
+
return processAISDKOutput(result, denyOutputPaths);
|
|
9445
|
+
},
|
|
9446
|
+
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9447
|
+
aggregateChunks: aggregateAISDKChunks
|
|
9448
|
+
})
|
|
9449
|
+
);
|
|
9450
|
+
this.unsubscribers.push(
|
|
9451
|
+
traceStreamingChannel(aiSDKChannels.streamText, {
|
|
9452
|
+
name: "streamText",
|
|
9453
|
+
type: "llm" /* LLM */,
|
|
9454
|
+
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9455
|
+
extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
|
|
9456
|
+
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9457
|
+
aggregateChunks: aggregateAISDKChunks,
|
|
9458
|
+
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9459
|
+
denyOutputPaths,
|
|
9460
|
+
endEvent,
|
|
9461
|
+
result,
|
|
9462
|
+
span,
|
|
9463
|
+
startTime
|
|
9464
|
+
})
|
|
9465
|
+
})
|
|
9466
|
+
);
|
|
9467
|
+
this.unsubscribers.push(
|
|
9468
|
+
traceSyncStreamChannel(aiSDKChannels.streamTextSync, {
|
|
9469
|
+
name: "streamText",
|
|
9470
|
+
type: "llm" /* LLM */,
|
|
9471
|
+
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9472
|
+
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9473
|
+
denyOutputPaths,
|
|
9474
|
+
endEvent,
|
|
9475
|
+
result,
|
|
9476
|
+
span,
|
|
9477
|
+
startTime
|
|
9478
|
+
})
|
|
9479
|
+
})
|
|
9480
|
+
);
|
|
9481
|
+
this.unsubscribers.push(
|
|
9482
|
+
traceStreamingChannel(aiSDKChannels.generateObject, {
|
|
9483
|
+
name: "generateObject",
|
|
9484
|
+
type: "llm" /* LLM */,
|
|
9485
|
+
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9486
|
+
extractOutput: (result, endEvent) => {
|
|
9487
|
+
finalizeAISDKChildTracing(endEvent);
|
|
9488
|
+
return processAISDKOutput(result, denyOutputPaths);
|
|
9489
|
+
},
|
|
9490
|
+
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9491
|
+
aggregateChunks: aggregateAISDKChunks
|
|
9492
|
+
})
|
|
9493
|
+
);
|
|
9494
|
+
this.unsubscribers.push(
|
|
9495
|
+
traceStreamingChannel(aiSDKChannels.streamObject, {
|
|
9496
|
+
name: "streamObject",
|
|
9497
|
+
type: "llm" /* LLM */,
|
|
9498
|
+
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9499
|
+
extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
|
|
9500
|
+
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9501
|
+
aggregateChunks: aggregateAISDKChunks,
|
|
9502
|
+
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9503
|
+
denyOutputPaths,
|
|
9504
|
+
endEvent,
|
|
9505
|
+
result,
|
|
9506
|
+
span,
|
|
9507
|
+
startTime
|
|
9508
|
+
})
|
|
9509
|
+
})
|
|
9510
|
+
);
|
|
9511
|
+
this.unsubscribers.push(
|
|
9512
|
+
traceSyncStreamChannel(aiSDKChannels.streamObjectSync, {
|
|
9513
|
+
name: "streamObject",
|
|
9514
|
+
type: "llm" /* LLM */,
|
|
9515
|
+
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9516
|
+
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9517
|
+
denyOutputPaths,
|
|
9518
|
+
endEvent,
|
|
9519
|
+
result,
|
|
9520
|
+
span,
|
|
9521
|
+
startTime
|
|
9522
|
+
})
|
|
9523
|
+
})
|
|
9524
|
+
);
|
|
9525
|
+
this.unsubscribers.push(
|
|
9526
|
+
traceStreamingChannel(aiSDKChannels.agentGenerate, {
|
|
9527
|
+
name: "Agent.generate",
|
|
9528
|
+
type: "llm" /* LLM */,
|
|
9529
|
+
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9530
|
+
extractOutput: (result, endEvent) => {
|
|
9531
|
+
finalizeAISDKChildTracing(endEvent);
|
|
9532
|
+
return processAISDKOutput(result, denyOutputPaths);
|
|
9533
|
+
},
|
|
9534
|
+
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9535
|
+
aggregateChunks: aggregateAISDKChunks
|
|
9536
|
+
})
|
|
9537
|
+
);
|
|
9538
|
+
this.unsubscribers.push(
|
|
9539
|
+
traceStreamingChannel(aiSDKChannels.agentStream, {
|
|
9540
|
+
name: "Agent.stream",
|
|
9541
|
+
type: "llm" /* LLM */,
|
|
9542
|
+
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9543
|
+
extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
|
|
9544
|
+
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9545
|
+
aggregateChunks: aggregateAISDKChunks,
|
|
9546
|
+
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9547
|
+
denyOutputPaths,
|
|
9548
|
+
endEvent,
|
|
9549
|
+
result,
|
|
9550
|
+
span,
|
|
9551
|
+
startTime
|
|
9552
|
+
})
|
|
9553
|
+
})
|
|
9554
|
+
);
|
|
9555
|
+
this.unsubscribers.push(
|
|
9556
|
+
traceStreamingChannel(aiSDKChannels.toolLoopAgentGenerate, {
|
|
9557
|
+
name: "ToolLoopAgent.generate",
|
|
9558
|
+
type: "llm" /* LLM */,
|
|
9559
|
+
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9560
|
+
extractOutput: (result, endEvent) => {
|
|
9561
|
+
finalizeAISDKChildTracing(endEvent);
|
|
9562
|
+
return processAISDKOutput(result, denyOutputPaths);
|
|
9563
|
+
},
|
|
9564
|
+
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9565
|
+
aggregateChunks: aggregateAISDKChunks
|
|
9566
|
+
})
|
|
9567
|
+
);
|
|
9568
|
+
this.unsubscribers.push(
|
|
9569
|
+
traceStreamingChannel(aiSDKChannels.toolLoopAgentStream, {
|
|
9570
|
+
name: "ToolLoopAgent.stream",
|
|
9571
|
+
type: "llm" /* LLM */,
|
|
9572
|
+
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9573
|
+
extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
|
|
9574
|
+
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9575
|
+
aggregateChunks: aggregateAISDKChunks,
|
|
9576
|
+
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9577
|
+
denyOutputPaths,
|
|
9578
|
+
endEvent,
|
|
9579
|
+
result,
|
|
9580
|
+
span,
|
|
9581
|
+
startTime
|
|
9582
|
+
})
|
|
9583
|
+
})
|
|
9584
|
+
);
|
|
9585
|
+
}
|
|
9586
|
+
};
|
|
9587
|
+
function processAISDKInput(params) {
|
|
9588
|
+
if (!params) return params;
|
|
9589
|
+
const input = processInputAttachments(params);
|
|
9590
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
9591
|
+
return input;
|
|
9592
|
+
}
|
|
9593
|
+
const { tools: _tools, ...rest } = input;
|
|
9594
|
+
return rest;
|
|
9595
|
+
}
|
|
9596
|
+
function prepareAISDKInput(params, event, span, denyOutputPaths) {
|
|
9597
|
+
const input = processAISDKInput(params);
|
|
9598
|
+
const metadata = extractMetadataFromParams(params, event.self);
|
|
9599
|
+
const childTracing = prepareAISDKChildTracing(
|
|
9600
|
+
params,
|
|
9601
|
+
event.self,
|
|
9602
|
+
span,
|
|
9603
|
+
denyOutputPaths
|
|
9604
|
+
);
|
|
9605
|
+
event.__braintrust_ai_sdk_model_wrapped = childTracing.modelWrapped;
|
|
9606
|
+
if (childTracing.cleanup) {
|
|
9607
|
+
event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
|
|
9608
|
+
}
|
|
9609
|
+
return {
|
|
9610
|
+
input,
|
|
9611
|
+
metadata
|
|
9612
|
+
};
|
|
9613
|
+
}
|
|
9614
|
+
function extractTopLevelAISDKMetrics(result, event, startTime) {
|
|
9615
|
+
const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
|
|
9616
|
+
if (startTime) {
|
|
9617
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
9618
|
+
}
|
|
9619
|
+
return metrics;
|
|
8499
9620
|
}
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
"
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
];
|
|
8517
|
-
var AISDKPlugin = class extends BasePlugin {
|
|
8518
|
-
unsubscribers = [];
|
|
8519
|
-
config;
|
|
8520
|
-
constructor(config = {}) {
|
|
8521
|
-
super();
|
|
8522
|
-
this.config = config;
|
|
9621
|
+
function hasModelChildTracing(event) {
|
|
9622
|
+
return event?.__braintrust_ai_sdk_model_wrapped === true;
|
|
9623
|
+
}
|
|
9624
|
+
function extractMetadataFromParams(params, self) {
|
|
9625
|
+
const metadata = {
|
|
9626
|
+
braintrust: {
|
|
9627
|
+
integration_name: "ai-sdk",
|
|
9628
|
+
sdk_language: "typescript"
|
|
9629
|
+
}
|
|
9630
|
+
};
|
|
9631
|
+
const agentModel = self && typeof self === "object" && "model" in self && self.model ? self.model : self && typeof self === "object" && "settings" in self && self.settings?.model ? self.settings?.model : void 0;
|
|
9632
|
+
const { model, provider } = serializeModelWithProvider(
|
|
9633
|
+
params.model ?? agentModel
|
|
9634
|
+
);
|
|
9635
|
+
if (model) {
|
|
9636
|
+
metadata.model = model;
|
|
8523
9637
|
}
|
|
8524
|
-
|
|
8525
|
-
|
|
9638
|
+
if (provider) {
|
|
9639
|
+
metadata.provider = provider;
|
|
8526
9640
|
}
|
|
8527
|
-
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
}
|
|
8531
|
-
this.unsubscribers = [];
|
|
9641
|
+
const tools = serializeAISDKToolsForLogging(params.tools);
|
|
9642
|
+
if (tools) {
|
|
9643
|
+
metadata.tools = tools;
|
|
8532
9644
|
}
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
}
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
return metrics;
|
|
8576
|
-
},
|
|
8577
|
-
aggregateChunks: aggregateAISDKChunks
|
|
8578
|
-
});
|
|
8579
|
-
this.subscribeToStreamingChannel("orchestrion:ai-sdk:generateObject", {
|
|
8580
|
-
name: "generateObject",
|
|
8581
|
-
type: "llm" /* LLM */,
|
|
8582
|
-
extractInput: (args) => {
|
|
8583
|
-
const params = args[0] || {};
|
|
8584
|
-
return {
|
|
8585
|
-
input: processAISDKInput(params),
|
|
8586
|
-
metadata: extractMetadataFromParams(params)
|
|
8587
|
-
};
|
|
8588
|
-
},
|
|
8589
|
-
extractOutput: (result) => {
|
|
8590
|
-
return processAISDKOutput(result, denyOutputPaths);
|
|
8591
|
-
},
|
|
8592
|
-
extractMetrics: (result, startTime) => {
|
|
8593
|
-
const metrics = extractTokenMetrics(result);
|
|
8594
|
-
if (startTime) {
|
|
8595
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8596
|
-
}
|
|
8597
|
-
return metrics;
|
|
8598
|
-
},
|
|
8599
|
-
aggregateChunks: aggregateAISDKChunks
|
|
8600
|
-
});
|
|
8601
|
-
this.subscribeToStreamingChannel("orchestrion:ai-sdk:streamObject", {
|
|
8602
|
-
name: "streamObject",
|
|
8603
|
-
type: "llm" /* LLM */,
|
|
8604
|
-
extractInput: (args) => {
|
|
8605
|
-
const params = args[0] || {};
|
|
8606
|
-
return {
|
|
8607
|
-
input: processAISDKInput(params),
|
|
8608
|
-
metadata: extractMetadataFromParams(params)
|
|
8609
|
-
};
|
|
8610
|
-
},
|
|
8611
|
-
extractOutput: (result) => {
|
|
8612
|
-
return processAISDKOutput(result, denyOutputPaths);
|
|
8613
|
-
},
|
|
8614
|
-
extractMetrics: (result, startTime) => {
|
|
8615
|
-
const metrics = extractTokenMetrics(result);
|
|
8616
|
-
if (startTime) {
|
|
8617
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8618
|
-
}
|
|
8619
|
-
return metrics;
|
|
8620
|
-
},
|
|
8621
|
-
aggregateChunks: aggregateAISDKChunks
|
|
8622
|
-
});
|
|
8623
|
-
this.subscribeToStreamingChannel("orchestrion:ai-sdk:Agent.generate", {
|
|
8624
|
-
name: "Agent.generate",
|
|
8625
|
-
type: "llm" /* LLM */,
|
|
8626
|
-
extractInput: (args) => {
|
|
8627
|
-
const params = args[0] || {};
|
|
8628
|
-
return {
|
|
8629
|
-
input: processAISDKInput(params),
|
|
8630
|
-
metadata: extractMetadataFromParams(params)
|
|
8631
|
-
};
|
|
8632
|
-
},
|
|
8633
|
-
extractOutput: (result) => {
|
|
8634
|
-
return processAISDKOutput(result, denyOutputPaths);
|
|
8635
|
-
},
|
|
8636
|
-
extractMetrics: (result, startTime) => {
|
|
8637
|
-
const metrics = extractTokenMetrics(result);
|
|
8638
|
-
if (startTime) {
|
|
8639
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8640
|
-
}
|
|
8641
|
-
return metrics;
|
|
8642
|
-
},
|
|
8643
|
-
aggregateChunks: aggregateAISDKChunks
|
|
8644
|
-
});
|
|
8645
|
-
this.subscribeToStreamingChannel("orchestrion:ai-sdk:Agent.stream", {
|
|
8646
|
-
name: "Agent.stream",
|
|
8647
|
-
type: "llm" /* LLM */,
|
|
8648
|
-
extractInput: (args) => {
|
|
8649
|
-
const params = args[0] || {};
|
|
8650
|
-
return {
|
|
8651
|
-
input: processAISDKInput(params),
|
|
8652
|
-
metadata: extractMetadataFromParams(params)
|
|
8653
|
-
};
|
|
8654
|
-
},
|
|
8655
|
-
extractOutput: (result) => {
|
|
8656
|
-
return processAISDKOutput(result, denyOutputPaths);
|
|
8657
|
-
},
|
|
8658
|
-
extractMetrics: (result, startTime) => {
|
|
8659
|
-
const metrics = extractTokenMetrics(result);
|
|
8660
|
-
if (startTime) {
|
|
8661
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
9645
|
+
return metadata;
|
|
9646
|
+
}
|
|
9647
|
+
function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
9648
|
+
const cleanup = [];
|
|
9649
|
+
const patchedModels = /* @__PURE__ */ new WeakSet();
|
|
9650
|
+
const patchedTools = /* @__PURE__ */ new WeakSet();
|
|
9651
|
+
let modelWrapped = false;
|
|
9652
|
+
const patchModel = (model) => {
|
|
9653
|
+
const resolvedModel = resolveAISDKModel(model);
|
|
9654
|
+
if (!resolvedModel || typeof resolvedModel !== "object" || typeof resolvedModel.doGenerate !== "function" || patchedModels.has(resolvedModel) || resolvedModel[AUTO_PATCHED_MODEL]) {
|
|
9655
|
+
return;
|
|
9656
|
+
}
|
|
9657
|
+
patchedModels.add(resolvedModel);
|
|
9658
|
+
resolvedModel[AUTO_PATCHED_MODEL] = true;
|
|
9659
|
+
modelWrapped = true;
|
|
9660
|
+
const originalDoGenerate = resolvedModel.doGenerate;
|
|
9661
|
+
const originalDoStream = resolvedModel.doStream;
|
|
9662
|
+
const baseMetadata = buildAISDKChildMetadata(resolvedModel);
|
|
9663
|
+
resolvedModel.doGenerate = async function doGeneratePatched(options) {
|
|
9664
|
+
return parentSpan.traced(
|
|
9665
|
+
async (span) => {
|
|
9666
|
+
const result = await Reflect.apply(
|
|
9667
|
+
originalDoGenerate,
|
|
9668
|
+
resolvedModel,
|
|
9669
|
+
[options]
|
|
9670
|
+
);
|
|
9671
|
+
span.log({
|
|
9672
|
+
output: processAISDKOutput(result, denyOutputPaths),
|
|
9673
|
+
metrics: extractTokenMetrics(result),
|
|
9674
|
+
...buildResolvedMetadataPayload(result)
|
|
9675
|
+
});
|
|
9676
|
+
return result;
|
|
9677
|
+
},
|
|
9678
|
+
{
|
|
9679
|
+
name: "doGenerate",
|
|
9680
|
+
spanAttributes: {
|
|
9681
|
+
type: "llm" /* LLM */
|
|
9682
|
+
},
|
|
9683
|
+
event: {
|
|
9684
|
+
input: processAISDKInput(options),
|
|
9685
|
+
metadata: baseMetadata
|
|
9686
|
+
}
|
|
8662
9687
|
}
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
* Subscribe to a channel for async methods that may return streams.
|
|
8670
|
-
* Handles both streaming and non-streaming responses.
|
|
8671
|
-
*/
|
|
8672
|
-
subscribeToStreamingChannel(channelName, config) {
|
|
8673
|
-
const channel = tracingChannel3(channelName);
|
|
8674
|
-
const spans = /* @__PURE__ */ new WeakMap();
|
|
8675
|
-
const handlers = {
|
|
8676
|
-
start: (event) => {
|
|
8677
|
-
const span = startSpan({
|
|
8678
|
-
name: config.name,
|
|
9688
|
+
);
|
|
9689
|
+
};
|
|
9690
|
+
if (originalDoStream) {
|
|
9691
|
+
resolvedModel.doStream = async function doStreamPatched(options) {
|
|
9692
|
+
const span = parentSpan.startSpan({
|
|
9693
|
+
name: "doStream",
|
|
8679
9694
|
spanAttributes: {
|
|
8680
|
-
type:
|
|
9695
|
+
type: "llm" /* LLM */
|
|
9696
|
+
},
|
|
9697
|
+
event: {
|
|
9698
|
+
input: processAISDKInput(options),
|
|
9699
|
+
metadata: baseMetadata
|
|
8681
9700
|
}
|
|
8682
9701
|
});
|
|
8683
|
-
const
|
|
8684
|
-
|
|
8685
|
-
|
|
8686
|
-
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
onComplete: (chunks) => {
|
|
8704
|
-
try {
|
|
8705
|
-
let output;
|
|
8706
|
-
let metrics;
|
|
8707
|
-
if (config.aggregateChunks) {
|
|
8708
|
-
const aggregated = config.aggregateChunks(chunks);
|
|
8709
|
-
output = aggregated.output;
|
|
8710
|
-
metrics = aggregated.metrics;
|
|
8711
|
-
} else {
|
|
8712
|
-
output = config.extractOutput(chunks);
|
|
8713
|
-
metrics = config.extractMetrics(chunks, startTime);
|
|
9702
|
+
const result = await withCurrent(
|
|
9703
|
+
span,
|
|
9704
|
+
() => Reflect.apply(originalDoStream, resolvedModel, [options])
|
|
9705
|
+
);
|
|
9706
|
+
const output = {};
|
|
9707
|
+
let text = "";
|
|
9708
|
+
let reasoning = "";
|
|
9709
|
+
const toolCalls = [];
|
|
9710
|
+
let object = void 0;
|
|
9711
|
+
const transformStream = new TransformStream({
|
|
9712
|
+
transform(chunk, controller) {
|
|
9713
|
+
switch (chunk.type) {
|
|
9714
|
+
case "text-delta":
|
|
9715
|
+
text += extractTextDelta(chunk);
|
|
9716
|
+
break;
|
|
9717
|
+
case "reasoning-delta":
|
|
9718
|
+
if (chunk.delta) {
|
|
9719
|
+
reasoning += chunk.delta;
|
|
9720
|
+
} else if (chunk.text) {
|
|
9721
|
+
reasoning += chunk.text;
|
|
8714
9722
|
}
|
|
8715
|
-
|
|
8716
|
-
|
|
9723
|
+
break;
|
|
9724
|
+
case "tool-call":
|
|
9725
|
+
toolCalls.push(chunk);
|
|
9726
|
+
break;
|
|
9727
|
+
case "object":
|
|
9728
|
+
object = chunk.object;
|
|
9729
|
+
break;
|
|
9730
|
+
case "raw":
|
|
9731
|
+
if (chunk.rawValue) {
|
|
9732
|
+
const rawVal = chunk.rawValue;
|
|
9733
|
+
if (rawVal.delta?.content) {
|
|
9734
|
+
text += rawVal.delta.content;
|
|
9735
|
+
} else if (rawVal.choices?.[0]?.delta?.content) {
|
|
9736
|
+
text += rawVal.choices[0].delta.content;
|
|
9737
|
+
} else if (typeof rawVal.text === "string") {
|
|
9738
|
+
text += rawVal.text;
|
|
9739
|
+
} else if (typeof rawVal.content === "string") {
|
|
9740
|
+
text += rawVal.content;
|
|
9741
|
+
}
|
|
9742
|
+
}
|
|
9743
|
+
break;
|
|
9744
|
+
case "finish":
|
|
9745
|
+
output.text = text;
|
|
9746
|
+
output.reasoning = reasoning;
|
|
9747
|
+
output.toolCalls = toolCalls;
|
|
9748
|
+
output.finishReason = chunk.finishReason;
|
|
9749
|
+
output.usage = chunk.usage;
|
|
9750
|
+
if (object !== void 0) {
|
|
9751
|
+
output.object = object;
|
|
8717
9752
|
}
|
|
8718
9753
|
span.log({
|
|
8719
|
-
output
|
|
8720
|
-
|
|
9754
|
+
output: processAISDKOutput(
|
|
9755
|
+
output,
|
|
9756
|
+
denyOutputPaths
|
|
9757
|
+
),
|
|
9758
|
+
metrics: extractTokenMetrics(output),
|
|
9759
|
+
...buildResolvedMetadataPayload(output)
|
|
8721
9760
|
});
|
|
8722
|
-
} catch (error) {
|
|
8723
|
-
console.error(
|
|
8724
|
-
`Error extracting output for ${channelName}:`,
|
|
8725
|
-
error
|
|
8726
|
-
);
|
|
8727
|
-
} finally {
|
|
8728
9761
|
span.end();
|
|
8729
|
-
|
|
8730
|
-
}
|
|
8731
|
-
|
|
8732
|
-
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
|
|
9762
|
+
break;
|
|
9763
|
+
}
|
|
9764
|
+
controller.enqueue(chunk);
|
|
9765
|
+
}
|
|
9766
|
+
});
|
|
9767
|
+
return {
|
|
9768
|
+
...result,
|
|
9769
|
+
stream: result.stream.pipeThrough(transformStream)
|
|
9770
|
+
};
|
|
9771
|
+
};
|
|
9772
|
+
}
|
|
9773
|
+
cleanup.push(() => {
|
|
9774
|
+
resolvedModel.doGenerate = originalDoGenerate;
|
|
9775
|
+
if (originalDoStream) {
|
|
9776
|
+
resolvedModel.doStream = originalDoStream;
|
|
9777
|
+
}
|
|
9778
|
+
delete resolvedModel[AUTO_PATCHED_MODEL];
|
|
9779
|
+
});
|
|
9780
|
+
};
|
|
9781
|
+
const patchTool = (tool, name) => {
|
|
9782
|
+
if (tool == null || typeof tool !== "object" || !("execute" in tool) || typeof tool.execute !== "function" || patchedTools.has(tool) || tool[AUTO_PATCHED_TOOL]) {
|
|
9783
|
+
return;
|
|
9784
|
+
}
|
|
9785
|
+
patchedTools.add(tool);
|
|
9786
|
+
tool[AUTO_PATCHED_TOOL] = true;
|
|
9787
|
+
const originalExecute = tool.execute;
|
|
9788
|
+
tool.execute = function executePatched(...args) {
|
|
9789
|
+
const result = Reflect.apply(originalExecute, this, args);
|
|
9790
|
+
if (isAsyncGenerator(result)) {
|
|
9791
|
+
return (async function* () {
|
|
9792
|
+
const span = parentSpan.startSpan({
|
|
9793
|
+
name,
|
|
9794
|
+
spanAttributes: {
|
|
9795
|
+
type: "tool" /* TOOL */
|
|
8736
9796
|
}
|
|
8737
9797
|
});
|
|
8738
|
-
|
|
9798
|
+
span.log({ input: args.length === 1 ? args[0] : args });
|
|
8739
9799
|
try {
|
|
8740
|
-
|
|
8741
|
-
const
|
|
9800
|
+
let lastValue;
|
|
9801
|
+
for await (const value of result) {
|
|
9802
|
+
lastValue = value;
|
|
9803
|
+
yield value;
|
|
9804
|
+
}
|
|
9805
|
+
span.log({ output: lastValue });
|
|
9806
|
+
} catch (error) {
|
|
8742
9807
|
span.log({
|
|
8743
|
-
|
|
8744
|
-
metrics
|
|
9808
|
+
error: error instanceof Error ? error.message : String(error)
|
|
8745
9809
|
});
|
|
8746
|
-
|
|
8747
|
-
console.error(`Error extracting output for ${channelName}:`, error);
|
|
9810
|
+
throw error;
|
|
8748
9811
|
} finally {
|
|
8749
9812
|
span.end();
|
|
8750
|
-
spans.delete(event);
|
|
8751
9813
|
}
|
|
9814
|
+
})();
|
|
9815
|
+
}
|
|
9816
|
+
return parentSpan.traced(
|
|
9817
|
+
async (span) => {
|
|
9818
|
+
span.log({ input: args.length === 1 ? args[0] : args });
|
|
9819
|
+
const awaitedResult = await result;
|
|
9820
|
+
span.log({ output: awaitedResult });
|
|
9821
|
+
return awaitedResult;
|
|
9822
|
+
},
|
|
9823
|
+
{
|
|
9824
|
+
name,
|
|
9825
|
+
spanAttributes: {
|
|
9826
|
+
type: "tool" /* TOOL */
|
|
9827
|
+
}
|
|
9828
|
+
}
|
|
9829
|
+
);
|
|
9830
|
+
};
|
|
9831
|
+
cleanup.push(() => {
|
|
9832
|
+
tool.execute = originalExecute;
|
|
9833
|
+
delete tool[AUTO_PATCHED_TOOL];
|
|
9834
|
+
});
|
|
9835
|
+
};
|
|
9836
|
+
const patchTools = (tools) => {
|
|
9837
|
+
if (!tools) {
|
|
9838
|
+
return;
|
|
9839
|
+
}
|
|
9840
|
+
const inferName = (tool, fallback) => tool && (tool.name || tool.toolName || tool.id) || fallback;
|
|
9841
|
+
if (Array.isArray(tools)) {
|
|
9842
|
+
tools.forEach(
|
|
9843
|
+
(tool, index) => patchTool(tool, inferName(tool, `tool[${index}]`))
|
|
9844
|
+
);
|
|
9845
|
+
return;
|
|
9846
|
+
}
|
|
9847
|
+
for (const [key, tool] of Object.entries(tools)) {
|
|
9848
|
+
patchTool(tool, key);
|
|
9849
|
+
}
|
|
9850
|
+
};
|
|
9851
|
+
if (params && typeof params === "object") {
|
|
9852
|
+
patchModel(params.model);
|
|
9853
|
+
patchTools(params.tools);
|
|
9854
|
+
}
|
|
9855
|
+
if (self && typeof self === "object") {
|
|
9856
|
+
const selfRecord = self;
|
|
9857
|
+
if (selfRecord.model !== void 0) {
|
|
9858
|
+
patchModel(selfRecord.model);
|
|
9859
|
+
}
|
|
9860
|
+
if (selfRecord.settings && typeof selfRecord.settings === "object") {
|
|
9861
|
+
if (selfRecord.settings.model !== void 0) {
|
|
9862
|
+
patchModel(selfRecord.settings.model);
|
|
9863
|
+
}
|
|
9864
|
+
if (selfRecord.settings.tools !== void 0) {
|
|
9865
|
+
patchTools(selfRecord.settings.tools);
|
|
9866
|
+
}
|
|
9867
|
+
}
|
|
9868
|
+
}
|
|
9869
|
+
return {
|
|
9870
|
+
cleanup: cleanup.length > 0 ? () => {
|
|
9871
|
+
while (cleanup.length > 0) {
|
|
9872
|
+
cleanup.pop()?.();
|
|
9873
|
+
}
|
|
9874
|
+
} : void 0,
|
|
9875
|
+
modelWrapped
|
|
9876
|
+
};
|
|
9877
|
+
}
|
|
9878
|
+
function finalizeAISDKChildTracing(event) {
|
|
9879
|
+
const cleanup = event?.__braintrust_ai_sdk_cleanup;
|
|
9880
|
+
if (event && typeof cleanup === "function") {
|
|
9881
|
+
cleanup();
|
|
9882
|
+
delete event.__braintrust_ai_sdk_cleanup;
|
|
9883
|
+
}
|
|
9884
|
+
}
|
|
9885
|
+
function patchAISDKStreamingResult(args) {
|
|
9886
|
+
const { denyOutputPaths, endEvent, result, span, startTime } = args;
|
|
9887
|
+
if (!result || typeof result !== "object") {
|
|
9888
|
+
return false;
|
|
9889
|
+
}
|
|
9890
|
+
const resultRecord = result;
|
|
9891
|
+
if (!isReadableStreamLike(resultRecord.baseStream)) {
|
|
9892
|
+
return false;
|
|
9893
|
+
}
|
|
9894
|
+
let firstChunkTime;
|
|
9895
|
+
const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
|
|
9896
|
+
new TransformStream({
|
|
9897
|
+
transform(chunk, controller) {
|
|
9898
|
+
if (firstChunkTime === void 0) {
|
|
9899
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
8752
9900
|
}
|
|
9901
|
+
controller.enqueue(chunk);
|
|
8753
9902
|
},
|
|
8754
|
-
|
|
8755
|
-
const
|
|
8756
|
-
if (
|
|
8757
|
-
|
|
9903
|
+
async flush() {
|
|
9904
|
+
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
9905
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
9906
|
+
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
8758
9907
|
}
|
|
8759
|
-
const
|
|
9908
|
+
const output = await processAISDKStreamingOutput(
|
|
9909
|
+
result,
|
|
9910
|
+
denyOutputPaths
|
|
9911
|
+
);
|
|
9912
|
+
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
8760
9913
|
span.log({
|
|
8761
|
-
|
|
9914
|
+
output,
|
|
9915
|
+
...metadata ? { metadata } : {},
|
|
9916
|
+
metrics
|
|
8762
9917
|
});
|
|
9918
|
+
finalizeAISDKChildTracing(endEvent);
|
|
8763
9919
|
span.end();
|
|
8764
|
-
spans.delete(event);
|
|
8765
9920
|
}
|
|
8766
|
-
}
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
|
|
8770
|
-
|
|
9921
|
+
})
|
|
9922
|
+
);
|
|
9923
|
+
Object.defineProperty(resultRecord, "baseStream", {
|
|
9924
|
+
configurable: true,
|
|
9925
|
+
enumerable: true,
|
|
9926
|
+
value: wrappedBaseStream,
|
|
9927
|
+
writable: true
|
|
9928
|
+
});
|
|
9929
|
+
return true;
|
|
9930
|
+
}
|
|
9931
|
+
function isReadableStreamLike(value) {
|
|
9932
|
+
return value != null && typeof value === "object" && typeof value.pipeThrough === "function";
|
|
9933
|
+
}
|
|
9934
|
+
async function processAISDKStreamingOutput(result, denyOutputPaths) {
|
|
9935
|
+
const output = processAISDKOutput(result, denyOutputPaths);
|
|
9936
|
+
if (!output || typeof output !== "object") {
|
|
9937
|
+
return output;
|
|
9938
|
+
}
|
|
9939
|
+
const outputRecord = output;
|
|
9940
|
+
try {
|
|
9941
|
+
if ("text" in result && typeof result.text === "string") {
|
|
9942
|
+
outputRecord.text = result.text;
|
|
9943
|
+
}
|
|
9944
|
+
} catch {
|
|
9945
|
+
}
|
|
9946
|
+
try {
|
|
9947
|
+
if ("object" in result) {
|
|
9948
|
+
const resolvedObject = await Promise.resolve(result.object);
|
|
9949
|
+
if (resolvedObject !== void 0) {
|
|
9950
|
+
outputRecord.object = resolvedObject;
|
|
9951
|
+
}
|
|
9952
|
+
}
|
|
9953
|
+
} catch {
|
|
8771
9954
|
}
|
|
8772
|
-
|
|
8773
|
-
function processAISDKInput(params) {
|
|
8774
|
-
if (!params) return params;
|
|
8775
|
-
return processInputAttachments(params);
|
|
9955
|
+
return outputRecord;
|
|
8776
9956
|
}
|
|
8777
|
-
function
|
|
8778
|
-
const
|
|
9957
|
+
function buildAISDKChildMetadata(model) {
|
|
9958
|
+
const { model: modelId, provider } = serializeModelWithProvider(model);
|
|
9959
|
+
return {
|
|
9960
|
+
...modelId ? { model: modelId } : {},
|
|
9961
|
+
...provider ? { provider } : {},
|
|
8779
9962
|
braintrust: {
|
|
8780
9963
|
integration_name: "ai-sdk",
|
|
8781
9964
|
sdk_language: "typescript"
|
|
8782
9965
|
}
|
|
8783
9966
|
};
|
|
8784
|
-
|
|
8785
|
-
|
|
8786
|
-
|
|
9967
|
+
}
|
|
9968
|
+
function buildResolvedMetadataPayload(result) {
|
|
9969
|
+
const gatewayInfo = extractGatewayRoutingInfo(result);
|
|
9970
|
+
const metadata = {};
|
|
9971
|
+
if (gatewayInfo?.provider) {
|
|
9972
|
+
metadata.provider = gatewayInfo.provider;
|
|
8787
9973
|
}
|
|
8788
|
-
if (
|
|
8789
|
-
metadata.
|
|
9974
|
+
if (gatewayInfo?.model) {
|
|
9975
|
+
metadata.model = gatewayInfo.model;
|
|
8790
9976
|
}
|
|
8791
|
-
|
|
9977
|
+
if (result.finishReason !== void 0) {
|
|
9978
|
+
metadata.finish_reason = result.finishReason;
|
|
9979
|
+
}
|
|
9980
|
+
return Object.keys(metadata).length > 0 ? { metadata } : {};
|
|
9981
|
+
}
|
|
9982
|
+
function resolveAISDKModel(model) {
|
|
9983
|
+
if (typeof model !== "string") {
|
|
9984
|
+
return model;
|
|
9985
|
+
}
|
|
9986
|
+
const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? null;
|
|
9987
|
+
if (provider && typeof provider.languageModel === "function") {
|
|
9988
|
+
return provider.languageModel(model);
|
|
9989
|
+
}
|
|
9990
|
+
return model;
|
|
9991
|
+
}
|
|
9992
|
+
function extractTextDelta(chunk) {
|
|
9993
|
+
if (typeof chunk.textDelta === "string") return chunk.textDelta;
|
|
9994
|
+
if (typeof chunk.delta === "string") return chunk.delta;
|
|
9995
|
+
if (typeof chunk.text === "string") return chunk.text;
|
|
9996
|
+
if (typeof chunk.content === "string") return chunk.content;
|
|
9997
|
+
return "";
|
|
9998
|
+
}
|
|
9999
|
+
function isAsyncGenerator(value) {
|
|
10000
|
+
return value != null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function" && typeof value.next === "function" && typeof value.return === "function" && typeof value.throw === "function";
|
|
8792
10001
|
}
|
|
8793
10002
|
function processAISDKOutput(output, denyOutputPaths) {
|
|
8794
10003
|
if (!output) return output;
|
|
8795
|
-
const
|
|
8796
|
-
|
|
8797
|
-
return omit(merged, denyOutputPaths);
|
|
10004
|
+
const merged = extractSerializableOutputFields(output);
|
|
10005
|
+
return normalizeAISDKLoggedOutput(omit(merged, denyOutputPaths));
|
|
8798
10006
|
}
|
|
8799
10007
|
function extractTokenMetrics(result) {
|
|
8800
10008
|
const metrics = {};
|
|
@@ -8844,12 +10052,14 @@ function extractTokenMetrics(result) {
|
|
|
8844
10052
|
}
|
|
8845
10053
|
return metrics;
|
|
8846
10054
|
}
|
|
8847
|
-
function aggregateAISDKChunks(chunks) {
|
|
10055
|
+
function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
8848
10056
|
const lastChunk = chunks[chunks.length - 1];
|
|
8849
10057
|
const output = {};
|
|
8850
10058
|
let metrics = {};
|
|
10059
|
+
let metadata;
|
|
8851
10060
|
if (lastChunk) {
|
|
8852
|
-
metrics = extractTokenMetrics(lastChunk);
|
|
10061
|
+
metrics = hasModelChildTracing(endEvent) ? {} : extractTokenMetrics(lastChunk);
|
|
10062
|
+
metadata = buildResolvedMetadataPayload(lastChunk).metadata;
|
|
8853
10063
|
if (lastChunk.text !== void 0) {
|
|
8854
10064
|
output.text = lastChunk.text;
|
|
8855
10065
|
}
|
|
@@ -8863,7 +10073,8 @@ function aggregateAISDKChunks(chunks) {
|
|
|
8863
10073
|
output.toolCalls = lastChunk.toolCalls;
|
|
8864
10074
|
}
|
|
8865
10075
|
}
|
|
8866
|
-
|
|
10076
|
+
finalizeAISDKChildTracing(endEvent);
|
|
10077
|
+
return { output, metrics, metadata };
|
|
8867
10078
|
}
|
|
8868
10079
|
function extractGetterValues(obj) {
|
|
8869
10080
|
const getterValues = {};
|
|
@@ -8883,7 +10094,7 @@ function extractGetterValues(obj) {
|
|
|
8883
10094
|
];
|
|
8884
10095
|
for (const name of getterNames) {
|
|
8885
10096
|
try {
|
|
8886
|
-
if (obj && name in obj &&
|
|
10097
|
+
if (obj && name in obj && isSerializableOutputValue(obj[name])) {
|
|
8887
10098
|
getterValues[name] = obj[name];
|
|
8888
10099
|
}
|
|
8889
10100
|
} catch {
|
|
@@ -8891,6 +10102,47 @@ function extractGetterValues(obj) {
|
|
|
8891
10102
|
}
|
|
8892
10103
|
return getterValues;
|
|
8893
10104
|
}
|
|
10105
|
+
function extractSerializableOutputFields(output) {
|
|
10106
|
+
const serialized = {};
|
|
10107
|
+
const directFieldNames = [
|
|
10108
|
+
"steps",
|
|
10109
|
+
"request",
|
|
10110
|
+
"responseMessages",
|
|
10111
|
+
"warnings",
|
|
10112
|
+
"rawResponse",
|
|
10113
|
+
"response",
|
|
10114
|
+
"providerMetadata",
|
|
10115
|
+
"experimental_providerMetadata"
|
|
10116
|
+
];
|
|
10117
|
+
for (const name of directFieldNames) {
|
|
10118
|
+
try {
|
|
10119
|
+
const value = output?.[name];
|
|
10120
|
+
if (isSerializableOutputValue(value)) {
|
|
10121
|
+
serialized[name] = value;
|
|
10122
|
+
}
|
|
10123
|
+
} catch {
|
|
10124
|
+
}
|
|
10125
|
+
}
|
|
10126
|
+
return {
|
|
10127
|
+
...serialized,
|
|
10128
|
+
...extractGetterValues(output)
|
|
10129
|
+
};
|
|
10130
|
+
}
|
|
10131
|
+
function isSerializableOutputValue(value) {
|
|
10132
|
+
if (typeof value === "function") {
|
|
10133
|
+
return false;
|
|
10134
|
+
}
|
|
10135
|
+
if (value && typeof value === "object" && typeof value.then === "function") {
|
|
10136
|
+
return false;
|
|
10137
|
+
}
|
|
10138
|
+
if (value && typeof value === "object" && typeof value.getReader === "function") {
|
|
10139
|
+
return false;
|
|
10140
|
+
}
|
|
10141
|
+
if (value && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function") {
|
|
10142
|
+
return false;
|
|
10143
|
+
}
|
|
10144
|
+
return true;
|
|
10145
|
+
}
|
|
8894
10146
|
function serializeModelWithProvider(model) {
|
|
8895
10147
|
const modelId = typeof model === "string" ? model : model?.modelId;
|
|
8896
10148
|
const explicitProvider = typeof model === "object" ? model?.provider : void 0;
|
|
@@ -8916,6 +10168,25 @@ function parseGatewayModelString(modelString) {
|
|
|
8916
10168
|
}
|
|
8917
10169
|
return { model: modelString };
|
|
8918
10170
|
}
|
|
10171
|
+
function extractGatewayRoutingInfo(result) {
|
|
10172
|
+
if (result?.steps && Array.isArray(result.steps) && result.steps.length > 0) {
|
|
10173
|
+
const routing2 = result.steps[0]?.providerMetadata?.gateway?.routing;
|
|
10174
|
+
if (routing2) {
|
|
10175
|
+
return {
|
|
10176
|
+
provider: routing2.resolvedProvider || routing2.finalProvider,
|
|
10177
|
+
model: routing2.resolvedProviderApiModelId
|
|
10178
|
+
};
|
|
10179
|
+
}
|
|
10180
|
+
}
|
|
10181
|
+
const routing = result?.providerMetadata?.gateway?.routing;
|
|
10182
|
+
if (routing) {
|
|
10183
|
+
return {
|
|
10184
|
+
provider: routing.resolvedProvider || routing.finalProvider,
|
|
10185
|
+
model: routing.resolvedProviderApiModelId
|
|
10186
|
+
};
|
|
10187
|
+
}
|
|
10188
|
+
return null;
|
|
10189
|
+
}
|
|
8919
10190
|
function extractCostFromResult(result) {
|
|
8920
10191
|
if (result?.steps && Array.isArray(result.steps) && result.steps.length > 0) {
|
|
8921
10192
|
let totalCost = 0;
|
|
@@ -9009,7 +10280,10 @@ function omitAtPath(obj, keys) {
|
|
|
9009
10280
|
if (Array.isArray(obj)) {
|
|
9010
10281
|
obj.forEach((item) => {
|
|
9011
10282
|
if (remainingKeys.length > 0) {
|
|
9012
|
-
omitAtPath(
|
|
10283
|
+
omitAtPath(
|
|
10284
|
+
item,
|
|
10285
|
+
remainingKeys
|
|
10286
|
+
);
|
|
9013
10287
|
}
|
|
9014
10288
|
});
|
|
9015
10289
|
}
|
|
@@ -9019,7 +10293,10 @@ function omitAtPath(obj, keys) {
|
|
|
9019
10293
|
}
|
|
9020
10294
|
} else {
|
|
9021
10295
|
if (obj && typeof obj === "object" && firstKey in obj) {
|
|
9022
|
-
omitAtPath(
|
|
10296
|
+
omitAtPath(
|
|
10297
|
+
obj[firstKey],
|
|
10298
|
+
remainingKeys
|
|
10299
|
+
);
|
|
9023
10300
|
}
|
|
9024
10301
|
}
|
|
9025
10302
|
}
|
|
@@ -9032,8 +10309,18 @@ function omit(obj, paths) {
|
|
|
9032
10309
|
return result;
|
|
9033
10310
|
}
|
|
9034
10311
|
|
|
10312
|
+
// src/instrumentation/plugins/claude-agent-sdk-channels.ts
|
|
10313
|
+
var claudeAgentSDKChannels = defineChannels(
|
|
10314
|
+
"@anthropic-ai/claude-agent-sdk",
|
|
10315
|
+
{
|
|
10316
|
+
query: channel({
|
|
10317
|
+
channelName: "query",
|
|
10318
|
+
kind: "async"
|
|
10319
|
+
})
|
|
10320
|
+
}
|
|
10321
|
+
);
|
|
10322
|
+
|
|
9035
10323
|
// src/instrumentation/plugins/claude-agent-sdk-plugin.ts
|
|
9036
|
-
import { tracingChannel as tracingChannel4 } from "dc-browser";
|
|
9037
10324
|
function filterSerializableOptions(options) {
|
|
9038
10325
|
const allowedKeys = [
|
|
9039
10326
|
"model",
|
|
@@ -9117,7 +10404,9 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
|
|
|
9117
10404
|
const input = buildLLMInput(prompt, conversationHistory);
|
|
9118
10405
|
const outputs = messages.map(
|
|
9119
10406
|
(m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
|
|
9120
|
-
).filter(
|
|
10407
|
+
).filter(
|
|
10408
|
+
(c) => c !== void 0
|
|
10409
|
+
);
|
|
9121
10410
|
const span = startSpan({
|
|
9122
10411
|
name: "anthropic.messages.create",
|
|
9123
10412
|
spanAttributes: {
|
|
@@ -9136,7 +10425,6 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
|
|
|
9136
10425
|
return lastMessage.message?.content && lastMessage.message?.role ? { content: lastMessage.message.content, role: lastMessage.message.role } : void 0;
|
|
9137
10426
|
}
|
|
9138
10427
|
var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
9139
|
-
unsubscribers = [];
|
|
9140
10428
|
onEnable() {
|
|
9141
10429
|
this.subscribeToQuery();
|
|
9142
10430
|
}
|
|
@@ -9152,12 +10440,13 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9152
10440
|
* and individual LLM calls.
|
|
9153
10441
|
*/
|
|
9154
10442
|
subscribeToQuery() {
|
|
9155
|
-
const
|
|
10443
|
+
const channel2 = claudeAgentSDKChannels.query.tracingChannel();
|
|
9156
10444
|
const spans = /* @__PURE__ */ new WeakMap();
|
|
9157
10445
|
const handlers = {
|
|
9158
10446
|
start: (event) => {
|
|
9159
|
-
const params = event.arguments[0]
|
|
9160
|
-
const
|
|
10447
|
+
const params = event.arguments[0];
|
|
10448
|
+
const prompt = params?.prompt;
|
|
10449
|
+
const options = params?.options ?? {};
|
|
9161
10450
|
const span = startSpan({
|
|
9162
10451
|
name: "Claude Agent",
|
|
9163
10452
|
spanAttributes: {
|
|
@@ -9169,7 +10458,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9169
10458
|
span.log({
|
|
9170
10459
|
input: typeof prompt === "string" ? prompt : {
|
|
9171
10460
|
type: "streaming",
|
|
9172
|
-
description: "AsyncIterable<
|
|
10461
|
+
description: "AsyncIterable<ClaudeAgentSDKMessage>"
|
|
9173
10462
|
},
|
|
9174
10463
|
metadata: filterSerializableOptions(options)
|
|
9175
10464
|
});
|
|
@@ -9191,12 +10480,19 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9191
10480
|
if (!spanData) {
|
|
9192
10481
|
return;
|
|
9193
10482
|
}
|
|
9194
|
-
|
|
9195
|
-
|
|
10483
|
+
const eventResult = event.result;
|
|
10484
|
+
if (eventResult === void 0) {
|
|
10485
|
+
spanData.span.end();
|
|
10486
|
+
spans.delete(event);
|
|
10487
|
+
return;
|
|
10488
|
+
}
|
|
10489
|
+
if (isAsyncIterable(eventResult)) {
|
|
10490
|
+
patchStreamIfNeeded(eventResult, {
|
|
9196
10491
|
onChunk: async (message) => {
|
|
9197
10492
|
const currentTime = getCurrentUnixTimestamp();
|
|
9198
10493
|
const params = event.arguments[0];
|
|
9199
|
-
const
|
|
10494
|
+
const prompt = params?.prompt;
|
|
10495
|
+
const options = params?.options ?? {};
|
|
9200
10496
|
const messageId = message.message?.id;
|
|
9201
10497
|
if (messageId && messageId !== spanData.currentMessageId) {
|
|
9202
10498
|
if (spanData.currentMessages.length > 0) {
|
|
@@ -9255,7 +10551,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9255
10551
|
onComplete: async () => {
|
|
9256
10552
|
try {
|
|
9257
10553
|
const params = event.arguments[0];
|
|
9258
|
-
const
|
|
10554
|
+
const prompt = params?.prompt;
|
|
10555
|
+
const options = params?.options ?? {};
|
|
9259
10556
|
if (spanData.currentMessages.length > 0) {
|
|
9260
10557
|
const finalMessage = await createLLMSpanForMessages(
|
|
9261
10558
|
spanData.currentMessages,
|
|
@@ -9293,7 +10590,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9293
10590
|
} else {
|
|
9294
10591
|
try {
|
|
9295
10592
|
spanData.span.log({
|
|
9296
|
-
output:
|
|
10593
|
+
output: eventResult
|
|
9297
10594
|
});
|
|
9298
10595
|
} catch (error) {
|
|
9299
10596
|
console.error(
|
|
@@ -9308,7 +10605,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9308
10605
|
},
|
|
9309
10606
|
error: (event) => {
|
|
9310
10607
|
const spanData = spans.get(event);
|
|
9311
|
-
if (!spanData) {
|
|
10608
|
+
if (!spanData || !event.error) {
|
|
9312
10609
|
return;
|
|
9313
10610
|
}
|
|
9314
10611
|
const { span } = spanData;
|
|
@@ -9319,53 +10616,39 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9319
10616
|
spans.delete(event);
|
|
9320
10617
|
}
|
|
9321
10618
|
};
|
|
9322
|
-
|
|
10619
|
+
channel2.subscribe(handlers);
|
|
9323
10620
|
this.unsubscribers.push(() => {
|
|
9324
|
-
|
|
10621
|
+
channel2.unsubscribe(handlers);
|
|
9325
10622
|
});
|
|
9326
10623
|
}
|
|
9327
10624
|
};
|
|
9328
10625
|
|
|
10626
|
+
// src/instrumentation/plugins/google-genai-channels.ts
|
|
10627
|
+
var googleGenAIChannels = defineChannels("@google/genai", {
|
|
10628
|
+
generateContent: channel({
|
|
10629
|
+
channelName: "models.generateContent",
|
|
10630
|
+
kind: "async"
|
|
10631
|
+
}),
|
|
10632
|
+
generateContentStream: channel({
|
|
10633
|
+
channelName: "models.generateContentStream",
|
|
10634
|
+
kind: "async"
|
|
10635
|
+
})
|
|
10636
|
+
});
|
|
10637
|
+
|
|
9329
10638
|
// src/instrumentation/plugins/google-genai-plugin.ts
|
|
9330
|
-
import { tracingChannel as tracingChannel5 } from "dc-browser";
|
|
9331
10639
|
var GoogleGenAIPlugin = class extends BasePlugin {
|
|
9332
|
-
unsubscribers = [];
|
|
9333
10640
|
onEnable() {
|
|
9334
10641
|
this.subscribeToGoogleGenAIChannels();
|
|
9335
10642
|
}
|
|
9336
10643
|
onDisable() {
|
|
9337
|
-
|
|
9338
|
-
unsubscribe();
|
|
9339
|
-
}
|
|
9340
|
-
this.unsubscribers = [];
|
|
10644
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
9341
10645
|
}
|
|
9342
10646
|
subscribeToGoogleGenAIChannels() {
|
|
9343
|
-
this.
|
|
9344
|
-
|
|
9345
|
-
|
|
9346
|
-
extractInput: (args) => {
|
|
9347
|
-
const params = args[0] || {};
|
|
9348
|
-
const input = serializeInput(params);
|
|
9349
|
-
const metadata = extractMetadata(params);
|
|
9350
|
-
return {
|
|
9351
|
-
input,
|
|
9352
|
-
metadata: { ...metadata, provider: "google-genai" }
|
|
9353
|
-
};
|
|
9354
|
-
},
|
|
9355
|
-
extractOutput: (result) => {
|
|
9356
|
-
return result;
|
|
9357
|
-
},
|
|
9358
|
-
extractMetrics: (result, startTime) => {
|
|
9359
|
-
return extractGenerateContentMetrics(result, startTime);
|
|
9360
|
-
}
|
|
9361
|
-
});
|
|
9362
|
-
this.subscribeToGoogleStreamingChannel(
|
|
9363
|
-
"orchestrion:google-genai:models.generateContentStream",
|
|
9364
|
-
{
|
|
9365
|
-
name: "google-genai.generateContentStream",
|
|
10647
|
+
this.unsubscribers.push(
|
|
10648
|
+
traceAsyncChannel(googleGenAIChannels.generateContent, {
|
|
10649
|
+
name: "google-genai.generateContent",
|
|
9366
10650
|
type: "llm" /* LLM */,
|
|
9367
|
-
extractInput: (
|
|
9368
|
-
const params = args[0] || {};
|
|
10651
|
+
extractInput: ([params]) => {
|
|
9369
10652
|
const input = serializeInput(params);
|
|
9370
10653
|
const metadata = extractMetadata(params);
|
|
9371
10654
|
return {
|
|
@@ -9373,150 +10656,37 @@ var GoogleGenAIPlugin = class extends BasePlugin {
|
|
|
9373
10656
|
metadata: { ...metadata, provider: "google-genai" }
|
|
9374
10657
|
};
|
|
9375
10658
|
},
|
|
9376
|
-
|
|
9377
|
-
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
const channel = tracingChannel5(channelName);
|
|
9382
|
-
const spans = /* @__PURE__ */ new WeakMap();
|
|
9383
|
-
const handlers = {
|
|
9384
|
-
start: (event) => {
|
|
9385
|
-
const span = startSpan({
|
|
9386
|
-
name: config.name,
|
|
9387
|
-
spanAttributes: {
|
|
9388
|
-
type: config.type
|
|
9389
|
-
}
|
|
9390
|
-
});
|
|
9391
|
-
const startTime = getCurrentUnixTimestamp();
|
|
9392
|
-
spans.set(event, { span, startTime });
|
|
9393
|
-
try {
|
|
9394
|
-
const { input, metadata } = config.extractInput(event.arguments);
|
|
9395
|
-
span.log({
|
|
9396
|
-
input,
|
|
9397
|
-
metadata
|
|
9398
|
-
});
|
|
9399
|
-
} catch (error) {
|
|
9400
|
-
console.error(`Error extracting input for ${channelName}:`, error);
|
|
9401
|
-
}
|
|
9402
|
-
},
|
|
9403
|
-
asyncEnd: (event) => {
|
|
9404
|
-
const spanData = spans.get(event);
|
|
9405
|
-
if (!spanData) {
|
|
9406
|
-
return;
|
|
9407
|
-
}
|
|
9408
|
-
const { span, startTime } = spanData;
|
|
9409
|
-
try {
|
|
9410
|
-
const output = config.extractOutput(event.result);
|
|
9411
|
-
const metrics = config.extractMetrics(event.result, startTime);
|
|
9412
|
-
span.log({
|
|
9413
|
-
output,
|
|
9414
|
-
metrics
|
|
9415
|
-
});
|
|
9416
|
-
} catch (error) {
|
|
9417
|
-
console.error(`Error extracting output for ${channelName}:`, error);
|
|
9418
|
-
} finally {
|
|
9419
|
-
span.end();
|
|
9420
|
-
spans.delete(event);
|
|
9421
|
-
}
|
|
9422
|
-
},
|
|
9423
|
-
error: (event) => {
|
|
9424
|
-
const spanData = spans.get(event);
|
|
9425
|
-
if (!spanData) {
|
|
9426
|
-
return;
|
|
10659
|
+
extractOutput: (result) => {
|
|
10660
|
+
return result;
|
|
10661
|
+
},
|
|
10662
|
+
extractMetrics: (result, startTime) => {
|
|
10663
|
+
return extractGenerateContentMetrics(result, startTime);
|
|
9427
10664
|
}
|
|
9428
|
-
|
|
9429
|
-
|
|
9430
|
-
|
|
9431
|
-
|
|
9432
|
-
|
|
9433
|
-
|
|
9434
|
-
|
|
9435
|
-
|
|
9436
|
-
|
|
9437
|
-
|
|
9438
|
-
channel.unsubscribe(handlers);
|
|
9439
|
-
});
|
|
9440
|
-
}
|
|
9441
|
-
subscribeToGoogleStreamingChannel(channelName, config) {
|
|
9442
|
-
const channel = tracingChannel5(channelName);
|
|
9443
|
-
const spans = /* @__PURE__ */ new WeakMap();
|
|
9444
|
-
const handlers = {
|
|
9445
|
-
start: (event) => {
|
|
9446
|
-
const span = startSpan({
|
|
9447
|
-
name: config.name,
|
|
9448
|
-
spanAttributes: {
|
|
9449
|
-
type: config.type
|
|
9450
|
-
}
|
|
9451
|
-
});
|
|
9452
|
-
const startTime = getCurrentUnixTimestamp();
|
|
9453
|
-
spans.set(event, { span, startTime });
|
|
9454
|
-
try {
|
|
9455
|
-
const { input, metadata } = config.extractInput(event.arguments);
|
|
9456
|
-
span.log({
|
|
10665
|
+
})
|
|
10666
|
+
);
|
|
10667
|
+
this.unsubscribers.push(
|
|
10668
|
+
traceStreamingChannel(googleGenAIChannels.generateContentStream, {
|
|
10669
|
+
name: "google-genai.generateContentStream",
|
|
10670
|
+
type: "llm" /* LLM */,
|
|
10671
|
+
extractInput: ([params]) => {
|
|
10672
|
+
const input = serializeInput(params);
|
|
10673
|
+
const metadata = extractMetadata(params);
|
|
10674
|
+
return {
|
|
9457
10675
|
input,
|
|
9458
|
-
metadata
|
|
9459
|
-
}
|
|
9460
|
-
}
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
|
|
9466
|
-
|
|
9467
|
-
|
|
9468
|
-
|
|
9469
|
-
const { span, startTime } = spanData;
|
|
9470
|
-
if (isAsyncIterable(event.result)) {
|
|
9471
|
-
patchStreamIfNeeded(event.result, {
|
|
9472
|
-
onComplete: (chunks) => {
|
|
9473
|
-
try {
|
|
9474
|
-
const { output, metrics } = config.aggregateChunks(
|
|
9475
|
-
chunks,
|
|
9476
|
-
startTime
|
|
9477
|
-
);
|
|
9478
|
-
span.log({
|
|
9479
|
-
output,
|
|
9480
|
-
metrics
|
|
9481
|
-
});
|
|
9482
|
-
} catch (error) {
|
|
9483
|
-
console.error(
|
|
9484
|
-
`Error extracting output for ${channelName}:`,
|
|
9485
|
-
error
|
|
9486
|
-
);
|
|
9487
|
-
} finally {
|
|
9488
|
-
span.end();
|
|
9489
|
-
}
|
|
9490
|
-
},
|
|
9491
|
-
onError: (error) => {
|
|
9492
|
-
span.log({
|
|
9493
|
-
error: error.message
|
|
9494
|
-
});
|
|
9495
|
-
span.end();
|
|
9496
|
-
}
|
|
9497
|
-
});
|
|
9498
|
-
} else {
|
|
9499
|
-
span.end();
|
|
9500
|
-
spans.delete(event);
|
|
9501
|
-
}
|
|
9502
|
-
},
|
|
9503
|
-
error: (event) => {
|
|
9504
|
-
const spanData = spans.get(event);
|
|
9505
|
-
if (!spanData) {
|
|
9506
|
-
return;
|
|
10676
|
+
metadata: { ...metadata, provider: "google-genai" }
|
|
10677
|
+
};
|
|
10678
|
+
},
|
|
10679
|
+
extractOutput: (result) => {
|
|
10680
|
+
return result;
|
|
10681
|
+
},
|
|
10682
|
+
extractMetrics: () => {
|
|
10683
|
+
return {};
|
|
10684
|
+
},
|
|
10685
|
+
aggregateChunks: (chunks, _result, _endEvent, startTime) => {
|
|
10686
|
+
return aggregateGenerateContentChunks(chunks, startTime);
|
|
9507
10687
|
}
|
|
9508
|
-
|
|
9509
|
-
|
|
9510
|
-
error: event.error.message
|
|
9511
|
-
});
|
|
9512
|
-
span.end();
|
|
9513
|
-
spans.delete(event);
|
|
9514
|
-
}
|
|
9515
|
-
};
|
|
9516
|
-
channel.subscribe(handlers);
|
|
9517
|
-
this.unsubscribers.push(() => {
|
|
9518
|
-
channel.unsubscribe(handlers);
|
|
9519
|
-
});
|
|
10688
|
+
})
|
|
10689
|
+
);
|
|
9520
10690
|
}
|
|
9521
10691
|
};
|
|
9522
10692
|
function serializeInput(params) {
|
|
@@ -9572,8 +10742,12 @@ function serializePart(part) {
|
|
|
9572
10742
|
const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
|
|
9573
10743
|
atob(data).split("").map((c) => c.charCodeAt(0))
|
|
9574
10744
|
) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
|
|
10745
|
+
const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
|
|
10746
|
+
buffer.byteOffset,
|
|
10747
|
+
buffer.byteOffset + buffer.byteLength
|
|
10748
|
+
) : buffer;
|
|
9575
10749
|
const attachment = new Attachment({
|
|
9576
|
-
data:
|
|
10750
|
+
data: arrayBuffer,
|
|
9577
10751
|
filename,
|
|
9578
10752
|
contentType: mimeType || "application/octet-stream"
|
|
9579
10753
|
});
|
|
@@ -9622,33 +10796,36 @@ function extractGenerateContentMetrics(response, startTime) {
|
|
|
9622
10796
|
const end = getCurrentUnixTimestamp();
|
|
9623
10797
|
metrics.duration = end - startTime;
|
|
9624
10798
|
}
|
|
9625
|
-
if (response
|
|
9626
|
-
|
|
9627
|
-
if (usage.promptTokenCount !== void 0) {
|
|
9628
|
-
metrics.prompt_tokens = usage.promptTokenCount;
|
|
9629
|
-
}
|
|
9630
|
-
if (usage.candidatesTokenCount !== void 0) {
|
|
9631
|
-
metrics.completion_tokens = usage.candidatesTokenCount;
|
|
9632
|
-
}
|
|
9633
|
-
if (usage.totalTokenCount !== void 0) {
|
|
9634
|
-
metrics.tokens = usage.totalTokenCount;
|
|
9635
|
-
}
|
|
9636
|
-
if (usage.cachedContentTokenCount !== void 0) {
|
|
9637
|
-
metrics.prompt_cached_tokens = usage.cachedContentTokenCount;
|
|
9638
|
-
}
|
|
9639
|
-
if (usage.thoughtsTokenCount !== void 0) {
|
|
9640
|
-
metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
|
|
9641
|
-
}
|
|
10799
|
+
if (response?.usageMetadata) {
|
|
10800
|
+
populateUsageMetrics(metrics, response.usageMetadata);
|
|
9642
10801
|
}
|
|
9643
10802
|
return metrics;
|
|
9644
10803
|
}
|
|
10804
|
+
function populateUsageMetrics(metrics, usage) {
|
|
10805
|
+
if (usage.promptTokenCount !== void 0) {
|
|
10806
|
+
metrics.prompt_tokens = usage.promptTokenCount;
|
|
10807
|
+
}
|
|
10808
|
+
if (usage.candidatesTokenCount !== void 0) {
|
|
10809
|
+
metrics.completion_tokens = usage.candidatesTokenCount;
|
|
10810
|
+
}
|
|
10811
|
+
if (usage.totalTokenCount !== void 0) {
|
|
10812
|
+
metrics.tokens = usage.totalTokenCount;
|
|
10813
|
+
}
|
|
10814
|
+
if (usage.cachedContentTokenCount !== void 0) {
|
|
10815
|
+
metrics.prompt_cached_tokens = usage.cachedContentTokenCount;
|
|
10816
|
+
}
|
|
10817
|
+
if (usage.thoughtsTokenCount !== void 0) {
|
|
10818
|
+
metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
|
|
10819
|
+
}
|
|
10820
|
+
}
|
|
9645
10821
|
function aggregateGenerateContentChunks(chunks, startTime) {
|
|
9646
|
-
const
|
|
9647
|
-
|
|
9648
|
-
|
|
9649
|
-
|
|
10822
|
+
const metrics = {};
|
|
10823
|
+
if (startTime !== void 0) {
|
|
10824
|
+
const end = getCurrentUnixTimestamp();
|
|
10825
|
+
metrics.duration = end - startTime;
|
|
10826
|
+
}
|
|
9650
10827
|
let firstTokenTime = null;
|
|
9651
|
-
if (chunks.length > 0 && firstTokenTime === null) {
|
|
10828
|
+
if (chunks.length > 0 && firstTokenTime === null && startTime !== void 0) {
|
|
9652
10829
|
firstTokenTime = getCurrentUnixTimestamp();
|
|
9653
10830
|
metrics.time_to_first_token = firstTokenTime - startTime;
|
|
9654
10831
|
}
|
|
@@ -9719,21 +10896,7 @@ function aggregateGenerateContentChunks(chunks, startTime) {
|
|
|
9719
10896
|
}
|
|
9720
10897
|
if (usageMetadata) {
|
|
9721
10898
|
output.usageMetadata = usageMetadata;
|
|
9722
|
-
|
|
9723
|
-
metrics.prompt_tokens = usageMetadata.promptTokenCount;
|
|
9724
|
-
}
|
|
9725
|
-
if (usageMetadata.candidatesTokenCount !== void 0) {
|
|
9726
|
-
metrics.completion_tokens = usageMetadata.candidatesTokenCount;
|
|
9727
|
-
}
|
|
9728
|
-
if (usageMetadata.totalTokenCount !== void 0) {
|
|
9729
|
-
metrics.tokens = usageMetadata.totalTokenCount;
|
|
9730
|
-
}
|
|
9731
|
-
if (usageMetadata.cachedContentTokenCount !== void 0) {
|
|
9732
|
-
metrics.prompt_cached_tokens = usageMetadata.cachedContentTokenCount;
|
|
9733
|
-
}
|
|
9734
|
-
if (usageMetadata.thoughtsTokenCount !== void 0) {
|
|
9735
|
-
metrics.completion_reasoning_tokens = usageMetadata.thoughtsTokenCount;
|
|
9736
|
-
}
|
|
10899
|
+
populateUsageMetrics(metrics, usageMetadata);
|
|
9737
10900
|
}
|
|
9738
10901
|
if (text) {
|
|
9739
10902
|
output.text = text;
|
|
@@ -9745,7 +10908,8 @@ function tryToDict(obj) {
|
|
|
9745
10908
|
return null;
|
|
9746
10909
|
}
|
|
9747
10910
|
if (typeof obj === "object") {
|
|
9748
|
-
if (
|
|
10911
|
+
if ("toJSON" in obj && // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
10912
|
+
typeof obj.toJSON === "function") {
|
|
9749
10913
|
return obj.toJSON();
|
|
9750
10914
|
}
|
|
9751
10915
|
return obj;
|