braintrust 3.29.0 → 3.31.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/dev/dist/index.d.mts +4 -1
- package/dev/dist/index.d.ts +4 -1
- package/dev/dist/index.js +1492 -887
- package/dev/dist/index.mjs +836 -231
- package/dist/apply-auto-instrumentation.js +217 -217
- package/dist/apply-auto-instrumentation.mjs +2 -2
- package/dist/auto-instrumentations/bundler/esbuild.cjs +13 -1
- package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
- package/dist/auto-instrumentations/bundler/next.cjs +22 -4
- package/dist/auto-instrumentations/bundler/next.mjs +12 -6
- package/dist/auto-instrumentations/bundler/rollup.cjs +13 -1
- package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
- package/dist/auto-instrumentations/bundler/vite.cjs +13 -1
- package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
- package/dist/auto-instrumentations/bundler/webpack-loader.cjs +13 -1
- package/dist/auto-instrumentations/bundler/webpack.cjs +13 -1
- package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
- package/dist/auto-instrumentations/{chunk-DKTGDNA7.mjs → chunk-LW4HDHXT.mjs} +1 -1
- package/dist/auto-instrumentations/{chunk-OMCZ3MV2.mjs → chunk-OXINGIEZ.mjs} +1 -1
- package/dist/auto-instrumentations/{chunk-AOIYCVEL.mjs → chunk-U64OYU4Q.mjs} +13 -1
- package/dist/auto-instrumentations/hook.mjs +18 -4
- package/dist/auto-instrumentations/index.cjs +13 -1
- package/dist/auto-instrumentations/index.mjs +1 -1
- package/dist/browser.d.mts +614 -480
- package/dist/browser.d.ts +614 -480
- package/dist/browser.js +1172 -305
- package/dist/browser.mjs +1172 -305
- package/dist/{chunk-6Z5S7VOU.js → chunk-4AQGZS6X.js} +13 -1
- package/dist/{chunk-M6XPNJC4.mjs → chunk-AJT4FR25.mjs} +703 -120
- package/dist/{chunk-7FA6VP2S.mjs → chunk-CE3BLB2L.mjs} +13 -1
- package/dist/{chunk-XLLGRXGR.js → chunk-V32LW47Z.js} +1819 -1236
- package/dist/cli.js +846 -241
- package/dist/edge-light.d.mts +1 -1
- package/dist/edge-light.d.ts +1 -1
- package/dist/edge-light.js +1172 -305
- package/dist/edge-light.mjs +1172 -305
- package/dist/index.d.mts +614 -480
- package/dist/index.d.ts +614 -480
- package/dist/index.js +915 -643
- package/dist/index.mjs +349 -77
- package/dist/instrumentation/index.d.mts +15 -0
- package/dist/instrumentation/index.d.ts +15 -0
- package/dist/instrumentation/index.js +836 -230
- package/dist/instrumentation/index.mjs +836 -230
- package/dist/vitest-evals-reporter.js +16 -16
- package/dist/vitest-evals-reporter.mjs +2 -2
- package/dist/workerd.d.mts +1 -1
- package/dist/workerd.d.ts +1 -1
- package/dist/workerd.js +1172 -305
- package/dist/workerd.mjs +1172 -305
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -41,7 +41,7 @@ var require_async = __commonJS({
|
|
|
41
41
|
"use strict";
|
|
42
42
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
43
43
|
exports2.read = void 0;
|
|
44
|
-
function
|
|
44
|
+
function read2(path9, settings, callback) {
|
|
45
45
|
settings.fs.lstat(path9, (lstatError, lstat) => {
|
|
46
46
|
if (lstatError !== null) {
|
|
47
47
|
callFailureCallback(callback, lstatError);
|
|
@@ -67,7 +67,7 @@ var require_async = __commonJS({
|
|
|
67
67
|
});
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
|
-
exports2.read =
|
|
70
|
+
exports2.read = read2;
|
|
71
71
|
function callFailureCallback(callback, error2) {
|
|
72
72
|
callback(error2);
|
|
73
73
|
}
|
|
@@ -83,7 +83,7 @@ var require_sync = __commonJS({
|
|
|
83
83
|
"use strict";
|
|
84
84
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
85
85
|
exports2.read = void 0;
|
|
86
|
-
function
|
|
86
|
+
function read2(path9, settings) {
|
|
87
87
|
const lstat = settings.fs.lstatSync(path9);
|
|
88
88
|
if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) {
|
|
89
89
|
return lstat;
|
|
@@ -101,7 +101,7 @@ var require_sync = __commonJS({
|
|
|
101
101
|
throw error2;
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
-
exports2.read =
|
|
104
|
+
exports2.read = read2;
|
|
105
105
|
}
|
|
106
106
|
});
|
|
107
107
|
|
|
@@ -327,14 +327,14 @@ var require_async2 = __commonJS({
|
|
|
327
327
|
var constants_1 = require_constants();
|
|
328
328
|
var utils = require_utils();
|
|
329
329
|
var common = require_common();
|
|
330
|
-
function
|
|
330
|
+
function read2(directory, settings, callback) {
|
|
331
331
|
if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) {
|
|
332
332
|
readdirWithFileTypes(directory, settings, callback);
|
|
333
333
|
return;
|
|
334
334
|
}
|
|
335
335
|
readdir2(directory, settings, callback);
|
|
336
336
|
}
|
|
337
|
-
exports2.read =
|
|
337
|
+
exports2.read = read2;
|
|
338
338
|
function readdirWithFileTypes(directory, settings, callback) {
|
|
339
339
|
settings.fs.readdir(directory, { withFileTypes: true }, (readdirError, dirents) => {
|
|
340
340
|
if (readdirError !== null) {
|
|
@@ -436,13 +436,13 @@ var require_sync2 = __commonJS({
|
|
|
436
436
|
var constants_1 = require_constants();
|
|
437
437
|
var utils = require_utils();
|
|
438
438
|
var common = require_common();
|
|
439
|
-
function
|
|
439
|
+
function read2(directory, settings) {
|
|
440
440
|
if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) {
|
|
441
441
|
return readdirWithFileTypes(directory, settings);
|
|
442
442
|
}
|
|
443
443
|
return readdir2(directory, settings);
|
|
444
444
|
}
|
|
445
|
-
exports2.read =
|
|
445
|
+
exports2.read = read2;
|
|
446
446
|
function readdirWithFileTypes(directory, settings) {
|
|
447
447
|
const dirents = settings.fs.readdirSync(directory, { withFileTypes: true });
|
|
448
448
|
return dirents.map((dirent) => {
|
|
@@ -1236,7 +1236,7 @@ var require_package = __commonJS({
|
|
|
1236
1236
|
"package.json"(exports2, module2) {
|
|
1237
1237
|
module2.exports = {
|
|
1238
1238
|
name: "braintrust",
|
|
1239
|
-
version: "3.
|
|
1239
|
+
version: "3.31.0",
|
|
1240
1240
|
description: "SDK for integrating Braintrust",
|
|
1241
1241
|
repository: {
|
|
1242
1242
|
type: "git",
|
|
@@ -5356,6 +5356,7 @@ var ProjectSettings = import_v36.z.union([
|
|
|
5356
5356
|
]),
|
|
5357
5357
|
disable_realtime_queries: import_v36.z.union([import_v36.z.boolean(), import_v36.z.null()]),
|
|
5358
5358
|
monitor_charts_use_metrics_start: import_v36.z.union([import_v36.z.boolean(), import_v36.z.null()]),
|
|
5359
|
+
blind_reviews: import_v36.z.union([import_v36.z.boolean(), import_v36.z.null()]),
|
|
5359
5360
|
default_preprocessor: NullableSavedFunctionId
|
|
5360
5361
|
}).partial(),
|
|
5361
5362
|
import_v36.z.null()
|
|
@@ -5417,6 +5418,7 @@ var WindowedAutomationConfig = import_v36.z.object({
|
|
|
5417
5418
|
auto_approve_tools: import_v36.z.array(import_v36.z.string().min(1)).optional().default([]),
|
|
5418
5419
|
harness: import_v36.z.enum(["native", "codex", "claude-code"]).optional(),
|
|
5419
5420
|
model: import_v36.z.string().min(1).optional(),
|
|
5421
|
+
endpoint_name: import_v36.z.string().min(1).optional(),
|
|
5420
5422
|
reasoning_effort: import_v36.z.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional()
|
|
5421
5423
|
}).optional(),
|
|
5422
5424
|
actions: import_v36.z.array(
|
|
@@ -7208,7 +7210,7 @@ var INSTRUMENTATION_NAMES = {
|
|
|
7208
7210
|
var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
|
|
7209
7211
|
"braintrust.spanInstrumentationName"
|
|
7210
7212
|
);
|
|
7211
|
-
var SDK_VERSION = true ? "3.
|
|
7213
|
+
var SDK_VERSION = true ? "3.31.0" : "0.0.0";
|
|
7212
7214
|
function withSpanInstrumentationName(args, instrumentationName) {
|
|
7213
7215
|
return {
|
|
7214
7216
|
...args,
|
|
@@ -10723,6 +10725,15 @@ function _internalStartSpanWithInitialMerge(args) {
|
|
|
10723
10725
|
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
10724
10726
|
}).span;
|
|
10725
10727
|
}
|
|
10728
|
+
function _internalStartSpanWithInitialMergeAndParentSpanIds(args) {
|
|
10729
|
+
return startSpanAndIsLogger(
|
|
10730
|
+
{
|
|
10731
|
+
...args,
|
|
10732
|
+
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
10733
|
+
},
|
|
10734
|
+
{ useParentSpanIdsForObjectParent: true }
|
|
10735
|
+
).span;
|
|
10736
|
+
}
|
|
10726
10737
|
function _internalStartSpanWithContext(args, context2) {
|
|
10727
10738
|
return startSpanAndIsLogger({
|
|
10728
10739
|
...args,
|
|
@@ -10733,7 +10744,7 @@ async function flush(options) {
|
|
|
10733
10744
|
const state = options?.state ?? _globalState;
|
|
10734
10745
|
return await state.bgLogger().flush();
|
|
10735
10746
|
}
|
|
10736
|
-
function startSpanAndIsLogger(args) {
|
|
10747
|
+
function startSpanAndIsLogger(args, internalOptions) {
|
|
10737
10748
|
const state = args?.state ?? _globalState;
|
|
10738
10749
|
const { parentObject, propagatedState } = getSpanParentObjectAndPropagatedState({
|
|
10739
10750
|
asyncFlush: args?.asyncFlush,
|
|
@@ -10747,7 +10758,7 @@ function startSpanAndIsLogger(args) {
|
|
|
10747
10758
|
) ? {
|
|
10748
10759
|
spanId: parentObject.data.span_id,
|
|
10749
10760
|
rootSpanId: parentObject.data.root_span_id
|
|
10750
|
-
} : void 0;
|
|
10761
|
+
} : internalOptions?.useParentSpanIdsForObjectParent ? args?.parentSpanIds : void 0;
|
|
10751
10762
|
const { parent: _ignoredParent, ...spanArgs } = args ?? {};
|
|
10752
10763
|
const span = new SpanImpl({
|
|
10753
10764
|
state,
|
|
@@ -14760,19 +14771,29 @@ function buildSpanScores(results) {
|
|
|
14760
14771
|
function _internalPrepareEvaluatorScore(scoreValue, name) {
|
|
14761
14772
|
if (scoreValue === null) return { results: null };
|
|
14762
14773
|
if (Array.isArray(scoreValue)) {
|
|
14774
|
+
const names = /* @__PURE__ */ new Set();
|
|
14763
14775
|
for (const score of scoreValue) {
|
|
14764
14776
|
if (!(typeof score === "object" && !isEmpty2(score))) {
|
|
14765
14777
|
throw new Error(
|
|
14766
14778
|
`When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(score)}`
|
|
14767
14779
|
);
|
|
14768
14780
|
}
|
|
14781
|
+
if (typeof score.name !== "string") {
|
|
14782
|
+
throw new Error(
|
|
14783
|
+
`When returning an array of scores, each score must have a name. Got: ${JSON.stringify(score)}`
|
|
14784
|
+
);
|
|
14785
|
+
}
|
|
14786
|
+
if (names.has(score.name)) {
|
|
14787
|
+
throw new Error(`Duplicate score name '${score.name}' in score array`);
|
|
14788
|
+
}
|
|
14789
|
+
names.add(score.name);
|
|
14769
14790
|
}
|
|
14770
14791
|
}
|
|
14771
14792
|
let results;
|
|
14772
14793
|
if (Array.isArray(scoreValue)) {
|
|
14773
14794
|
results = scoreValue;
|
|
14774
14795
|
} else if (typeof scoreValue === "object" && !isEmpty2(scoreValue)) {
|
|
14775
|
-
results = [scoreValue];
|
|
14796
|
+
results = [{ ...scoreValue, name: scoreValue.name ?? name }];
|
|
14776
14797
|
} else {
|
|
14777
14798
|
results = [{ name, score: scoreValue }];
|
|
14778
14799
|
}
|
|
@@ -17176,6 +17197,131 @@ function unsubscribeAll(unsubscribers) {
|
|
|
17176
17197
|
return [];
|
|
17177
17198
|
}
|
|
17178
17199
|
|
|
17200
|
+
// src/instrumentation/core/channel-definitions.ts
|
|
17201
|
+
function channel(spec) {
|
|
17202
|
+
return spec;
|
|
17203
|
+
}
|
|
17204
|
+
function defineChannels(pkg, channels, options) {
|
|
17205
|
+
const { instrumentationName } = options;
|
|
17206
|
+
return Object.fromEntries(
|
|
17207
|
+
Object.entries(channels).map(([key, spec]) => {
|
|
17208
|
+
const fullChannelName = `orchestrion:${pkg}:${spec.channelName}`;
|
|
17209
|
+
if (spec.kind === "async") {
|
|
17210
|
+
const asyncSpec = spec;
|
|
17211
|
+
const tracingChannel2 = () => isomorph_default.newTracingChannel(
|
|
17212
|
+
fullChannelName
|
|
17213
|
+
);
|
|
17214
|
+
const intercept2 = (interceptor) => {
|
|
17215
|
+
const hook = tracingChannel2();
|
|
17216
|
+
return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
|
|
17217
|
+
};
|
|
17218
|
+
};
|
|
17219
|
+
return [
|
|
17220
|
+
key,
|
|
17221
|
+
{
|
|
17222
|
+
...asyncSpec,
|
|
17223
|
+
instrumentationName,
|
|
17224
|
+
intercept: intercept2,
|
|
17225
|
+
invoke: (target, thisArg, args, additional) => {
|
|
17226
|
+
const hook = tracingChannel2();
|
|
17227
|
+
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
17228
|
+
},
|
|
17229
|
+
tracingChannel: tracingChannel2,
|
|
17230
|
+
tracePromise: (fn, context2) => tracingChannel2().tracePromise(
|
|
17231
|
+
fn,
|
|
17232
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
17233
|
+
context2
|
|
17234
|
+
)
|
|
17235
|
+
}
|
|
17236
|
+
];
|
|
17237
|
+
}
|
|
17238
|
+
const syncSpec = spec;
|
|
17239
|
+
const tracingChannel = () => isomorph_default.newTracingChannel(
|
|
17240
|
+
fullChannelName
|
|
17241
|
+
);
|
|
17242
|
+
const intercept = (interceptor) => {
|
|
17243
|
+
const hook = tracingChannel();
|
|
17244
|
+
return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
|
|
17245
|
+
};
|
|
17246
|
+
};
|
|
17247
|
+
return [
|
|
17248
|
+
key,
|
|
17249
|
+
{
|
|
17250
|
+
...syncSpec,
|
|
17251
|
+
instrumentationName,
|
|
17252
|
+
intercept,
|
|
17253
|
+
invoke: (target, thisArg, args, additional) => {
|
|
17254
|
+
const hook = tracingChannel();
|
|
17255
|
+
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
17256
|
+
},
|
|
17257
|
+
tracingChannel,
|
|
17258
|
+
traceSync: (fn, context2) => tracingChannel().traceSync(
|
|
17259
|
+
fn,
|
|
17260
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
17261
|
+
context2
|
|
17262
|
+
)
|
|
17263
|
+
}
|
|
17264
|
+
];
|
|
17265
|
+
})
|
|
17266
|
+
);
|
|
17267
|
+
}
|
|
17268
|
+
|
|
17269
|
+
// src/instrumentation/plugins/openai-channels.ts
|
|
17270
|
+
var openAIChannels = defineChannels(
|
|
17271
|
+
"openai",
|
|
17272
|
+
{
|
|
17273
|
+
filesCreateTraced: channel({
|
|
17274
|
+
channelName: "files.create-traced",
|
|
17275
|
+
kind: "async"
|
|
17276
|
+
}),
|
|
17277
|
+
batchesRetrieveTraced: channel({
|
|
17278
|
+
channelName: "batches.retrieve-traced",
|
|
17279
|
+
kind: "async"
|
|
17280
|
+
}),
|
|
17281
|
+
batchesCompleteTrace: channel({
|
|
17282
|
+
channelName: "batches.complete-trace",
|
|
17283
|
+
kind: "async"
|
|
17284
|
+
}),
|
|
17285
|
+
chatCompletionsCreate: channel({
|
|
17286
|
+
channelName: "chat.completions.create",
|
|
17287
|
+
kind: "async"
|
|
17288
|
+
}),
|
|
17289
|
+
embeddingsCreate: channel({
|
|
17290
|
+
channelName: "embeddings.create",
|
|
17291
|
+
kind: "async"
|
|
17292
|
+
}),
|
|
17293
|
+
betaChatCompletionsParse: channel({
|
|
17294
|
+
channelName: "beta.chat.completions.parse",
|
|
17295
|
+
kind: "async"
|
|
17296
|
+
}),
|
|
17297
|
+
betaChatCompletionsStream: channel({
|
|
17298
|
+
channelName: "beta.chat.completions.stream",
|
|
17299
|
+
kind: "sync-stream"
|
|
17300
|
+
}),
|
|
17301
|
+
moderationsCreate: channel({
|
|
17302
|
+
channelName: "moderations.create",
|
|
17303
|
+
kind: "async"
|
|
17304
|
+
}),
|
|
17305
|
+
responsesCreate: channel({
|
|
17306
|
+
channelName: "responses.create",
|
|
17307
|
+
kind: "async"
|
|
17308
|
+
}),
|
|
17309
|
+
responsesStream: channel({
|
|
17310
|
+
channelName: "responses.stream",
|
|
17311
|
+
kind: "sync-stream"
|
|
17312
|
+
}),
|
|
17313
|
+
responsesParse: channel({
|
|
17314
|
+
channelName: "responses.parse",
|
|
17315
|
+
kind: "async"
|
|
17316
|
+
}),
|
|
17317
|
+
responsesCompact: channel({
|
|
17318
|
+
channelName: "responses.compact",
|
|
17319
|
+
kind: "async"
|
|
17320
|
+
})
|
|
17321
|
+
},
|
|
17322
|
+
{ instrumentationName: INSTRUMENTATION_NAMES.OPENAI }
|
|
17323
|
+
);
|
|
17324
|
+
|
|
17179
17325
|
// src/wrappers/attachment-utils.ts
|
|
17180
17326
|
function getExtensionFromMediaType(mediaType) {
|
|
17181
17327
|
const extensionMap = {
|
|
@@ -17351,118 +17497,91 @@ function processInputAttachments(input) {
|
|
|
17351
17497
|
return processNode(input);
|
|
17352
17498
|
}
|
|
17353
17499
|
|
|
17354
|
-
// src/instrumentation/
|
|
17355
|
-
|
|
17356
|
-
|
|
17357
|
-
|
|
17358
|
-
|
|
17359
|
-
|
|
17360
|
-
|
|
17361
|
-
|
|
17362
|
-
|
|
17363
|
-
|
|
17364
|
-
|
|
17365
|
-
|
|
17366
|
-
|
|
17367
|
-
|
|
17368
|
-
|
|
17369
|
-
|
|
17370
|
-
|
|
17371
|
-
|
|
17372
|
-
|
|
17373
|
-
|
|
17374
|
-
|
|
17375
|
-
|
|
17376
|
-
...asyncSpec,
|
|
17377
|
-
instrumentationName,
|
|
17378
|
-
intercept: intercept2,
|
|
17379
|
-
invoke: (target, thisArg, args, additional) => {
|
|
17380
|
-
const hook = tracingChannel2();
|
|
17381
|
-
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
17382
|
-
},
|
|
17383
|
-
tracingChannel: tracingChannel2,
|
|
17384
|
-
tracePromise: (fn, context2) => tracingChannel2().tracePromise(
|
|
17385
|
-
fn,
|
|
17386
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
17387
|
-
context2
|
|
17388
|
-
)
|
|
17389
|
-
}
|
|
17390
|
-
];
|
|
17500
|
+
// src/instrumentation/plugins/openai-span-data.ts
|
|
17501
|
+
var OPENAI_METADATA_KEYS = [
|
|
17502
|
+
"model",
|
|
17503
|
+
"temperature",
|
|
17504
|
+
"top_p",
|
|
17505
|
+
"max_tokens",
|
|
17506
|
+
"frequency_penalty",
|
|
17507
|
+
"presence_penalty",
|
|
17508
|
+
"stop",
|
|
17509
|
+
"response_format",
|
|
17510
|
+
"tools",
|
|
17511
|
+
"tool_choice",
|
|
17512
|
+
"parallel_tool_calls",
|
|
17513
|
+
"max_tool_calls"
|
|
17514
|
+
];
|
|
17515
|
+
function batchMetadata(params) {
|
|
17516
|
+
const metadata = { provider: "openai" };
|
|
17517
|
+
for (const key of OPENAI_METADATA_KEYS) {
|
|
17518
|
+
try {
|
|
17519
|
+
const value = Reflect.get(params, key);
|
|
17520
|
+
if (value !== void 0) {
|
|
17521
|
+
metadata[key] = value;
|
|
17391
17522
|
}
|
|
17392
|
-
|
|
17393
|
-
|
|
17394
|
-
|
|
17395
|
-
|
|
17396
|
-
|
|
17397
|
-
|
|
17398
|
-
|
|
17399
|
-
|
|
17400
|
-
|
|
17401
|
-
|
|
17402
|
-
|
|
17403
|
-
|
|
17404
|
-
|
|
17405
|
-
|
|
17406
|
-
|
|
17407
|
-
|
|
17408
|
-
|
|
17409
|
-
|
|
17410
|
-
|
|
17411
|
-
|
|
17412
|
-
|
|
17413
|
-
|
|
17414
|
-
|
|
17415
|
-
|
|
17416
|
-
|
|
17417
|
-
|
|
17418
|
-
|
|
17419
|
-
|
|
17420
|
-
|
|
17523
|
+
} catch {
|
|
17524
|
+
}
|
|
17525
|
+
}
|
|
17526
|
+
return metadata;
|
|
17527
|
+
}
|
|
17528
|
+
function extractOpenAIBatchInput(endpoint, params) {
|
|
17529
|
+
const input = endpoint === "/v1/chat/completions" ? params.messages : params.input;
|
|
17530
|
+
return {
|
|
17531
|
+
input: processInputAttachments(input),
|
|
17532
|
+
metadata: batchMetadata(params)
|
|
17533
|
+
};
|
|
17534
|
+
}
|
|
17535
|
+
function extractOpenAIChatInput(params) {
|
|
17536
|
+
const { messages, ...metadata } = params;
|
|
17537
|
+
return {
|
|
17538
|
+
input: processInputAttachments(messages),
|
|
17539
|
+
metadata: { ...metadata, provider: "openai" }
|
|
17540
|
+
};
|
|
17541
|
+
}
|
|
17542
|
+
function extractOpenAIResponsesInput(params) {
|
|
17543
|
+
const { input, ...metadata } = params;
|
|
17544
|
+
return {
|
|
17545
|
+
input: processInputAttachments(input),
|
|
17546
|
+
metadata: { ...metadata, provider: "openai" }
|
|
17547
|
+
};
|
|
17548
|
+
}
|
|
17549
|
+
function extractOpenAIResponsesMetadata(result) {
|
|
17550
|
+
if (!result) {
|
|
17551
|
+
return void 0;
|
|
17552
|
+
}
|
|
17553
|
+
const { output: _output, usage: _usage, ...metadata } = result;
|
|
17554
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
17555
|
+
}
|
|
17556
|
+
function processImagesInOutput(output) {
|
|
17557
|
+
if (Array.isArray(output)) {
|
|
17558
|
+
return output.map(processImagesInOutput);
|
|
17559
|
+
}
|
|
17560
|
+
if (isObject(output) && output.type === "image_generation_call" && typeof output.result === "string" && output.result) {
|
|
17561
|
+
const fileExtension = output.output_format || "png";
|
|
17562
|
+
const contentType = `image/${fileExtension}`;
|
|
17563
|
+
const baseFilename = typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
17564
|
+
let binaryString;
|
|
17565
|
+
try {
|
|
17566
|
+
binaryString = atob(output.result);
|
|
17567
|
+
} catch {
|
|
17568
|
+
return output;
|
|
17569
|
+
}
|
|
17570
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
17571
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
17572
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
17573
|
+
}
|
|
17574
|
+
return {
|
|
17575
|
+
...output,
|
|
17576
|
+
result: new Attachment({
|
|
17577
|
+
data: new Blob([bytes], { type: contentType }),
|
|
17578
|
+
filename: `${baseFilename}.${fileExtension}`,
|
|
17579
|
+
contentType
|
|
17580
|
+
})
|
|
17581
|
+
};
|
|
17582
|
+
}
|
|
17583
|
+
return output;
|
|
17421
17584
|
}
|
|
17422
|
-
|
|
17423
|
-
// src/instrumentation/plugins/openai-channels.ts
|
|
17424
|
-
var openAIChannels = defineChannels(
|
|
17425
|
-
"openai",
|
|
17426
|
-
{
|
|
17427
|
-
chatCompletionsCreate: channel({
|
|
17428
|
-
channelName: "chat.completions.create",
|
|
17429
|
-
kind: "async"
|
|
17430
|
-
}),
|
|
17431
|
-
embeddingsCreate: channel({
|
|
17432
|
-
channelName: "embeddings.create",
|
|
17433
|
-
kind: "async"
|
|
17434
|
-
}),
|
|
17435
|
-
betaChatCompletionsParse: channel({
|
|
17436
|
-
channelName: "beta.chat.completions.parse",
|
|
17437
|
-
kind: "async"
|
|
17438
|
-
}),
|
|
17439
|
-
betaChatCompletionsStream: channel({
|
|
17440
|
-
channelName: "beta.chat.completions.stream",
|
|
17441
|
-
kind: "sync-stream"
|
|
17442
|
-
}),
|
|
17443
|
-
moderationsCreate: channel({
|
|
17444
|
-
channelName: "moderations.create",
|
|
17445
|
-
kind: "async"
|
|
17446
|
-
}),
|
|
17447
|
-
responsesCreate: channel({
|
|
17448
|
-
channelName: "responses.create",
|
|
17449
|
-
kind: "async"
|
|
17450
|
-
}),
|
|
17451
|
-
responsesStream: channel({
|
|
17452
|
-
channelName: "responses.stream",
|
|
17453
|
-
kind: "sync-stream"
|
|
17454
|
-
}),
|
|
17455
|
-
responsesParse: channel({
|
|
17456
|
-
channelName: "responses.parse",
|
|
17457
|
-
kind: "async"
|
|
17458
|
-
}),
|
|
17459
|
-
responsesCompact: channel({
|
|
17460
|
-
channelName: "responses.compact",
|
|
17461
|
-
kind: "async"
|
|
17462
|
-
})
|
|
17463
|
-
},
|
|
17464
|
-
{ instrumentationName: INSTRUMENTATION_NAMES.OPENAI }
|
|
17465
|
-
);
|
|
17466
17585
|
|
|
17467
17586
|
// src/openai-utils.ts
|
|
17468
17587
|
var BRAINTRUST_CACHED_STREAM_METRIC = "__braintrust_cached_metric";
|
|
@@ -17519,23 +17638,573 @@ function getCachedMetricFromHeaders(headers) {
|
|
|
17519
17638
|
return parseCachedHeader(headers.get(LEGACY_CACHED_HEADER));
|
|
17520
17639
|
}
|
|
17521
17640
|
|
|
17641
|
+
// src/instrumentation/plugins/openai-batch-instrumentation.ts
|
|
17642
|
+
var SUPPORTED_ENDPOINTS = /* @__PURE__ */ new Set(["/v1/chat/completions", "/v1/responses"]);
|
|
17643
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
17644
|
+
"completed",
|
|
17645
|
+
"failed",
|
|
17646
|
+
"expired",
|
|
17647
|
+
"cancelled"
|
|
17648
|
+
]);
|
|
17649
|
+
var pendingBatchTraces = /* @__PURE__ */ new Map();
|
|
17650
|
+
function read(value, key) {
|
|
17651
|
+
if (!isObject(value)) {
|
|
17652
|
+
return void 0;
|
|
17653
|
+
}
|
|
17654
|
+
try {
|
|
17655
|
+
return Reflect.get(value, key);
|
|
17656
|
+
} catch {
|
|
17657
|
+
return void 0;
|
|
17658
|
+
}
|
|
17659
|
+
}
|
|
17660
|
+
function isBatchRecordIterable(value) {
|
|
17661
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") {
|
|
17662
|
+
return false;
|
|
17663
|
+
}
|
|
17664
|
+
return typeof read(value, Symbol.iterator) === "function" || typeof read(value, Symbol.asyncIterator) === "function";
|
|
17665
|
+
}
|
|
17666
|
+
function validCustomId(value) {
|
|
17667
|
+
return typeof value === "string" && value.length > 0 && value.length <= 64;
|
|
17668
|
+
}
|
|
17669
|
+
function logBatchInstrumentationError(context2, error2) {
|
|
17670
|
+
debugLogger.debug(`OpenAI Batch instrumentation ${context2}:`, error2);
|
|
17671
|
+
}
|
|
17672
|
+
async function exportParent(parent) {
|
|
17673
|
+
if ("toStr" in parent && typeof parent.toStr === "function") {
|
|
17674
|
+
return parent.toStr();
|
|
17675
|
+
}
|
|
17676
|
+
if ("export" in parent && typeof parent.export === "function") {
|
|
17677
|
+
return await parent.export();
|
|
17678
|
+
}
|
|
17679
|
+
return void 0;
|
|
17680
|
+
}
|
|
17681
|
+
async function deterministicDigest(namespace, ...parts) {
|
|
17682
|
+
const encoded = new TextEncoder().encode(
|
|
17683
|
+
[namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
|
|
17684
|
+
);
|
|
17685
|
+
return new Uint8Array(
|
|
17686
|
+
await globalThis.crypto.subtle.digest("SHA-256", encoded)
|
|
17687
|
+
);
|
|
17688
|
+
}
|
|
17689
|
+
function digestHex(bytes, length) {
|
|
17690
|
+
return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
17691
|
+
}
|
|
17692
|
+
function digestUuid(bytes) {
|
|
17693
|
+
const hex = digestHex(bytes, 16);
|
|
17694
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
17695
|
+
}
|
|
17696
|
+
async function batchSpanIds(inputFileId) {
|
|
17697
|
+
const [row, span, root] = await Promise.all([
|
|
17698
|
+
deterministicDigest("openai:batch:row", inputFileId),
|
|
17699
|
+
deterministicDigest("openai:batch:span", inputFileId),
|
|
17700
|
+
deterministicDigest("openai:batch:root", inputFileId)
|
|
17701
|
+
]);
|
|
17702
|
+
return {
|
|
17703
|
+
rowId: digestUuid(row),
|
|
17704
|
+
spanId: digestHex(span, 8),
|
|
17705
|
+
rootSpanId: digestHex(root, 16)
|
|
17706
|
+
};
|
|
17707
|
+
}
|
|
17708
|
+
async function childSpanIds(inputFileId, customId) {
|
|
17709
|
+
const [row, span] = await Promise.all([
|
|
17710
|
+
deterministicDigest("openai:batch:child:row", inputFileId, customId),
|
|
17711
|
+
deterministicDigest("openai:batch:child:span", inputFileId, customId)
|
|
17712
|
+
]);
|
|
17713
|
+
return { rowId: digestUuid(row), spanId: digestHex(span, 8) };
|
|
17714
|
+
}
|
|
17715
|
+
async function startBatchSpan(context2) {
|
|
17716
|
+
const ids = await batchSpanIds(context2.inputFileId);
|
|
17717
|
+
const parent = SpanComponentsV4.fromStr(context2.parent);
|
|
17718
|
+
const hasParentSpan = Boolean(
|
|
17719
|
+
parent.data.row_id && parent.data.span_id && parent.data.root_span_id
|
|
17720
|
+
);
|
|
17721
|
+
return withCurrent(
|
|
17722
|
+
NOOP_SPAN,
|
|
17723
|
+
() => _internalStartSpanWithInitialMergeAndParentSpanIds(
|
|
17724
|
+
withSpanInstrumentationName(
|
|
17725
|
+
{
|
|
17726
|
+
name: "openai.batch",
|
|
17727
|
+
type: "task" /* TASK */,
|
|
17728
|
+
parent: context2.parent,
|
|
17729
|
+
...!hasParentSpan ? {
|
|
17730
|
+
parentSpanIds: {
|
|
17731
|
+
parentSpanIds: [],
|
|
17732
|
+
rootSpanId: ids.rootSpanId
|
|
17733
|
+
}
|
|
17734
|
+
} : {},
|
|
17735
|
+
spanId: ids.spanId,
|
|
17736
|
+
startTime: context2.taskStartTime,
|
|
17737
|
+
event: {
|
|
17738
|
+
id: ids.rowId,
|
|
17739
|
+
metadata: {
|
|
17740
|
+
endpoint: context2.endpoint,
|
|
17741
|
+
input_file_id: context2.inputFileId,
|
|
17742
|
+
provider: "openai"
|
|
17743
|
+
}
|
|
17744
|
+
}
|
|
17745
|
+
},
|
|
17746
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
17747
|
+
)
|
|
17748
|
+
)
|
|
17749
|
+
);
|
|
17750
|
+
}
|
|
17751
|
+
async function startBatchChild(context2, taskParent, input) {
|
|
17752
|
+
const ids = await childSpanIds(context2.inputFileId, input.customId);
|
|
17753
|
+
return withCurrent(
|
|
17754
|
+
NOOP_SPAN,
|
|
17755
|
+
() => _internalStartSpanWithInitialMerge(
|
|
17756
|
+
withSpanInstrumentationName(
|
|
17757
|
+
{
|
|
17758
|
+
name: context2.endpoint === "/v1/chat/completions" ? "Chat Completion" : "openai.responses.create",
|
|
17759
|
+
type: "llm" /* LLM */,
|
|
17760
|
+
parent: taskParent,
|
|
17761
|
+
spanId: ids.spanId,
|
|
17762
|
+
startTime: context2.childStartTime,
|
|
17763
|
+
event: {
|
|
17764
|
+
id: ids.rowId,
|
|
17765
|
+
...input.spanData?.input !== void 0 ? { input: input.spanData.input } : {},
|
|
17766
|
+
metadata: {
|
|
17767
|
+
...input.spanData?.metadata,
|
|
17768
|
+
custom_id: input.customId,
|
|
17769
|
+
provider: "openai"
|
|
17770
|
+
}
|
|
17771
|
+
}
|
|
17772
|
+
},
|
|
17773
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
17774
|
+
)
|
|
17775
|
+
)
|
|
17776
|
+
);
|
|
17777
|
+
}
|
|
17778
|
+
async function* jsonlRecords(file, onIssue = () => {
|
|
17779
|
+
}) {
|
|
17780
|
+
const resolvedFile = await file;
|
|
17781
|
+
if (typeof resolvedFile === "string") {
|
|
17782
|
+
for (const line of resolvedFile.split("\n")) {
|
|
17783
|
+
if (!line.trim()) {
|
|
17784
|
+
continue;
|
|
17785
|
+
}
|
|
17786
|
+
try {
|
|
17787
|
+
yield JSON.parse(line.replace(/\r$/, ""));
|
|
17788
|
+
} catch (error2) {
|
|
17789
|
+
logBatchInstrumentationError("skipped malformed JSONL", error2);
|
|
17790
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
17791
|
+
}
|
|
17792
|
+
}
|
|
17793
|
+
return;
|
|
17794
|
+
}
|
|
17795
|
+
const body = read(resolvedFile, "body");
|
|
17796
|
+
const getReader = read(body, "getReader");
|
|
17797
|
+
if (isObject(body) && typeof getReader === "function") {
|
|
17798
|
+
let reader;
|
|
17799
|
+
try {
|
|
17800
|
+
reader = Reflect.apply(getReader, body, []);
|
|
17801
|
+
const decoder = new TextDecoder();
|
|
17802
|
+
let pending = "";
|
|
17803
|
+
while (true) {
|
|
17804
|
+
const readChunk = read(reader, "read");
|
|
17805
|
+
if (typeof readChunk !== "function") {
|
|
17806
|
+
throw new Error("Response body stream has no read method");
|
|
17807
|
+
}
|
|
17808
|
+
const chunk = await Reflect.apply(readChunk, reader, []);
|
|
17809
|
+
if (!isObject(chunk)) {
|
|
17810
|
+
throw new Error("Response body stream returned an invalid chunk");
|
|
17811
|
+
}
|
|
17812
|
+
if (chunk.done === true) {
|
|
17813
|
+
pending += decoder.decode();
|
|
17814
|
+
break;
|
|
17815
|
+
}
|
|
17816
|
+
if (!(chunk.value instanceof Uint8Array)) {
|
|
17817
|
+
throw new Error("Response body stream returned a non-byte chunk");
|
|
17818
|
+
}
|
|
17819
|
+
pending += decoder.decode(chunk.value, { stream: true });
|
|
17820
|
+
let newline = pending.indexOf("\n");
|
|
17821
|
+
while (newline !== -1) {
|
|
17822
|
+
const line = pending.slice(0, newline).replace(/\r$/, "");
|
|
17823
|
+
pending = pending.slice(newline + 1);
|
|
17824
|
+
if (line.trim()) {
|
|
17825
|
+
try {
|
|
17826
|
+
yield JSON.parse(line);
|
|
17827
|
+
} catch (error2) {
|
|
17828
|
+
logBatchInstrumentationError("skipped malformed JSONL", error2);
|
|
17829
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
17830
|
+
}
|
|
17831
|
+
}
|
|
17832
|
+
newline = pending.indexOf("\n");
|
|
17833
|
+
}
|
|
17834
|
+
}
|
|
17835
|
+
if (pending.trim()) {
|
|
17836
|
+
try {
|
|
17837
|
+
yield JSON.parse(pending.replace(/\r$/, ""));
|
|
17838
|
+
} catch (error2) {
|
|
17839
|
+
logBatchInstrumentationError("skipped malformed JSONL", error2);
|
|
17840
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
17841
|
+
}
|
|
17842
|
+
}
|
|
17843
|
+
} catch (error2) {
|
|
17844
|
+
logBatchInstrumentationError("could not read JSONL response body", error2);
|
|
17845
|
+
onIssue(new Error("OpenAI Batch response body could not be read"));
|
|
17846
|
+
} finally {
|
|
17847
|
+
const releaseLock = read(reader, "releaseLock");
|
|
17848
|
+
if (typeof releaseLock === "function") {
|
|
17849
|
+
try {
|
|
17850
|
+
Reflect.apply(releaseLock, reader, []);
|
|
17851
|
+
} catch (error2) {
|
|
17852
|
+
logBatchInstrumentationError(
|
|
17853
|
+
"could not release stream reader",
|
|
17854
|
+
error2
|
|
17855
|
+
);
|
|
17856
|
+
}
|
|
17857
|
+
}
|
|
17858
|
+
}
|
|
17859
|
+
return;
|
|
17860
|
+
}
|
|
17861
|
+
if (isBatchRecordIterable(resolvedFile)) {
|
|
17862
|
+
for await (const record of resolvedFile) {
|
|
17863
|
+
yield record;
|
|
17864
|
+
}
|
|
17865
|
+
return;
|
|
17866
|
+
}
|
|
17867
|
+
logBatchInstrumentationError("skipped invalid JSONL source", resolvedFile);
|
|
17868
|
+
onIssue(new Error("OpenAI Batch file source is invalid"));
|
|
17869
|
+
}
|
|
17870
|
+
async function readBatchInputs(file) {
|
|
17871
|
+
const inputs = /* @__PURE__ */ new Map();
|
|
17872
|
+
const issues = [];
|
|
17873
|
+
let endpoint;
|
|
17874
|
+
try {
|
|
17875
|
+
for await (const value of jsonlRecords(
|
|
17876
|
+
file,
|
|
17877
|
+
(issue) => issues.push(issue)
|
|
17878
|
+
)) {
|
|
17879
|
+
const customId = read(value, "custom_id");
|
|
17880
|
+
const url = read(value, "url");
|
|
17881
|
+
const body = read(value, "body");
|
|
17882
|
+
if (!validCustomId(customId) || inputs.has(customId) || read(value, "method") !== "POST" || typeof url !== "string" || !SUPPORTED_ENDPOINTS.has(url) || endpoint !== void 0 && endpoint !== url || !isObject(body)) {
|
|
17883
|
+
issues.push(new Error("OpenAI Batch input contains an invalid record"));
|
|
17884
|
+
continue;
|
|
17885
|
+
}
|
|
17886
|
+
endpoint = url;
|
|
17887
|
+
let spanData;
|
|
17888
|
+
try {
|
|
17889
|
+
spanData = extractOpenAIBatchInput(url, body);
|
|
17890
|
+
} catch (error2) {
|
|
17891
|
+
logBatchInstrumentationError("could not extract batch input", error2);
|
|
17892
|
+
}
|
|
17893
|
+
inputs.set(customId, { customId, spanData });
|
|
17894
|
+
}
|
|
17895
|
+
} catch (error2) {
|
|
17896
|
+
logBatchInstrumentationError("could not process input file", error2);
|
|
17897
|
+
issues.push(new Error("OpenAI Batch input file could not be processed"));
|
|
17898
|
+
}
|
|
17899
|
+
if (!endpoint || inputs.size === 0) {
|
|
17900
|
+
issues.push(new Error("OpenAI Batch input contains no supported records"));
|
|
17901
|
+
}
|
|
17902
|
+
return { endpoint, inputs, issues };
|
|
17903
|
+
}
|
|
17904
|
+
async function writePendingSpans(trace, endTime) {
|
|
17905
|
+
const task = await startBatchSpan(trace.context);
|
|
17906
|
+
const taskParent = await task.export();
|
|
17907
|
+
for (const input of trace.inputs.values()) {
|
|
17908
|
+
try {
|
|
17909
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
17910
|
+
if (endTime !== void 0) {
|
|
17911
|
+
child.end({ endTime });
|
|
17912
|
+
}
|
|
17913
|
+
} catch (error2) {
|
|
17914
|
+
logBatchInstrumentationError("could not write batch request span", error2);
|
|
17915
|
+
}
|
|
17916
|
+
}
|
|
17917
|
+
if (endTime !== void 0) {
|
|
17918
|
+
if (trace.status && trace.status !== "completed") {
|
|
17919
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
17920
|
+
}
|
|
17921
|
+
task.end({ endTime });
|
|
17922
|
+
}
|
|
17923
|
+
}
|
|
17924
|
+
var interceptOpenAIFilesCreateTraced = async (target, thisArg, args) => {
|
|
17925
|
+
const startTime = getCurrentUnixTimestamp();
|
|
17926
|
+
const inputPromise = readBatchInputs(args[0].inputFileContent);
|
|
17927
|
+
const parentPromise = exportParent(args[0].parent);
|
|
17928
|
+
const file = await Reflect.apply(target, thisArg, args);
|
|
17929
|
+
try {
|
|
17930
|
+
const inputFileId = read(file, "id");
|
|
17931
|
+
const [inputData, exportedParent2] = await Promise.all([
|
|
17932
|
+
inputPromise,
|
|
17933
|
+
parentPromise
|
|
17934
|
+
]);
|
|
17935
|
+
if (typeof inputFileId !== "string" || !exportedParent2 || !inputData.endpoint || inputData.issues.length > 0) {
|
|
17936
|
+
if (inputData.issues[0]) {
|
|
17937
|
+
logBatchInstrumentationError(
|
|
17938
|
+
"skipped invalid input file",
|
|
17939
|
+
inputData.issues[0]
|
|
17940
|
+
);
|
|
17941
|
+
}
|
|
17942
|
+
return file;
|
|
17943
|
+
}
|
|
17944
|
+
const trace = {
|
|
17945
|
+
context: {
|
|
17946
|
+
inputFileId,
|
|
17947
|
+
endpoint: inputData.endpoint,
|
|
17948
|
+
parent: exportedParent2,
|
|
17949
|
+
taskStartTime: startTime,
|
|
17950
|
+
childStartTime: startTime
|
|
17951
|
+
},
|
|
17952
|
+
inputs: inputData.inputs
|
|
17953
|
+
};
|
|
17954
|
+
pendingBatchTraces.set(inputFileId, trace);
|
|
17955
|
+
await writePendingSpans(trace);
|
|
17956
|
+
} catch (error2) {
|
|
17957
|
+
logBatchInstrumentationError("could not start batch spans", error2);
|
|
17958
|
+
}
|
|
17959
|
+
return file;
|
|
17960
|
+
};
|
|
17961
|
+
function validTimestamp(value) {
|
|
17962
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
17963
|
+
}
|
|
17964
|
+
function terminalEndTime(batch, startTime) {
|
|
17965
|
+
let timestamp;
|
|
17966
|
+
switch (batch.status) {
|
|
17967
|
+
case "completed":
|
|
17968
|
+
timestamp = batch.completed_at;
|
|
17969
|
+
break;
|
|
17970
|
+
case "failed":
|
|
17971
|
+
timestamp = batch.failed_at;
|
|
17972
|
+
break;
|
|
17973
|
+
case "expired":
|
|
17974
|
+
timestamp = batch.expired_at;
|
|
17975
|
+
break;
|
|
17976
|
+
default:
|
|
17977
|
+
timestamp = batch.cancelled_at;
|
|
17978
|
+
}
|
|
17979
|
+
return validTimestamp(timestamp) ? Math.max(timestamp, startTime) : Math.max(getCurrentUnixTimestamp(), startTime);
|
|
17980
|
+
}
|
|
17981
|
+
async function updateBatchTimestamps(batch) {
|
|
17982
|
+
const trace = pendingBatchTraces.get(batch.input_file_id);
|
|
17983
|
+
if (!trace || trace.context.endpoint !== batch.endpoint) {
|
|
17984
|
+
return;
|
|
17985
|
+
}
|
|
17986
|
+
if (validTimestamp(batch.created_at)) {
|
|
17987
|
+
trace.context.taskStartTime = batch.created_at;
|
|
17988
|
+
}
|
|
17989
|
+
trace.context.childStartTime = validTimestamp(batch.in_progress_at) ? Math.max(batch.in_progress_at, trace.context.taskStartTime) : trace.context.taskStartTime;
|
|
17990
|
+
trace.status = batch.status;
|
|
17991
|
+
if (TERMINAL_STATUSES.has(batch.status)) {
|
|
17992
|
+
trace.endTime = terminalEndTime(batch, trace.context.childStartTime);
|
|
17993
|
+
}
|
|
17994
|
+
await writePendingSpans(trace, trace.endTime);
|
|
17995
|
+
}
|
|
17996
|
+
var interceptOpenAIBatchesRetrieveTraced = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (batch) => {
|
|
17997
|
+
try {
|
|
17998
|
+
await updateBatchTimestamps(batch);
|
|
17999
|
+
} catch (error2) {
|
|
18000
|
+
logBatchInstrumentationError("could not update batch timestamps", error2);
|
|
18001
|
+
}
|
|
18002
|
+
return batch;
|
|
18003
|
+
});
|
|
18004
|
+
function errorFromResult(result) {
|
|
18005
|
+
const error2 = read(result.value, "error");
|
|
18006
|
+
if (isObject(error2)) {
|
|
18007
|
+
const message = read(error2, "message");
|
|
18008
|
+
return new Error(
|
|
18009
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
18010
|
+
);
|
|
18011
|
+
}
|
|
18012
|
+
const response = read(result.value, "response");
|
|
18013
|
+
const statusCode = read(response, "status_code");
|
|
18014
|
+
if (result.source === "error" || typeof statusCode === "number" && (statusCode < 200 || statusCode >= 300)) {
|
|
18015
|
+
const message = read(read(read(response, "body"), "error"), "message");
|
|
18016
|
+
return new Error(
|
|
18017
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
18018
|
+
);
|
|
18019
|
+
}
|
|
18020
|
+
return void 0;
|
|
18021
|
+
}
|
|
18022
|
+
async function completeBatchResult(context2, taskParent, endTime, input, result) {
|
|
18023
|
+
const child = await startBatchChild(context2, taskParent, input);
|
|
18024
|
+
try {
|
|
18025
|
+
const resultError = errorFromResult(result);
|
|
18026
|
+
const responseBody = read(read(result.value, "response"), "body");
|
|
18027
|
+
if (resultError) {
|
|
18028
|
+
child.log({ error: resultError });
|
|
18029
|
+
} else if (isObject(responseBody)) {
|
|
18030
|
+
const model = read(responseBody, "model");
|
|
18031
|
+
child.log({
|
|
18032
|
+
output: context2.endpoint === "/v1/chat/completions" ? read(responseBody, "choices") : processImagesInOutput(read(responseBody, "output")),
|
|
18033
|
+
...typeof model === "string" ? { metadata: { model } } : {},
|
|
18034
|
+
metrics: parseMetricsFromUsage(read(responseBody, "usage"))
|
|
18035
|
+
});
|
|
18036
|
+
} else {
|
|
18037
|
+
child.log({ error: new Error("OpenAI Batch response body is missing") });
|
|
18038
|
+
}
|
|
18039
|
+
} catch (error2) {
|
|
18040
|
+
child.log({ error: error2 });
|
|
18041
|
+
} finally {
|
|
18042
|
+
child.end({ endTime });
|
|
18043
|
+
}
|
|
18044
|
+
}
|
|
18045
|
+
async function completeResultFile({
|
|
18046
|
+
context: context2,
|
|
18047
|
+
endTime,
|
|
18048
|
+
file,
|
|
18049
|
+
inputs,
|
|
18050
|
+
issues,
|
|
18051
|
+
seen,
|
|
18052
|
+
source,
|
|
18053
|
+
taskParent
|
|
18054
|
+
}) {
|
|
18055
|
+
if (file === void 0) {
|
|
18056
|
+
return;
|
|
18057
|
+
}
|
|
18058
|
+
for await (const value of jsonlRecords(file, (issue) => issues.push(issue))) {
|
|
18059
|
+
const customId = read(value, "custom_id");
|
|
18060
|
+
if (!validCustomId(customId) || !isObject(value)) {
|
|
18061
|
+
issues.push(
|
|
18062
|
+
new Error("OpenAI Batch result is missing a valid custom_id")
|
|
18063
|
+
);
|
|
18064
|
+
continue;
|
|
18065
|
+
}
|
|
18066
|
+
if (seen.has(customId)) {
|
|
18067
|
+
issues.push(new Error("OpenAI Batch result contains a duplicate"));
|
|
18068
|
+
continue;
|
|
18069
|
+
}
|
|
18070
|
+
const input = inputs.get(customId);
|
|
18071
|
+
if (!input) {
|
|
18072
|
+
issues.push(
|
|
18073
|
+
new Error("OpenAI Batch result does not match an input record")
|
|
18074
|
+
);
|
|
18075
|
+
continue;
|
|
18076
|
+
}
|
|
18077
|
+
seen.add(customId);
|
|
18078
|
+
await completeBatchResult(context2, taskParent, endTime, input, {
|
|
18079
|
+
value,
|
|
18080
|
+
source
|
|
18081
|
+
});
|
|
18082
|
+
}
|
|
18083
|
+
}
|
|
18084
|
+
function sameInputs(first, second) {
|
|
18085
|
+
return first.size === second.size && [...first.keys()].every((customId) => second.has(customId));
|
|
18086
|
+
}
|
|
18087
|
+
async function contextForCompletion(inputFileId, inputData) {
|
|
18088
|
+
if (!inputData.endpoint || inputData.issues.length > 0) {
|
|
18089
|
+
return void 0;
|
|
18090
|
+
}
|
|
18091
|
+
const existing = pendingBatchTraces.get(inputFileId);
|
|
18092
|
+
if (existing) {
|
|
18093
|
+
if (existing.context.endpoint !== inputData.endpoint || !sameInputs(existing.inputs, inputData.inputs)) {
|
|
18094
|
+
return void 0;
|
|
18095
|
+
}
|
|
18096
|
+
return { ...existing, inputs: inputData.inputs };
|
|
18097
|
+
}
|
|
18098
|
+
const parent = await exportParent(getSpanParentObject());
|
|
18099
|
+
if (!parent) {
|
|
18100
|
+
return void 0;
|
|
18101
|
+
}
|
|
18102
|
+
const startTime = getCurrentUnixTimestamp();
|
|
18103
|
+
return {
|
|
18104
|
+
context: {
|
|
18105
|
+
inputFileId,
|
|
18106
|
+
endpoint: inputData.endpoint,
|
|
18107
|
+
parent,
|
|
18108
|
+
taskStartTime: startTime,
|
|
18109
|
+
childStartTime: startTime
|
|
18110
|
+
},
|
|
18111
|
+
inputs: inputData.inputs
|
|
18112
|
+
};
|
|
18113
|
+
}
|
|
18114
|
+
async function completeBatch(args) {
|
|
18115
|
+
const inputData = await readBatchInputs(args.inputFileContent);
|
|
18116
|
+
const trace = await contextForCompletion(args.inputFileId, inputData);
|
|
18117
|
+
if (!trace) {
|
|
18118
|
+
logBatchInstrumentationError(
|
|
18119
|
+
"left batch spans pending",
|
|
18120
|
+
inputData.issues[0] ?? new Error("OpenAI Batch input does not match")
|
|
18121
|
+
);
|
|
18122
|
+
return;
|
|
18123
|
+
}
|
|
18124
|
+
const endTime = trace.endTime ?? getCurrentUnixTimestamp();
|
|
18125
|
+
const task = await startBatchSpan(trace.context);
|
|
18126
|
+
const taskParent = await task.export();
|
|
18127
|
+
const issues = [];
|
|
18128
|
+
const seen = /* @__PURE__ */ new Set();
|
|
18129
|
+
await Promise.all([
|
|
18130
|
+
completeResultFile({
|
|
18131
|
+
context: trace.context,
|
|
18132
|
+
endTime,
|
|
18133
|
+
file: args.outputFileContent,
|
|
18134
|
+
inputs: trace.inputs,
|
|
18135
|
+
issues,
|
|
18136
|
+
seen,
|
|
18137
|
+
source: "output",
|
|
18138
|
+
taskParent
|
|
18139
|
+
}),
|
|
18140
|
+
completeResultFile({
|
|
18141
|
+
context: trace.context,
|
|
18142
|
+
endTime,
|
|
18143
|
+
file: args.errorFileContent,
|
|
18144
|
+
inputs: trace.inputs,
|
|
18145
|
+
issues,
|
|
18146
|
+
seen,
|
|
18147
|
+
source: "error",
|
|
18148
|
+
taskParent
|
|
18149
|
+
})
|
|
18150
|
+
]);
|
|
18151
|
+
if (issues.length > 0) {
|
|
18152
|
+
logBatchInstrumentationError("left batch spans pending", issues[0]);
|
|
18153
|
+
return;
|
|
18154
|
+
}
|
|
18155
|
+
const missing = [...trace.inputs.values()].filter(
|
|
18156
|
+
({ customId }) => !seen.has(customId)
|
|
18157
|
+
);
|
|
18158
|
+
if (!trace.status || trace.status === "completed") {
|
|
18159
|
+
if (missing.length > 0) {
|
|
18160
|
+
logBatchInstrumentationError(
|
|
18161
|
+
"left batch spans pending",
|
|
18162
|
+
new Error("OpenAI Batch result files are incomplete")
|
|
18163
|
+
);
|
|
18164
|
+
return;
|
|
18165
|
+
}
|
|
18166
|
+
} else {
|
|
18167
|
+
for (const input of missing) {
|
|
18168
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
18169
|
+
child.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
18170
|
+
child.end({ endTime });
|
|
18171
|
+
}
|
|
18172
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
18173
|
+
}
|
|
18174
|
+
task.end({ endTime });
|
|
18175
|
+
pendingBatchTraces.delete(args.inputFileId);
|
|
18176
|
+
}
|
|
18177
|
+
var interceptOpenAIBatchTraceComplete = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (result) => {
|
|
18178
|
+
try {
|
|
18179
|
+
await completeBatch(args[0]);
|
|
18180
|
+
} catch (error2) {
|
|
18181
|
+
logBatchInstrumentationError("could not complete batch", error2);
|
|
18182
|
+
}
|
|
18183
|
+
return result;
|
|
18184
|
+
});
|
|
18185
|
+
|
|
17522
18186
|
// src/instrumentation/plugins/openai-plugin.ts
|
|
17523
18187
|
var OpenAIPlugin = class extends BasePlugin {
|
|
17524
18188
|
constructor() {
|
|
17525
18189
|
super();
|
|
17526
18190
|
}
|
|
17527
18191
|
onEnable() {
|
|
18192
|
+
this.unsubscribers.push(
|
|
18193
|
+
openAIChannels.filesCreateTraced.intercept(
|
|
18194
|
+
interceptOpenAIFilesCreateTraced
|
|
18195
|
+
),
|
|
18196
|
+
openAIChannels.batchesRetrieveTraced.intercept(
|
|
18197
|
+
interceptOpenAIBatchesRetrieveTraced
|
|
18198
|
+
),
|
|
18199
|
+
openAIChannels.batchesCompleteTrace.intercept(
|
|
18200
|
+
interceptOpenAIBatchTraceComplete
|
|
18201
|
+
)
|
|
18202
|
+
);
|
|
17528
18203
|
this.unsubscribers.push(
|
|
17529
18204
|
traceStreamingChannel(openAIChannels.chatCompletionsCreate, {
|
|
17530
18205
|
name: "Chat Completion",
|
|
17531
18206
|
type: "llm" /* LLM */,
|
|
17532
|
-
extractInput: ([params]) =>
|
|
17533
|
-
const { messages, ...metadata } = params;
|
|
17534
|
-
return {
|
|
17535
|
-
input: processInputAttachments(messages),
|
|
17536
|
-
metadata: { ...metadata, provider: "openai" }
|
|
17537
|
-
};
|
|
17538
|
-
},
|
|
18207
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
17539
18208
|
extractOutput: (result) => {
|
|
17540
18209
|
return result?.choices;
|
|
17541
18210
|
},
|
|
@@ -17581,13 +18250,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
17581
18250
|
traceStreamingChannel(openAIChannels.betaChatCompletionsParse, {
|
|
17582
18251
|
name: "Chat Completion",
|
|
17583
18252
|
type: "llm" /* LLM */,
|
|
17584
|
-
extractInput: ([params]) =>
|
|
17585
|
-
const { messages, ...metadata } = params;
|
|
17586
|
-
return {
|
|
17587
|
-
input: processInputAttachments(messages),
|
|
17588
|
-
metadata: { ...metadata, provider: "openai" }
|
|
17589
|
-
};
|
|
17590
|
-
},
|
|
18253
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
17591
18254
|
extractOutput: (result) => {
|
|
17592
18255
|
return result?.choices;
|
|
17593
18256
|
},
|
|
@@ -17609,13 +18272,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
17609
18272
|
traceSyncStreamChannel(openAIChannels.betaChatCompletionsStream, {
|
|
17610
18273
|
name: "Chat Completion",
|
|
17611
18274
|
type: "llm" /* LLM */,
|
|
17612
|
-
extractInput: ([params]) =>
|
|
17613
|
-
const { messages, ...metadata } = params;
|
|
17614
|
-
return {
|
|
17615
|
-
input: processInputAttachments(messages),
|
|
17616
|
-
metadata: { ...metadata, provider: "openai" }
|
|
17617
|
-
};
|
|
17618
|
-
}
|
|
18275
|
+
extractInput: ([params]) => extractOpenAIChatInput(params)
|
|
17619
18276
|
})
|
|
17620
18277
|
);
|
|
17621
18278
|
this.unsubscribers.push(
|
|
@@ -17645,23 +18302,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
17645
18302
|
traceStreamingChannel(openAIChannels.responsesCreate, {
|
|
17646
18303
|
name: "openai.responses.create",
|
|
17647
18304
|
type: "llm" /* LLM */,
|
|
17648
|
-
extractInput: ([params]) =>
|
|
17649
|
-
const { input, ...metadata } = params;
|
|
17650
|
-
return {
|
|
17651
|
-
input: processInputAttachments(input),
|
|
17652
|
-
metadata: { ...metadata, provider: "openai" }
|
|
17653
|
-
};
|
|
17654
|
-
},
|
|
18305
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
17655
18306
|
extractOutput: (result) => {
|
|
17656
18307
|
return processImagesInOutput(result?.output);
|
|
17657
18308
|
},
|
|
17658
|
-
extractMetadata: (result) =>
|
|
17659
|
-
if (!result) {
|
|
17660
|
-
return void 0;
|
|
17661
|
-
}
|
|
17662
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
17663
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
17664
|
-
},
|
|
18309
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
17665
18310
|
extractMetrics: (result, startTime, endEvent) => {
|
|
17666
18311
|
const metrics = withCachedMetric(
|
|
17667
18312
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -17680,13 +18325,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
17680
18325
|
traceSyncStreamChannel(openAIChannels.responsesStream, {
|
|
17681
18326
|
name: "openai.responses.create",
|
|
17682
18327
|
type: "llm" /* LLM */,
|
|
17683
|
-
extractInput: ([params]) =>
|
|
17684
|
-
const { input, ...metadata } = params;
|
|
17685
|
-
return {
|
|
17686
|
-
input: processInputAttachments(input),
|
|
17687
|
-
metadata: { ...metadata, provider: "openai" }
|
|
17688
|
-
};
|
|
17689
|
-
},
|
|
18328
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
17690
18329
|
extractFromEvent: (event) => {
|
|
17691
18330
|
if (event.type !== "response.completed" || !event.response) {
|
|
17692
18331
|
return {};
|
|
@@ -17709,23 +18348,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
17709
18348
|
traceStreamingChannel(openAIChannels.responsesParse, {
|
|
17710
18349
|
name: "openai.responses.parse",
|
|
17711
18350
|
type: "llm" /* LLM */,
|
|
17712
|
-
extractInput: ([params]) =>
|
|
17713
|
-
const { input, ...metadata } = params;
|
|
17714
|
-
return {
|
|
17715
|
-
input: processInputAttachments(input),
|
|
17716
|
-
metadata: { ...metadata, provider: "openai" }
|
|
17717
|
-
};
|
|
17718
|
-
},
|
|
18351
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
17719
18352
|
extractOutput: (result) => {
|
|
17720
18353
|
return processImagesInOutput(result?.output);
|
|
17721
18354
|
},
|
|
17722
|
-
extractMetadata: (result) =>
|
|
17723
|
-
if (!result) {
|
|
17724
|
-
return void 0;
|
|
17725
|
-
}
|
|
17726
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
17727
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
17728
|
-
},
|
|
18355
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
17729
18356
|
extractMetrics: (result, startTime, endEvent) => {
|
|
17730
18357
|
const metrics = withCachedMetric(
|
|
17731
18358
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -17744,23 +18371,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
17744
18371
|
traceAsyncChannel(openAIChannels.responsesCompact, {
|
|
17745
18372
|
name: "openai.responses.compact",
|
|
17746
18373
|
type: "llm" /* LLM */,
|
|
17747
|
-
extractInput: ([params]) =>
|
|
17748
|
-
const { input, ...metadata } = params;
|
|
17749
|
-
return {
|
|
17750
|
-
input: processInputAttachments(input),
|
|
17751
|
-
metadata: { ...metadata, provider: "openai" }
|
|
17752
|
-
};
|
|
17753
|
-
},
|
|
18374
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
17754
18375
|
extractOutput: (result) => {
|
|
17755
18376
|
return processImagesInOutput(result?.output);
|
|
17756
18377
|
},
|
|
17757
|
-
extractMetadata: (result) =>
|
|
17758
|
-
if (!result) {
|
|
17759
|
-
return void 0;
|
|
17760
|
-
}
|
|
17761
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
17762
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
17763
|
-
},
|
|
18378
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
17764
18379
|
extractMetrics: (result, startTime, endEvent) => {
|
|
17765
18380
|
const metrics = withCachedMetric(
|
|
17766
18381
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -17816,35 +18431,6 @@ function withCachedMetric(metrics, result, endEvent) {
|
|
|
17816
18431
|
cached
|
|
17817
18432
|
};
|
|
17818
18433
|
}
|
|
17819
|
-
function processImagesInOutput(output) {
|
|
17820
|
-
if (Array.isArray(output)) {
|
|
17821
|
-
return output.map(processImagesInOutput);
|
|
17822
|
-
}
|
|
17823
|
-
if (isObject(output)) {
|
|
17824
|
-
if (output.type === "image_generation_call" && output.result && typeof output.result === "string") {
|
|
17825
|
-
const fileExtension = output.output_format || "png";
|
|
17826
|
-
const contentType = `image/${fileExtension}`;
|
|
17827
|
-
const baseFilename = output.revised_prompt && typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
17828
|
-
const filename = `${baseFilename}.${fileExtension}`;
|
|
17829
|
-
const binaryString = atob(output.result);
|
|
17830
|
-
const bytes = new Uint8Array(binaryString.length);
|
|
17831
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
17832
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
17833
|
-
}
|
|
17834
|
-
const blob = new Blob([bytes], { type: contentType });
|
|
17835
|
-
const attachment = new Attachment({
|
|
17836
|
-
data: blob,
|
|
17837
|
-
filename,
|
|
17838
|
-
contentType
|
|
17839
|
-
});
|
|
17840
|
-
return {
|
|
17841
|
-
...output,
|
|
17842
|
-
result: attachment
|
|
17843
|
-
};
|
|
17844
|
-
}
|
|
17845
|
-
}
|
|
17846
|
-
return output;
|
|
17847
|
-
}
|
|
17848
18434
|
function mergeLogprobTokens(existing, incoming) {
|
|
17849
18435
|
if (incoming === void 0) {
|
|
17850
18436
|
return existing;
|
|
@@ -22988,6 +23574,12 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
|
|
|
22988
23574
|
if (!activeEntry) {
|
|
22989
23575
|
return result;
|
|
22990
23576
|
}
|
|
23577
|
+
const executionOptions = args[1];
|
|
23578
|
+
const toolCallId = isObject(executionOptions) ? executionOptions.toolCallId : void 0;
|
|
23579
|
+
const toolInput = {
|
|
23580
|
+
input: serializeToolExecutionInput(args),
|
|
23581
|
+
...typeof toolCallId === "string" ? { metadata: { toolCallId } } : {}
|
|
23582
|
+
};
|
|
22991
23583
|
if (isAsyncGenerator2(result)) {
|
|
22992
23584
|
return (async function* () {
|
|
22993
23585
|
const span = activeEntry.parentSpan.startSpan(
|
|
@@ -23001,7 +23593,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
|
|
|
23001
23593
|
INSTRUMENTATION_NAMES.AI_SDK
|
|
23002
23594
|
)
|
|
23003
23595
|
);
|
|
23004
|
-
span.log(
|
|
23596
|
+
span.log(toolInput);
|
|
23005
23597
|
try {
|
|
23006
23598
|
let lastValue;
|
|
23007
23599
|
for await (const value of result) {
|
|
@@ -23019,7 +23611,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
|
|
|
23019
23611
|
}
|
|
23020
23612
|
return activeEntry.parentSpan.traced(
|
|
23021
23613
|
async (span) => {
|
|
23022
|
-
span.log(
|
|
23614
|
+
span.log(toolInput);
|
|
23023
23615
|
const awaitedResult = await result;
|
|
23024
23616
|
span.log({ output: awaitedResult });
|
|
23025
23617
|
return awaitedResult;
|
|
@@ -37141,14 +37733,17 @@ function getMetricsFromResponse(response) {
|
|
|
37141
37733
|
if (!isRecord(usageMetadata)) {
|
|
37142
37734
|
continue;
|
|
37143
37735
|
}
|
|
37144
|
-
const inputTokenDetails = usageMetadata.input_token_details;
|
|
37736
|
+
const inputTokenDetails = isRecord(usageMetadata.input_token_details) ? usageMetadata.input_token_details : {};
|
|
37145
37737
|
const outputTokenDetails = usageMetadata.output_token_details;
|
|
37146
37738
|
return normalizeTokenMetrics({
|
|
37147
37739
|
total_tokens: usageMetadata.total_tokens,
|
|
37148
37740
|
prompt_tokens: usageMetadata.input_tokens,
|
|
37149
37741
|
completion_tokens: usageMetadata.output_tokens,
|
|
37150
|
-
|
|
37151
|
-
|
|
37742
|
+
// Prefer TTL-specific cache writes over the aggregate when available.
|
|
37743
|
+
prompt_cache_creation_tokens: inputTokenDetails.ephemeral_5m_input_tokens == null && inputTokenDetails.ephemeral_1h_input_tokens == null ? inputTokenDetails.cache_creation : void 0,
|
|
37744
|
+
prompt_cache_creation_5m_tokens: inputTokenDetails.ephemeral_5m_input_tokens,
|
|
37745
|
+
prompt_cache_creation_1h_tokens: inputTokenDetails.ephemeral_1h_input_tokens,
|
|
37746
|
+
prompt_cached_tokens: inputTokenDetails.cache_read,
|
|
37152
37747
|
completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
|
|
37153
37748
|
});
|
|
37154
37749
|
}
|
|
@@ -37864,7 +38459,7 @@ function extractSession(event) {
|
|
|
37864
38459
|
return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
|
|
37865
38460
|
}
|
|
37866
38461
|
function isPiAgent(value) {
|
|
37867
|
-
return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
|
|
38462
|
+
return isObject(value) && (typeof value.streamFunction === "function" || typeof value.streamFn === "function") && typeof value.subscribe === "function";
|
|
37868
38463
|
}
|
|
37869
38464
|
function promptContextStore() {
|
|
37870
38465
|
piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
|
|
@@ -37874,17 +38469,21 @@ function currentPiPromptState() {
|
|
|
37874
38469
|
return promptContextStore().getStore();
|
|
37875
38470
|
}
|
|
37876
38471
|
function installPiAgentInstrumentation(agent) {
|
|
38472
|
+
const property = typeof agent.streamFunction === "function" ? "streamFunction" : "streamFn";
|
|
38473
|
+
const streamFunction = agent[property];
|
|
37877
38474
|
const existing = piAgentPatchStates.get(agent);
|
|
37878
|
-
if (!existing ||
|
|
38475
|
+
if (streamFunction && (!existing || existing.property !== property || streamFunction !== existing.wrappedStreamFunction)) {
|
|
37879
38476
|
const patchState = {
|
|
37880
|
-
|
|
37881
|
-
|
|
38477
|
+
originalStreamFunction: streamFunction,
|
|
38478
|
+
property,
|
|
38479
|
+
wrappedStreamFunction: streamFunction
|
|
37882
38480
|
};
|
|
37883
|
-
patchState.
|
|
38481
|
+
patchState.wrappedStreamFunction = makeInstrumentedStreamFunction(
|
|
37884
38482
|
agent,
|
|
37885
|
-
patchState.
|
|
38483
|
+
patchState.originalStreamFunction,
|
|
38484
|
+
property
|
|
37886
38485
|
);
|
|
37887
|
-
agent
|
|
38486
|
+
agent[property] = patchState.wrappedStreamFunction;
|
|
37888
38487
|
piAgentPatchStates.set(agent, patchState);
|
|
37889
38488
|
}
|
|
37890
38489
|
if (piAgentEventSubscriptions.has(agent)) {
|
|
@@ -37909,15 +38508,21 @@ function installPiAgentInstrumentation(agent) {
|
|
|
37909
38508
|
logInstrumentationError4("Pi Coding Agent event subscription", error2);
|
|
37910
38509
|
}
|
|
37911
38510
|
}
|
|
37912
|
-
function
|
|
37913
|
-
return async function
|
|
37914
|
-
const invokeOriginal = () => Reflect.apply(
|
|
38511
|
+
function makeInstrumentedStreamFunction(agent, originalStreamFunction, property) {
|
|
38512
|
+
return async function instrumentedPiStreamFunction(model, context2, options) {
|
|
38513
|
+
const invokeOriginal = () => Reflect.apply(originalStreamFunction, this, [model, context2, options]);
|
|
37915
38514
|
const state = currentPiPromptState();
|
|
37916
38515
|
if (!state || state.agent !== agent || state.finalized) {
|
|
37917
38516
|
return invokeOriginal();
|
|
37918
38517
|
}
|
|
37919
38518
|
wrapPiToolExecutors(context2.tools);
|
|
37920
|
-
const llmState = await startPiLlmSpan(
|
|
38519
|
+
const llmState = await startPiLlmSpan(
|
|
38520
|
+
state,
|
|
38521
|
+
model,
|
|
38522
|
+
context2,
|
|
38523
|
+
property,
|
|
38524
|
+
options
|
|
38525
|
+
);
|
|
37921
38526
|
try {
|
|
37922
38527
|
const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
|
|
37923
38528
|
return patchAssistantMessageStream(stream, state, llmState);
|
|
@@ -37954,12 +38559,12 @@ function wrapPiToolExecutors(tools) {
|
|
|
37954
38559
|
}
|
|
37955
38560
|
}
|
|
37956
38561
|
}
|
|
37957
|
-
async function startPiLlmSpan(state, model, context2, options) {
|
|
38562
|
+
async function startPiLlmSpan(state, model, context2, property, options) {
|
|
37958
38563
|
const metadata = {
|
|
37959
38564
|
...extractModelMetadata2(model),
|
|
37960
38565
|
...extractStreamOptionsMetadata(options),
|
|
37961
38566
|
...extractToolMetadata(context2.tools),
|
|
37962
|
-
"pi_coding_agent.operation":
|
|
38567
|
+
"pi_coding_agent.operation": `agent.${property}`
|
|
37963
38568
|
};
|
|
37964
38569
|
const span = startSpan(
|
|
37965
38570
|
withSpanInstrumentationName(
|
|
@@ -44056,7 +44661,7 @@ var openRouterAgentConfigs = [
|
|
|
44056
44661
|
];
|
|
44057
44662
|
|
|
44058
44663
|
// src/auto-instrumentations/configs/pi-coding-agent.ts
|
|
44059
|
-
var piCodingAgentVersionRange = ">=0.79.0 <0.
|
|
44664
|
+
var piCodingAgentVersionRange = ">=0.79.0 <1.0.0";
|
|
44060
44665
|
var piCodingAgentConfigs = [
|
|
44061
44666
|
{
|
|
44062
44667
|
channelName: piCodingAgentChannels.prompt.channelName,
|