braintrust 3.3.0-rc.45 → 3.4.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 +53 -9
- package/dev/dist/index.d.ts +53 -9
- package/dev/dist/index.js +1839 -1298
- package/dev/dist/index.mjs +1503 -962
- package/dist/auto-instrumentations/bundler/esbuild.cjs +270 -23
- package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
- package/dist/auto-instrumentations/bundler/rollup.cjs +270 -23
- package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
- package/dist/auto-instrumentations/bundler/vite.cjs +270 -23
- package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
- package/dist/auto-instrumentations/bundler/webpack.cjs +270 -23
- package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
- package/dist/auto-instrumentations/{chunk-OLOPGWTJ.mjs → chunk-D5ZPIUEL.mjs} +1 -1
- package/dist/auto-instrumentations/chunk-LVWWLUMN.mjs +535 -0
- package/dist/auto-instrumentations/hook.mjs +306 -23
- package/dist/auto-instrumentations/index.cjs +270 -23
- 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/esm-hook.mjs +7 -8
- package/dist/browser.d.mts +558 -47
- package/dist/browser.d.ts +558 -47
- package/dist/browser.js +2432 -2174
- package/dist/browser.mjs +2432 -2174
- package/dist/cli.js +1732 -1105
- package/dist/edge-light.d.mts +1 -1
- package/dist/edge-light.d.ts +1 -1
- package/dist/edge-light.js +2342 -2086
- package/dist/edge-light.mjs +2342 -2086
- package/dist/index.d.mts +558 -47
- package/dist/index.d.ts +558 -47
- package/dist/index.js +2655 -2399
- package/dist/index.mjs +2433 -2177
- package/dist/instrumentation/index.d.mts +16 -22
- package/dist/instrumentation/index.d.ts +16 -22
- package/dist/instrumentation/index.js +1558 -1068
- package/dist/instrumentation/index.mjs +1558 -1068
- package/dist/workerd.d.mts +1 -1
- package/dist/workerd.d.ts +1 -1
- package/dist/workerd.js +2342 -2086
- package/dist/workerd.mjs +2342 -2086
- package/package.json +6 -3
- package/dist/auto-instrumentations/chunk-KVX7OFPD.mjs +0 -288
|
@@ -1,5 +1,52 @@
|
|
|
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 DefaultTracingChannel = class {
|
|
15
|
+
hasSubscribers = false;
|
|
16
|
+
subscribe(_handlers) {
|
|
17
|
+
}
|
|
18
|
+
unsubscribe(_handlers) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
traceSync(fn, _message, thisArg, ...args) {
|
|
23
|
+
return fn.apply(thisArg, args);
|
|
24
|
+
}
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
tracePromise(fn, _message, thisArg, ...args) {
|
|
27
|
+
return Promise.resolve(fn.apply(thisArg, args));
|
|
28
|
+
}
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
traceCallback(fn, _position, _message, thisArg, ...args) {
|
|
31
|
+
return fn.apply(thisArg, args);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var iso = {
|
|
35
|
+
buildType: "unknown",
|
|
36
|
+
// Will be set by configureBrowser() or configureNode()
|
|
37
|
+
getRepoInfo: async (_settings) => void 0,
|
|
38
|
+
getPastNAncestors: async () => [],
|
|
39
|
+
getEnv: (_name) => void 0,
|
|
40
|
+
getCallerLocation: () => void 0,
|
|
41
|
+
newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
|
+
newTracingChannel: (_nameOrChannels) => new DefaultTracingChannel(),
|
|
44
|
+
processOn: (_0, _1) => {
|
|
45
|
+
},
|
|
46
|
+
basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
|
|
47
|
+
writeln: (text) => console.log(text)
|
|
48
|
+
};
|
|
49
|
+
var isomorph_default = iso;
|
|
3
50
|
|
|
4
51
|
// src/instrumentation/core/stream-patcher.ts
|
|
5
52
|
function isAsyncIterable(value) {
|
|
@@ -16,7 +63,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
16
63
|
return stream;
|
|
17
64
|
}
|
|
18
65
|
const originalIteratorFn = stream[Symbol.asyncIterator];
|
|
19
|
-
if (originalIteratorFn
|
|
66
|
+
if ("__braintrust_patched" in originalIteratorFn && originalIteratorFn["__braintrust_patched"]) {
|
|
20
67
|
return stream;
|
|
21
68
|
}
|
|
22
69
|
try {
|
|
@@ -57,7 +104,10 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
57
104
|
completed = true;
|
|
58
105
|
if (options.onError) {
|
|
59
106
|
try {
|
|
60
|
-
options.onError(
|
|
107
|
+
options.onError(
|
|
108
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
109
|
+
chunks
|
|
110
|
+
);
|
|
61
111
|
} catch (handlerError) {
|
|
62
112
|
console.error("Error in stream onError handler:", handlerError);
|
|
63
113
|
}
|
|
@@ -85,7 +135,8 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
85
135
|
iterator.throw = async function(...args) {
|
|
86
136
|
if (!completed) {
|
|
87
137
|
completed = true;
|
|
88
|
-
const
|
|
138
|
+
const rawError = args[0];
|
|
139
|
+
const error = rawError instanceof Error ? rawError : new Error(String(rawError));
|
|
89
140
|
if (options.onError) {
|
|
90
141
|
try {
|
|
91
142
|
options.onError(error, chunks);
|
|
@@ -99,7 +150,9 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
99
150
|
}
|
|
100
151
|
return iterator;
|
|
101
152
|
};
|
|
102
|
-
patchedIteratorFn
|
|
153
|
+
Object.defineProperty(patchedIteratorFn, "__braintrust_patched", {
|
|
154
|
+
value: true
|
|
155
|
+
});
|
|
103
156
|
stream[Symbol.asyncIterator] = patchedIteratorFn;
|
|
104
157
|
return stream;
|
|
105
158
|
} catch (error) {
|
|
@@ -111,6 +164,111 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
111
164
|
// src/logger.ts
|
|
112
165
|
import { v4 as uuidv42 } from "uuid";
|
|
113
166
|
|
|
167
|
+
// src/debug-logger.ts
|
|
168
|
+
var PREFIX = "[braintrust]";
|
|
169
|
+
var DEBUG_LOG_LEVEL_SYMBOL = Symbol.for("braintrust-debug-log-level");
|
|
170
|
+
var LOG_LEVEL_PRIORITY = {
|
|
171
|
+
error: 0,
|
|
172
|
+
warn: 1,
|
|
173
|
+
info: 2,
|
|
174
|
+
debug: 3
|
|
175
|
+
};
|
|
176
|
+
var hasWarnedAboutInvalidEnvValue = false;
|
|
177
|
+
var debugLogStateResolver = void 0;
|
|
178
|
+
function warnInvalidEnvValue(value) {
|
|
179
|
+
if (hasWarnedAboutInvalidEnvValue) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
hasWarnedAboutInvalidEnvValue = true;
|
|
183
|
+
console.warn(
|
|
184
|
+
PREFIX,
|
|
185
|
+
`Invalid BRAINTRUST_DEBUG_LOG_LEVEL value "${value}". Expected "error", "warn", "info", or "debug".`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
function normalizeDebugLogLevelOption(option) {
|
|
189
|
+
if (option === false) {
|
|
190
|
+
return void 0;
|
|
191
|
+
}
|
|
192
|
+
if (option === "error" || option === "warn" || option === "info" || option === "debug") {
|
|
193
|
+
return option;
|
|
194
|
+
}
|
|
195
|
+
throw new Error(
|
|
196
|
+
`Invalid debugLogLevel value "${option}". Expected false, "error", "warn", "info", or "debug".`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
function parseDebugLogLevelEnv(value) {
|
|
200
|
+
if (!value) {
|
|
201
|
+
return void 0;
|
|
202
|
+
}
|
|
203
|
+
if (value === "error" || value === "warn" || value === "info" || value === "debug") {
|
|
204
|
+
return value;
|
|
205
|
+
}
|
|
206
|
+
warnInvalidEnvValue(value);
|
|
207
|
+
return void 0;
|
|
208
|
+
}
|
|
209
|
+
function getEnvDebugLogLevel() {
|
|
210
|
+
return parseDebugLogLevelEnv(isomorph_default.getEnv("BRAINTRUST_DEBUG_LOG_LEVEL"));
|
|
211
|
+
}
|
|
212
|
+
function setGlobalDebugLogLevel(level) {
|
|
213
|
+
globalThis[DEBUG_LOG_LEVEL_SYMBOL] = level;
|
|
214
|
+
}
|
|
215
|
+
function setDebugLogStateResolver(resolver) {
|
|
216
|
+
debugLogStateResolver = resolver;
|
|
217
|
+
}
|
|
218
|
+
function resolveDebugLogLevel(state) {
|
|
219
|
+
const stateLevel = state?.getDebugLogLevel?.();
|
|
220
|
+
const hasStateOverride = state?.hasDebugLogLevelOverride?.() ?? false;
|
|
221
|
+
if (hasStateOverride) {
|
|
222
|
+
return stateLevel;
|
|
223
|
+
}
|
|
224
|
+
const globalLevel = (
|
|
225
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
226
|
+
globalThis[DEBUG_LOG_LEVEL_SYMBOL]
|
|
227
|
+
);
|
|
228
|
+
if (globalLevel !== void 0) {
|
|
229
|
+
return globalLevel === false ? void 0 : globalLevel;
|
|
230
|
+
}
|
|
231
|
+
return getEnvDebugLogLevel();
|
|
232
|
+
}
|
|
233
|
+
function emit(method, state, args) {
|
|
234
|
+
const level = resolveDebugLogLevel(state);
|
|
235
|
+
if (!level || LOG_LEVEL_PRIORITY[method] > LOG_LEVEL_PRIORITY[level]) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (method === "info") {
|
|
239
|
+
console.log(PREFIX, ...args);
|
|
240
|
+
} else if (method === "debug") {
|
|
241
|
+
console.debug(PREFIX, ...args);
|
|
242
|
+
} else if (method === "warn") {
|
|
243
|
+
console.warn(PREFIX, ...args);
|
|
244
|
+
} else {
|
|
245
|
+
console.error(PREFIX, ...args);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function createDebugLogger(state) {
|
|
249
|
+
const resolveState = () => state ?? debugLogStateResolver?.();
|
|
250
|
+
return {
|
|
251
|
+
info(...args) {
|
|
252
|
+
emit("info", resolveState(), args);
|
|
253
|
+
},
|
|
254
|
+
debug(...args) {
|
|
255
|
+
emit("debug", resolveState(), args);
|
|
256
|
+
},
|
|
257
|
+
warn(...args) {
|
|
258
|
+
emit("warn", resolveState(), args);
|
|
259
|
+
},
|
|
260
|
+
error(...args) {
|
|
261
|
+
emit("error", resolveState(), args);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
var debugLogger = {
|
|
266
|
+
...createDebugLogger(),
|
|
267
|
+
forState(state) {
|
|
268
|
+
return createDebugLogger(state);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
114
272
|
// src/queue.ts
|
|
115
273
|
var DEFAULT_QUEUE_SIZE = 15e3;
|
|
116
274
|
var Queue = class {
|
|
@@ -119,7 +277,7 @@ var Queue = class {
|
|
|
119
277
|
enforceSizeLimit = false;
|
|
120
278
|
constructor(maxSize) {
|
|
121
279
|
if (maxSize < 1) {
|
|
122
|
-
|
|
280
|
+
debugLogger.warn(
|
|
123
281
|
`maxSize ${maxSize} is <1, using default ${DEFAULT_QUEUE_SIZE}`
|
|
124
282
|
);
|
|
125
283
|
maxSize = DEFAULT_QUEUE_SIZE;
|
|
@@ -3461,34 +3619,6 @@ function devNullWritableStream() {
|
|
|
3461
3619
|
});
|
|
3462
3620
|
}
|
|
3463
3621
|
|
|
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
3622
|
// src/prompt-cache/disk-cache.ts
|
|
3493
3623
|
function canUseDiskCache() {
|
|
3494
3624
|
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);
|
|
@@ -4192,7 +4322,10 @@ var loginSchema = z8.strictObject({
|
|
|
4192
4322
|
proxyUrl: z8.string(),
|
|
4193
4323
|
loginToken: z8.string(),
|
|
4194
4324
|
orgId: z8.string().nullish(),
|
|
4195
|
-
gitMetadataSettings: GitMetadataSettings.nullish()
|
|
4325
|
+
gitMetadataSettings: GitMetadataSettings.nullish(),
|
|
4326
|
+
debugLogLevel: z8.enum(["error", "warn", "info", "debug"]).optional(),
|
|
4327
|
+
// Distinguishes explicit false from unset so env fallback stays disabled after deserialization.
|
|
4328
|
+
debugLogLevelDisabled: z8.boolean().optional()
|
|
4196
4329
|
});
|
|
4197
4330
|
var stateNonce = 0;
|
|
4198
4331
|
var BraintrustState = class _BraintrustState {
|
|
@@ -4213,6 +4346,16 @@ var BraintrustState = class _BraintrustState {
|
|
|
4213
4346
|
this._bgLogger = new SyncLazyValue(
|
|
4214
4347
|
() => new HTTPBackgroundLogger(new LazyValue(defaultGetLogConn), loginParams)
|
|
4215
4348
|
);
|
|
4349
|
+
if (loginParams.debugLogLevel !== void 0) {
|
|
4350
|
+
this.debugLogLevelConfigured = true;
|
|
4351
|
+
this.debugLogLevel = normalizeDebugLogLevelOption(
|
|
4352
|
+
loginParams.debugLogLevel
|
|
4353
|
+
);
|
|
4354
|
+
setGlobalDebugLogLevel(this.debugLogLevel ?? false);
|
|
4355
|
+
} else {
|
|
4356
|
+
this.debugLogLevel = getEnvDebugLogLevel();
|
|
4357
|
+
setGlobalDebugLogLevel(void 0);
|
|
4358
|
+
}
|
|
4216
4359
|
this.resetLoginInfo();
|
|
4217
4360
|
const memoryCache = new LRUCache({
|
|
4218
4361
|
max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_MEMORY_MAX")) ?? 1 << 10
|
|
@@ -4257,6 +4400,8 @@ var BraintrustState = class _BraintrustState {
|
|
|
4257
4400
|
proxyUrl = null;
|
|
4258
4401
|
loggedIn = false;
|
|
4259
4402
|
gitMetadataSettings;
|
|
4403
|
+
debugLogLevel;
|
|
4404
|
+
debugLogLevelConfigured = false;
|
|
4260
4405
|
fetch = globalThis.fetch;
|
|
4261
4406
|
_appConn = null;
|
|
4262
4407
|
_apiConn = null;
|
|
@@ -4322,6 +4467,11 @@ var BraintrustState = class _BraintrustState {
|
|
|
4322
4467
|
this.proxyUrl = other.proxyUrl;
|
|
4323
4468
|
this.loggedIn = other.loggedIn;
|
|
4324
4469
|
this.gitMetadataSettings = other.gitMetadataSettings;
|
|
4470
|
+
this.debugLogLevel = other.debugLogLevel;
|
|
4471
|
+
this.debugLogLevelConfigured = other.debugLogLevelConfigured;
|
|
4472
|
+
setGlobalDebugLogLevel(
|
|
4473
|
+
this.debugLogLevelConfigured ? this.debugLogLevel ?? false : void 0
|
|
4474
|
+
);
|
|
4325
4475
|
this._appConn = other._appConn;
|
|
4326
4476
|
this._apiConn = other._apiConn;
|
|
4327
4477
|
this.loginReplaceApiConn(this.apiConn());
|
|
@@ -4346,7 +4496,9 @@ var BraintrustState = class _BraintrustState {
|
|
|
4346
4496
|
orgName: this.orgName,
|
|
4347
4497
|
apiUrl: this.apiUrl,
|
|
4348
4498
|
proxyUrl: this.proxyUrl,
|
|
4349
|
-
gitMetadataSettings: this.gitMetadataSettings
|
|
4499
|
+
gitMetadataSettings: this.gitMetadataSettings,
|
|
4500
|
+
...this.debugLogLevel ? { debugLogLevel: this.debugLogLevel } : {},
|
|
4501
|
+
...this.debugLogLevelConfigured && !this.debugLogLevel ? { debugLogLevelDisabled: true } : {}
|
|
4350
4502
|
};
|
|
4351
4503
|
}
|
|
4352
4504
|
static deserialize(serialized, opts) {
|
|
@@ -4373,6 +4525,10 @@ var BraintrustState = class _BraintrustState {
|
|
|
4373
4525
|
state.proxyConn().set_token(state.loginToken);
|
|
4374
4526
|
}
|
|
4375
4527
|
state.loggedIn = true;
|
|
4528
|
+
state.debugLogLevelConfigured = "debugLogLevel" in serializedParsed.data || !!serializedParsed.data.debugLogLevelDisabled;
|
|
4529
|
+
setGlobalDebugLogLevel(
|
|
4530
|
+
state.debugLogLevelConfigured ? state.debugLogLevel ?? false : void 0
|
|
4531
|
+
);
|
|
4376
4532
|
state.loginReplaceApiConn(state.apiConn());
|
|
4377
4533
|
return state;
|
|
4378
4534
|
}
|
|
@@ -4385,7 +4541,22 @@ var BraintrustState = class _BraintrustState {
|
|
|
4385
4541
|
setMaskingFunction(maskingFunction) {
|
|
4386
4542
|
this.bgLogger().setMaskingFunction(maskingFunction);
|
|
4387
4543
|
}
|
|
4544
|
+
setDebugLogLevel(option) {
|
|
4545
|
+
if (option === void 0) {
|
|
4546
|
+
return;
|
|
4547
|
+
}
|
|
4548
|
+
this.debugLogLevelConfigured = true;
|
|
4549
|
+
this.debugLogLevel = normalizeDebugLogLevelOption(option);
|
|
4550
|
+
setGlobalDebugLogLevel(this.debugLogLevel ?? false);
|
|
4551
|
+
}
|
|
4552
|
+
getDebugLogLevel() {
|
|
4553
|
+
return this.debugLogLevel;
|
|
4554
|
+
}
|
|
4555
|
+
hasDebugLogLevelOverride() {
|
|
4556
|
+
return this.debugLogLevelConfigured;
|
|
4557
|
+
}
|
|
4388
4558
|
async login(loginParams) {
|
|
4559
|
+
this.setDebugLogLevel(loginParams.debugLogLevel);
|
|
4389
4560
|
if (this.apiUrl && !loginParams.forceLogin) {
|
|
4390
4561
|
return;
|
|
4391
4562
|
}
|
|
@@ -4483,6 +4654,7 @@ var BraintrustState = class _BraintrustState {
|
|
|
4483
4654
|
};
|
|
4484
4655
|
var _globalState;
|
|
4485
4656
|
var _internalGetGlobalState = () => _globalState;
|
|
4657
|
+
setDebugLogStateResolver(() => _internalGetGlobalState());
|
|
4486
4658
|
var FailedHTTPResponse = class extends Error {
|
|
4487
4659
|
status;
|
|
4488
4660
|
text;
|
|
@@ -4597,7 +4769,7 @@ var HTTPConnection = class _HTTPConnection {
|
|
|
4597
4769
|
return await resp.json();
|
|
4598
4770
|
} catch (e) {
|
|
4599
4771
|
if (i < tries - 1) {
|
|
4600
|
-
|
|
4772
|
+
debugLogger.debug(
|
|
4601
4773
|
`Retrying API request ${object_type} ${JSON.stringify(args)} ${e.status} ${e.text}`
|
|
4602
4774
|
);
|
|
4603
4775
|
continue;
|
|
@@ -4809,7 +4981,7 @@ with a Blob/ArrayBuffer, or run the program on Node.js.`
|
|
|
4809
4981
|
try {
|
|
4810
4982
|
statSync(data);
|
|
4811
4983
|
} catch (e) {
|
|
4812
|
-
|
|
4984
|
+
debugLogger.warn(`Failed to read file: ${e}`);
|
|
4813
4985
|
}
|
|
4814
4986
|
}
|
|
4815
4987
|
};
|
|
@@ -5521,7 +5693,7 @@ var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
|
|
|
5521
5693
|
this.queueDropLoggingPeriod = queueDropLoggingPeriodEnv;
|
|
5522
5694
|
}
|
|
5523
5695
|
if (isomorph_default.getEnv("BRAINTRUST_LOG_FLUSH_CHUNK_SIZE")) {
|
|
5524
|
-
|
|
5696
|
+
debugLogger.warn(
|
|
5525
5697
|
"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
5698
|
);
|
|
5527
5699
|
}
|
|
@@ -5583,7 +5755,10 @@ var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
|
|
|
5583
5755
|
const versionInfo = await conn.get_json("version");
|
|
5584
5756
|
serverLimit = z8.object({ logs3_payload_max_bytes: z8.number().nullish() }).parse(versionInfo).logs3_payload_max_bytes ?? null;
|
|
5585
5757
|
} catch (e) {
|
|
5586
|
-
|
|
5758
|
+
debugLogger.warn(
|
|
5759
|
+
"Failed to fetch version info for payload limit:",
|
|
5760
|
+
e
|
|
5761
|
+
);
|
|
5587
5762
|
}
|
|
5588
5763
|
const validServerLimit = serverLimit !== null && serverLimit > 0 ? serverLimit : null;
|
|
5589
5764
|
const canUseOverflow = validServerLimit !== null;
|
|
@@ -5727,16 +5902,16 @@ var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
|
|
|
5727
5902
|
if (isRetrying) {
|
|
5728
5903
|
errmsg += ". Retrying";
|
|
5729
5904
|
}
|
|
5730
|
-
|
|
5905
|
+
debugLogger.warn(errmsg);
|
|
5731
5906
|
if (!isRetrying) {
|
|
5732
|
-
|
|
5907
|
+
debugLogger.warn(
|
|
5733
5908
|
`Failed to construct log records to flush after ${this.numTries} attempts. Dropping batch`
|
|
5734
5909
|
);
|
|
5735
5910
|
throw e;
|
|
5736
5911
|
} else {
|
|
5737
|
-
|
|
5912
|
+
debugLogger.warn(e);
|
|
5738
5913
|
const sleepTimeS = BACKGROUND_LOGGER_BASE_SLEEP_TIME_S * 2 ** i;
|
|
5739
|
-
|
|
5914
|
+
debugLogger.info(`Sleeping for ${sleepTimeS}s`);
|
|
5740
5915
|
await new Promise(
|
|
5741
5916
|
(resolve) => setTimeout(resolve, sleepTimeS * 1e3)
|
|
5742
5917
|
);
|
|
@@ -5837,15 +6012,15 @@ Error: ${errorText}`;
|
|
|
5837
6012
|
this.logFailedPayloadsDir();
|
|
5838
6013
|
}
|
|
5839
6014
|
if (!isRetrying) {
|
|
5840
|
-
|
|
6015
|
+
debugLogger.warn(
|
|
5841
6016
|
`log request failed after ${this.numTries} retries. Dropping batch`
|
|
5842
6017
|
);
|
|
5843
6018
|
throw new Error(errMsg);
|
|
5844
6019
|
} else {
|
|
5845
|
-
|
|
6020
|
+
debugLogger.warn(errMsg);
|
|
5846
6021
|
if (isRetrying) {
|
|
5847
6022
|
const sleepTimeS = BACKGROUND_LOGGER_BASE_SLEEP_TIME_S * 2 ** i;
|
|
5848
|
-
|
|
6023
|
+
debugLogger.info(`Sleeping for ${sleepTimeS}s`);
|
|
5849
6024
|
await new Promise(
|
|
5850
6025
|
(resolve) => setTimeout(resolve, sleepTimeS * 1e3)
|
|
5851
6026
|
);
|
|
@@ -5860,7 +6035,7 @@ Error: ${errorText}`;
|
|
|
5860
6035
|
this.queueDropLoggingState.numDropped += numItems;
|
|
5861
6036
|
const timeNow = getCurrentUnixTimestamp();
|
|
5862
6037
|
if (timeNow - this.queueDropLoggingState.lastLoggedTimestamp > this.queueDropLoggingPeriod) {
|
|
5863
|
-
|
|
6038
|
+
debugLogger.warn(
|
|
5864
6039
|
`Dropped ${this.queueDropLoggingState.numDropped} elements due to full queue`
|
|
5865
6040
|
);
|
|
5866
6041
|
if (this.failedPublishPayloadsDir) {
|
|
@@ -5892,7 +6067,7 @@ Error: ${errorText}`;
|
|
|
5892
6067
|
await _HTTPBackgroundLogger.writePayloadToDir({ payloadDir, payload });
|
|
5893
6068
|
}
|
|
5894
6069
|
} catch (e) {
|
|
5895
|
-
|
|
6070
|
+
debugLogger.error(e);
|
|
5896
6071
|
}
|
|
5897
6072
|
}
|
|
5898
6073
|
static async writePayloadToDir({
|
|
@@ -5900,7 +6075,7 @@ Error: ${errorText}`;
|
|
|
5900
6075
|
payload
|
|
5901
6076
|
}) {
|
|
5902
6077
|
if (!(isomorph_default.pathJoin && isomorph_default.mkdir && isomorph_default.writeFile)) {
|
|
5903
|
-
|
|
6078
|
+
debugLogger.warn(
|
|
5904
6079
|
"Cannot dump payloads: filesystem-operations not supported on this platform"
|
|
5905
6080
|
);
|
|
5906
6081
|
return;
|
|
@@ -5913,7 +6088,7 @@ Error: ${errorText}`;
|
|
|
5913
6088
|
await isomorph_default.mkdir(payloadDir, { recursive: true });
|
|
5914
6089
|
await isomorph_default.writeFile(payloadFile, payload);
|
|
5915
6090
|
} catch (e) {
|
|
5916
|
-
|
|
6091
|
+
debugLogger.error(
|
|
5917
6092
|
`Failed to write failed payload to output file ${payloadFile}:
|
|
5918
6093
|
`,
|
|
5919
6094
|
e
|
|
@@ -5944,7 +6119,9 @@ Error: ${errorText}`;
|
|
|
5944
6119
|
}
|
|
5945
6120
|
}
|
|
5946
6121
|
logFailedPayloadsDir() {
|
|
5947
|
-
|
|
6122
|
+
debugLogger.warn(
|
|
6123
|
+
`Logging failed payloads to ${this.failedPublishPayloadsDir}`
|
|
6124
|
+
);
|
|
5948
6125
|
}
|
|
5949
6126
|
// Should only be called by BraintrustState.
|
|
5950
6127
|
internalReplaceApiConn(apiConn) {
|
|
@@ -6355,7 +6532,14 @@ var ObjectFetcher = class {
|
|
|
6355
6532
|
async *fetchRecordsFromApi(batchSize) {
|
|
6356
6533
|
const state = await this.getState();
|
|
6357
6534
|
const objectId = await this.id;
|
|
6358
|
-
const
|
|
6535
|
+
const batchLimit = batchSize ?? DEFAULT_FETCH_BATCH_SIZE;
|
|
6536
|
+
const internalLimit = this._internal_btql?.limit;
|
|
6537
|
+
const limit = batchSize !== void 0 ? batchSize : internalLimit ?? batchLimit;
|
|
6538
|
+
const internalBtqlWithoutReservedQueryKeys = Object.fromEntries(
|
|
6539
|
+
Object.entries(this._internal_btql ?? {}).filter(
|
|
6540
|
+
([key]) => key !== "cursor" && key !== "limit" && key !== "select" && key !== "from"
|
|
6541
|
+
)
|
|
6542
|
+
);
|
|
6359
6543
|
let cursor = void 0;
|
|
6360
6544
|
let iterations = 0;
|
|
6361
6545
|
while (true) {
|
|
@@ -6363,7 +6547,6 @@ var ObjectFetcher = class {
|
|
|
6363
6547
|
`btql`,
|
|
6364
6548
|
{
|
|
6365
6549
|
query: {
|
|
6366
|
-
...this._internal_btql,
|
|
6367
6550
|
select: [
|
|
6368
6551
|
{
|
|
6369
6552
|
op: "star"
|
|
@@ -6383,7 +6566,8 @@ var ObjectFetcher = class {
|
|
|
6383
6566
|
]
|
|
6384
6567
|
},
|
|
6385
6568
|
cursor,
|
|
6386
|
-
limit
|
|
6569
|
+
limit,
|
|
6570
|
+
...internalBtqlWithoutReservedQueryKeys
|
|
6387
6571
|
},
|
|
6388
6572
|
use_columnstore: false,
|
|
6389
6573
|
brainstore_realtime: true,
|
|
@@ -6656,7 +6840,7 @@ var Experiment2 = class extends ObjectFetcher {
|
|
|
6656
6840
|
scores = results["scores"];
|
|
6657
6841
|
metrics = results["metrics"];
|
|
6658
6842
|
} catch (e) {
|
|
6659
|
-
|
|
6843
|
+
debugLogger.forState(state).warn(
|
|
6660
6844
|
`Failed to fetch experiment scores and metrics: ${e}
|
|
6661
6845
|
|
|
6662
6846
|
View complete results in Braintrust or run experiment.summarize() again.`
|
|
@@ -6733,7 +6917,7 @@ View complete results in Braintrust or run experiment.summarize() again.`
|
|
|
6733
6917
|
* @deprecated This function is deprecated. You can simply remove it from your code.
|
|
6734
6918
|
*/
|
|
6735
6919
|
async close() {
|
|
6736
|
-
|
|
6920
|
+
debugLogger.forState(this.state).warn(
|
|
6737
6921
|
"close is deprecated and will be removed in a future version of braintrust. It is now a no-op and can be removed"
|
|
6738
6922
|
);
|
|
6739
6923
|
return this.id;
|
|
@@ -6890,8 +7074,8 @@ var SpanImpl = class _SpanImpl {
|
|
|
6890
7074
|
...serializableInternalData,
|
|
6891
7075
|
[IS_MERGE_FIELD]: this.isMerge
|
|
6892
7076
|
});
|
|
6893
|
-
if (partialRecord.metrics?.end) {
|
|
6894
|
-
this.loggedEndTime = partialRecord.metrics
|
|
7077
|
+
if (typeof partialRecord.metrics?.end === "number") {
|
|
7078
|
+
this.loggedEndTime = partialRecord.metrics.end;
|
|
6895
7079
|
}
|
|
6896
7080
|
if (this.parentObjectType === 1 /* EXPERIMENT */) {
|
|
6897
7081
|
const cachedSpan = {
|
|
@@ -7126,7 +7310,7 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
7126
7310
|
constructor(state, lazyMetadata, pinnedVersion, legacy, _internal_btql) {
|
|
7127
7311
|
const isLegacyDataset = legacy ?? DEFAULT_IS_LEGACY_DATASET;
|
|
7128
7312
|
if (isLegacyDataset) {
|
|
7129
|
-
|
|
7313
|
+
debugLogger.forState(state).warn(
|
|
7130
7314
|
`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
7315
|
);
|
|
7132
7316
|
}
|
|
@@ -7357,7 +7541,7 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
7357
7541
|
* @deprecated This function is deprecated. You can simply remove it from your code.
|
|
7358
7542
|
*/
|
|
7359
7543
|
async close() {
|
|
7360
|
-
|
|
7544
|
+
debugLogger.forState(this.state).warn(
|
|
7361
7545
|
"close is deprecated and will be removed in a future version of braintrust. It is now a no-op and can be removed"
|
|
7362
7546
|
);
|
|
7363
7547
|
return this.id;
|
|
@@ -7368,6 +7552,49 @@ var Dataset2 = class extends ObjectFetcher {
|
|
|
7368
7552
|
};
|
|
7369
7553
|
var TEST_API_KEY = "___TEST_API_KEY__THIS_IS_NOT_REAL___";
|
|
7370
7554
|
|
|
7555
|
+
// src/instrumentation/core/channel-tracing-utils.ts
|
|
7556
|
+
function hasChannelSpanInfo(value) {
|
|
7557
|
+
return isObject(value) && isObject(value.span_info);
|
|
7558
|
+
}
|
|
7559
|
+
function getChannelSpanInfo(event) {
|
|
7560
|
+
if (isObject(event.span_info)) {
|
|
7561
|
+
return event.span_info;
|
|
7562
|
+
}
|
|
7563
|
+
const firstArg = event.arguments?.[0];
|
|
7564
|
+
if (hasChannelSpanInfo(firstArg)) {
|
|
7565
|
+
return firstArg.span_info;
|
|
7566
|
+
}
|
|
7567
|
+
return void 0;
|
|
7568
|
+
}
|
|
7569
|
+
function buildStartSpanArgs(config, event) {
|
|
7570
|
+
const spanInfo = getChannelSpanInfo(event);
|
|
7571
|
+
const spanAttributes = {
|
|
7572
|
+
type: config.type
|
|
7573
|
+
};
|
|
7574
|
+
if (isObject(spanInfo?.spanAttributes)) {
|
|
7575
|
+
mergeDicts(spanAttributes, spanInfo.spanAttributes);
|
|
7576
|
+
}
|
|
7577
|
+
return {
|
|
7578
|
+
name: typeof spanInfo?.name === "string" && spanInfo.name ? spanInfo.name : config.name,
|
|
7579
|
+
spanAttributes,
|
|
7580
|
+
spanInfoMetadata: isObject(spanInfo?.metadata) ? spanInfo.metadata : void 0
|
|
7581
|
+
};
|
|
7582
|
+
}
|
|
7583
|
+
function mergeInputMetadata(metadata, spanInfoMetadata) {
|
|
7584
|
+
if (!spanInfoMetadata) {
|
|
7585
|
+
return isObject(metadata) ? (
|
|
7586
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
7587
|
+
metadata
|
|
7588
|
+
) : void 0;
|
|
7589
|
+
}
|
|
7590
|
+
const mergedMetadata = {};
|
|
7591
|
+
mergeDicts(mergedMetadata, spanInfoMetadata);
|
|
7592
|
+
if (isObject(metadata)) {
|
|
7593
|
+
mergeDicts(mergedMetadata, metadata);
|
|
7594
|
+
}
|
|
7595
|
+
return mergedMetadata;
|
|
7596
|
+
}
|
|
7597
|
+
|
|
7371
7598
|
// src/instrumentation/core/plugin.ts
|
|
7372
7599
|
var BasePlugin = class {
|
|
7373
7600
|
enabled = false;
|
|
@@ -7399,23 +7626,25 @@ var BasePlugin = class {
|
|
|
7399
7626
|
* @param handlers - Event handlers
|
|
7400
7627
|
*/
|
|
7401
7628
|
subscribe(channelName, handlers) {
|
|
7402
|
-
const
|
|
7403
|
-
|
|
7629
|
+
const channel2 = isomorph_default.newTracingChannel(channelName);
|
|
7630
|
+
channel2.subscribe(handlers);
|
|
7404
7631
|
}
|
|
7405
7632
|
/**
|
|
7406
7633
|
* Subscribe to a channel for async methods (non-streaming).
|
|
7407
7634
|
* Creates a span and logs input/output/metrics.
|
|
7408
7635
|
*/
|
|
7409
7636
|
subscribeToChannel(channelName, config) {
|
|
7410
|
-
const
|
|
7637
|
+
const channel2 = isomorph_default.newTracingChannel(channelName);
|
|
7411
7638
|
const spans = /* @__PURE__ */ new WeakMap();
|
|
7412
7639
|
const handlers = {
|
|
7413
7640
|
start: (event) => {
|
|
7641
|
+
const { name, spanAttributes, spanInfoMetadata } = buildStartSpanArgs(
|
|
7642
|
+
config,
|
|
7643
|
+
event
|
|
7644
|
+
);
|
|
7414
7645
|
const span = startSpan({
|
|
7415
|
-
name
|
|
7416
|
-
spanAttributes
|
|
7417
|
-
type: config.type
|
|
7418
|
-
}
|
|
7646
|
+
name,
|
|
7647
|
+
spanAttributes
|
|
7419
7648
|
});
|
|
7420
7649
|
const startTime = getCurrentUnixTimestamp();
|
|
7421
7650
|
spans.set(event, { span, startTime });
|
|
@@ -7423,7 +7652,7 @@ var BasePlugin = class {
|
|
|
7423
7652
|
const { input, metadata } = config.extractInput(event.arguments);
|
|
7424
7653
|
span.log({
|
|
7425
7654
|
input,
|
|
7426
|
-
metadata
|
|
7655
|
+
metadata: mergeInputMetadata(metadata, spanInfoMetadata)
|
|
7427
7656
|
});
|
|
7428
7657
|
} catch (error) {
|
|
7429
7658
|
console.error(`Error extracting input for ${channelName}:`, error);
|
|
@@ -7436,10 +7665,12 @@ var BasePlugin = class {
|
|
|
7436
7665
|
}
|
|
7437
7666
|
const { span, startTime } = spanData;
|
|
7438
7667
|
try {
|
|
7439
|
-
const output = config.extractOutput(event.result);
|
|
7440
|
-
const metrics = config.extractMetrics(event.result, startTime);
|
|
7668
|
+
const output = config.extractOutput(event.result, event);
|
|
7669
|
+
const metrics = config.extractMetrics(event.result, startTime, event);
|
|
7670
|
+
const metadata = config.extractMetadata?.(event.result, event);
|
|
7441
7671
|
span.log({
|
|
7442
7672
|
output,
|
|
7673
|
+
...metadata !== void 0 ? { metadata } : {},
|
|
7443
7674
|
metrics
|
|
7444
7675
|
});
|
|
7445
7676
|
} catch (error) {
|
|
@@ -7462,9 +7693,9 @@ var BasePlugin = class {
|
|
|
7462
7693
|
spans.delete(event);
|
|
7463
7694
|
}
|
|
7464
7695
|
};
|
|
7465
|
-
|
|
7696
|
+
channel2.subscribe(handlers);
|
|
7466
7697
|
this.unsubscribers.push(() => {
|
|
7467
|
-
|
|
7698
|
+
channel2.unsubscribe(handlers);
|
|
7468
7699
|
});
|
|
7469
7700
|
}
|
|
7470
7701
|
/**
|
|
@@ -7472,15 +7703,17 @@ var BasePlugin = class {
|
|
|
7472
7703
|
* Handles both streaming and non-streaming responses.
|
|
7473
7704
|
*/
|
|
7474
7705
|
subscribeToStreamingChannel(channelName, config) {
|
|
7475
|
-
const
|
|
7706
|
+
const channel2 = isomorph_default.newTracingChannel(channelName);
|
|
7476
7707
|
const spans = /* @__PURE__ */ new WeakMap();
|
|
7477
7708
|
const handlers = {
|
|
7478
7709
|
start: (event) => {
|
|
7710
|
+
const { name, spanAttributes, spanInfoMetadata } = buildStartSpanArgs(
|
|
7711
|
+
config,
|
|
7712
|
+
event
|
|
7713
|
+
);
|
|
7479
7714
|
const span = startSpan({
|
|
7480
|
-
name
|
|
7481
|
-
spanAttributes
|
|
7482
|
-
type: config.type
|
|
7483
|
-
}
|
|
7715
|
+
name,
|
|
7716
|
+
spanAttributes
|
|
7484
7717
|
});
|
|
7485
7718
|
const startTime = getCurrentUnixTimestamp();
|
|
7486
7719
|
spans.set(event, { span, startTime });
|
|
@@ -7488,7 +7721,7 @@ var BasePlugin = class {
|
|
|
7488
7721
|
const { input, metadata } = config.extractInput(event.arguments);
|
|
7489
7722
|
span.log({
|
|
7490
7723
|
input,
|
|
7491
|
-
metadata
|
|
7724
|
+
metadata: mergeInputMetadata(metadata, spanInfoMetadata)
|
|
7492
7725
|
});
|
|
7493
7726
|
} catch (error) {
|
|
7494
7727
|
console.error(`Error extracting input for ${channelName}:`, error);
|
|
@@ -7501,24 +7734,39 @@ var BasePlugin = class {
|
|
|
7501
7734
|
}
|
|
7502
7735
|
const { span, startTime } = spanData;
|
|
7503
7736
|
if (isAsyncIterable(event.result)) {
|
|
7737
|
+
let firstChunkTime;
|
|
7504
7738
|
patchStreamIfNeeded(event.result, {
|
|
7739
|
+
onChunk: () => {
|
|
7740
|
+
if (firstChunkTime === void 0) {
|
|
7741
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
7742
|
+
}
|
|
7743
|
+
},
|
|
7505
7744
|
onComplete: (chunks) => {
|
|
7506
7745
|
try {
|
|
7507
7746
|
let output;
|
|
7508
7747
|
let metrics;
|
|
7748
|
+
let metadata;
|
|
7509
7749
|
if (config.aggregateChunks) {
|
|
7510
|
-
const aggregated = config.aggregateChunks(
|
|
7750
|
+
const aggregated = config.aggregateChunks(
|
|
7751
|
+
chunks,
|
|
7752
|
+
event.result,
|
|
7753
|
+
event
|
|
7754
|
+
);
|
|
7511
7755
|
output = aggregated.output;
|
|
7512
7756
|
metrics = aggregated.metrics;
|
|
7757
|
+
metadata = aggregated.metadata;
|
|
7513
7758
|
} else {
|
|
7514
|
-
output = config.extractOutput(chunks);
|
|
7515
|
-
metrics = config.extractMetrics(chunks, startTime);
|
|
7759
|
+
output = config.extractOutput(chunks, event);
|
|
7760
|
+
metrics = config.extractMetrics(chunks, startTime, event);
|
|
7516
7761
|
}
|
|
7517
|
-
if (
|
|
7762
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
7763
|
+
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
7764
|
+
} else if (metrics.time_to_first_token === void 0 && chunks.length > 0) {
|
|
7518
7765
|
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
7519
7766
|
}
|
|
7520
7767
|
span.log({
|
|
7521
7768
|
output,
|
|
7769
|
+
...metadata !== void 0 ? { metadata } : {},
|
|
7522
7770
|
metrics
|
|
7523
7771
|
});
|
|
7524
7772
|
} catch (error) {
|
|
@@ -7539,10 +7787,16 @@ var BasePlugin = class {
|
|
|
7539
7787
|
});
|
|
7540
7788
|
} else {
|
|
7541
7789
|
try {
|
|
7542
|
-
const output = config.extractOutput(event.result);
|
|
7543
|
-
const
|
|
7790
|
+
const output = config.extractOutput(event.result, event);
|
|
7791
|
+
const metadata = config.extractMetadata ? config.extractMetadata(event.result, event) : void 0;
|
|
7792
|
+
const metrics = config.extractMetrics(
|
|
7793
|
+
event.result,
|
|
7794
|
+
startTime,
|
|
7795
|
+
event
|
|
7796
|
+
);
|
|
7544
7797
|
span.log({
|
|
7545
7798
|
output,
|
|
7799
|
+
...metadata !== void 0 ? { metadata } : {},
|
|
7546
7800
|
metrics
|
|
7547
7801
|
});
|
|
7548
7802
|
} catch (error) {
|
|
@@ -7566,9 +7820,9 @@ var BasePlugin = class {
|
|
|
7566
7820
|
spans.delete(event);
|
|
7567
7821
|
}
|
|
7568
7822
|
};
|
|
7569
|
-
|
|
7823
|
+
channel2.subscribe(handlers);
|
|
7570
7824
|
this.unsubscribers.push(() => {
|
|
7571
|
-
|
|
7825
|
+
channel2.unsubscribe(handlers);
|
|
7572
7826
|
});
|
|
7573
7827
|
}
|
|
7574
7828
|
/**
|
|
@@ -7576,15 +7830,17 @@ var BasePlugin = class {
|
|
|
7576
7830
|
* Used for methods like beta.chat.completions.stream() and responses.stream().
|
|
7577
7831
|
*/
|
|
7578
7832
|
subscribeToSyncStreamChannel(channelName, config) {
|
|
7579
|
-
const
|
|
7833
|
+
const channel2 = isomorph_default.newTracingChannel(channelName);
|
|
7580
7834
|
const spans = /* @__PURE__ */ new WeakMap();
|
|
7581
7835
|
const handlers = {
|
|
7582
7836
|
start: (event) => {
|
|
7837
|
+
const { name, spanAttributes, spanInfoMetadata } = buildStartSpanArgs(
|
|
7838
|
+
config,
|
|
7839
|
+
event
|
|
7840
|
+
);
|
|
7583
7841
|
const span = startSpan({
|
|
7584
|
-
name
|
|
7585
|
-
spanAttributes
|
|
7586
|
-
type: config.type
|
|
7587
|
-
}
|
|
7842
|
+
name,
|
|
7843
|
+
spanAttributes
|
|
7588
7844
|
});
|
|
7589
7845
|
const startTime = getCurrentUnixTimestamp();
|
|
7590
7846
|
spans.set(event, { span, startTime });
|
|
@@ -7592,7 +7848,7 @@ var BasePlugin = class {
|
|
|
7592
7848
|
const { input, metadata } = config.extractInput(event.arguments);
|
|
7593
7849
|
span.log({
|
|
7594
7850
|
input,
|
|
7595
|
-
metadata
|
|
7851
|
+
metadata: mergeInputMetadata(metadata, spanInfoMetadata)
|
|
7596
7852
|
});
|
|
7597
7853
|
} catch (error) {
|
|
7598
7854
|
console.error(`Error extracting input for ${channelName}:`, error);
|
|
@@ -7676,9 +7932,9 @@ var BasePlugin = class {
|
|
|
7676
7932
|
spans.delete(event);
|
|
7677
7933
|
}
|
|
7678
7934
|
};
|
|
7679
|
-
|
|
7935
|
+
channel2.subscribe(handlers);
|
|
7680
7936
|
this.unsubscribers.push(() => {
|
|
7681
|
-
|
|
7937
|
+
channel2.unsubscribe(handlers);
|
|
7682
7938
|
});
|
|
7683
7939
|
}
|
|
7684
7940
|
};
|
|
@@ -7701,149 +7957,635 @@ function isValidChannelName(channelName) {
|
|
|
7701
7957
|
return /^braintrust:[^:]+:.+$/.test(channelName);
|
|
7702
7958
|
}
|
|
7703
7959
|
|
|
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";
|
|
7960
|
+
// src/instrumentation/core/channel-tracing.ts
|
|
7961
|
+
function isSyncStreamLike(value) {
|
|
7962
|
+
return !!value && typeof value === "object" && typeof value.on === "function";
|
|
7724
7963
|
}
|
|
7725
|
-
function
|
|
7964
|
+
function hasChoices(value) {
|
|
7965
|
+
return !!value && typeof value === "object" && "choices" in value;
|
|
7966
|
+
}
|
|
7967
|
+
function normalizeMetadata(metadata) {
|
|
7968
|
+
return isObject(metadata) ? metadata : void 0;
|
|
7969
|
+
}
|
|
7970
|
+
function startSpanForEvent(config, event, channelName) {
|
|
7971
|
+
const { name, spanAttributes, spanInfoMetadata } = buildStartSpanArgs(
|
|
7972
|
+
config,
|
|
7973
|
+
event
|
|
7974
|
+
);
|
|
7975
|
+
const span = startSpan({
|
|
7976
|
+
name,
|
|
7977
|
+
spanAttributes
|
|
7978
|
+
});
|
|
7979
|
+
const startTime = getCurrentUnixTimestamp();
|
|
7726
7980
|
try {
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
7735
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
7736
|
-
}
|
|
7737
|
-
return new Blob([bytes], { type: mediaType });
|
|
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;
|
|
7981
|
+
const { input, metadata } = config.extractInput(event.arguments);
|
|
7982
|
+
span.log({
|
|
7983
|
+
input,
|
|
7984
|
+
metadata: mergeInputMetadata(metadata, spanInfoMetadata)
|
|
7985
|
+
});
|
|
7986
|
+
} catch (error) {
|
|
7987
|
+
console.error(`Error extracting input for ${channelName}:`, error);
|
|
7758
7988
|
}
|
|
7759
|
-
return
|
|
7989
|
+
return { span, startTime };
|
|
7760
7990
|
}
|
|
7761
|
-
function
|
|
7762
|
-
|
|
7763
|
-
|
|
7991
|
+
function logErrorAndEnd(states, event) {
|
|
7992
|
+
const spanData = states.get(event);
|
|
7993
|
+
if (!spanData) {
|
|
7994
|
+
return;
|
|
7764
7995
|
}
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
return
|
|
7790
|
-
...part,
|
|
7791
|
-
image: attachment
|
|
7792
|
-
};
|
|
7996
|
+
spanData.span.log({
|
|
7997
|
+
error: event.error.message
|
|
7998
|
+
});
|
|
7999
|
+
spanData.span.end();
|
|
8000
|
+
states.delete(event);
|
|
8001
|
+
}
|
|
8002
|
+
function traceAsyncChannel(channel2, config) {
|
|
8003
|
+
const tracingChannel = channel2.tracingChannel();
|
|
8004
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
8005
|
+
const channelName = channel2.channelName;
|
|
8006
|
+
const handlers = {
|
|
8007
|
+
start: (event) => {
|
|
8008
|
+
states.set(
|
|
8009
|
+
event,
|
|
8010
|
+
startSpanForEvent(
|
|
8011
|
+
config,
|
|
8012
|
+
event,
|
|
8013
|
+
channelName
|
|
8014
|
+
)
|
|
8015
|
+
);
|
|
8016
|
+
},
|
|
8017
|
+
asyncEnd: (event) => {
|
|
8018
|
+
const spanData = states.get(event);
|
|
8019
|
+
if (!spanData) {
|
|
8020
|
+
return;
|
|
7793
8021
|
}
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
const
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
8022
|
+
const asyncEndEvent = event;
|
|
8023
|
+
const { span, startTime } = spanData;
|
|
8024
|
+
try {
|
|
8025
|
+
const output = config.extractOutput(
|
|
8026
|
+
asyncEndEvent.result,
|
|
8027
|
+
asyncEndEvent
|
|
8028
|
+
);
|
|
8029
|
+
const metrics = config.extractMetrics(
|
|
8030
|
+
asyncEndEvent.result,
|
|
8031
|
+
startTime,
|
|
8032
|
+
asyncEndEvent
|
|
8033
|
+
);
|
|
8034
|
+
const metadata = config.extractMetadata?.(
|
|
8035
|
+
asyncEndEvent.result,
|
|
8036
|
+
asyncEndEvent
|
|
8037
|
+
);
|
|
8038
|
+
span.log({
|
|
8039
|
+
output,
|
|
8040
|
+
...normalizeMetadata(metadata) !== void 0 ? { metadata: normalizeMetadata(metadata) } : {},
|
|
8041
|
+
metrics
|
|
7805
8042
|
});
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
8043
|
+
} catch (error) {
|
|
8044
|
+
console.error(`Error extracting output for ${channelName}:`, error);
|
|
8045
|
+
} finally {
|
|
8046
|
+
span.end();
|
|
8047
|
+
states.delete(event);
|
|
7810
8048
|
}
|
|
8049
|
+
},
|
|
8050
|
+
error: (event) => {
|
|
8051
|
+
logErrorAndEnd(states, event);
|
|
7811
8052
|
}
|
|
7812
|
-
return part;
|
|
7813
8053
|
};
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
}
|
|
7818
|
-
if (Array.isArray(message.content)) {
|
|
7819
|
-
return {
|
|
7820
|
-
...message,
|
|
7821
|
-
content: message.content.map(processContentPart)
|
|
7822
|
-
};
|
|
7823
|
-
}
|
|
7824
|
-
return message;
|
|
8054
|
+
tracingChannel.subscribe(handlers);
|
|
8055
|
+
return () => {
|
|
8056
|
+
tracingChannel.unsubscribe(handlers);
|
|
7825
8057
|
};
|
|
7826
|
-
if (Array.isArray(input)) {
|
|
7827
|
-
return input.map(processMessage);
|
|
7828
|
-
} else if (typeof input === "object" && input.content) {
|
|
7829
|
-
return processMessage(input);
|
|
7830
|
-
}
|
|
7831
|
-
return input;
|
|
7832
8058
|
}
|
|
7833
|
-
|
|
7834
|
-
|
|
7835
|
-
|
|
7836
|
-
|
|
8059
|
+
function traceStreamingChannel(channel2, config) {
|
|
8060
|
+
const tracingChannel = channel2.tracingChannel();
|
|
8061
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
8062
|
+
const channelName = channel2.channelName;
|
|
8063
|
+
const handlers = {
|
|
8064
|
+
start: (event) => {
|
|
8065
|
+
states.set(
|
|
8066
|
+
event,
|
|
8067
|
+
startSpanForEvent(
|
|
8068
|
+
config,
|
|
8069
|
+
event,
|
|
8070
|
+
channelName
|
|
8071
|
+
)
|
|
8072
|
+
);
|
|
8073
|
+
},
|
|
8074
|
+
asyncEnd: (event) => {
|
|
8075
|
+
const spanData = states.get(event);
|
|
8076
|
+
if (!spanData) {
|
|
8077
|
+
return;
|
|
8078
|
+
}
|
|
8079
|
+
const asyncEndEvent = event;
|
|
8080
|
+
const { span, startTime } = spanData;
|
|
8081
|
+
if (isAsyncIterable(asyncEndEvent.result)) {
|
|
8082
|
+
let firstChunkTime;
|
|
8083
|
+
patchStreamIfNeeded(asyncEndEvent.result, {
|
|
8084
|
+
onChunk: () => {
|
|
8085
|
+
if (firstChunkTime === void 0) {
|
|
8086
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
8087
|
+
}
|
|
8088
|
+
},
|
|
8089
|
+
onComplete: (chunks) => {
|
|
8090
|
+
try {
|
|
8091
|
+
let output;
|
|
8092
|
+
let metrics;
|
|
8093
|
+
let metadata;
|
|
8094
|
+
if (config.aggregateChunks) {
|
|
8095
|
+
const aggregated = config.aggregateChunks(
|
|
8096
|
+
chunks,
|
|
8097
|
+
asyncEndEvent.result,
|
|
8098
|
+
asyncEndEvent,
|
|
8099
|
+
startTime
|
|
8100
|
+
);
|
|
8101
|
+
output = aggregated.output;
|
|
8102
|
+
metrics = aggregated.metrics;
|
|
8103
|
+
metadata = aggregated.metadata;
|
|
8104
|
+
} else {
|
|
8105
|
+
output = config.extractOutput(
|
|
8106
|
+
chunks,
|
|
8107
|
+
asyncEndEvent
|
|
8108
|
+
);
|
|
8109
|
+
metrics = config.extractMetrics(
|
|
8110
|
+
chunks,
|
|
8111
|
+
startTime,
|
|
8112
|
+
asyncEndEvent
|
|
8113
|
+
);
|
|
8114
|
+
}
|
|
8115
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
8116
|
+
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
8117
|
+
} else if (metrics.time_to_first_token === void 0 && chunks.length > 0) {
|
|
8118
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8119
|
+
}
|
|
8120
|
+
span.log({
|
|
8121
|
+
output,
|
|
8122
|
+
...metadata !== void 0 ? { metadata } : {},
|
|
8123
|
+
metrics
|
|
8124
|
+
});
|
|
8125
|
+
} catch (error) {
|
|
8126
|
+
console.error(
|
|
8127
|
+
`Error extracting output for ${channelName}:`,
|
|
8128
|
+
error
|
|
8129
|
+
);
|
|
8130
|
+
} finally {
|
|
8131
|
+
span.end();
|
|
8132
|
+
states.delete(event);
|
|
8133
|
+
}
|
|
8134
|
+
},
|
|
8135
|
+
onError: (error) => {
|
|
8136
|
+
span.log({
|
|
8137
|
+
error: error.message
|
|
8138
|
+
});
|
|
8139
|
+
span.end();
|
|
8140
|
+
states.delete(event);
|
|
8141
|
+
}
|
|
8142
|
+
});
|
|
8143
|
+
return;
|
|
8144
|
+
}
|
|
8145
|
+
try {
|
|
8146
|
+
const output = config.extractOutput(
|
|
8147
|
+
asyncEndEvent.result,
|
|
8148
|
+
asyncEndEvent
|
|
8149
|
+
);
|
|
8150
|
+
const metrics = config.extractMetrics(
|
|
8151
|
+
asyncEndEvent.result,
|
|
8152
|
+
startTime,
|
|
8153
|
+
asyncEndEvent
|
|
8154
|
+
);
|
|
8155
|
+
const metadata = config.extractMetadata?.(
|
|
8156
|
+
asyncEndEvent.result,
|
|
8157
|
+
asyncEndEvent
|
|
8158
|
+
);
|
|
8159
|
+
span.log({
|
|
8160
|
+
output,
|
|
8161
|
+
...normalizeMetadata(metadata) !== void 0 ? { metadata: normalizeMetadata(metadata) } : {},
|
|
8162
|
+
metrics
|
|
8163
|
+
});
|
|
8164
|
+
} catch (error) {
|
|
8165
|
+
console.error(`Error extracting output for ${channelName}:`, error);
|
|
8166
|
+
} finally {
|
|
8167
|
+
span.end();
|
|
8168
|
+
states.delete(event);
|
|
8169
|
+
}
|
|
8170
|
+
},
|
|
8171
|
+
error: (event) => {
|
|
8172
|
+
logErrorAndEnd(states, event);
|
|
8173
|
+
}
|
|
8174
|
+
};
|
|
8175
|
+
tracingChannel.subscribe(handlers);
|
|
8176
|
+
return () => {
|
|
8177
|
+
tracingChannel.unsubscribe(handlers);
|
|
8178
|
+
};
|
|
8179
|
+
}
|
|
8180
|
+
function traceSyncStreamChannel(channel2, config) {
|
|
8181
|
+
const tracingChannel = channel2.tracingChannel();
|
|
8182
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
8183
|
+
const channelName = channel2.channelName;
|
|
8184
|
+
const handlers = {
|
|
8185
|
+
start: (event) => {
|
|
8186
|
+
states.set(
|
|
8187
|
+
event,
|
|
8188
|
+
startSpanForEvent(
|
|
8189
|
+
config,
|
|
8190
|
+
event,
|
|
8191
|
+
channelName
|
|
8192
|
+
)
|
|
8193
|
+
);
|
|
8194
|
+
},
|
|
8195
|
+
end: (event) => {
|
|
8196
|
+
const spanData = states.get(event);
|
|
8197
|
+
if (!spanData) {
|
|
8198
|
+
return;
|
|
8199
|
+
}
|
|
8200
|
+
const { span, startTime } = spanData;
|
|
8201
|
+
const resultEvent = event;
|
|
8202
|
+
const stream = resultEvent.result;
|
|
8203
|
+
if (!isSyncStreamLike(stream)) {
|
|
8204
|
+
span.end();
|
|
8205
|
+
states.delete(event);
|
|
8206
|
+
return;
|
|
8207
|
+
}
|
|
8208
|
+
let first = true;
|
|
8209
|
+
stream.on("chunk", () => {
|
|
8210
|
+
if (first) {
|
|
8211
|
+
span.log({
|
|
8212
|
+
metrics: {
|
|
8213
|
+
time_to_first_token: getCurrentUnixTimestamp() - startTime
|
|
8214
|
+
}
|
|
8215
|
+
});
|
|
8216
|
+
first = false;
|
|
8217
|
+
}
|
|
8218
|
+
});
|
|
8219
|
+
stream.on("chatCompletion", (completion) => {
|
|
8220
|
+
try {
|
|
8221
|
+
if (hasChoices(completion)) {
|
|
8222
|
+
span.log({
|
|
8223
|
+
output: completion.choices
|
|
8224
|
+
});
|
|
8225
|
+
}
|
|
8226
|
+
} catch (error) {
|
|
8227
|
+
console.error(
|
|
8228
|
+
`Error extracting chatCompletion for ${channelName}:`,
|
|
8229
|
+
error
|
|
8230
|
+
);
|
|
8231
|
+
}
|
|
8232
|
+
});
|
|
8233
|
+
stream.on("event", (streamEvent) => {
|
|
8234
|
+
if (!config.extractFromEvent) {
|
|
8235
|
+
return;
|
|
8236
|
+
}
|
|
8237
|
+
try {
|
|
8238
|
+
if (first) {
|
|
8239
|
+
span.log({
|
|
8240
|
+
metrics: {
|
|
8241
|
+
time_to_first_token: getCurrentUnixTimestamp() - startTime
|
|
8242
|
+
}
|
|
8243
|
+
});
|
|
8244
|
+
first = false;
|
|
8245
|
+
}
|
|
8246
|
+
const extracted = config.extractFromEvent(streamEvent);
|
|
8247
|
+
if (extracted && Object.keys(extracted).length > 0) {
|
|
8248
|
+
span.log(extracted);
|
|
8249
|
+
}
|
|
8250
|
+
} catch (error) {
|
|
8251
|
+
console.error(`Error extracting event for ${channelName}:`, error);
|
|
8252
|
+
}
|
|
8253
|
+
});
|
|
8254
|
+
stream.on("end", () => {
|
|
8255
|
+
span.end();
|
|
8256
|
+
states.delete(event);
|
|
8257
|
+
});
|
|
8258
|
+
stream.on("error", (error) => {
|
|
8259
|
+
span.log({
|
|
8260
|
+
error: error.message
|
|
8261
|
+
});
|
|
8262
|
+
span.end();
|
|
8263
|
+
states.delete(event);
|
|
8264
|
+
});
|
|
8265
|
+
},
|
|
8266
|
+
error: (event) => {
|
|
8267
|
+
logErrorAndEnd(states, event);
|
|
8268
|
+
}
|
|
8269
|
+
};
|
|
8270
|
+
tracingChannel.subscribe(handlers);
|
|
8271
|
+
return () => {
|
|
8272
|
+
tracingChannel.unsubscribe(handlers);
|
|
8273
|
+
};
|
|
8274
|
+
}
|
|
8275
|
+
function unsubscribeAll(unsubscribers) {
|
|
8276
|
+
for (const unsubscribe of unsubscribers) {
|
|
8277
|
+
unsubscribe();
|
|
8278
|
+
}
|
|
8279
|
+
return [];
|
|
8280
|
+
}
|
|
8281
|
+
|
|
8282
|
+
// src/wrappers/attachment-utils.ts
|
|
8283
|
+
function getExtensionFromMediaType(mediaType) {
|
|
8284
|
+
const extensionMap = {
|
|
8285
|
+
"image/png": "png",
|
|
8286
|
+
"image/jpeg": "jpg",
|
|
8287
|
+
"image/gif": "gif",
|
|
8288
|
+
"image/webp": "webp",
|
|
8289
|
+
"image/svg+xml": "svg",
|
|
8290
|
+
"audio/mpeg": "mp3",
|
|
8291
|
+
"audio/wav": "wav",
|
|
8292
|
+
"audio/ogg": "ogg",
|
|
8293
|
+
"video/mp4": "mp4",
|
|
8294
|
+
"video/webm": "webm",
|
|
8295
|
+
"application/pdf": "pdf",
|
|
8296
|
+
"application/json": "json",
|
|
8297
|
+
"text/plain": "txt",
|
|
8298
|
+
"text/html": "html",
|
|
8299
|
+
"text/csv": "csv"
|
|
8300
|
+
};
|
|
8301
|
+
return extensionMap[mediaType] || "bin";
|
|
8302
|
+
}
|
|
8303
|
+
function convertDataToBlob(data, mediaType) {
|
|
8304
|
+
try {
|
|
8305
|
+
if (typeof data === "string") {
|
|
8306
|
+
if (data.startsWith("data:")) {
|
|
8307
|
+
const base64Match = data.match(/^data:[^;]+;base64,(.+)$/);
|
|
8308
|
+
if (base64Match) {
|
|
8309
|
+
const base64 = base64Match[1];
|
|
8310
|
+
const binaryString = atob(base64);
|
|
8311
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
8312
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
8313
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
8314
|
+
}
|
|
8315
|
+
return new Blob([bytes], { type: mediaType });
|
|
8316
|
+
}
|
|
8317
|
+
} else if (data.startsWith("http://") || data.startsWith("https://")) {
|
|
8318
|
+
return null;
|
|
8319
|
+
} else {
|
|
8320
|
+
const binaryString = atob(data);
|
|
8321
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
8322
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
8323
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
8324
|
+
}
|
|
8325
|
+
return new Blob([bytes], { type: mediaType });
|
|
8326
|
+
}
|
|
8327
|
+
} else if (data instanceof Uint8Array) {
|
|
8328
|
+
return new Blob([data], { type: mediaType });
|
|
8329
|
+
} else if (data instanceof ArrayBuffer) {
|
|
8330
|
+
return new Blob([data], { type: mediaType });
|
|
8331
|
+
} else if (typeof Buffer !== "undefined" && data instanceof Buffer) {
|
|
8332
|
+
return new Blob([data], { type: mediaType });
|
|
8333
|
+
}
|
|
8334
|
+
} catch {
|
|
8335
|
+
return null;
|
|
8336
|
+
}
|
|
8337
|
+
return null;
|
|
8338
|
+
}
|
|
8339
|
+
function processInputAttachments(input) {
|
|
8340
|
+
if (!input) {
|
|
8341
|
+
return input;
|
|
8342
|
+
}
|
|
8343
|
+
let attachmentIndex = 0;
|
|
8344
|
+
const inferMediaTypeFromDataUrl = (value, fallback) => {
|
|
8345
|
+
const mediaTypeMatch = value.match(/^data:([^;]+);/);
|
|
8346
|
+
return mediaTypeMatch?.[1] || fallback;
|
|
8347
|
+
};
|
|
8348
|
+
const toAttachment = (value, mediaType, filename) => {
|
|
8349
|
+
const blob = convertDataToBlob(value, mediaType);
|
|
8350
|
+
if (!blob) {
|
|
8351
|
+
return null;
|
|
8352
|
+
}
|
|
8353
|
+
return new Attachment({
|
|
8354
|
+
data: blob,
|
|
8355
|
+
filename,
|
|
8356
|
+
contentType: mediaType
|
|
8357
|
+
});
|
|
8358
|
+
};
|
|
8359
|
+
const processNode = (node) => {
|
|
8360
|
+
if (Array.isArray(node)) {
|
|
8361
|
+
return node.map(processNode);
|
|
8362
|
+
}
|
|
8363
|
+
if (!node || typeof node !== "object") {
|
|
8364
|
+
return node;
|
|
8365
|
+
}
|
|
8366
|
+
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:")) {
|
|
8367
|
+
const mediaType = inferMediaTypeFromDataUrl(
|
|
8368
|
+
node.image_url.url,
|
|
8369
|
+
"image/png"
|
|
8370
|
+
);
|
|
8371
|
+
const filename = `image.${getExtensionFromMediaType(mediaType)}`;
|
|
8372
|
+
const attachment = toAttachment(node.image_url.url, mediaType, filename);
|
|
8373
|
+
if (attachment) {
|
|
8374
|
+
return {
|
|
8375
|
+
...node,
|
|
8376
|
+
image_url: {
|
|
8377
|
+
...node.image_url,
|
|
8378
|
+
url: attachment
|
|
8379
|
+
}
|
|
8380
|
+
};
|
|
8381
|
+
}
|
|
8382
|
+
}
|
|
8383
|
+
if (node.type === "file" && node.file && typeof node.file === "object" && typeof node.file.file_data === "string" && node.file.file_data.startsWith("data:")) {
|
|
8384
|
+
const mediaType = inferMediaTypeFromDataUrl(
|
|
8385
|
+
node.file.file_data,
|
|
8386
|
+
"application/octet-stream"
|
|
8387
|
+
);
|
|
8388
|
+
const filename = typeof node.file.filename === "string" && node.file.filename ? node.file.filename : `document.${getExtensionFromMediaType(mediaType)}`;
|
|
8389
|
+
const attachment = toAttachment(node.file.file_data, mediaType, filename);
|
|
8390
|
+
if (attachment) {
|
|
8391
|
+
return {
|
|
8392
|
+
...node,
|
|
8393
|
+
file: {
|
|
8394
|
+
...node.file,
|
|
8395
|
+
file_data: attachment
|
|
8396
|
+
}
|
|
8397
|
+
};
|
|
8398
|
+
}
|
|
8399
|
+
}
|
|
8400
|
+
if (node.type === "image" && node.image) {
|
|
8401
|
+
let mediaType = "image/png";
|
|
8402
|
+
if (typeof node.image === "string" && node.image.startsWith("data:")) {
|
|
8403
|
+
mediaType = inferMediaTypeFromDataUrl(node.image, mediaType);
|
|
8404
|
+
} else if (node.mediaType) {
|
|
8405
|
+
mediaType = node.mediaType;
|
|
8406
|
+
}
|
|
8407
|
+
const filename = `input_image_${attachmentIndex}.${getExtensionFromMediaType(mediaType)}`;
|
|
8408
|
+
const attachment = toAttachment(node.image, mediaType, filename);
|
|
8409
|
+
if (attachment) {
|
|
8410
|
+
attachmentIndex++;
|
|
8411
|
+
return {
|
|
8412
|
+
...node,
|
|
8413
|
+
image: attachment
|
|
8414
|
+
};
|
|
8415
|
+
}
|
|
8416
|
+
}
|
|
8417
|
+
if (node.type === "file" && node.data) {
|
|
8418
|
+
const mediaType = node.mediaType || "application/octet-stream";
|
|
8419
|
+
const filename = node.filename || `input_file_${attachmentIndex}.${getExtensionFromMediaType(mediaType)}`;
|
|
8420
|
+
const attachment = toAttachment(node.data, mediaType, filename);
|
|
8421
|
+
if (attachment) {
|
|
8422
|
+
attachmentIndex++;
|
|
8423
|
+
return {
|
|
8424
|
+
...node,
|
|
8425
|
+
data: attachment
|
|
8426
|
+
};
|
|
8427
|
+
}
|
|
8428
|
+
}
|
|
8429
|
+
const processed = {};
|
|
8430
|
+
for (const [key, value] of Object.entries(node)) {
|
|
8431
|
+
processed[key] = processNode(value);
|
|
8432
|
+
}
|
|
8433
|
+
return processed;
|
|
8434
|
+
};
|
|
8435
|
+
if (Array.isArray(input)) {
|
|
8436
|
+
return input.map(processNode);
|
|
8437
|
+
}
|
|
8438
|
+
return processNode(input);
|
|
8439
|
+
}
|
|
8440
|
+
|
|
8441
|
+
// src/instrumentation/core/channel-definitions.ts
|
|
8442
|
+
function channel(spec) {
|
|
8443
|
+
return spec;
|
|
8444
|
+
}
|
|
8445
|
+
function defineChannels(pkg, channels) {
|
|
8446
|
+
return Object.fromEntries(
|
|
8447
|
+
Object.entries(channels).map(([key, spec]) => {
|
|
8448
|
+
const fullChannelName = `orchestrion:${pkg}:${spec.channelName}`;
|
|
8449
|
+
if (spec.kind === "async") {
|
|
8450
|
+
const asyncSpec = spec;
|
|
8451
|
+
const tracingChannel2 = () => isomorph_default.newTracingChannel(
|
|
8452
|
+
fullChannelName
|
|
8453
|
+
);
|
|
8454
|
+
return [
|
|
8455
|
+
key,
|
|
8456
|
+
{
|
|
8457
|
+
...asyncSpec,
|
|
8458
|
+
tracingChannel: tracingChannel2,
|
|
8459
|
+
tracePromise: (fn, context) => tracingChannel2().tracePromise(
|
|
8460
|
+
fn,
|
|
8461
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
8462
|
+
context
|
|
8463
|
+
)
|
|
8464
|
+
}
|
|
8465
|
+
];
|
|
8466
|
+
}
|
|
8467
|
+
const syncSpec = spec;
|
|
8468
|
+
const tracingChannel = () => isomorph_default.newTracingChannel(
|
|
8469
|
+
fullChannelName
|
|
8470
|
+
);
|
|
8471
|
+
return [
|
|
8472
|
+
key,
|
|
8473
|
+
{
|
|
8474
|
+
...syncSpec,
|
|
8475
|
+
tracingChannel,
|
|
8476
|
+
traceSync: (fn, context) => tracingChannel().traceSync(
|
|
8477
|
+
fn,
|
|
8478
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
8479
|
+
context
|
|
8480
|
+
)
|
|
8481
|
+
}
|
|
8482
|
+
];
|
|
8483
|
+
})
|
|
8484
|
+
);
|
|
8485
|
+
}
|
|
8486
|
+
|
|
8487
|
+
// src/instrumentation/plugins/openai-channels.ts
|
|
8488
|
+
var openAIChannels = defineChannels("openai", {
|
|
8489
|
+
chatCompletionsCreate: channel({
|
|
8490
|
+
channelName: "chat.completions.create",
|
|
8491
|
+
kind: "async"
|
|
8492
|
+
}),
|
|
8493
|
+
embeddingsCreate: channel({
|
|
8494
|
+
channelName: "embeddings.create",
|
|
8495
|
+
kind: "async"
|
|
8496
|
+
}),
|
|
8497
|
+
betaChatCompletionsParse: channel({
|
|
8498
|
+
channelName: "beta.chat.completions.parse",
|
|
8499
|
+
kind: "async"
|
|
8500
|
+
}),
|
|
8501
|
+
betaChatCompletionsStream: channel({
|
|
8502
|
+
channelName: "beta.chat.completions.stream",
|
|
8503
|
+
kind: "sync-stream"
|
|
8504
|
+
}),
|
|
8505
|
+
moderationsCreate: channel({
|
|
8506
|
+
channelName: "moderations.create",
|
|
8507
|
+
kind: "async"
|
|
8508
|
+
}),
|
|
8509
|
+
responsesCreate: channel({
|
|
8510
|
+
channelName: "responses.create",
|
|
8511
|
+
kind: "async"
|
|
8512
|
+
}),
|
|
8513
|
+
responsesStream: channel({
|
|
8514
|
+
channelName: "responses.stream",
|
|
8515
|
+
kind: "sync-stream"
|
|
8516
|
+
}),
|
|
8517
|
+
responsesParse: channel({
|
|
8518
|
+
channelName: "responses.parse",
|
|
8519
|
+
kind: "async"
|
|
8520
|
+
})
|
|
8521
|
+
});
|
|
8522
|
+
|
|
8523
|
+
// src/openai-utils.ts
|
|
8524
|
+
var BRAINTRUST_CACHED_STREAM_METRIC = "__braintrust_cached_metric";
|
|
8525
|
+
var LEGACY_CACHED_HEADER = "x-cached";
|
|
8526
|
+
var X_CACHED_HEADER = "x-bt-cached";
|
|
8527
|
+
var TOKEN_NAME_MAP = {
|
|
8528
|
+
input_tokens: "prompt_tokens",
|
|
8529
|
+
output_tokens: "completion_tokens",
|
|
8530
|
+
total_tokens: "tokens"
|
|
8531
|
+
};
|
|
8532
|
+
var TOKEN_PREFIX_MAP = {
|
|
8533
|
+
input: "prompt",
|
|
8534
|
+
output: "completion"
|
|
8535
|
+
};
|
|
8536
|
+
function parseMetricsFromUsage(usage) {
|
|
8537
|
+
if (!usage) {
|
|
8538
|
+
return {};
|
|
8539
|
+
}
|
|
8540
|
+
const metrics = {};
|
|
8541
|
+
for (const [oaiName, value] of Object.entries(usage)) {
|
|
8542
|
+
if (typeof value === "number") {
|
|
8543
|
+
const metricName = TOKEN_NAME_MAP[oaiName] || oaiName;
|
|
8544
|
+
metrics[metricName] = value;
|
|
8545
|
+
continue;
|
|
8546
|
+
}
|
|
8547
|
+
if (!oaiName.endsWith("_tokens_details") || !isObject(value)) {
|
|
8548
|
+
continue;
|
|
8549
|
+
}
|
|
8550
|
+
const rawPrefix = oaiName.slice(0, -"_tokens_details".length);
|
|
8551
|
+
const prefix = TOKEN_PREFIX_MAP[rawPrefix] || rawPrefix;
|
|
8552
|
+
for (const [key, nestedValue] of Object.entries(value)) {
|
|
8553
|
+
if (typeof nestedValue !== "number") {
|
|
8554
|
+
continue;
|
|
8555
|
+
}
|
|
8556
|
+
metrics[`${prefix}_${key}`] = nestedValue;
|
|
8557
|
+
}
|
|
8558
|
+
}
|
|
8559
|
+
return metrics;
|
|
8560
|
+
}
|
|
8561
|
+
function parseCachedHeader(value) {
|
|
8562
|
+
if (!value) {
|
|
8563
|
+
return void 0;
|
|
8564
|
+
}
|
|
8565
|
+
return ["true", "hit"].includes(value.toLowerCase()) ? 1 : 0;
|
|
8566
|
+
}
|
|
8567
|
+
function getCachedMetricFromHeaders(headers) {
|
|
8568
|
+
if (!headers || typeof headers.get !== "function") {
|
|
8569
|
+
return void 0;
|
|
8570
|
+
}
|
|
8571
|
+
const cachedHeader = headers.get(X_CACHED_HEADER);
|
|
8572
|
+
if (cachedHeader) {
|
|
8573
|
+
return parseCachedHeader(cachedHeader);
|
|
8574
|
+
}
|
|
8575
|
+
return parseCachedHeader(headers.get(LEGACY_CACHED_HEADER));
|
|
8576
|
+
}
|
|
8577
|
+
|
|
8578
|
+
// src/instrumentation/plugins/openai-plugin.ts
|
|
8579
|
+
var OpenAIPlugin = class extends BasePlugin {
|
|
8580
|
+
constructor() {
|
|
7837
8581
|
super();
|
|
7838
8582
|
}
|
|
7839
8583
|
onEnable() {
|
|
7840
|
-
this.
|
|
7841
|
-
|
|
7842
|
-
{
|
|
8584
|
+
this.unsubscribers.push(
|
|
8585
|
+
traceStreamingChannel(openAIChannels.chatCompletionsCreate, {
|
|
7843
8586
|
name: "Chat Completion",
|
|
7844
8587
|
type: "llm" /* LLM */,
|
|
7845
|
-
extractInput: (
|
|
7846
|
-
const params = args[0] || {};
|
|
8588
|
+
extractInput: ([params]) => {
|
|
7847
8589
|
const { messages, ...metadata } = params;
|
|
7848
8590
|
return {
|
|
7849
8591
|
input: processInputAttachments(messages),
|
|
@@ -7853,41 +8595,49 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
7853
8595
|
extractOutput: (result) => {
|
|
7854
8596
|
return result?.choices;
|
|
7855
8597
|
},
|
|
7856
|
-
extractMetrics: (result, startTime) => {
|
|
7857
|
-
const metrics =
|
|
8598
|
+
extractMetrics: (result, startTime, endEvent) => {
|
|
8599
|
+
const metrics = withCachedMetric(
|
|
8600
|
+
parseMetricsFromUsage(result?.usage),
|
|
8601
|
+
result,
|
|
8602
|
+
endEvent
|
|
8603
|
+
);
|
|
7858
8604
|
if (startTime) {
|
|
7859
8605
|
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
7860
8606
|
}
|
|
7861
8607
|
return metrics;
|
|
7862
8608
|
},
|
|
7863
8609
|
aggregateChunks: aggregateChatCompletionChunks
|
|
7864
|
-
}
|
|
8610
|
+
})
|
|
7865
8611
|
);
|
|
7866
|
-
this.
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
8612
|
+
this.unsubscribers.push(
|
|
8613
|
+
traceAsyncChannel(openAIChannels.embeddingsCreate, {
|
|
8614
|
+
name: "Embedding",
|
|
8615
|
+
type: "llm" /* LLM */,
|
|
8616
|
+
extractInput: ([params]) => {
|
|
8617
|
+
const { input, ...metadata } = params;
|
|
8618
|
+
return {
|
|
8619
|
+
input,
|
|
8620
|
+
metadata: { ...metadata, provider: "openai" }
|
|
8621
|
+
};
|
|
8622
|
+
},
|
|
8623
|
+
extractOutput: (result) => {
|
|
8624
|
+
const embedding = result?.data?.[0]?.embedding;
|
|
8625
|
+
return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
|
|
8626
|
+
},
|
|
8627
|
+
extractMetrics: (result, _startTime, endEvent) => {
|
|
8628
|
+
return withCachedMetric(
|
|
8629
|
+
parseMetricsFromUsage(result?.usage),
|
|
8630
|
+
result,
|
|
8631
|
+
endEvent
|
|
8632
|
+
);
|
|
8633
|
+
}
|
|
8634
|
+
})
|
|
8635
|
+
);
|
|
8636
|
+
this.unsubscribers.push(
|
|
8637
|
+
traceStreamingChannel(openAIChannels.betaChatCompletionsParse, {
|
|
7887
8638
|
name: "Chat Completion",
|
|
7888
8639
|
type: "llm" /* LLM */,
|
|
7889
|
-
extractInput: (
|
|
7890
|
-
const params = args[0] || {};
|
|
8640
|
+
extractInput: ([params]) => {
|
|
7891
8641
|
const { messages, ...metadata } = params;
|
|
7892
8642
|
return {
|
|
7893
8643
|
input: processInputAttachments(messages),
|
|
@@ -7897,164 +8647,196 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
7897
8647
|
extractOutput: (result) => {
|
|
7898
8648
|
return result?.choices;
|
|
7899
8649
|
},
|
|
7900
|
-
extractMetrics: (result, startTime) => {
|
|
7901
|
-
const metrics =
|
|
8650
|
+
extractMetrics: (result, startTime, endEvent) => {
|
|
8651
|
+
const metrics = withCachedMetric(
|
|
8652
|
+
parseMetricsFromUsage(result?.usage),
|
|
8653
|
+
result,
|
|
8654
|
+
endEvent
|
|
8655
|
+
);
|
|
7902
8656
|
if (startTime) {
|
|
7903
8657
|
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
7904
8658
|
}
|
|
7905
8659
|
return metrics;
|
|
7906
8660
|
},
|
|
7907
8661
|
aggregateChunks: aggregateChatCompletionChunks
|
|
7908
|
-
}
|
|
8662
|
+
})
|
|
7909
8663
|
);
|
|
7910
|
-
this.
|
|
7911
|
-
|
|
7912
|
-
{
|
|
8664
|
+
this.unsubscribers.push(
|
|
8665
|
+
traceSyncStreamChannel(openAIChannels.betaChatCompletionsStream, {
|
|
7913
8666
|
name: "Chat Completion",
|
|
7914
8667
|
type: "llm" /* LLM */,
|
|
7915
|
-
extractInput: (
|
|
7916
|
-
const params = args[0] || {};
|
|
8668
|
+
extractInput: ([params]) => {
|
|
7917
8669
|
const { messages, ...metadata } = params;
|
|
7918
8670
|
return {
|
|
7919
8671
|
input: processInputAttachments(messages),
|
|
7920
8672
|
metadata: { ...metadata, provider: "openai" }
|
|
7921
8673
|
};
|
|
7922
8674
|
}
|
|
7923
|
-
}
|
|
8675
|
+
})
|
|
7924
8676
|
);
|
|
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 {};
|
|
8677
|
+
this.unsubscribers.push(
|
|
8678
|
+
traceAsyncChannel(openAIChannels.moderationsCreate, {
|
|
8679
|
+
name: "Moderation",
|
|
8680
|
+
type: "llm" /* LLM */,
|
|
8681
|
+
extractInput: ([params]) => {
|
|
8682
|
+
const { input, ...metadata } = params;
|
|
8683
|
+
return {
|
|
8684
|
+
input,
|
|
8685
|
+
metadata: { ...metadata, provider: "openai" }
|
|
8686
|
+
};
|
|
8687
|
+
},
|
|
8688
|
+
extractOutput: (result) => {
|
|
8689
|
+
return result?.results;
|
|
8690
|
+
},
|
|
8691
|
+
extractMetrics: (result, _startTime, endEvent) => {
|
|
8692
|
+
return withCachedMetric(
|
|
8693
|
+
parseMetricsFromUsage(result?.usage),
|
|
8694
|
+
result,
|
|
8695
|
+
endEvent
|
|
8696
|
+
);
|
|
7979
8697
|
}
|
|
7980
|
-
|
|
7981
|
-
|
|
8698
|
+
})
|
|
8699
|
+
);
|
|
8700
|
+
this.unsubscribers.push(
|
|
8701
|
+
traceStreamingChannel(openAIChannels.responsesCreate, {
|
|
8702
|
+
name: "openai.responses.create",
|
|
8703
|
+
type: "llm" /* LLM */,
|
|
8704
|
+
extractInput: ([params]) => {
|
|
8705
|
+
const { input, ...metadata } = params;
|
|
8706
|
+
return {
|
|
8707
|
+
input: processInputAttachments(input),
|
|
8708
|
+
metadata: { ...metadata, provider: "openai" }
|
|
8709
|
+
};
|
|
8710
|
+
},
|
|
8711
|
+
extractOutput: (result) => {
|
|
8712
|
+
return processImagesInOutput(result?.output);
|
|
8713
|
+
},
|
|
8714
|
+
extractMetadata: (result) => {
|
|
8715
|
+
if (!result) {
|
|
8716
|
+
return void 0;
|
|
8717
|
+
}
|
|
8718
|
+
const { output: _output, usage: _usage, ...metadata } = result;
|
|
8719
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
8720
|
+
},
|
|
8721
|
+
extractMetrics: (result, startTime, endEvent) => {
|
|
8722
|
+
const metrics = withCachedMetric(
|
|
8723
|
+
parseMetricsFromUsage(result?.usage),
|
|
8724
|
+
result,
|
|
8725
|
+
endEvent
|
|
8726
|
+
);
|
|
8727
|
+
if (startTime) {
|
|
8728
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8729
|
+
}
|
|
8730
|
+
return metrics;
|
|
8731
|
+
},
|
|
8732
|
+
aggregateChunks: aggregateResponseStreamEvents
|
|
8733
|
+
})
|
|
8734
|
+
);
|
|
8735
|
+
this.unsubscribers.push(
|
|
8736
|
+
traceSyncStreamChannel(openAIChannels.responsesStream, {
|
|
8737
|
+
name: "openai.responses.create",
|
|
8738
|
+
type: "llm" /* LLM */,
|
|
8739
|
+
extractInput: ([params]) => {
|
|
8740
|
+
const { input, ...metadata } = params;
|
|
8741
|
+
return {
|
|
8742
|
+
input: processInputAttachments(input),
|
|
8743
|
+
metadata: { ...metadata, provider: "openai" }
|
|
8744
|
+
};
|
|
8745
|
+
},
|
|
8746
|
+
extractFromEvent: (event) => {
|
|
8747
|
+
if (event.type !== "response.completed" || !event.response) {
|
|
8748
|
+
return {};
|
|
8749
|
+
}
|
|
8750
|
+
const response = event.response;
|
|
7982
8751
|
const data = {};
|
|
7983
|
-
if (response
|
|
8752
|
+
if (response.output !== void 0) {
|
|
7984
8753
|
data.output = processImagesInOutput(response.output);
|
|
7985
8754
|
}
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
data.metadata = metadata;
|
|
7990
|
-
}
|
|
8755
|
+
const { usage: _usage, output: _output, ...metadata } = response;
|
|
8756
|
+
if (Object.keys(metadata).length > 0) {
|
|
8757
|
+
data.metadata = metadata;
|
|
7991
8758
|
}
|
|
7992
|
-
data.metrics = parseMetricsFromUsage(response
|
|
8759
|
+
data.metrics = parseMetricsFromUsage(response.usage);
|
|
7993
8760
|
return data;
|
|
7994
8761
|
}
|
|
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
|
-
|
|
8762
|
+
})
|
|
8763
|
+
);
|
|
8764
|
+
this.unsubscribers.push(
|
|
8765
|
+
traceStreamingChannel(openAIChannels.responsesParse, {
|
|
8766
|
+
name: "openai.responses.parse",
|
|
8767
|
+
type: "llm" /* LLM */,
|
|
8768
|
+
extractInput: ([params]) => {
|
|
8769
|
+
const { input, ...metadata } = params;
|
|
8770
|
+
return {
|
|
8771
|
+
input: processInputAttachments(input),
|
|
8772
|
+
metadata: { ...metadata, provider: "openai" }
|
|
8773
|
+
};
|
|
8774
|
+
},
|
|
8775
|
+
extractOutput: (result) => {
|
|
8776
|
+
return processImagesInOutput(result?.output);
|
|
8777
|
+
},
|
|
8778
|
+
extractMetadata: (result) => {
|
|
8779
|
+
if (!result) {
|
|
8780
|
+
return void 0;
|
|
8781
|
+
}
|
|
8782
|
+
const { output: _output, usage: _usage, ...metadata } = result;
|
|
8783
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
8784
|
+
},
|
|
8785
|
+
extractMetrics: (result, startTime, endEvent) => {
|
|
8786
|
+
const metrics = withCachedMetric(
|
|
8787
|
+
parseMetricsFromUsage(result?.usage),
|
|
8788
|
+
result,
|
|
8789
|
+
endEvent
|
|
8790
|
+
);
|
|
8791
|
+
if (startTime) {
|
|
8792
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8793
|
+
}
|
|
8794
|
+
return metrics;
|
|
8795
|
+
},
|
|
8796
|
+
aggregateChunks: aggregateResponseStreamEvents
|
|
8797
|
+
})
|
|
8798
|
+
);
|
|
8020
8799
|
}
|
|
8021
8800
|
onDisable() {
|
|
8801
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
8022
8802
|
}
|
|
8023
8803
|
};
|
|
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 {};
|
|
8804
|
+
function getCachedMetricFromEndEvent(endEvent) {
|
|
8805
|
+
if (!isObject(endEvent)) {
|
|
8806
|
+
return void 0;
|
|
8036
8807
|
}
|
|
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
|
-
}
|
|
8808
|
+
const response = endEvent.response;
|
|
8809
|
+
if (!isObject(response)) {
|
|
8810
|
+
return void 0;
|
|
8056
8811
|
}
|
|
8057
|
-
|
|
8812
|
+
const headers = response.headers;
|
|
8813
|
+
if (!headers || typeof headers.get !== "function") {
|
|
8814
|
+
return void 0;
|
|
8815
|
+
}
|
|
8816
|
+
return getCachedMetricFromHeaders(headers);
|
|
8817
|
+
}
|
|
8818
|
+
function withCachedMetric(metrics, result, endEvent) {
|
|
8819
|
+
if (metrics.cached !== void 0) {
|
|
8820
|
+
return metrics;
|
|
8821
|
+
}
|
|
8822
|
+
const cachedFromEvent = getCachedMetricFromEndEvent(endEvent);
|
|
8823
|
+
if (cachedFromEvent !== void 0) {
|
|
8824
|
+
return {
|
|
8825
|
+
...metrics,
|
|
8826
|
+
cached: cachedFromEvent
|
|
8827
|
+
};
|
|
8828
|
+
}
|
|
8829
|
+
if (!isObject(result)) {
|
|
8830
|
+
return metrics;
|
|
8831
|
+
}
|
|
8832
|
+
const cached = result[BRAINTRUST_CACHED_STREAM_METRIC];
|
|
8833
|
+
if (typeof cached !== "number") {
|
|
8834
|
+
return metrics;
|
|
8835
|
+
}
|
|
8836
|
+
return {
|
|
8837
|
+
...metrics,
|
|
8838
|
+
cached
|
|
8839
|
+
};
|
|
8058
8840
|
}
|
|
8059
8841
|
function processImagesInOutput(output) {
|
|
8060
8842
|
if (Array.isArray(output)) {
|
|
@@ -8085,7 +8867,7 @@ function processImagesInOutput(output) {
|
|
|
8085
8867
|
}
|
|
8086
8868
|
return output;
|
|
8087
8869
|
}
|
|
8088
|
-
function aggregateChatCompletionChunks(chunks) {
|
|
8870
|
+
function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
|
|
8089
8871
|
let role = void 0;
|
|
8090
8872
|
let content = void 0;
|
|
8091
8873
|
let tool_calls = void 0;
|
|
@@ -8127,6 +8909,7 @@ function aggregateChatCompletionChunks(chunks) {
|
|
|
8127
8909
|
}
|
|
8128
8910
|
}
|
|
8129
8911
|
}
|
|
8912
|
+
metrics = withCachedMetric(metrics, streamResult, endEvent);
|
|
8130
8913
|
return {
|
|
8131
8914
|
metrics,
|
|
8132
8915
|
output: [
|
|
@@ -8143,9 +8926,33 @@ function aggregateChatCompletionChunks(chunks) {
|
|
|
8143
8926
|
]
|
|
8144
8927
|
};
|
|
8145
8928
|
}
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8929
|
+
function aggregateResponseStreamEvents(chunks, _streamResult, endEvent) {
|
|
8930
|
+
let output = void 0;
|
|
8931
|
+
let metrics = {};
|
|
8932
|
+
let metadata = void 0;
|
|
8933
|
+
for (const chunk of chunks) {
|
|
8934
|
+
if (!chunk || !chunk.type || !chunk.response) {
|
|
8935
|
+
continue;
|
|
8936
|
+
}
|
|
8937
|
+
if (chunk.type !== "response.completed") {
|
|
8938
|
+
continue;
|
|
8939
|
+
}
|
|
8940
|
+
const response = chunk.response;
|
|
8941
|
+
if (response?.output !== void 0) {
|
|
8942
|
+
output = processImagesInOutput(response.output);
|
|
8943
|
+
}
|
|
8944
|
+
const { usage: _usage, output: _output, ...rest } = response || {};
|
|
8945
|
+
if (Object.keys(rest).length > 0) {
|
|
8946
|
+
metadata = rest;
|
|
8947
|
+
}
|
|
8948
|
+
metrics = parseMetricsFromUsage(response?.usage);
|
|
8949
|
+
}
|
|
8950
|
+
return {
|
|
8951
|
+
output,
|
|
8952
|
+
metrics: withCachedMetric(metrics, void 0, endEvent),
|
|
8953
|
+
...metadata !== void 0 ? { metadata } : {}
|
|
8954
|
+
};
|
|
8955
|
+
}
|
|
8149
8956
|
|
|
8150
8957
|
// src/wrappers/anthropic-tokens-util.ts
|
|
8151
8958
|
function finalizeAnthropicTokens(metrics) {
|
|
@@ -8166,216 +8973,76 @@ function extractAnthropicCacheTokens(cacheReadTokens = 0, cacheCreationTokens =
|
|
|
8166
8973
|
}
|
|
8167
8974
|
return cacheTokens;
|
|
8168
8975
|
}
|
|
8169
|
-
|
|
8170
|
-
// src/instrumentation/plugins/anthropic-
|
|
8171
|
-
var
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
}
|
|
8176
|
-
|
|
8177
|
-
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
return
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
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
|
-
);
|
|
8266
|
-
}
|
|
8267
|
-
/**
|
|
8268
|
-
* Subscribe to a channel for async methods that may return streams.
|
|
8269
|
-
* Handles both streaming and non-streaming responses based on the stream parameter.
|
|
8270
|
-
*/
|
|
8271
|
-
subscribeToStreamingChannel(channelName, config) {
|
|
8272
|
-
const channel = tracingChannel2(channelName);
|
|
8273
|
-
const spans = /* @__PURE__ */ new WeakMap();
|
|
8274
|
-
const handlers = {
|
|
8275
|
-
start: (event) => {
|
|
8276
|
-
const span = startSpan({
|
|
8277
|
-
name: config.name,
|
|
8278
|
-
spanAttributes: {
|
|
8279
|
-
type: config.type
|
|
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
|
-
}
|
|
8293
|
-
},
|
|
8294
|
-
asyncEnd: (event) => {
|
|
8295
|
-
const spanData = spans.get(event);
|
|
8296
|
-
if (!spanData) {
|
|
8297
|
-
return;
|
|
8298
|
-
}
|
|
8299
|
-
const { span, startTime } = spanData;
|
|
8300
|
-
const isStreaming = config.isStreaming ? config.isStreaming(event.arguments) : isAsyncIterable(event.result);
|
|
8301
|
-
if (isStreaming && isAsyncIterable(event.result)) {
|
|
8302
|
-
patchStreamIfNeeded(event.result, {
|
|
8303
|
-
onComplete: (chunks) => {
|
|
8304
|
-
try {
|
|
8305
|
-
let output;
|
|
8306
|
-
let metrics;
|
|
8307
|
-
let metadata = {};
|
|
8308
|
-
if (config.aggregateChunks) {
|
|
8309
|
-
const aggregated = config.aggregateChunks(chunks);
|
|
8310
|
-
output = aggregated.output;
|
|
8311
|
-
metrics = aggregated.metrics;
|
|
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);
|
|
8359
|
-
}
|
|
8976
|
+
|
|
8977
|
+
// src/instrumentation/plugins/anthropic-channels.ts
|
|
8978
|
+
var anthropicChannels = defineChannels("@anthropic-ai/sdk", {
|
|
8979
|
+
messagesCreate: channel({
|
|
8980
|
+
channelName: "messages.create",
|
|
8981
|
+
kind: "async"
|
|
8982
|
+
}),
|
|
8983
|
+
betaMessagesCreate: channel({
|
|
8984
|
+
channelName: "beta.messages.create",
|
|
8985
|
+
kind: "async"
|
|
8986
|
+
})
|
|
8987
|
+
});
|
|
8988
|
+
|
|
8989
|
+
// src/instrumentation/plugins/anthropic-plugin.ts
|
|
8990
|
+
var AnthropicPlugin = class extends BasePlugin {
|
|
8991
|
+
onEnable() {
|
|
8992
|
+
this.subscribeToAnthropicChannels();
|
|
8993
|
+
}
|
|
8994
|
+
onDisable() {
|
|
8995
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
8996
|
+
}
|
|
8997
|
+
subscribeToAnthropicChannels() {
|
|
8998
|
+
const anthropicConfig = {
|
|
8999
|
+
name: "anthropic.messages.create",
|
|
9000
|
+
type: "llm" /* LLM */,
|
|
9001
|
+
extractInput: (args) => {
|
|
9002
|
+
const params = args[0] || {};
|
|
9003
|
+
const input = coalesceInput(params.messages || [], params.system);
|
|
9004
|
+
const metadata = filterFrom(params, ["messages", "system"]);
|
|
9005
|
+
return {
|
|
9006
|
+
input: processAttachmentsInInput(input),
|
|
9007
|
+
metadata: { ...metadata, provider: "anthropic" }
|
|
9008
|
+
};
|
|
9009
|
+
},
|
|
9010
|
+
extractOutput: (message) => {
|
|
9011
|
+
return message ? { role: message.role, content: message.content } : null;
|
|
9012
|
+
},
|
|
9013
|
+
extractMetrics: (message, startTime) => {
|
|
9014
|
+
const metrics = parseMetricsFromUsage2(message?.usage);
|
|
9015
|
+
if (startTime) {
|
|
9016
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8360
9017
|
}
|
|
9018
|
+
const finalized = finalizeAnthropicTokens(metrics);
|
|
9019
|
+
return Object.fromEntries(
|
|
9020
|
+
Object.entries(finalized).filter(
|
|
9021
|
+
(entry) => entry[1] !== void 0
|
|
9022
|
+
)
|
|
9023
|
+
);
|
|
8361
9024
|
},
|
|
8362
|
-
|
|
8363
|
-
const
|
|
8364
|
-
|
|
8365
|
-
|
|
9025
|
+
extractMetadata: (message) => {
|
|
9026
|
+
const metadata = {};
|
|
9027
|
+
const metas = ["stop_reason", "stop_sequence"];
|
|
9028
|
+
for (const m of metas) {
|
|
9029
|
+
if (message?.[m] !== void 0) {
|
|
9030
|
+
metadata[m] = message[m];
|
|
9031
|
+
}
|
|
8366
9032
|
}
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
});
|
|
8371
|
-
span.end();
|
|
8372
|
-
spans.delete(event);
|
|
8373
|
-
}
|
|
9033
|
+
return metadata;
|
|
9034
|
+
},
|
|
9035
|
+
aggregateChunks: (chunks) => aggregateAnthropicStreamChunks(chunks)
|
|
8374
9036
|
};
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
9037
|
+
this.unsubscribers.push(
|
|
9038
|
+
traceStreamingChannel(anthropicChannels.messagesCreate, anthropicConfig)
|
|
9039
|
+
);
|
|
9040
|
+
this.unsubscribers.push(
|
|
9041
|
+
traceStreamingChannel(anthropicChannels.betaMessagesCreate, {
|
|
9042
|
+
...anthropicConfig,
|
|
9043
|
+
name: "anthropic.beta.messages.create"
|
|
9044
|
+
})
|
|
9045
|
+
);
|
|
8379
9046
|
}
|
|
8380
9047
|
};
|
|
8381
9048
|
function parseMetricsFromUsage2(usage) {
|
|
@@ -8399,29 +9066,29 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
8399
9066
|
const deltas = [];
|
|
8400
9067
|
let metrics = {};
|
|
8401
9068
|
let metadata = {};
|
|
8402
|
-
for (const
|
|
8403
|
-
switch (
|
|
9069
|
+
for (const event of chunks) {
|
|
9070
|
+
switch (event?.type) {
|
|
8404
9071
|
case "message_start":
|
|
8405
|
-
if (
|
|
8406
|
-
const initialMetrics = parseMetricsFromUsage2(
|
|
9072
|
+
if (event.message?.usage) {
|
|
9073
|
+
const initialMetrics = parseMetricsFromUsage2(event.message.usage);
|
|
8407
9074
|
metrics = { ...metrics, ...initialMetrics };
|
|
8408
9075
|
}
|
|
8409
9076
|
break;
|
|
8410
9077
|
case "content_block_delta":
|
|
8411
|
-
if (
|
|
8412
|
-
const text =
|
|
9078
|
+
if (event.delta?.type === "text_delta") {
|
|
9079
|
+
const text = event.delta.text;
|
|
8413
9080
|
if (text) {
|
|
8414
9081
|
deltas.push(text);
|
|
8415
9082
|
}
|
|
8416
9083
|
}
|
|
8417
9084
|
break;
|
|
8418
9085
|
case "message_delta":
|
|
8419
|
-
if (
|
|
8420
|
-
const finalMetrics = parseMetricsFromUsage2(
|
|
9086
|
+
if (event.usage) {
|
|
9087
|
+
const finalMetrics = parseMetricsFromUsage2(event.usage);
|
|
8421
9088
|
metrics = { ...metrics, ...finalMetrics };
|
|
8422
9089
|
}
|
|
8423
|
-
if (
|
|
8424
|
-
metadata = { ...metadata, ...
|
|
9090
|
+
if (event.delta) {
|
|
9091
|
+
metadata = { ...metadata, ...event.delta };
|
|
8425
9092
|
}
|
|
8426
9093
|
break;
|
|
8427
9094
|
}
|
|
@@ -8429,7 +9096,9 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
8429
9096
|
const output = deltas.join("");
|
|
8430
9097
|
const finalized = finalizeAnthropicTokens(metrics);
|
|
8431
9098
|
const filteredMetrics = Object.fromEntries(
|
|
8432
|
-
Object.entries(finalized).filter(
|
|
9099
|
+
Object.entries(finalized).filter(
|
|
9100
|
+
(entry) => entry[1] !== void 0
|
|
9101
|
+
)
|
|
8433
9102
|
);
|
|
8434
9103
|
return {
|
|
8435
9104
|
output,
|
|
@@ -8437,6 +9106,9 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
8437
9106
|
metadata
|
|
8438
9107
|
};
|
|
8439
9108
|
}
|
|
9109
|
+
function isAnthropicBase64ContentBlock(input) {
|
|
9110
|
+
return (input.type === "image" || input.type === "document") && isObject(input.source) && input.source.type === "base64";
|
|
9111
|
+
}
|
|
8440
9112
|
function convertBase64ToAttachment(source, contentType) {
|
|
8441
9113
|
const mediaType = typeof source.media_type === "string" ? source.media_type : "image/png";
|
|
8442
9114
|
const base64Data = source.data;
|
|
@@ -8460,14 +9132,14 @@ function convertBase64ToAttachment(source, contentType) {
|
|
|
8460
9132
|
data: attachment
|
|
8461
9133
|
};
|
|
8462
9134
|
}
|
|
8463
|
-
return source;
|
|
9135
|
+
return { ...source };
|
|
8464
9136
|
}
|
|
8465
9137
|
function processAttachmentsInInput(input) {
|
|
8466
9138
|
if (Array.isArray(input)) {
|
|
8467
9139
|
return input.map(processAttachmentsInInput);
|
|
8468
9140
|
}
|
|
8469
9141
|
if (isObject(input)) {
|
|
8470
|
-
if ((input
|
|
9142
|
+
if (isAnthropicBase64ContentBlock(input)) {
|
|
8471
9143
|
return {
|
|
8472
9144
|
...input,
|
|
8473
9145
|
source: convertBase64ToAttachment(input.source, input.type)
|
|
@@ -8498,8 +9170,35 @@ function filterFrom(obj, fieldsToRemove) {
|
|
|
8498
9170
|
return result;
|
|
8499
9171
|
}
|
|
8500
9172
|
|
|
9173
|
+
// src/instrumentation/plugins/ai-sdk-channels.ts
|
|
9174
|
+
var aiSDKChannels = defineChannels("ai", {
|
|
9175
|
+
generateText: channel({
|
|
9176
|
+
channelName: "generateText",
|
|
9177
|
+
kind: "async"
|
|
9178
|
+
}),
|
|
9179
|
+
streamText: channel({
|
|
9180
|
+
channelName: "streamText",
|
|
9181
|
+
kind: "async"
|
|
9182
|
+
}),
|
|
9183
|
+
generateObject: channel({
|
|
9184
|
+
channelName: "generateObject",
|
|
9185
|
+
kind: "async"
|
|
9186
|
+
}),
|
|
9187
|
+
streamObject: channel({
|
|
9188
|
+
channelName: "streamObject",
|
|
9189
|
+
kind: "async"
|
|
9190
|
+
}),
|
|
9191
|
+
agentGenerate: channel({
|
|
9192
|
+
channelName: "Agent.generate",
|
|
9193
|
+
kind: "async"
|
|
9194
|
+
}),
|
|
9195
|
+
agentStream: channel({
|
|
9196
|
+
channelName: "Agent.stream",
|
|
9197
|
+
kind: "async"
|
|
9198
|
+
})
|
|
9199
|
+
});
|
|
9200
|
+
|
|
8501
9201
|
// src/instrumentation/plugins/ai-sdk-plugin.ts
|
|
8502
|
-
import { tracingChannel as tracingChannel3 } from "dc-browser";
|
|
8503
9202
|
var DEFAULT_DENY_OUTPUT_PATHS = [
|
|
8504
9203
|
// v3
|
|
8505
9204
|
"roundtrips[].request.body",
|
|
@@ -8515,7 +9214,6 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
|
|
|
8515
9214
|
"steps[].response.headers"
|
|
8516
9215
|
];
|
|
8517
9216
|
var AISDKPlugin = class extends BasePlugin {
|
|
8518
|
-
unsubscribers = [];
|
|
8519
9217
|
config;
|
|
8520
9218
|
constructor(config = {}) {
|
|
8521
9219
|
super();
|
|
@@ -8525,249 +9223,148 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
8525
9223
|
this.subscribeToAISDK();
|
|
8526
9224
|
}
|
|
8527
9225
|
onDisable() {
|
|
8528
|
-
|
|
8529
|
-
unsubscribe();
|
|
8530
|
-
}
|
|
8531
|
-
this.unsubscribers = [];
|
|
9226
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
8532
9227
|
}
|
|
8533
9228
|
subscribeToAISDK() {
|
|
8534
9229
|
const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
|
|
8535
|
-
this.
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
}
|
|
8553
|
-
return metrics;
|
|
8554
|
-
},
|
|
8555
|
-
aggregateChunks: aggregateAISDKChunks
|
|
8556
|
-
});
|
|
8557
|
-
this.subscribeToStreamingChannel("orchestrion:ai-sdk:streamText", {
|
|
8558
|
-
name: "streamText",
|
|
8559
|
-
type: "llm" /* LLM */,
|
|
8560
|
-
extractInput: (args) => {
|
|
8561
|
-
const params = args[0] || {};
|
|
8562
|
-
return {
|
|
8563
|
-
input: processAISDKInput(params),
|
|
8564
|
-
metadata: extractMetadataFromParams(params)
|
|
8565
|
-
};
|
|
8566
|
-
},
|
|
8567
|
-
extractOutput: (result) => {
|
|
8568
|
-
return processAISDKOutput(result, denyOutputPaths);
|
|
8569
|
-
},
|
|
8570
|
-
extractMetrics: (result, startTime) => {
|
|
8571
|
-
const metrics = extractTokenMetrics(result);
|
|
8572
|
-
if (startTime) {
|
|
8573
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
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;
|
|
8662
|
-
}
|
|
8663
|
-
return metrics;
|
|
8664
|
-
},
|
|
8665
|
-
aggregateChunks: aggregateAISDKChunks
|
|
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,
|
|
8679
|
-
spanAttributes: {
|
|
8680
|
-
type: config.type
|
|
9230
|
+
this.unsubscribers.push(
|
|
9231
|
+
traceStreamingChannel(aiSDKChannels.generateText, {
|
|
9232
|
+
name: "generateText",
|
|
9233
|
+
type: "llm" /* LLM */,
|
|
9234
|
+
extractInput: ([params]) => {
|
|
9235
|
+
return {
|
|
9236
|
+
input: processAISDKInput(params),
|
|
9237
|
+
metadata: extractMetadataFromParams(params)
|
|
9238
|
+
};
|
|
9239
|
+
},
|
|
9240
|
+
extractOutput: (result) => {
|
|
9241
|
+
return processAISDKOutput(result, denyOutputPaths);
|
|
9242
|
+
},
|
|
9243
|
+
extractMetrics: (result, startTime) => {
|
|
9244
|
+
const metrics = extractTokenMetrics(result);
|
|
9245
|
+
if (startTime) {
|
|
9246
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8681
9247
|
}
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
8686
|
-
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
return;
|
|
8699
|
-
}
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
|
|
8730
|
-
|
|
8731
|
-
|
|
8732
|
-
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
|
|
8745
|
-
|
|
8746
|
-
|
|
8747
|
-
|
|
8748
|
-
|
|
8749
|
-
|
|
8750
|
-
spans.delete(event);
|
|
9248
|
+
return metrics;
|
|
9249
|
+
},
|
|
9250
|
+
aggregateChunks: aggregateAISDKChunks
|
|
9251
|
+
})
|
|
9252
|
+
);
|
|
9253
|
+
this.unsubscribers.push(
|
|
9254
|
+
traceStreamingChannel(aiSDKChannels.streamText, {
|
|
9255
|
+
name: "streamText",
|
|
9256
|
+
type: "llm" /* LLM */,
|
|
9257
|
+
extractInput: ([params]) => {
|
|
9258
|
+
return {
|
|
9259
|
+
input: processAISDKInput(params),
|
|
9260
|
+
metadata: extractMetadataFromParams(params)
|
|
9261
|
+
};
|
|
9262
|
+
},
|
|
9263
|
+
extractOutput: (result) => {
|
|
9264
|
+
return processAISDKOutput(result, denyOutputPaths);
|
|
9265
|
+
},
|
|
9266
|
+
extractMetrics: (result, startTime) => {
|
|
9267
|
+
const metrics = extractTokenMetrics(result);
|
|
9268
|
+
if (startTime) {
|
|
9269
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
9270
|
+
}
|
|
9271
|
+
return metrics;
|
|
9272
|
+
},
|
|
9273
|
+
aggregateChunks: aggregateAISDKChunks
|
|
9274
|
+
})
|
|
9275
|
+
);
|
|
9276
|
+
this.unsubscribers.push(
|
|
9277
|
+
traceStreamingChannel(aiSDKChannels.generateObject, {
|
|
9278
|
+
name: "generateObject",
|
|
9279
|
+
type: "llm" /* LLM */,
|
|
9280
|
+
extractInput: ([params]) => {
|
|
9281
|
+
return {
|
|
9282
|
+
input: processAISDKInput(params),
|
|
9283
|
+
metadata: extractMetadataFromParams(params)
|
|
9284
|
+
};
|
|
9285
|
+
},
|
|
9286
|
+
extractOutput: (result) => {
|
|
9287
|
+
return processAISDKOutput(result, denyOutputPaths);
|
|
9288
|
+
},
|
|
9289
|
+
extractMetrics: (result, startTime) => {
|
|
9290
|
+
const metrics = extractTokenMetrics(result);
|
|
9291
|
+
if (startTime) {
|
|
9292
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
9293
|
+
}
|
|
9294
|
+
return metrics;
|
|
9295
|
+
},
|
|
9296
|
+
aggregateChunks: aggregateAISDKChunks
|
|
9297
|
+
})
|
|
9298
|
+
);
|
|
9299
|
+
this.unsubscribers.push(
|
|
9300
|
+
traceStreamingChannel(aiSDKChannels.streamObject, {
|
|
9301
|
+
name: "streamObject",
|
|
9302
|
+
type: "llm" /* LLM */,
|
|
9303
|
+
extractInput: ([params]) => {
|
|
9304
|
+
return {
|
|
9305
|
+
input: processAISDKInput(params),
|
|
9306
|
+
metadata: extractMetadataFromParams(params)
|
|
9307
|
+
};
|
|
9308
|
+
},
|
|
9309
|
+
extractOutput: (result) => {
|
|
9310
|
+
return processAISDKOutput(result, denyOutputPaths);
|
|
9311
|
+
},
|
|
9312
|
+
extractMetrics: (result, startTime) => {
|
|
9313
|
+
const metrics = extractTokenMetrics(result);
|
|
9314
|
+
if (startTime) {
|
|
9315
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
8751
9316
|
}
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
|
|
8770
|
-
|
|
9317
|
+
return metrics;
|
|
9318
|
+
},
|
|
9319
|
+
aggregateChunks: aggregateAISDKChunks
|
|
9320
|
+
})
|
|
9321
|
+
);
|
|
9322
|
+
this.unsubscribers.push(
|
|
9323
|
+
traceStreamingChannel(aiSDKChannels.agentGenerate, {
|
|
9324
|
+
name: "Agent.generate",
|
|
9325
|
+
type: "llm" /* LLM */,
|
|
9326
|
+
extractInput: ([params]) => {
|
|
9327
|
+
return {
|
|
9328
|
+
input: processAISDKInput(params),
|
|
9329
|
+
metadata: extractMetadataFromParams(params)
|
|
9330
|
+
};
|
|
9331
|
+
},
|
|
9332
|
+
extractOutput: (result) => {
|
|
9333
|
+
return processAISDKOutput(result, denyOutputPaths);
|
|
9334
|
+
},
|
|
9335
|
+
extractMetrics: (result, startTime) => {
|
|
9336
|
+
const metrics = extractTokenMetrics(result);
|
|
9337
|
+
if (startTime) {
|
|
9338
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
9339
|
+
}
|
|
9340
|
+
return metrics;
|
|
9341
|
+
},
|
|
9342
|
+
aggregateChunks: aggregateAISDKChunks
|
|
9343
|
+
})
|
|
9344
|
+
);
|
|
9345
|
+
this.unsubscribers.push(
|
|
9346
|
+
traceStreamingChannel(aiSDKChannels.agentStream, {
|
|
9347
|
+
name: "Agent.stream",
|
|
9348
|
+
type: "llm" /* LLM */,
|
|
9349
|
+
extractInput: ([params]) => {
|
|
9350
|
+
return {
|
|
9351
|
+
input: processAISDKInput(params),
|
|
9352
|
+
metadata: extractMetadataFromParams(params)
|
|
9353
|
+
};
|
|
9354
|
+
},
|
|
9355
|
+
extractOutput: (result) => {
|
|
9356
|
+
return processAISDKOutput(result, denyOutputPaths);
|
|
9357
|
+
},
|
|
9358
|
+
extractMetrics: (result, startTime) => {
|
|
9359
|
+
const metrics = extractTokenMetrics(result);
|
|
9360
|
+
if (startTime) {
|
|
9361
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
9362
|
+
}
|
|
9363
|
+
return metrics;
|
|
9364
|
+
},
|
|
9365
|
+
aggregateChunks: aggregateAISDKChunks
|
|
9366
|
+
})
|
|
9367
|
+
);
|
|
8771
9368
|
}
|
|
8772
9369
|
};
|
|
8773
9370
|
function processAISDKInput(params) {
|
|
@@ -9009,7 +9606,10 @@ function omitAtPath(obj, keys) {
|
|
|
9009
9606
|
if (Array.isArray(obj)) {
|
|
9010
9607
|
obj.forEach((item) => {
|
|
9011
9608
|
if (remainingKeys.length > 0) {
|
|
9012
|
-
omitAtPath(
|
|
9609
|
+
omitAtPath(
|
|
9610
|
+
item,
|
|
9611
|
+
remainingKeys
|
|
9612
|
+
);
|
|
9013
9613
|
}
|
|
9014
9614
|
});
|
|
9015
9615
|
}
|
|
@@ -9019,7 +9619,10 @@ function omitAtPath(obj, keys) {
|
|
|
9019
9619
|
}
|
|
9020
9620
|
} else {
|
|
9021
9621
|
if (obj && typeof obj === "object" && firstKey in obj) {
|
|
9022
|
-
omitAtPath(
|
|
9622
|
+
omitAtPath(
|
|
9623
|
+
obj[firstKey],
|
|
9624
|
+
remainingKeys
|
|
9625
|
+
);
|
|
9023
9626
|
}
|
|
9024
9627
|
}
|
|
9025
9628
|
}
|
|
@@ -9032,8 +9635,18 @@ function omit(obj, paths) {
|
|
|
9032
9635
|
return result;
|
|
9033
9636
|
}
|
|
9034
9637
|
|
|
9638
|
+
// src/instrumentation/plugins/claude-agent-sdk-channels.ts
|
|
9639
|
+
var claudeAgentSDKChannels = defineChannels(
|
|
9640
|
+
"@anthropic-ai/claude-agent-sdk",
|
|
9641
|
+
{
|
|
9642
|
+
query: channel({
|
|
9643
|
+
channelName: "query",
|
|
9644
|
+
kind: "async"
|
|
9645
|
+
})
|
|
9646
|
+
}
|
|
9647
|
+
);
|
|
9648
|
+
|
|
9035
9649
|
// src/instrumentation/plugins/claude-agent-sdk-plugin.ts
|
|
9036
|
-
import { tracingChannel as tracingChannel4 } from "dc-browser";
|
|
9037
9650
|
function filterSerializableOptions(options) {
|
|
9038
9651
|
const allowedKeys = [
|
|
9039
9652
|
"model",
|
|
@@ -9117,7 +9730,9 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
|
|
|
9117
9730
|
const input = buildLLMInput(prompt, conversationHistory);
|
|
9118
9731
|
const outputs = messages.map(
|
|
9119
9732
|
(m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
|
|
9120
|
-
).filter(
|
|
9733
|
+
).filter(
|
|
9734
|
+
(c) => c !== void 0
|
|
9735
|
+
);
|
|
9121
9736
|
const span = startSpan({
|
|
9122
9737
|
name: "anthropic.messages.create",
|
|
9123
9738
|
spanAttributes: {
|
|
@@ -9136,7 +9751,6 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
|
|
|
9136
9751
|
return lastMessage.message?.content && lastMessage.message?.role ? { content: lastMessage.message.content, role: lastMessage.message.role } : void 0;
|
|
9137
9752
|
}
|
|
9138
9753
|
var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
9139
|
-
unsubscribers = [];
|
|
9140
9754
|
onEnable() {
|
|
9141
9755
|
this.subscribeToQuery();
|
|
9142
9756
|
}
|
|
@@ -9152,12 +9766,13 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9152
9766
|
* and individual LLM calls.
|
|
9153
9767
|
*/
|
|
9154
9768
|
subscribeToQuery() {
|
|
9155
|
-
const
|
|
9769
|
+
const channel2 = claudeAgentSDKChannels.query.tracingChannel();
|
|
9156
9770
|
const spans = /* @__PURE__ */ new WeakMap();
|
|
9157
9771
|
const handlers = {
|
|
9158
9772
|
start: (event) => {
|
|
9159
|
-
const params = event.arguments[0]
|
|
9160
|
-
const
|
|
9773
|
+
const params = event.arguments[0];
|
|
9774
|
+
const prompt = params?.prompt;
|
|
9775
|
+
const options = params?.options ?? {};
|
|
9161
9776
|
const span = startSpan({
|
|
9162
9777
|
name: "Claude Agent",
|
|
9163
9778
|
spanAttributes: {
|
|
@@ -9169,7 +9784,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9169
9784
|
span.log({
|
|
9170
9785
|
input: typeof prompt === "string" ? prompt : {
|
|
9171
9786
|
type: "streaming",
|
|
9172
|
-
description: "AsyncIterable<
|
|
9787
|
+
description: "AsyncIterable<ClaudeAgentSDKMessage>"
|
|
9173
9788
|
},
|
|
9174
9789
|
metadata: filterSerializableOptions(options)
|
|
9175
9790
|
});
|
|
@@ -9191,12 +9806,19 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9191
9806
|
if (!spanData) {
|
|
9192
9807
|
return;
|
|
9193
9808
|
}
|
|
9194
|
-
|
|
9195
|
-
|
|
9809
|
+
const eventResult = event.result;
|
|
9810
|
+
if (eventResult === void 0) {
|
|
9811
|
+
spanData.span.end();
|
|
9812
|
+
spans.delete(event);
|
|
9813
|
+
return;
|
|
9814
|
+
}
|
|
9815
|
+
if (isAsyncIterable(eventResult)) {
|
|
9816
|
+
patchStreamIfNeeded(eventResult, {
|
|
9196
9817
|
onChunk: async (message) => {
|
|
9197
9818
|
const currentTime = getCurrentUnixTimestamp();
|
|
9198
9819
|
const params = event.arguments[0];
|
|
9199
|
-
const
|
|
9820
|
+
const prompt = params?.prompt;
|
|
9821
|
+
const options = params?.options ?? {};
|
|
9200
9822
|
const messageId = message.message?.id;
|
|
9201
9823
|
if (messageId && messageId !== spanData.currentMessageId) {
|
|
9202
9824
|
if (spanData.currentMessages.length > 0) {
|
|
@@ -9255,7 +9877,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9255
9877
|
onComplete: async () => {
|
|
9256
9878
|
try {
|
|
9257
9879
|
const params = event.arguments[0];
|
|
9258
|
-
const
|
|
9880
|
+
const prompt = params?.prompt;
|
|
9881
|
+
const options = params?.options ?? {};
|
|
9259
9882
|
if (spanData.currentMessages.length > 0) {
|
|
9260
9883
|
const finalMessage = await createLLMSpanForMessages(
|
|
9261
9884
|
spanData.currentMessages,
|
|
@@ -9293,7 +9916,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9293
9916
|
} else {
|
|
9294
9917
|
try {
|
|
9295
9918
|
spanData.span.log({
|
|
9296
|
-
output:
|
|
9919
|
+
output: eventResult
|
|
9297
9920
|
});
|
|
9298
9921
|
} catch (error) {
|
|
9299
9922
|
console.error(
|
|
@@ -9308,7 +9931,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9308
9931
|
},
|
|
9309
9932
|
error: (event) => {
|
|
9310
9933
|
const spanData = spans.get(event);
|
|
9311
|
-
if (!spanData) {
|
|
9934
|
+
if (!spanData || !event.error) {
|
|
9312
9935
|
return;
|
|
9313
9936
|
}
|
|
9314
9937
|
const { span } = spanData;
|
|
@@ -9319,53 +9942,39 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
9319
9942
|
spans.delete(event);
|
|
9320
9943
|
}
|
|
9321
9944
|
};
|
|
9322
|
-
|
|
9945
|
+
channel2.subscribe(handlers);
|
|
9323
9946
|
this.unsubscribers.push(() => {
|
|
9324
|
-
|
|
9947
|
+
channel2.unsubscribe(handlers);
|
|
9325
9948
|
});
|
|
9326
9949
|
}
|
|
9327
9950
|
};
|
|
9328
9951
|
|
|
9952
|
+
// src/instrumentation/plugins/google-genai-channels.ts
|
|
9953
|
+
var googleGenAIChannels = defineChannels("@google/genai", {
|
|
9954
|
+
generateContent: channel({
|
|
9955
|
+
channelName: "models.generateContent",
|
|
9956
|
+
kind: "async"
|
|
9957
|
+
}),
|
|
9958
|
+
generateContentStream: channel({
|
|
9959
|
+
channelName: "models.generateContentStream",
|
|
9960
|
+
kind: "async"
|
|
9961
|
+
})
|
|
9962
|
+
});
|
|
9963
|
+
|
|
9329
9964
|
// src/instrumentation/plugins/google-genai-plugin.ts
|
|
9330
|
-
import { tracingChannel as tracingChannel5 } from "dc-browser";
|
|
9331
9965
|
var GoogleGenAIPlugin = class extends BasePlugin {
|
|
9332
|
-
unsubscribers = [];
|
|
9333
9966
|
onEnable() {
|
|
9334
9967
|
this.subscribeToGoogleGenAIChannels();
|
|
9335
9968
|
}
|
|
9336
9969
|
onDisable() {
|
|
9337
|
-
|
|
9338
|
-
unsubscribe();
|
|
9339
|
-
}
|
|
9340
|
-
this.unsubscribers = [];
|
|
9970
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
9341
9971
|
}
|
|
9342
9972
|
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",
|
|
9973
|
+
this.unsubscribers.push(
|
|
9974
|
+
traceAsyncChannel(googleGenAIChannels.generateContent, {
|
|
9975
|
+
name: "google-genai.generateContent",
|
|
9366
9976
|
type: "llm" /* LLM */,
|
|
9367
|
-
extractInput: (
|
|
9368
|
-
const params = args[0] || {};
|
|
9977
|
+
extractInput: ([params]) => {
|
|
9369
9978
|
const input = serializeInput(params);
|
|
9370
9979
|
const metadata = extractMetadata(params);
|
|
9371
9980
|
return {
|
|
@@ -9373,150 +9982,37 @@ var GoogleGenAIPlugin = class extends BasePlugin {
|
|
|
9373
9982
|
metadata: { ...metadata, provider: "google-genai" }
|
|
9374
9983
|
};
|
|
9375
9984
|
},
|
|
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;
|
|
9985
|
+
extractOutput: (result) => {
|
|
9986
|
+
return result;
|
|
9987
|
+
},
|
|
9988
|
+
extractMetrics: (result, startTime) => {
|
|
9989
|
+
return extractGenerateContentMetrics(result, startTime);
|
|
9427
9990
|
}
|
|
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({
|
|
9991
|
+
})
|
|
9992
|
+
);
|
|
9993
|
+
this.unsubscribers.push(
|
|
9994
|
+
traceStreamingChannel(googleGenAIChannels.generateContentStream, {
|
|
9995
|
+
name: "google-genai.generateContentStream",
|
|
9996
|
+
type: "llm" /* LLM */,
|
|
9997
|
+
extractInput: ([params]) => {
|
|
9998
|
+
const input = serializeInput(params);
|
|
9999
|
+
const metadata = extractMetadata(params);
|
|
10000
|
+
return {
|
|
9457
10001
|
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;
|
|
10002
|
+
metadata: { ...metadata, provider: "google-genai" }
|
|
10003
|
+
};
|
|
10004
|
+
},
|
|
10005
|
+
extractOutput: (result) => {
|
|
10006
|
+
return result;
|
|
10007
|
+
},
|
|
10008
|
+
extractMetrics: () => {
|
|
10009
|
+
return {};
|
|
10010
|
+
},
|
|
10011
|
+
aggregateChunks: (chunks, _result, _endEvent, startTime) => {
|
|
10012
|
+
return aggregateGenerateContentChunks(chunks, startTime);
|
|
9507
10013
|
}
|
|
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
|
-
});
|
|
10014
|
+
})
|
|
10015
|
+
);
|
|
9520
10016
|
}
|
|
9521
10017
|
};
|
|
9522
10018
|
function serializeInput(params) {
|
|
@@ -9572,8 +10068,12 @@ function serializePart(part) {
|
|
|
9572
10068
|
const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
|
|
9573
10069
|
atob(data).split("").map((c) => c.charCodeAt(0))
|
|
9574
10070
|
) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
|
|
10071
|
+
const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
|
|
10072
|
+
buffer.byteOffset,
|
|
10073
|
+
buffer.byteOffset + buffer.byteLength
|
|
10074
|
+
) : buffer;
|
|
9575
10075
|
const attachment = new Attachment({
|
|
9576
|
-
data:
|
|
10076
|
+
data: arrayBuffer,
|
|
9577
10077
|
filename,
|
|
9578
10078
|
contentType: mimeType || "application/octet-stream"
|
|
9579
10079
|
});
|
|
@@ -9622,33 +10122,36 @@ function extractGenerateContentMetrics(response, startTime) {
|
|
|
9622
10122
|
const end = getCurrentUnixTimestamp();
|
|
9623
10123
|
metrics.duration = end - startTime;
|
|
9624
10124
|
}
|
|
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
|
-
}
|
|
10125
|
+
if (response?.usageMetadata) {
|
|
10126
|
+
populateUsageMetrics(metrics, response.usageMetadata);
|
|
9642
10127
|
}
|
|
9643
10128
|
return metrics;
|
|
9644
10129
|
}
|
|
10130
|
+
function populateUsageMetrics(metrics, usage) {
|
|
10131
|
+
if (usage.promptTokenCount !== void 0) {
|
|
10132
|
+
metrics.prompt_tokens = usage.promptTokenCount;
|
|
10133
|
+
}
|
|
10134
|
+
if (usage.candidatesTokenCount !== void 0) {
|
|
10135
|
+
metrics.completion_tokens = usage.candidatesTokenCount;
|
|
10136
|
+
}
|
|
10137
|
+
if (usage.totalTokenCount !== void 0) {
|
|
10138
|
+
metrics.tokens = usage.totalTokenCount;
|
|
10139
|
+
}
|
|
10140
|
+
if (usage.cachedContentTokenCount !== void 0) {
|
|
10141
|
+
metrics.prompt_cached_tokens = usage.cachedContentTokenCount;
|
|
10142
|
+
}
|
|
10143
|
+
if (usage.thoughtsTokenCount !== void 0) {
|
|
10144
|
+
metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
|
|
10145
|
+
}
|
|
10146
|
+
}
|
|
9645
10147
|
function aggregateGenerateContentChunks(chunks, startTime) {
|
|
9646
|
-
const
|
|
9647
|
-
|
|
9648
|
-
|
|
9649
|
-
|
|
10148
|
+
const metrics = {};
|
|
10149
|
+
if (startTime !== void 0) {
|
|
10150
|
+
const end = getCurrentUnixTimestamp();
|
|
10151
|
+
metrics.duration = end - startTime;
|
|
10152
|
+
}
|
|
9650
10153
|
let firstTokenTime = null;
|
|
9651
|
-
if (chunks.length > 0 && firstTokenTime === null) {
|
|
10154
|
+
if (chunks.length > 0 && firstTokenTime === null && startTime !== void 0) {
|
|
9652
10155
|
firstTokenTime = getCurrentUnixTimestamp();
|
|
9653
10156
|
metrics.time_to_first_token = firstTokenTime - startTime;
|
|
9654
10157
|
}
|
|
@@ -9719,21 +10222,7 @@ function aggregateGenerateContentChunks(chunks, startTime) {
|
|
|
9719
10222
|
}
|
|
9720
10223
|
if (usageMetadata) {
|
|
9721
10224
|
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
|
-
}
|
|
10225
|
+
populateUsageMetrics(metrics, usageMetadata);
|
|
9737
10226
|
}
|
|
9738
10227
|
if (text) {
|
|
9739
10228
|
output.text = text;
|
|
@@ -9745,7 +10234,8 @@ function tryToDict(obj) {
|
|
|
9745
10234
|
return null;
|
|
9746
10235
|
}
|
|
9747
10236
|
if (typeof obj === "object") {
|
|
9748
|
-
if (
|
|
10237
|
+
if ("toJSON" in obj && // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
10238
|
+
typeof obj.toJSON === "function") {
|
|
9749
10239
|
return obj.toJSON();
|
|
9750
10240
|
}
|
|
9751
10241
|
return obj;
|