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
|
@@ -3963,6 +3963,7 @@ var ProjectSettings = import_v36.z.union([
|
|
|
3963
3963
|
]),
|
|
3964
3964
|
disable_realtime_queries: import_v36.z.union([import_v36.z.boolean(), import_v36.z.null()]),
|
|
3965
3965
|
monitor_charts_use_metrics_start: import_v36.z.union([import_v36.z.boolean(), import_v36.z.null()]),
|
|
3966
|
+
blind_reviews: import_v36.z.union([import_v36.z.boolean(), import_v36.z.null()]),
|
|
3966
3967
|
default_preprocessor: NullableSavedFunctionId
|
|
3967
3968
|
}).partial(),
|
|
3968
3969
|
import_v36.z.null()
|
|
@@ -4024,6 +4025,7 @@ var WindowedAutomationConfig = import_v36.z.object({
|
|
|
4024
4025
|
auto_approve_tools: import_v36.z.array(import_v36.z.string().min(1)).optional().default([]),
|
|
4025
4026
|
harness: import_v36.z.enum(["native", "codex", "claude-code"]).optional(),
|
|
4026
4027
|
model: import_v36.z.string().min(1).optional(),
|
|
4028
|
+
endpoint_name: import_v36.z.string().min(1).optional(),
|
|
4027
4029
|
reasoning_effort: import_v36.z.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional()
|
|
4028
4030
|
}).optional(),
|
|
4029
4031
|
actions: import_v36.z.array(
|
|
@@ -5815,7 +5817,7 @@ var INSTRUMENTATION_NAMES = {
|
|
|
5815
5817
|
var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
|
|
5816
5818
|
"braintrust.spanInstrumentationName"
|
|
5817
5819
|
);
|
|
5818
|
-
var SDK_VERSION = true ? "3.
|
|
5820
|
+
var SDK_VERSION = true ? "3.31.0" : "0.0.0";
|
|
5819
5821
|
function withSpanInstrumentationName(args, instrumentationName) {
|
|
5820
5822
|
return {
|
|
5821
5823
|
...args,
|
|
@@ -8531,6 +8533,9 @@ function getSpanParentObjectAndPropagatedState(options) {
|
|
|
8531
8533
|
}
|
|
8532
8534
|
return { parentObject: NOOP_SPAN, propagatedState: void 0 };
|
|
8533
8535
|
}
|
|
8536
|
+
function getSpanParentObject(options) {
|
|
8537
|
+
return getSpanParentObjectAndPropagatedState(options).parentObject;
|
|
8538
|
+
}
|
|
8534
8539
|
function currentBraintrustParent(state) {
|
|
8535
8540
|
const resolvedState = state ?? _globalState;
|
|
8536
8541
|
const experiment = currentExperiment({ state: resolvedState });
|
|
@@ -8777,6 +8782,15 @@ function _internalStartSpanWithInitialMerge(args) {
|
|
|
8777
8782
|
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
8778
8783
|
}).span;
|
|
8779
8784
|
}
|
|
8785
|
+
function _internalStartSpanWithInitialMergeAndParentSpanIds(args) {
|
|
8786
|
+
return startSpanAndIsLogger(
|
|
8787
|
+
{
|
|
8788
|
+
...args,
|
|
8789
|
+
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
8790
|
+
},
|
|
8791
|
+
{ useParentSpanIdsForObjectParent: true }
|
|
8792
|
+
).span;
|
|
8793
|
+
}
|
|
8780
8794
|
function _internalStartSpanWithContext(args, context) {
|
|
8781
8795
|
return startSpanAndIsLogger({
|
|
8782
8796
|
...args,
|
|
@@ -8787,7 +8801,7 @@ async function flush(options) {
|
|
|
8787
8801
|
const state = options?.state ?? _globalState;
|
|
8788
8802
|
return await state.bgLogger().flush();
|
|
8789
8803
|
}
|
|
8790
|
-
function startSpanAndIsLogger(args) {
|
|
8804
|
+
function startSpanAndIsLogger(args, internalOptions) {
|
|
8791
8805
|
const state = args?.state ?? _globalState;
|
|
8792
8806
|
const { parentObject, propagatedState } = getSpanParentObjectAndPropagatedState({
|
|
8793
8807
|
asyncFlush: args?.asyncFlush,
|
|
@@ -8801,7 +8815,7 @@ function startSpanAndIsLogger(args) {
|
|
|
8801
8815
|
) ? {
|
|
8802
8816
|
spanId: parentObject.data.span_id,
|
|
8803
8817
|
rootSpanId: parentObject.data.root_span_id
|
|
8804
|
-
} : void 0;
|
|
8818
|
+
} : internalOptions?.useParentSpanIdsForObjectParent ? args?.parentSpanIds : void 0;
|
|
8805
8819
|
const { parent: _ignoredParent, ...spanArgs } = args ?? {};
|
|
8806
8820
|
const span = new SpanImpl({
|
|
8807
8821
|
state,
|
|
@@ -11831,6 +11845,131 @@ function unsubscribeAll(unsubscribers) {
|
|
|
11831
11845
|
return [];
|
|
11832
11846
|
}
|
|
11833
11847
|
|
|
11848
|
+
// src/instrumentation/core/channel-definitions.ts
|
|
11849
|
+
function channel(spec) {
|
|
11850
|
+
return spec;
|
|
11851
|
+
}
|
|
11852
|
+
function defineChannels(pkg, channels, options) {
|
|
11853
|
+
const { instrumentationName } = options;
|
|
11854
|
+
return Object.fromEntries(
|
|
11855
|
+
Object.entries(channels).map(([key, spec]) => {
|
|
11856
|
+
const fullChannelName = `orchestrion:${pkg}:${spec.channelName}`;
|
|
11857
|
+
if (spec.kind === "async") {
|
|
11858
|
+
const asyncSpec = spec;
|
|
11859
|
+
const tracingChannel2 = () => isomorph_default.newTracingChannel(
|
|
11860
|
+
fullChannelName
|
|
11861
|
+
);
|
|
11862
|
+
const intercept2 = (interceptor) => {
|
|
11863
|
+
const hook = tracingChannel2();
|
|
11864
|
+
return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
|
|
11865
|
+
};
|
|
11866
|
+
};
|
|
11867
|
+
return [
|
|
11868
|
+
key,
|
|
11869
|
+
{
|
|
11870
|
+
...asyncSpec,
|
|
11871
|
+
instrumentationName,
|
|
11872
|
+
intercept: intercept2,
|
|
11873
|
+
invoke: (target, thisArg, args, additional) => {
|
|
11874
|
+
const hook = tracingChannel2();
|
|
11875
|
+
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
11876
|
+
},
|
|
11877
|
+
tracingChannel: tracingChannel2,
|
|
11878
|
+
tracePromise: (fn, context) => tracingChannel2().tracePromise(
|
|
11879
|
+
fn,
|
|
11880
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
11881
|
+
context
|
|
11882
|
+
)
|
|
11883
|
+
}
|
|
11884
|
+
];
|
|
11885
|
+
}
|
|
11886
|
+
const syncSpec = spec;
|
|
11887
|
+
const tracingChannel = () => isomorph_default.newTracingChannel(
|
|
11888
|
+
fullChannelName
|
|
11889
|
+
);
|
|
11890
|
+
const intercept = (interceptor) => {
|
|
11891
|
+
const hook = tracingChannel();
|
|
11892
|
+
return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
|
|
11893
|
+
};
|
|
11894
|
+
};
|
|
11895
|
+
return [
|
|
11896
|
+
key,
|
|
11897
|
+
{
|
|
11898
|
+
...syncSpec,
|
|
11899
|
+
instrumentationName,
|
|
11900
|
+
intercept,
|
|
11901
|
+
invoke: (target, thisArg, args, additional) => {
|
|
11902
|
+
const hook = tracingChannel();
|
|
11903
|
+
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
11904
|
+
},
|
|
11905
|
+
tracingChannel,
|
|
11906
|
+
traceSync: (fn, context) => tracingChannel().traceSync(
|
|
11907
|
+
fn,
|
|
11908
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
11909
|
+
context
|
|
11910
|
+
)
|
|
11911
|
+
}
|
|
11912
|
+
];
|
|
11913
|
+
})
|
|
11914
|
+
);
|
|
11915
|
+
}
|
|
11916
|
+
|
|
11917
|
+
// src/instrumentation/plugins/openai-channels.ts
|
|
11918
|
+
var openAIChannels = defineChannels(
|
|
11919
|
+
"openai",
|
|
11920
|
+
{
|
|
11921
|
+
filesCreateTraced: channel({
|
|
11922
|
+
channelName: "files.create-traced",
|
|
11923
|
+
kind: "async"
|
|
11924
|
+
}),
|
|
11925
|
+
batchesRetrieveTraced: channel({
|
|
11926
|
+
channelName: "batches.retrieve-traced",
|
|
11927
|
+
kind: "async"
|
|
11928
|
+
}),
|
|
11929
|
+
batchesCompleteTrace: channel({
|
|
11930
|
+
channelName: "batches.complete-trace",
|
|
11931
|
+
kind: "async"
|
|
11932
|
+
}),
|
|
11933
|
+
chatCompletionsCreate: channel({
|
|
11934
|
+
channelName: "chat.completions.create",
|
|
11935
|
+
kind: "async"
|
|
11936
|
+
}),
|
|
11937
|
+
embeddingsCreate: channel({
|
|
11938
|
+
channelName: "embeddings.create",
|
|
11939
|
+
kind: "async"
|
|
11940
|
+
}),
|
|
11941
|
+
betaChatCompletionsParse: channel({
|
|
11942
|
+
channelName: "beta.chat.completions.parse",
|
|
11943
|
+
kind: "async"
|
|
11944
|
+
}),
|
|
11945
|
+
betaChatCompletionsStream: channel({
|
|
11946
|
+
channelName: "beta.chat.completions.stream",
|
|
11947
|
+
kind: "sync-stream"
|
|
11948
|
+
}),
|
|
11949
|
+
moderationsCreate: channel({
|
|
11950
|
+
channelName: "moderations.create",
|
|
11951
|
+
kind: "async"
|
|
11952
|
+
}),
|
|
11953
|
+
responsesCreate: channel({
|
|
11954
|
+
channelName: "responses.create",
|
|
11955
|
+
kind: "async"
|
|
11956
|
+
}),
|
|
11957
|
+
responsesStream: channel({
|
|
11958
|
+
channelName: "responses.stream",
|
|
11959
|
+
kind: "sync-stream"
|
|
11960
|
+
}),
|
|
11961
|
+
responsesParse: channel({
|
|
11962
|
+
channelName: "responses.parse",
|
|
11963
|
+
kind: "async"
|
|
11964
|
+
}),
|
|
11965
|
+
responsesCompact: channel({
|
|
11966
|
+
channelName: "responses.compact",
|
|
11967
|
+
kind: "async"
|
|
11968
|
+
})
|
|
11969
|
+
},
|
|
11970
|
+
{ instrumentationName: INSTRUMENTATION_NAMES.OPENAI }
|
|
11971
|
+
);
|
|
11972
|
+
|
|
11834
11973
|
// src/wrappers/attachment-utils.ts
|
|
11835
11974
|
function getExtensionFromMediaType(mediaType) {
|
|
11836
11975
|
const extensionMap = {
|
|
@@ -12006,118 +12145,91 @@ function processInputAttachments(input) {
|
|
|
12006
12145
|
return processNode(input);
|
|
12007
12146
|
}
|
|
12008
12147
|
|
|
12009
|
-
// src/instrumentation/
|
|
12010
|
-
|
|
12011
|
-
|
|
12012
|
-
|
|
12013
|
-
|
|
12014
|
-
|
|
12015
|
-
|
|
12016
|
-
|
|
12017
|
-
|
|
12018
|
-
|
|
12019
|
-
|
|
12020
|
-
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
|
|
12024
|
-
|
|
12025
|
-
|
|
12026
|
-
|
|
12027
|
-
|
|
12028
|
-
|
|
12029
|
-
|
|
12030
|
-
|
|
12031
|
-
...asyncSpec,
|
|
12032
|
-
instrumentationName,
|
|
12033
|
-
intercept: intercept2,
|
|
12034
|
-
invoke: (target, thisArg, args, additional) => {
|
|
12035
|
-
const hook = tracingChannel2();
|
|
12036
|
-
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
12037
|
-
},
|
|
12038
|
-
tracingChannel: tracingChannel2,
|
|
12039
|
-
tracePromise: (fn, context) => tracingChannel2().tracePromise(
|
|
12040
|
-
fn,
|
|
12041
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
12042
|
-
context
|
|
12043
|
-
)
|
|
12044
|
-
}
|
|
12045
|
-
];
|
|
12148
|
+
// src/instrumentation/plugins/openai-span-data.ts
|
|
12149
|
+
var OPENAI_METADATA_KEYS = [
|
|
12150
|
+
"model",
|
|
12151
|
+
"temperature",
|
|
12152
|
+
"top_p",
|
|
12153
|
+
"max_tokens",
|
|
12154
|
+
"frequency_penalty",
|
|
12155
|
+
"presence_penalty",
|
|
12156
|
+
"stop",
|
|
12157
|
+
"response_format",
|
|
12158
|
+
"tools",
|
|
12159
|
+
"tool_choice",
|
|
12160
|
+
"parallel_tool_calls",
|
|
12161
|
+
"max_tool_calls"
|
|
12162
|
+
];
|
|
12163
|
+
function batchMetadata(params) {
|
|
12164
|
+
const metadata = { provider: "openai" };
|
|
12165
|
+
for (const key of OPENAI_METADATA_KEYS) {
|
|
12166
|
+
try {
|
|
12167
|
+
const value = Reflect.get(params, key);
|
|
12168
|
+
if (value !== void 0) {
|
|
12169
|
+
metadata[key] = value;
|
|
12046
12170
|
}
|
|
12047
|
-
|
|
12048
|
-
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
|
|
12052
|
-
|
|
12053
|
-
|
|
12054
|
-
|
|
12055
|
-
|
|
12056
|
-
|
|
12057
|
-
|
|
12058
|
-
|
|
12059
|
-
|
|
12060
|
-
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
|
|
12064
|
-
|
|
12065
|
-
|
|
12066
|
-
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
|
|
12070
|
-
|
|
12071
|
-
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
|
|
12171
|
+
} catch {
|
|
12172
|
+
}
|
|
12173
|
+
}
|
|
12174
|
+
return metadata;
|
|
12175
|
+
}
|
|
12176
|
+
function extractOpenAIBatchInput(endpoint, params) {
|
|
12177
|
+
const input = endpoint === "/v1/chat/completions" ? params.messages : params.input;
|
|
12178
|
+
return {
|
|
12179
|
+
input: processInputAttachments(input),
|
|
12180
|
+
metadata: batchMetadata(params)
|
|
12181
|
+
};
|
|
12182
|
+
}
|
|
12183
|
+
function extractOpenAIChatInput(params) {
|
|
12184
|
+
const { messages, ...metadata } = params;
|
|
12185
|
+
return {
|
|
12186
|
+
input: processInputAttachments(messages),
|
|
12187
|
+
metadata: { ...metadata, provider: "openai" }
|
|
12188
|
+
};
|
|
12189
|
+
}
|
|
12190
|
+
function extractOpenAIResponsesInput(params) {
|
|
12191
|
+
const { input, ...metadata } = params;
|
|
12192
|
+
return {
|
|
12193
|
+
input: processInputAttachments(input),
|
|
12194
|
+
metadata: { ...metadata, provider: "openai" }
|
|
12195
|
+
};
|
|
12196
|
+
}
|
|
12197
|
+
function extractOpenAIResponsesMetadata(result) {
|
|
12198
|
+
if (!result) {
|
|
12199
|
+
return void 0;
|
|
12200
|
+
}
|
|
12201
|
+
const { output: _output, usage: _usage, ...metadata } = result;
|
|
12202
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
12203
|
+
}
|
|
12204
|
+
function processImagesInOutput(output) {
|
|
12205
|
+
if (Array.isArray(output)) {
|
|
12206
|
+
return output.map(processImagesInOutput);
|
|
12207
|
+
}
|
|
12208
|
+
if (isObject(output) && output.type === "image_generation_call" && typeof output.result === "string" && output.result) {
|
|
12209
|
+
const fileExtension = output.output_format || "png";
|
|
12210
|
+
const contentType = `image/${fileExtension}`;
|
|
12211
|
+
const baseFilename = typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
12212
|
+
let binaryString;
|
|
12213
|
+
try {
|
|
12214
|
+
binaryString = atob(output.result);
|
|
12215
|
+
} catch {
|
|
12216
|
+
return output;
|
|
12217
|
+
}
|
|
12218
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
12219
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
12220
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
12221
|
+
}
|
|
12222
|
+
return {
|
|
12223
|
+
...output,
|
|
12224
|
+
result: new Attachment({
|
|
12225
|
+
data: new Blob([bytes], { type: contentType }),
|
|
12226
|
+
filename: `${baseFilename}.${fileExtension}`,
|
|
12227
|
+
contentType
|
|
12228
|
+
})
|
|
12229
|
+
};
|
|
12230
|
+
}
|
|
12231
|
+
return output;
|
|
12076
12232
|
}
|
|
12077
|
-
|
|
12078
|
-
// src/instrumentation/plugins/openai-channels.ts
|
|
12079
|
-
var openAIChannels = defineChannels(
|
|
12080
|
-
"openai",
|
|
12081
|
-
{
|
|
12082
|
-
chatCompletionsCreate: channel({
|
|
12083
|
-
channelName: "chat.completions.create",
|
|
12084
|
-
kind: "async"
|
|
12085
|
-
}),
|
|
12086
|
-
embeddingsCreate: channel({
|
|
12087
|
-
channelName: "embeddings.create",
|
|
12088
|
-
kind: "async"
|
|
12089
|
-
}),
|
|
12090
|
-
betaChatCompletionsParse: channel({
|
|
12091
|
-
channelName: "beta.chat.completions.parse",
|
|
12092
|
-
kind: "async"
|
|
12093
|
-
}),
|
|
12094
|
-
betaChatCompletionsStream: channel({
|
|
12095
|
-
channelName: "beta.chat.completions.stream",
|
|
12096
|
-
kind: "sync-stream"
|
|
12097
|
-
}),
|
|
12098
|
-
moderationsCreate: channel({
|
|
12099
|
-
channelName: "moderations.create",
|
|
12100
|
-
kind: "async"
|
|
12101
|
-
}),
|
|
12102
|
-
responsesCreate: channel({
|
|
12103
|
-
channelName: "responses.create",
|
|
12104
|
-
kind: "async"
|
|
12105
|
-
}),
|
|
12106
|
-
responsesStream: channel({
|
|
12107
|
-
channelName: "responses.stream",
|
|
12108
|
-
kind: "sync-stream"
|
|
12109
|
-
}),
|
|
12110
|
-
responsesParse: channel({
|
|
12111
|
-
channelName: "responses.parse",
|
|
12112
|
-
kind: "async"
|
|
12113
|
-
}),
|
|
12114
|
-
responsesCompact: channel({
|
|
12115
|
-
channelName: "responses.compact",
|
|
12116
|
-
kind: "async"
|
|
12117
|
-
})
|
|
12118
|
-
},
|
|
12119
|
-
{ instrumentationName: INSTRUMENTATION_NAMES.OPENAI }
|
|
12120
|
-
);
|
|
12121
12233
|
|
|
12122
12234
|
// src/openai-utils.ts
|
|
12123
12235
|
var BRAINTRUST_CACHED_STREAM_METRIC = "__braintrust_cached_metric";
|
|
@@ -12174,23 +12286,573 @@ function getCachedMetricFromHeaders(headers) {
|
|
|
12174
12286
|
return parseCachedHeader(headers.get(LEGACY_CACHED_HEADER));
|
|
12175
12287
|
}
|
|
12176
12288
|
|
|
12289
|
+
// src/instrumentation/plugins/openai-batch-instrumentation.ts
|
|
12290
|
+
var SUPPORTED_ENDPOINTS = /* @__PURE__ */ new Set(["/v1/chat/completions", "/v1/responses"]);
|
|
12291
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
12292
|
+
"completed",
|
|
12293
|
+
"failed",
|
|
12294
|
+
"expired",
|
|
12295
|
+
"cancelled"
|
|
12296
|
+
]);
|
|
12297
|
+
var pendingBatchTraces = /* @__PURE__ */ new Map();
|
|
12298
|
+
function read(value, key) {
|
|
12299
|
+
if (!isObject(value)) {
|
|
12300
|
+
return void 0;
|
|
12301
|
+
}
|
|
12302
|
+
try {
|
|
12303
|
+
return Reflect.get(value, key);
|
|
12304
|
+
} catch {
|
|
12305
|
+
return void 0;
|
|
12306
|
+
}
|
|
12307
|
+
}
|
|
12308
|
+
function isBatchRecordIterable(value) {
|
|
12309
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") {
|
|
12310
|
+
return false;
|
|
12311
|
+
}
|
|
12312
|
+
return typeof read(value, Symbol.iterator) === "function" || typeof read(value, Symbol.asyncIterator) === "function";
|
|
12313
|
+
}
|
|
12314
|
+
function validCustomId(value) {
|
|
12315
|
+
return typeof value === "string" && value.length > 0 && value.length <= 64;
|
|
12316
|
+
}
|
|
12317
|
+
function logBatchInstrumentationError(context, error) {
|
|
12318
|
+
debugLogger.debug(`OpenAI Batch instrumentation ${context}:`, error);
|
|
12319
|
+
}
|
|
12320
|
+
async function exportParent(parent) {
|
|
12321
|
+
if ("toStr" in parent && typeof parent.toStr === "function") {
|
|
12322
|
+
return parent.toStr();
|
|
12323
|
+
}
|
|
12324
|
+
if ("export" in parent && typeof parent.export === "function") {
|
|
12325
|
+
return await parent.export();
|
|
12326
|
+
}
|
|
12327
|
+
return void 0;
|
|
12328
|
+
}
|
|
12329
|
+
async function deterministicDigest(namespace, ...parts) {
|
|
12330
|
+
const encoded = new TextEncoder().encode(
|
|
12331
|
+
[namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
|
|
12332
|
+
);
|
|
12333
|
+
return new Uint8Array(
|
|
12334
|
+
await globalThis.crypto.subtle.digest("SHA-256", encoded)
|
|
12335
|
+
);
|
|
12336
|
+
}
|
|
12337
|
+
function digestHex(bytes, length) {
|
|
12338
|
+
return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
12339
|
+
}
|
|
12340
|
+
function digestUuid(bytes) {
|
|
12341
|
+
const hex = digestHex(bytes, 16);
|
|
12342
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
12343
|
+
}
|
|
12344
|
+
async function batchSpanIds(inputFileId) {
|
|
12345
|
+
const [row, span, root] = await Promise.all([
|
|
12346
|
+
deterministicDigest("openai:batch:row", inputFileId),
|
|
12347
|
+
deterministicDigest("openai:batch:span", inputFileId),
|
|
12348
|
+
deterministicDigest("openai:batch:root", inputFileId)
|
|
12349
|
+
]);
|
|
12350
|
+
return {
|
|
12351
|
+
rowId: digestUuid(row),
|
|
12352
|
+
spanId: digestHex(span, 8),
|
|
12353
|
+
rootSpanId: digestHex(root, 16)
|
|
12354
|
+
};
|
|
12355
|
+
}
|
|
12356
|
+
async function childSpanIds(inputFileId, customId) {
|
|
12357
|
+
const [row, span] = await Promise.all([
|
|
12358
|
+
deterministicDigest("openai:batch:child:row", inputFileId, customId),
|
|
12359
|
+
deterministicDigest("openai:batch:child:span", inputFileId, customId)
|
|
12360
|
+
]);
|
|
12361
|
+
return { rowId: digestUuid(row), spanId: digestHex(span, 8) };
|
|
12362
|
+
}
|
|
12363
|
+
async function startBatchSpan(context) {
|
|
12364
|
+
const ids = await batchSpanIds(context.inputFileId);
|
|
12365
|
+
const parent = SpanComponentsV4.fromStr(context.parent);
|
|
12366
|
+
const hasParentSpan = Boolean(
|
|
12367
|
+
parent.data.row_id && parent.data.span_id && parent.data.root_span_id
|
|
12368
|
+
);
|
|
12369
|
+
return withCurrent(
|
|
12370
|
+
NOOP_SPAN,
|
|
12371
|
+
() => _internalStartSpanWithInitialMergeAndParentSpanIds(
|
|
12372
|
+
withSpanInstrumentationName(
|
|
12373
|
+
{
|
|
12374
|
+
name: "openai.batch",
|
|
12375
|
+
type: "task" /* TASK */,
|
|
12376
|
+
parent: context.parent,
|
|
12377
|
+
...!hasParentSpan ? {
|
|
12378
|
+
parentSpanIds: {
|
|
12379
|
+
parentSpanIds: [],
|
|
12380
|
+
rootSpanId: ids.rootSpanId
|
|
12381
|
+
}
|
|
12382
|
+
} : {},
|
|
12383
|
+
spanId: ids.spanId,
|
|
12384
|
+
startTime: context.taskStartTime,
|
|
12385
|
+
event: {
|
|
12386
|
+
id: ids.rowId,
|
|
12387
|
+
metadata: {
|
|
12388
|
+
endpoint: context.endpoint,
|
|
12389
|
+
input_file_id: context.inputFileId,
|
|
12390
|
+
provider: "openai"
|
|
12391
|
+
}
|
|
12392
|
+
}
|
|
12393
|
+
},
|
|
12394
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
12395
|
+
)
|
|
12396
|
+
)
|
|
12397
|
+
);
|
|
12398
|
+
}
|
|
12399
|
+
async function startBatchChild(context, taskParent, input) {
|
|
12400
|
+
const ids = await childSpanIds(context.inputFileId, input.customId);
|
|
12401
|
+
return withCurrent(
|
|
12402
|
+
NOOP_SPAN,
|
|
12403
|
+
() => _internalStartSpanWithInitialMerge(
|
|
12404
|
+
withSpanInstrumentationName(
|
|
12405
|
+
{
|
|
12406
|
+
name: context.endpoint === "/v1/chat/completions" ? "Chat Completion" : "openai.responses.create",
|
|
12407
|
+
type: "llm" /* LLM */,
|
|
12408
|
+
parent: taskParent,
|
|
12409
|
+
spanId: ids.spanId,
|
|
12410
|
+
startTime: context.childStartTime,
|
|
12411
|
+
event: {
|
|
12412
|
+
id: ids.rowId,
|
|
12413
|
+
...input.spanData?.input !== void 0 ? { input: input.spanData.input } : {},
|
|
12414
|
+
metadata: {
|
|
12415
|
+
...input.spanData?.metadata,
|
|
12416
|
+
custom_id: input.customId,
|
|
12417
|
+
provider: "openai"
|
|
12418
|
+
}
|
|
12419
|
+
}
|
|
12420
|
+
},
|
|
12421
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
12422
|
+
)
|
|
12423
|
+
)
|
|
12424
|
+
);
|
|
12425
|
+
}
|
|
12426
|
+
async function* jsonlRecords(file, onIssue = () => {
|
|
12427
|
+
}) {
|
|
12428
|
+
const resolvedFile = await file;
|
|
12429
|
+
if (typeof resolvedFile === "string") {
|
|
12430
|
+
for (const line of resolvedFile.split("\n")) {
|
|
12431
|
+
if (!line.trim()) {
|
|
12432
|
+
continue;
|
|
12433
|
+
}
|
|
12434
|
+
try {
|
|
12435
|
+
yield JSON.parse(line.replace(/\r$/, ""));
|
|
12436
|
+
} catch (error) {
|
|
12437
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
12438
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
12439
|
+
}
|
|
12440
|
+
}
|
|
12441
|
+
return;
|
|
12442
|
+
}
|
|
12443
|
+
const body = read(resolvedFile, "body");
|
|
12444
|
+
const getReader = read(body, "getReader");
|
|
12445
|
+
if (isObject(body) && typeof getReader === "function") {
|
|
12446
|
+
let reader;
|
|
12447
|
+
try {
|
|
12448
|
+
reader = Reflect.apply(getReader, body, []);
|
|
12449
|
+
const decoder = new TextDecoder();
|
|
12450
|
+
let pending = "";
|
|
12451
|
+
while (true) {
|
|
12452
|
+
const readChunk = read(reader, "read");
|
|
12453
|
+
if (typeof readChunk !== "function") {
|
|
12454
|
+
throw new Error("Response body stream has no read method");
|
|
12455
|
+
}
|
|
12456
|
+
const chunk = await Reflect.apply(readChunk, reader, []);
|
|
12457
|
+
if (!isObject(chunk)) {
|
|
12458
|
+
throw new Error("Response body stream returned an invalid chunk");
|
|
12459
|
+
}
|
|
12460
|
+
if (chunk.done === true) {
|
|
12461
|
+
pending += decoder.decode();
|
|
12462
|
+
break;
|
|
12463
|
+
}
|
|
12464
|
+
if (!(chunk.value instanceof Uint8Array)) {
|
|
12465
|
+
throw new Error("Response body stream returned a non-byte chunk");
|
|
12466
|
+
}
|
|
12467
|
+
pending += decoder.decode(chunk.value, { stream: true });
|
|
12468
|
+
let newline = pending.indexOf("\n");
|
|
12469
|
+
while (newline !== -1) {
|
|
12470
|
+
const line = pending.slice(0, newline).replace(/\r$/, "");
|
|
12471
|
+
pending = pending.slice(newline + 1);
|
|
12472
|
+
if (line.trim()) {
|
|
12473
|
+
try {
|
|
12474
|
+
yield JSON.parse(line);
|
|
12475
|
+
} catch (error) {
|
|
12476
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
12477
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
12478
|
+
}
|
|
12479
|
+
}
|
|
12480
|
+
newline = pending.indexOf("\n");
|
|
12481
|
+
}
|
|
12482
|
+
}
|
|
12483
|
+
if (pending.trim()) {
|
|
12484
|
+
try {
|
|
12485
|
+
yield JSON.parse(pending.replace(/\r$/, ""));
|
|
12486
|
+
} catch (error) {
|
|
12487
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
12488
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
12489
|
+
}
|
|
12490
|
+
}
|
|
12491
|
+
} catch (error) {
|
|
12492
|
+
logBatchInstrumentationError("could not read JSONL response body", error);
|
|
12493
|
+
onIssue(new Error("OpenAI Batch response body could not be read"));
|
|
12494
|
+
} finally {
|
|
12495
|
+
const releaseLock = read(reader, "releaseLock");
|
|
12496
|
+
if (typeof releaseLock === "function") {
|
|
12497
|
+
try {
|
|
12498
|
+
Reflect.apply(releaseLock, reader, []);
|
|
12499
|
+
} catch (error) {
|
|
12500
|
+
logBatchInstrumentationError(
|
|
12501
|
+
"could not release stream reader",
|
|
12502
|
+
error
|
|
12503
|
+
);
|
|
12504
|
+
}
|
|
12505
|
+
}
|
|
12506
|
+
}
|
|
12507
|
+
return;
|
|
12508
|
+
}
|
|
12509
|
+
if (isBatchRecordIterable(resolvedFile)) {
|
|
12510
|
+
for await (const record of resolvedFile) {
|
|
12511
|
+
yield record;
|
|
12512
|
+
}
|
|
12513
|
+
return;
|
|
12514
|
+
}
|
|
12515
|
+
logBatchInstrumentationError("skipped invalid JSONL source", resolvedFile);
|
|
12516
|
+
onIssue(new Error("OpenAI Batch file source is invalid"));
|
|
12517
|
+
}
|
|
12518
|
+
async function readBatchInputs(file) {
|
|
12519
|
+
const inputs = /* @__PURE__ */ new Map();
|
|
12520
|
+
const issues = [];
|
|
12521
|
+
let endpoint;
|
|
12522
|
+
try {
|
|
12523
|
+
for await (const value of jsonlRecords(
|
|
12524
|
+
file,
|
|
12525
|
+
(issue) => issues.push(issue)
|
|
12526
|
+
)) {
|
|
12527
|
+
const customId = read(value, "custom_id");
|
|
12528
|
+
const url = read(value, "url");
|
|
12529
|
+
const body = read(value, "body");
|
|
12530
|
+
if (!validCustomId(customId) || inputs.has(customId) || read(value, "method") !== "POST" || typeof url !== "string" || !SUPPORTED_ENDPOINTS.has(url) || endpoint !== void 0 && endpoint !== url || !isObject(body)) {
|
|
12531
|
+
issues.push(new Error("OpenAI Batch input contains an invalid record"));
|
|
12532
|
+
continue;
|
|
12533
|
+
}
|
|
12534
|
+
endpoint = url;
|
|
12535
|
+
let spanData;
|
|
12536
|
+
try {
|
|
12537
|
+
spanData = extractOpenAIBatchInput(url, body);
|
|
12538
|
+
} catch (error) {
|
|
12539
|
+
logBatchInstrumentationError("could not extract batch input", error);
|
|
12540
|
+
}
|
|
12541
|
+
inputs.set(customId, { customId, spanData });
|
|
12542
|
+
}
|
|
12543
|
+
} catch (error) {
|
|
12544
|
+
logBatchInstrumentationError("could not process input file", error);
|
|
12545
|
+
issues.push(new Error("OpenAI Batch input file could not be processed"));
|
|
12546
|
+
}
|
|
12547
|
+
if (!endpoint || inputs.size === 0) {
|
|
12548
|
+
issues.push(new Error("OpenAI Batch input contains no supported records"));
|
|
12549
|
+
}
|
|
12550
|
+
return { endpoint, inputs, issues };
|
|
12551
|
+
}
|
|
12552
|
+
async function writePendingSpans(trace, endTime) {
|
|
12553
|
+
const task = await startBatchSpan(trace.context);
|
|
12554
|
+
const taskParent = await task.export();
|
|
12555
|
+
for (const input of trace.inputs.values()) {
|
|
12556
|
+
try {
|
|
12557
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
12558
|
+
if (endTime !== void 0) {
|
|
12559
|
+
child.end({ endTime });
|
|
12560
|
+
}
|
|
12561
|
+
} catch (error) {
|
|
12562
|
+
logBatchInstrumentationError("could not write batch request span", error);
|
|
12563
|
+
}
|
|
12564
|
+
}
|
|
12565
|
+
if (endTime !== void 0) {
|
|
12566
|
+
if (trace.status && trace.status !== "completed") {
|
|
12567
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
12568
|
+
}
|
|
12569
|
+
task.end({ endTime });
|
|
12570
|
+
}
|
|
12571
|
+
}
|
|
12572
|
+
var interceptOpenAIFilesCreateTraced = async (target, thisArg, args) => {
|
|
12573
|
+
const startTime = getCurrentUnixTimestamp();
|
|
12574
|
+
const inputPromise = readBatchInputs(args[0].inputFileContent);
|
|
12575
|
+
const parentPromise = exportParent(args[0].parent);
|
|
12576
|
+
const file = await Reflect.apply(target, thisArg, args);
|
|
12577
|
+
try {
|
|
12578
|
+
const inputFileId = read(file, "id");
|
|
12579
|
+
const [inputData, exportedParent2] = await Promise.all([
|
|
12580
|
+
inputPromise,
|
|
12581
|
+
parentPromise
|
|
12582
|
+
]);
|
|
12583
|
+
if (typeof inputFileId !== "string" || !exportedParent2 || !inputData.endpoint || inputData.issues.length > 0) {
|
|
12584
|
+
if (inputData.issues[0]) {
|
|
12585
|
+
logBatchInstrumentationError(
|
|
12586
|
+
"skipped invalid input file",
|
|
12587
|
+
inputData.issues[0]
|
|
12588
|
+
);
|
|
12589
|
+
}
|
|
12590
|
+
return file;
|
|
12591
|
+
}
|
|
12592
|
+
const trace = {
|
|
12593
|
+
context: {
|
|
12594
|
+
inputFileId,
|
|
12595
|
+
endpoint: inputData.endpoint,
|
|
12596
|
+
parent: exportedParent2,
|
|
12597
|
+
taskStartTime: startTime,
|
|
12598
|
+
childStartTime: startTime
|
|
12599
|
+
},
|
|
12600
|
+
inputs: inputData.inputs
|
|
12601
|
+
};
|
|
12602
|
+
pendingBatchTraces.set(inputFileId, trace);
|
|
12603
|
+
await writePendingSpans(trace);
|
|
12604
|
+
} catch (error) {
|
|
12605
|
+
logBatchInstrumentationError("could not start batch spans", error);
|
|
12606
|
+
}
|
|
12607
|
+
return file;
|
|
12608
|
+
};
|
|
12609
|
+
function validTimestamp(value) {
|
|
12610
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
12611
|
+
}
|
|
12612
|
+
function terminalEndTime(batch, startTime) {
|
|
12613
|
+
let timestamp;
|
|
12614
|
+
switch (batch.status) {
|
|
12615
|
+
case "completed":
|
|
12616
|
+
timestamp = batch.completed_at;
|
|
12617
|
+
break;
|
|
12618
|
+
case "failed":
|
|
12619
|
+
timestamp = batch.failed_at;
|
|
12620
|
+
break;
|
|
12621
|
+
case "expired":
|
|
12622
|
+
timestamp = batch.expired_at;
|
|
12623
|
+
break;
|
|
12624
|
+
default:
|
|
12625
|
+
timestamp = batch.cancelled_at;
|
|
12626
|
+
}
|
|
12627
|
+
return validTimestamp(timestamp) ? Math.max(timestamp, startTime) : Math.max(getCurrentUnixTimestamp(), startTime);
|
|
12628
|
+
}
|
|
12629
|
+
async function updateBatchTimestamps(batch) {
|
|
12630
|
+
const trace = pendingBatchTraces.get(batch.input_file_id);
|
|
12631
|
+
if (!trace || trace.context.endpoint !== batch.endpoint) {
|
|
12632
|
+
return;
|
|
12633
|
+
}
|
|
12634
|
+
if (validTimestamp(batch.created_at)) {
|
|
12635
|
+
trace.context.taskStartTime = batch.created_at;
|
|
12636
|
+
}
|
|
12637
|
+
trace.context.childStartTime = validTimestamp(batch.in_progress_at) ? Math.max(batch.in_progress_at, trace.context.taskStartTime) : trace.context.taskStartTime;
|
|
12638
|
+
trace.status = batch.status;
|
|
12639
|
+
if (TERMINAL_STATUSES.has(batch.status)) {
|
|
12640
|
+
trace.endTime = terminalEndTime(batch, trace.context.childStartTime);
|
|
12641
|
+
}
|
|
12642
|
+
await writePendingSpans(trace, trace.endTime);
|
|
12643
|
+
}
|
|
12644
|
+
var interceptOpenAIBatchesRetrieveTraced = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (batch) => {
|
|
12645
|
+
try {
|
|
12646
|
+
await updateBatchTimestamps(batch);
|
|
12647
|
+
} catch (error) {
|
|
12648
|
+
logBatchInstrumentationError("could not update batch timestamps", error);
|
|
12649
|
+
}
|
|
12650
|
+
return batch;
|
|
12651
|
+
});
|
|
12652
|
+
function errorFromResult(result) {
|
|
12653
|
+
const error = read(result.value, "error");
|
|
12654
|
+
if (isObject(error)) {
|
|
12655
|
+
const message = read(error, "message");
|
|
12656
|
+
return new Error(
|
|
12657
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
12658
|
+
);
|
|
12659
|
+
}
|
|
12660
|
+
const response = read(result.value, "response");
|
|
12661
|
+
const statusCode = read(response, "status_code");
|
|
12662
|
+
if (result.source === "error" || typeof statusCode === "number" && (statusCode < 200 || statusCode >= 300)) {
|
|
12663
|
+
const message = read(read(read(response, "body"), "error"), "message");
|
|
12664
|
+
return new Error(
|
|
12665
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
12666
|
+
);
|
|
12667
|
+
}
|
|
12668
|
+
return void 0;
|
|
12669
|
+
}
|
|
12670
|
+
async function completeBatchResult(context, taskParent, endTime, input, result) {
|
|
12671
|
+
const child = await startBatchChild(context, taskParent, input);
|
|
12672
|
+
try {
|
|
12673
|
+
const resultError = errorFromResult(result);
|
|
12674
|
+
const responseBody = read(read(result.value, "response"), "body");
|
|
12675
|
+
if (resultError) {
|
|
12676
|
+
child.log({ error: resultError });
|
|
12677
|
+
} else if (isObject(responseBody)) {
|
|
12678
|
+
const model = read(responseBody, "model");
|
|
12679
|
+
child.log({
|
|
12680
|
+
output: context.endpoint === "/v1/chat/completions" ? read(responseBody, "choices") : processImagesInOutput(read(responseBody, "output")),
|
|
12681
|
+
...typeof model === "string" ? { metadata: { model } } : {},
|
|
12682
|
+
metrics: parseMetricsFromUsage(read(responseBody, "usage"))
|
|
12683
|
+
});
|
|
12684
|
+
} else {
|
|
12685
|
+
child.log({ error: new Error("OpenAI Batch response body is missing") });
|
|
12686
|
+
}
|
|
12687
|
+
} catch (error) {
|
|
12688
|
+
child.log({ error });
|
|
12689
|
+
} finally {
|
|
12690
|
+
child.end({ endTime });
|
|
12691
|
+
}
|
|
12692
|
+
}
|
|
12693
|
+
async function completeResultFile({
|
|
12694
|
+
context,
|
|
12695
|
+
endTime,
|
|
12696
|
+
file,
|
|
12697
|
+
inputs,
|
|
12698
|
+
issues,
|
|
12699
|
+
seen,
|
|
12700
|
+
source,
|
|
12701
|
+
taskParent
|
|
12702
|
+
}) {
|
|
12703
|
+
if (file === void 0) {
|
|
12704
|
+
return;
|
|
12705
|
+
}
|
|
12706
|
+
for await (const value of jsonlRecords(file, (issue) => issues.push(issue))) {
|
|
12707
|
+
const customId = read(value, "custom_id");
|
|
12708
|
+
if (!validCustomId(customId) || !isObject(value)) {
|
|
12709
|
+
issues.push(
|
|
12710
|
+
new Error("OpenAI Batch result is missing a valid custom_id")
|
|
12711
|
+
);
|
|
12712
|
+
continue;
|
|
12713
|
+
}
|
|
12714
|
+
if (seen.has(customId)) {
|
|
12715
|
+
issues.push(new Error("OpenAI Batch result contains a duplicate"));
|
|
12716
|
+
continue;
|
|
12717
|
+
}
|
|
12718
|
+
const input = inputs.get(customId);
|
|
12719
|
+
if (!input) {
|
|
12720
|
+
issues.push(
|
|
12721
|
+
new Error("OpenAI Batch result does not match an input record")
|
|
12722
|
+
);
|
|
12723
|
+
continue;
|
|
12724
|
+
}
|
|
12725
|
+
seen.add(customId);
|
|
12726
|
+
await completeBatchResult(context, taskParent, endTime, input, {
|
|
12727
|
+
value,
|
|
12728
|
+
source
|
|
12729
|
+
});
|
|
12730
|
+
}
|
|
12731
|
+
}
|
|
12732
|
+
function sameInputs(first, second) {
|
|
12733
|
+
return first.size === second.size && [...first.keys()].every((customId) => second.has(customId));
|
|
12734
|
+
}
|
|
12735
|
+
async function contextForCompletion(inputFileId, inputData) {
|
|
12736
|
+
if (!inputData.endpoint || inputData.issues.length > 0) {
|
|
12737
|
+
return void 0;
|
|
12738
|
+
}
|
|
12739
|
+
const existing = pendingBatchTraces.get(inputFileId);
|
|
12740
|
+
if (existing) {
|
|
12741
|
+
if (existing.context.endpoint !== inputData.endpoint || !sameInputs(existing.inputs, inputData.inputs)) {
|
|
12742
|
+
return void 0;
|
|
12743
|
+
}
|
|
12744
|
+
return { ...existing, inputs: inputData.inputs };
|
|
12745
|
+
}
|
|
12746
|
+
const parent = await exportParent(getSpanParentObject());
|
|
12747
|
+
if (!parent) {
|
|
12748
|
+
return void 0;
|
|
12749
|
+
}
|
|
12750
|
+
const startTime = getCurrentUnixTimestamp();
|
|
12751
|
+
return {
|
|
12752
|
+
context: {
|
|
12753
|
+
inputFileId,
|
|
12754
|
+
endpoint: inputData.endpoint,
|
|
12755
|
+
parent,
|
|
12756
|
+
taskStartTime: startTime,
|
|
12757
|
+
childStartTime: startTime
|
|
12758
|
+
},
|
|
12759
|
+
inputs: inputData.inputs
|
|
12760
|
+
};
|
|
12761
|
+
}
|
|
12762
|
+
async function completeBatch(args) {
|
|
12763
|
+
const inputData = await readBatchInputs(args.inputFileContent);
|
|
12764
|
+
const trace = await contextForCompletion(args.inputFileId, inputData);
|
|
12765
|
+
if (!trace) {
|
|
12766
|
+
logBatchInstrumentationError(
|
|
12767
|
+
"left batch spans pending",
|
|
12768
|
+
inputData.issues[0] ?? new Error("OpenAI Batch input does not match")
|
|
12769
|
+
);
|
|
12770
|
+
return;
|
|
12771
|
+
}
|
|
12772
|
+
const endTime = trace.endTime ?? getCurrentUnixTimestamp();
|
|
12773
|
+
const task = await startBatchSpan(trace.context);
|
|
12774
|
+
const taskParent = await task.export();
|
|
12775
|
+
const issues = [];
|
|
12776
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12777
|
+
await Promise.all([
|
|
12778
|
+
completeResultFile({
|
|
12779
|
+
context: trace.context,
|
|
12780
|
+
endTime,
|
|
12781
|
+
file: args.outputFileContent,
|
|
12782
|
+
inputs: trace.inputs,
|
|
12783
|
+
issues,
|
|
12784
|
+
seen,
|
|
12785
|
+
source: "output",
|
|
12786
|
+
taskParent
|
|
12787
|
+
}),
|
|
12788
|
+
completeResultFile({
|
|
12789
|
+
context: trace.context,
|
|
12790
|
+
endTime,
|
|
12791
|
+
file: args.errorFileContent,
|
|
12792
|
+
inputs: trace.inputs,
|
|
12793
|
+
issues,
|
|
12794
|
+
seen,
|
|
12795
|
+
source: "error",
|
|
12796
|
+
taskParent
|
|
12797
|
+
})
|
|
12798
|
+
]);
|
|
12799
|
+
if (issues.length > 0) {
|
|
12800
|
+
logBatchInstrumentationError("left batch spans pending", issues[0]);
|
|
12801
|
+
return;
|
|
12802
|
+
}
|
|
12803
|
+
const missing = [...trace.inputs.values()].filter(
|
|
12804
|
+
({ customId }) => !seen.has(customId)
|
|
12805
|
+
);
|
|
12806
|
+
if (!trace.status || trace.status === "completed") {
|
|
12807
|
+
if (missing.length > 0) {
|
|
12808
|
+
logBatchInstrumentationError(
|
|
12809
|
+
"left batch spans pending",
|
|
12810
|
+
new Error("OpenAI Batch result files are incomplete")
|
|
12811
|
+
);
|
|
12812
|
+
return;
|
|
12813
|
+
}
|
|
12814
|
+
} else {
|
|
12815
|
+
for (const input of missing) {
|
|
12816
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
12817
|
+
child.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
12818
|
+
child.end({ endTime });
|
|
12819
|
+
}
|
|
12820
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
12821
|
+
}
|
|
12822
|
+
task.end({ endTime });
|
|
12823
|
+
pendingBatchTraces.delete(args.inputFileId);
|
|
12824
|
+
}
|
|
12825
|
+
var interceptOpenAIBatchTraceComplete = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (result) => {
|
|
12826
|
+
try {
|
|
12827
|
+
await completeBatch(args[0]);
|
|
12828
|
+
} catch (error) {
|
|
12829
|
+
logBatchInstrumentationError("could not complete batch", error);
|
|
12830
|
+
}
|
|
12831
|
+
return result;
|
|
12832
|
+
});
|
|
12833
|
+
|
|
12177
12834
|
// src/instrumentation/plugins/openai-plugin.ts
|
|
12178
12835
|
var OpenAIPlugin = class extends BasePlugin {
|
|
12179
12836
|
constructor() {
|
|
12180
12837
|
super();
|
|
12181
12838
|
}
|
|
12182
12839
|
onEnable() {
|
|
12840
|
+
this.unsubscribers.push(
|
|
12841
|
+
openAIChannels.filesCreateTraced.intercept(
|
|
12842
|
+
interceptOpenAIFilesCreateTraced
|
|
12843
|
+
),
|
|
12844
|
+
openAIChannels.batchesRetrieveTraced.intercept(
|
|
12845
|
+
interceptOpenAIBatchesRetrieveTraced
|
|
12846
|
+
),
|
|
12847
|
+
openAIChannels.batchesCompleteTrace.intercept(
|
|
12848
|
+
interceptOpenAIBatchTraceComplete
|
|
12849
|
+
)
|
|
12850
|
+
);
|
|
12183
12851
|
this.unsubscribers.push(
|
|
12184
12852
|
traceStreamingChannel(openAIChannels.chatCompletionsCreate, {
|
|
12185
12853
|
name: "Chat Completion",
|
|
12186
12854
|
type: "llm" /* LLM */,
|
|
12187
|
-
extractInput: ([params]) =>
|
|
12188
|
-
const { messages, ...metadata } = params;
|
|
12189
|
-
return {
|
|
12190
|
-
input: processInputAttachments(messages),
|
|
12191
|
-
metadata: { ...metadata, provider: "openai" }
|
|
12192
|
-
};
|
|
12193
|
-
},
|
|
12855
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
12194
12856
|
extractOutput: (result) => {
|
|
12195
12857
|
return result?.choices;
|
|
12196
12858
|
},
|
|
@@ -12236,13 +12898,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
12236
12898
|
traceStreamingChannel(openAIChannels.betaChatCompletionsParse, {
|
|
12237
12899
|
name: "Chat Completion",
|
|
12238
12900
|
type: "llm" /* LLM */,
|
|
12239
|
-
extractInput: ([params]) =>
|
|
12240
|
-
const { messages, ...metadata } = params;
|
|
12241
|
-
return {
|
|
12242
|
-
input: processInputAttachments(messages),
|
|
12243
|
-
metadata: { ...metadata, provider: "openai" }
|
|
12244
|
-
};
|
|
12245
|
-
},
|
|
12901
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
12246
12902
|
extractOutput: (result) => {
|
|
12247
12903
|
return result?.choices;
|
|
12248
12904
|
},
|
|
@@ -12264,13 +12920,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
12264
12920
|
traceSyncStreamChannel(openAIChannels.betaChatCompletionsStream, {
|
|
12265
12921
|
name: "Chat Completion",
|
|
12266
12922
|
type: "llm" /* LLM */,
|
|
12267
|
-
extractInput: ([params]) =>
|
|
12268
|
-
const { messages, ...metadata } = params;
|
|
12269
|
-
return {
|
|
12270
|
-
input: processInputAttachments(messages),
|
|
12271
|
-
metadata: { ...metadata, provider: "openai" }
|
|
12272
|
-
};
|
|
12273
|
-
}
|
|
12923
|
+
extractInput: ([params]) => extractOpenAIChatInput(params)
|
|
12274
12924
|
})
|
|
12275
12925
|
);
|
|
12276
12926
|
this.unsubscribers.push(
|
|
@@ -12300,23 +12950,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
12300
12950
|
traceStreamingChannel(openAIChannels.responsesCreate, {
|
|
12301
12951
|
name: "openai.responses.create",
|
|
12302
12952
|
type: "llm" /* LLM */,
|
|
12303
|
-
extractInput: ([params]) =>
|
|
12304
|
-
const { input, ...metadata } = params;
|
|
12305
|
-
return {
|
|
12306
|
-
input: processInputAttachments(input),
|
|
12307
|
-
metadata: { ...metadata, provider: "openai" }
|
|
12308
|
-
};
|
|
12309
|
-
},
|
|
12953
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
12310
12954
|
extractOutput: (result) => {
|
|
12311
12955
|
return processImagesInOutput(result?.output);
|
|
12312
12956
|
},
|
|
12313
|
-
extractMetadata: (result) =>
|
|
12314
|
-
if (!result) {
|
|
12315
|
-
return void 0;
|
|
12316
|
-
}
|
|
12317
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
12318
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
12319
|
-
},
|
|
12957
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
12320
12958
|
extractMetrics: (result, startTime, endEvent) => {
|
|
12321
12959
|
const metrics = withCachedMetric(
|
|
12322
12960
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -12335,13 +12973,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
12335
12973
|
traceSyncStreamChannel(openAIChannels.responsesStream, {
|
|
12336
12974
|
name: "openai.responses.create",
|
|
12337
12975
|
type: "llm" /* LLM */,
|
|
12338
|
-
extractInput: ([params]) =>
|
|
12339
|
-
const { input, ...metadata } = params;
|
|
12340
|
-
return {
|
|
12341
|
-
input: processInputAttachments(input),
|
|
12342
|
-
metadata: { ...metadata, provider: "openai" }
|
|
12343
|
-
};
|
|
12344
|
-
},
|
|
12976
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
12345
12977
|
extractFromEvent: (event) => {
|
|
12346
12978
|
if (event.type !== "response.completed" || !event.response) {
|
|
12347
12979
|
return {};
|
|
@@ -12364,23 +12996,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
12364
12996
|
traceStreamingChannel(openAIChannels.responsesParse, {
|
|
12365
12997
|
name: "openai.responses.parse",
|
|
12366
12998
|
type: "llm" /* LLM */,
|
|
12367
|
-
extractInput: ([params]) =>
|
|
12368
|
-
const { input, ...metadata } = params;
|
|
12369
|
-
return {
|
|
12370
|
-
input: processInputAttachments(input),
|
|
12371
|
-
metadata: { ...metadata, provider: "openai" }
|
|
12372
|
-
};
|
|
12373
|
-
},
|
|
12999
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
12374
13000
|
extractOutput: (result) => {
|
|
12375
13001
|
return processImagesInOutput(result?.output);
|
|
12376
13002
|
},
|
|
12377
|
-
extractMetadata: (result) =>
|
|
12378
|
-
if (!result) {
|
|
12379
|
-
return void 0;
|
|
12380
|
-
}
|
|
12381
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
12382
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
12383
|
-
},
|
|
13003
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
12384
13004
|
extractMetrics: (result, startTime, endEvent) => {
|
|
12385
13005
|
const metrics = withCachedMetric(
|
|
12386
13006
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -12399,23 +13019,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
12399
13019
|
traceAsyncChannel(openAIChannels.responsesCompact, {
|
|
12400
13020
|
name: "openai.responses.compact",
|
|
12401
13021
|
type: "llm" /* LLM */,
|
|
12402
|
-
extractInput: ([params]) =>
|
|
12403
|
-
const { input, ...metadata } = params;
|
|
12404
|
-
return {
|
|
12405
|
-
input: processInputAttachments(input),
|
|
12406
|
-
metadata: { ...metadata, provider: "openai" }
|
|
12407
|
-
};
|
|
12408
|
-
},
|
|
13022
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
12409
13023
|
extractOutput: (result) => {
|
|
12410
13024
|
return processImagesInOutput(result?.output);
|
|
12411
13025
|
},
|
|
12412
|
-
extractMetadata: (result) =>
|
|
12413
|
-
if (!result) {
|
|
12414
|
-
return void 0;
|
|
12415
|
-
}
|
|
12416
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
12417
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
12418
|
-
},
|
|
13026
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
12419
13027
|
extractMetrics: (result, startTime, endEvent) => {
|
|
12420
13028
|
const metrics = withCachedMetric(
|
|
12421
13029
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -12471,35 +13079,6 @@ function withCachedMetric(metrics, result, endEvent) {
|
|
|
12471
13079
|
cached
|
|
12472
13080
|
};
|
|
12473
13081
|
}
|
|
12474
|
-
function processImagesInOutput(output) {
|
|
12475
|
-
if (Array.isArray(output)) {
|
|
12476
|
-
return output.map(processImagesInOutput);
|
|
12477
|
-
}
|
|
12478
|
-
if (isObject(output)) {
|
|
12479
|
-
if (output.type === "image_generation_call" && output.result && typeof output.result === "string") {
|
|
12480
|
-
const fileExtension = output.output_format || "png";
|
|
12481
|
-
const contentType = `image/${fileExtension}`;
|
|
12482
|
-
const baseFilename = output.revised_prompt && typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
12483
|
-
const filename = `${baseFilename}.${fileExtension}`;
|
|
12484
|
-
const binaryString = atob(output.result);
|
|
12485
|
-
const bytes = new Uint8Array(binaryString.length);
|
|
12486
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
12487
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
12488
|
-
}
|
|
12489
|
-
const blob = new Blob([bytes], { type: contentType });
|
|
12490
|
-
const attachment = new Attachment({
|
|
12491
|
-
data: blob,
|
|
12492
|
-
filename,
|
|
12493
|
-
contentType
|
|
12494
|
-
});
|
|
12495
|
-
return {
|
|
12496
|
-
...output,
|
|
12497
|
-
result: attachment
|
|
12498
|
-
};
|
|
12499
|
-
}
|
|
12500
|
-
}
|
|
12501
|
-
return output;
|
|
12502
|
-
}
|
|
12503
13082
|
function mergeLogprobTokens(existing, incoming) {
|
|
12504
13083
|
if (incoming === void 0) {
|
|
12505
13084
|
return existing;
|
|
@@ -17643,6 +18222,12 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
|
|
|
17643
18222
|
if (!activeEntry) {
|
|
17644
18223
|
return result;
|
|
17645
18224
|
}
|
|
18225
|
+
const executionOptions = args[1];
|
|
18226
|
+
const toolCallId = isObject(executionOptions) ? executionOptions.toolCallId : void 0;
|
|
18227
|
+
const toolInput = {
|
|
18228
|
+
input: serializeToolExecutionInput(args),
|
|
18229
|
+
...typeof toolCallId === "string" ? { metadata: { toolCallId } } : {}
|
|
18230
|
+
};
|
|
17646
18231
|
if (isAsyncGenerator(result)) {
|
|
17647
18232
|
return (async function* () {
|
|
17648
18233
|
const span = activeEntry.parentSpan.startSpan(
|
|
@@ -17656,7 +18241,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
|
|
|
17656
18241
|
INSTRUMENTATION_NAMES.AI_SDK
|
|
17657
18242
|
)
|
|
17658
18243
|
);
|
|
17659
|
-
span.log(
|
|
18244
|
+
span.log(toolInput);
|
|
17660
18245
|
try {
|
|
17661
18246
|
let lastValue;
|
|
17662
18247
|
for await (const value of result) {
|
|
@@ -17674,7 +18259,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
|
|
|
17674
18259
|
}
|
|
17675
18260
|
return activeEntry.parentSpan.traced(
|
|
17676
18261
|
async (span) => {
|
|
17677
|
-
span.log(
|
|
18262
|
+
span.log(toolInput);
|
|
17678
18263
|
const awaitedResult = await result;
|
|
17679
18264
|
span.log({ output: awaitedResult });
|
|
17680
18265
|
return awaitedResult;
|
|
@@ -31796,14 +32381,17 @@ function getMetricsFromResponse(response) {
|
|
|
31796
32381
|
if (!isRecord(usageMetadata)) {
|
|
31797
32382
|
continue;
|
|
31798
32383
|
}
|
|
31799
|
-
const inputTokenDetails = usageMetadata.input_token_details;
|
|
32384
|
+
const inputTokenDetails = isRecord(usageMetadata.input_token_details) ? usageMetadata.input_token_details : {};
|
|
31800
32385
|
const outputTokenDetails = usageMetadata.output_token_details;
|
|
31801
32386
|
return normalizeTokenMetrics({
|
|
31802
32387
|
total_tokens: usageMetadata.total_tokens,
|
|
31803
32388
|
prompt_tokens: usageMetadata.input_tokens,
|
|
31804
32389
|
completion_tokens: usageMetadata.output_tokens,
|
|
31805
|
-
|
|
31806
|
-
|
|
32390
|
+
// Prefer TTL-specific cache writes over the aggregate when available.
|
|
32391
|
+
prompt_cache_creation_tokens: inputTokenDetails.ephemeral_5m_input_tokens == null && inputTokenDetails.ephemeral_1h_input_tokens == null ? inputTokenDetails.cache_creation : void 0,
|
|
32392
|
+
prompt_cache_creation_5m_tokens: inputTokenDetails.ephemeral_5m_input_tokens,
|
|
32393
|
+
prompt_cache_creation_1h_tokens: inputTokenDetails.ephemeral_1h_input_tokens,
|
|
32394
|
+
prompt_cached_tokens: inputTokenDetails.cache_read,
|
|
31807
32395
|
completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
|
|
31808
32396
|
});
|
|
31809
32397
|
}
|
|
@@ -32519,7 +33107,7 @@ function extractSession(event) {
|
|
|
32519
33107
|
return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
|
|
32520
33108
|
}
|
|
32521
33109
|
function isPiAgent(value) {
|
|
32522
|
-
return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
|
|
33110
|
+
return isObject(value) && (typeof value.streamFunction === "function" || typeof value.streamFn === "function") && typeof value.subscribe === "function";
|
|
32523
33111
|
}
|
|
32524
33112
|
function promptContextStore() {
|
|
32525
33113
|
piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
|
|
@@ -32529,17 +33117,21 @@ function currentPiPromptState() {
|
|
|
32529
33117
|
return promptContextStore().getStore();
|
|
32530
33118
|
}
|
|
32531
33119
|
function installPiAgentInstrumentation(agent) {
|
|
33120
|
+
const property = typeof agent.streamFunction === "function" ? "streamFunction" : "streamFn";
|
|
33121
|
+
const streamFunction = agent[property];
|
|
32532
33122
|
const existing = piAgentPatchStates.get(agent);
|
|
32533
|
-
if (!existing ||
|
|
33123
|
+
if (streamFunction && (!existing || existing.property !== property || streamFunction !== existing.wrappedStreamFunction)) {
|
|
32534
33124
|
const patchState = {
|
|
32535
|
-
|
|
32536
|
-
|
|
33125
|
+
originalStreamFunction: streamFunction,
|
|
33126
|
+
property,
|
|
33127
|
+
wrappedStreamFunction: streamFunction
|
|
32537
33128
|
};
|
|
32538
|
-
patchState.
|
|
33129
|
+
patchState.wrappedStreamFunction = makeInstrumentedStreamFunction(
|
|
32539
33130
|
agent,
|
|
32540
|
-
patchState.
|
|
33131
|
+
patchState.originalStreamFunction,
|
|
33132
|
+
property
|
|
32541
33133
|
);
|
|
32542
|
-
agent
|
|
33134
|
+
agent[property] = patchState.wrappedStreamFunction;
|
|
32543
33135
|
piAgentPatchStates.set(agent, patchState);
|
|
32544
33136
|
}
|
|
32545
33137
|
if (piAgentEventSubscriptions.has(agent)) {
|
|
@@ -32564,15 +33156,21 @@ function installPiAgentInstrumentation(agent) {
|
|
|
32564
33156
|
logInstrumentationError4("Pi Coding Agent event subscription", error);
|
|
32565
33157
|
}
|
|
32566
33158
|
}
|
|
32567
|
-
function
|
|
32568
|
-
return async function
|
|
32569
|
-
const invokeOriginal = () => Reflect.apply(
|
|
33159
|
+
function makeInstrumentedStreamFunction(agent, originalStreamFunction, property) {
|
|
33160
|
+
return async function instrumentedPiStreamFunction(model, context, options) {
|
|
33161
|
+
const invokeOriginal = () => Reflect.apply(originalStreamFunction, this, [model, context, options]);
|
|
32570
33162
|
const state = currentPiPromptState();
|
|
32571
33163
|
if (!state || state.agent !== agent || state.finalized) {
|
|
32572
33164
|
return invokeOriginal();
|
|
32573
33165
|
}
|
|
32574
33166
|
wrapPiToolExecutors(context.tools);
|
|
32575
|
-
const llmState = await startPiLlmSpan(
|
|
33167
|
+
const llmState = await startPiLlmSpan(
|
|
33168
|
+
state,
|
|
33169
|
+
model,
|
|
33170
|
+
context,
|
|
33171
|
+
property,
|
|
33172
|
+
options
|
|
33173
|
+
);
|
|
32576
33174
|
try {
|
|
32577
33175
|
const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
|
|
32578
33176
|
return patchAssistantMessageStream(stream, state, llmState);
|
|
@@ -32609,12 +33207,12 @@ function wrapPiToolExecutors(tools) {
|
|
|
32609
33207
|
}
|
|
32610
33208
|
}
|
|
32611
33209
|
}
|
|
32612
|
-
async function startPiLlmSpan(state, model, context, options) {
|
|
33210
|
+
async function startPiLlmSpan(state, model, context, property, options) {
|
|
32613
33211
|
const metadata = {
|
|
32614
33212
|
...extractModelMetadata2(model),
|
|
32615
33213
|
...extractStreamOptionsMetadata(options),
|
|
32616
33214
|
...extractToolMetadata(context.tools),
|
|
32617
|
-
"pi_coding_agent.operation":
|
|
33215
|
+
"pi_coding_agent.operation": `agent.${property}`
|
|
32618
33216
|
};
|
|
32619
33217
|
const span = startSpan(
|
|
32620
33218
|
withSpanInstrumentationName(
|
|
@@ -36925,7 +37523,15 @@ var MAX_EVE_PROVIDER_CACHE_ENTRIES = 1e4;
|
|
|
36925
37523
|
function createEveInstrumentationProvider(options = {}) {
|
|
36926
37524
|
const bridge = new EveProviderBridge(options.metadata);
|
|
36927
37525
|
return {
|
|
37526
|
+
// Eve versions before tracePolicy use capture to decide whether provider
|
|
37527
|
+
// events include content. Newer versions prefer tracePolicy when both are
|
|
37528
|
+
// present, so keep the deprecated field for backwards compatibility.
|
|
36928
37529
|
capture: "content",
|
|
37530
|
+
tracePolicy: () => ({
|
|
37531
|
+
emit: true,
|
|
37532
|
+
recordInputs: true,
|
|
37533
|
+
recordOutputs: true
|
|
37534
|
+
}),
|
|
36929
37535
|
events: {
|
|
36930
37536
|
"action.completed": (event, context) => bridge.handleActionTerminal(event, context),
|
|
36931
37537
|
"action.failed": (event, context) => bridge.handleActionTerminal(event, context),
|