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/dev/dist/index.mjs
CHANGED
|
@@ -4118,6 +4118,7 @@ var ProjectSettings = z6.union([
|
|
|
4118
4118
|
]),
|
|
4119
4119
|
disable_realtime_queries: z6.union([z6.boolean(), z6.null()]),
|
|
4120
4120
|
monitor_charts_use_metrics_start: z6.union([z6.boolean(), z6.null()]),
|
|
4121
|
+
blind_reviews: z6.union([z6.boolean(), z6.null()]),
|
|
4121
4122
|
default_preprocessor: NullableSavedFunctionId
|
|
4122
4123
|
}).partial(),
|
|
4123
4124
|
z6.null()
|
|
@@ -4179,6 +4180,7 @@ var WindowedAutomationConfig = z6.object({
|
|
|
4179
4180
|
auto_approve_tools: z6.array(z6.string().min(1)).optional().default([]),
|
|
4180
4181
|
harness: z6.enum(["native", "codex", "claude-code"]).optional(),
|
|
4181
4182
|
model: z6.string().min(1).optional(),
|
|
4183
|
+
endpoint_name: z6.string().min(1).optional(),
|
|
4182
4184
|
reasoning_effort: z6.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional()
|
|
4183
4185
|
}).optional(),
|
|
4184
4186
|
actions: z6.array(
|
|
@@ -5972,7 +5974,7 @@ var INSTRUMENTATION_NAMES = {
|
|
|
5972
5974
|
var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
|
|
5973
5975
|
"braintrust.spanInstrumentationName"
|
|
5974
5976
|
);
|
|
5975
|
-
var SDK_VERSION = true ? "3.
|
|
5977
|
+
var SDK_VERSION = true ? "3.31.0" : "0.0.0";
|
|
5976
5978
|
function withSpanInstrumentationName(args, instrumentationName) {
|
|
5977
5979
|
return {
|
|
5978
5980
|
...args,
|
|
@@ -9487,6 +9489,15 @@ function _internalStartSpanWithInitialMerge(args) {
|
|
|
9487
9489
|
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
9488
9490
|
}).span;
|
|
9489
9491
|
}
|
|
9492
|
+
function _internalStartSpanWithInitialMergeAndParentSpanIds(args) {
|
|
9493
|
+
return startSpanAndIsLogger(
|
|
9494
|
+
{
|
|
9495
|
+
...args,
|
|
9496
|
+
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
9497
|
+
},
|
|
9498
|
+
{ useParentSpanIdsForObjectParent: true }
|
|
9499
|
+
).span;
|
|
9500
|
+
}
|
|
9490
9501
|
function _internalStartSpanWithContext(args, context) {
|
|
9491
9502
|
return startSpanAndIsLogger({
|
|
9492
9503
|
...args,
|
|
@@ -9497,7 +9508,7 @@ async function flush(options) {
|
|
|
9497
9508
|
const state = options?.state ?? _globalState;
|
|
9498
9509
|
return await state.bgLogger().flush();
|
|
9499
9510
|
}
|
|
9500
|
-
function startSpanAndIsLogger(args) {
|
|
9511
|
+
function startSpanAndIsLogger(args, internalOptions) {
|
|
9501
9512
|
const state = args?.state ?? _globalState;
|
|
9502
9513
|
const { parentObject, propagatedState } = getSpanParentObjectAndPropagatedState({
|
|
9503
9514
|
asyncFlush: args?.asyncFlush,
|
|
@@ -9511,7 +9522,7 @@ function startSpanAndIsLogger(args) {
|
|
|
9511
9522
|
) ? {
|
|
9512
9523
|
spanId: parentObject.data.span_id,
|
|
9513
9524
|
rootSpanId: parentObject.data.root_span_id
|
|
9514
|
-
} : void 0;
|
|
9525
|
+
} : internalOptions?.useParentSpanIdsForObjectParent ? args?.parentSpanIds : void 0;
|
|
9515
9526
|
const { parent: _ignoredParent, ...spanArgs } = args ?? {};
|
|
9516
9527
|
const span = new SpanImpl({
|
|
9517
9528
|
state,
|
|
@@ -12811,6 +12822,131 @@ function unsubscribeAll(unsubscribers) {
|
|
|
12811
12822
|
return [];
|
|
12812
12823
|
}
|
|
12813
12824
|
|
|
12825
|
+
// src/instrumentation/core/channel-definitions.ts
|
|
12826
|
+
function channel(spec) {
|
|
12827
|
+
return spec;
|
|
12828
|
+
}
|
|
12829
|
+
function defineChannels(pkg, channels, options) {
|
|
12830
|
+
const { instrumentationName } = options;
|
|
12831
|
+
return Object.fromEntries(
|
|
12832
|
+
Object.entries(channels).map(([key, spec]) => {
|
|
12833
|
+
const fullChannelName = `orchestrion:${pkg}:${spec.channelName}`;
|
|
12834
|
+
if (spec.kind === "async") {
|
|
12835
|
+
const asyncSpec = spec;
|
|
12836
|
+
const tracingChannel2 = () => isomorph_default.newTracingChannel(
|
|
12837
|
+
fullChannelName
|
|
12838
|
+
);
|
|
12839
|
+
const intercept2 = (interceptor) => {
|
|
12840
|
+
const hook = tracingChannel2();
|
|
12841
|
+
return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
|
|
12842
|
+
};
|
|
12843
|
+
};
|
|
12844
|
+
return [
|
|
12845
|
+
key,
|
|
12846
|
+
{
|
|
12847
|
+
...asyncSpec,
|
|
12848
|
+
instrumentationName,
|
|
12849
|
+
intercept: intercept2,
|
|
12850
|
+
invoke: (target, thisArg, args, additional) => {
|
|
12851
|
+
const hook = tracingChannel2();
|
|
12852
|
+
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
12853
|
+
},
|
|
12854
|
+
tracingChannel: tracingChannel2,
|
|
12855
|
+
tracePromise: (fn, context) => tracingChannel2().tracePromise(
|
|
12856
|
+
fn,
|
|
12857
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
12858
|
+
context
|
|
12859
|
+
)
|
|
12860
|
+
}
|
|
12861
|
+
];
|
|
12862
|
+
}
|
|
12863
|
+
const syncSpec = spec;
|
|
12864
|
+
const tracingChannel = () => isomorph_default.newTracingChannel(
|
|
12865
|
+
fullChannelName
|
|
12866
|
+
);
|
|
12867
|
+
const intercept = (interceptor) => {
|
|
12868
|
+
const hook = tracingChannel();
|
|
12869
|
+
return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
|
|
12870
|
+
};
|
|
12871
|
+
};
|
|
12872
|
+
return [
|
|
12873
|
+
key,
|
|
12874
|
+
{
|
|
12875
|
+
...syncSpec,
|
|
12876
|
+
instrumentationName,
|
|
12877
|
+
intercept,
|
|
12878
|
+
invoke: (target, thisArg, args, additional) => {
|
|
12879
|
+
const hook = tracingChannel();
|
|
12880
|
+
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
12881
|
+
},
|
|
12882
|
+
tracingChannel,
|
|
12883
|
+
traceSync: (fn, context) => tracingChannel().traceSync(
|
|
12884
|
+
fn,
|
|
12885
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
12886
|
+
context
|
|
12887
|
+
)
|
|
12888
|
+
}
|
|
12889
|
+
];
|
|
12890
|
+
})
|
|
12891
|
+
);
|
|
12892
|
+
}
|
|
12893
|
+
|
|
12894
|
+
// src/instrumentation/plugins/openai-channels.ts
|
|
12895
|
+
var openAIChannels = defineChannels(
|
|
12896
|
+
"openai",
|
|
12897
|
+
{
|
|
12898
|
+
filesCreateTraced: channel({
|
|
12899
|
+
channelName: "files.create-traced",
|
|
12900
|
+
kind: "async"
|
|
12901
|
+
}),
|
|
12902
|
+
batchesRetrieveTraced: channel({
|
|
12903
|
+
channelName: "batches.retrieve-traced",
|
|
12904
|
+
kind: "async"
|
|
12905
|
+
}),
|
|
12906
|
+
batchesCompleteTrace: channel({
|
|
12907
|
+
channelName: "batches.complete-trace",
|
|
12908
|
+
kind: "async"
|
|
12909
|
+
}),
|
|
12910
|
+
chatCompletionsCreate: channel({
|
|
12911
|
+
channelName: "chat.completions.create",
|
|
12912
|
+
kind: "async"
|
|
12913
|
+
}),
|
|
12914
|
+
embeddingsCreate: channel({
|
|
12915
|
+
channelName: "embeddings.create",
|
|
12916
|
+
kind: "async"
|
|
12917
|
+
}),
|
|
12918
|
+
betaChatCompletionsParse: channel({
|
|
12919
|
+
channelName: "beta.chat.completions.parse",
|
|
12920
|
+
kind: "async"
|
|
12921
|
+
}),
|
|
12922
|
+
betaChatCompletionsStream: channel({
|
|
12923
|
+
channelName: "beta.chat.completions.stream",
|
|
12924
|
+
kind: "sync-stream"
|
|
12925
|
+
}),
|
|
12926
|
+
moderationsCreate: channel({
|
|
12927
|
+
channelName: "moderations.create",
|
|
12928
|
+
kind: "async"
|
|
12929
|
+
}),
|
|
12930
|
+
responsesCreate: channel({
|
|
12931
|
+
channelName: "responses.create",
|
|
12932
|
+
kind: "async"
|
|
12933
|
+
}),
|
|
12934
|
+
responsesStream: channel({
|
|
12935
|
+
channelName: "responses.stream",
|
|
12936
|
+
kind: "sync-stream"
|
|
12937
|
+
}),
|
|
12938
|
+
responsesParse: channel({
|
|
12939
|
+
channelName: "responses.parse",
|
|
12940
|
+
kind: "async"
|
|
12941
|
+
}),
|
|
12942
|
+
responsesCompact: channel({
|
|
12943
|
+
channelName: "responses.compact",
|
|
12944
|
+
kind: "async"
|
|
12945
|
+
})
|
|
12946
|
+
},
|
|
12947
|
+
{ instrumentationName: INSTRUMENTATION_NAMES.OPENAI }
|
|
12948
|
+
);
|
|
12949
|
+
|
|
12814
12950
|
// src/wrappers/attachment-utils.ts
|
|
12815
12951
|
function getExtensionFromMediaType(mediaType) {
|
|
12816
12952
|
const extensionMap = {
|
|
@@ -12986,118 +13122,91 @@ function processInputAttachments(input) {
|
|
|
12986
13122
|
return processNode(input);
|
|
12987
13123
|
}
|
|
12988
13124
|
|
|
12989
|
-
// src/instrumentation/
|
|
12990
|
-
|
|
12991
|
-
|
|
12992
|
-
|
|
12993
|
-
|
|
12994
|
-
|
|
12995
|
-
|
|
12996
|
-
|
|
12997
|
-
|
|
12998
|
-
|
|
12999
|
-
|
|
13000
|
-
|
|
13001
|
-
|
|
13002
|
-
|
|
13003
|
-
|
|
13004
|
-
|
|
13005
|
-
|
|
13006
|
-
|
|
13007
|
-
|
|
13008
|
-
|
|
13009
|
-
|
|
13010
|
-
|
|
13011
|
-
...asyncSpec,
|
|
13012
|
-
instrumentationName,
|
|
13013
|
-
intercept: intercept2,
|
|
13014
|
-
invoke: (target, thisArg, args, additional) => {
|
|
13015
|
-
const hook = tracingChannel2();
|
|
13016
|
-
return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
|
|
13017
|
-
},
|
|
13018
|
-
tracingChannel: tracingChannel2,
|
|
13019
|
-
tracePromise: (fn, context) => tracingChannel2().tracePromise(
|
|
13020
|
-
fn,
|
|
13021
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
13022
|
-
context
|
|
13023
|
-
)
|
|
13024
|
-
}
|
|
13025
|
-
];
|
|
13125
|
+
// src/instrumentation/plugins/openai-span-data.ts
|
|
13126
|
+
var OPENAI_METADATA_KEYS = [
|
|
13127
|
+
"model",
|
|
13128
|
+
"temperature",
|
|
13129
|
+
"top_p",
|
|
13130
|
+
"max_tokens",
|
|
13131
|
+
"frequency_penalty",
|
|
13132
|
+
"presence_penalty",
|
|
13133
|
+
"stop",
|
|
13134
|
+
"response_format",
|
|
13135
|
+
"tools",
|
|
13136
|
+
"tool_choice",
|
|
13137
|
+
"parallel_tool_calls",
|
|
13138
|
+
"max_tool_calls"
|
|
13139
|
+
];
|
|
13140
|
+
function batchMetadata(params) {
|
|
13141
|
+
const metadata = { provider: "openai" };
|
|
13142
|
+
for (const key of OPENAI_METADATA_KEYS) {
|
|
13143
|
+
try {
|
|
13144
|
+
const value = Reflect.get(params, key);
|
|
13145
|
+
if (value !== void 0) {
|
|
13146
|
+
metadata[key] = value;
|
|
13026
13147
|
}
|
|
13027
|
-
|
|
13028
|
-
|
|
13029
|
-
|
|
13030
|
-
|
|
13031
|
-
|
|
13032
|
-
|
|
13033
|
-
|
|
13034
|
-
|
|
13035
|
-
|
|
13036
|
-
|
|
13037
|
-
|
|
13038
|
-
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
|
|
13042
|
-
|
|
13043
|
-
|
|
13044
|
-
|
|
13045
|
-
|
|
13046
|
-
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13148
|
+
} catch {
|
|
13149
|
+
}
|
|
13150
|
+
}
|
|
13151
|
+
return metadata;
|
|
13152
|
+
}
|
|
13153
|
+
function extractOpenAIBatchInput(endpoint, params) {
|
|
13154
|
+
const input = endpoint === "/v1/chat/completions" ? params.messages : params.input;
|
|
13155
|
+
return {
|
|
13156
|
+
input: processInputAttachments(input),
|
|
13157
|
+
metadata: batchMetadata(params)
|
|
13158
|
+
};
|
|
13159
|
+
}
|
|
13160
|
+
function extractOpenAIChatInput(params) {
|
|
13161
|
+
const { messages, ...metadata } = params;
|
|
13162
|
+
return {
|
|
13163
|
+
input: processInputAttachments(messages),
|
|
13164
|
+
metadata: { ...metadata, provider: "openai" }
|
|
13165
|
+
};
|
|
13166
|
+
}
|
|
13167
|
+
function extractOpenAIResponsesInput(params) {
|
|
13168
|
+
const { input, ...metadata } = params;
|
|
13169
|
+
return {
|
|
13170
|
+
input: processInputAttachments(input),
|
|
13171
|
+
metadata: { ...metadata, provider: "openai" }
|
|
13172
|
+
};
|
|
13173
|
+
}
|
|
13174
|
+
function extractOpenAIResponsesMetadata(result) {
|
|
13175
|
+
if (!result) {
|
|
13176
|
+
return void 0;
|
|
13177
|
+
}
|
|
13178
|
+
const { output: _output, usage: _usage, ...metadata } = result;
|
|
13179
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
13180
|
+
}
|
|
13181
|
+
function processImagesInOutput(output) {
|
|
13182
|
+
if (Array.isArray(output)) {
|
|
13183
|
+
return output.map(processImagesInOutput);
|
|
13184
|
+
}
|
|
13185
|
+
if (isObject(output) && output.type === "image_generation_call" && typeof output.result === "string" && output.result) {
|
|
13186
|
+
const fileExtension = output.output_format || "png";
|
|
13187
|
+
const contentType = `image/${fileExtension}`;
|
|
13188
|
+
const baseFilename = typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
13189
|
+
let binaryString;
|
|
13190
|
+
try {
|
|
13191
|
+
binaryString = atob(output.result);
|
|
13192
|
+
} catch {
|
|
13193
|
+
return output;
|
|
13194
|
+
}
|
|
13195
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
13196
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
13197
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
13198
|
+
}
|
|
13199
|
+
return {
|
|
13200
|
+
...output,
|
|
13201
|
+
result: new Attachment({
|
|
13202
|
+
data: new Blob([bytes], { type: contentType }),
|
|
13203
|
+
filename: `${baseFilename}.${fileExtension}`,
|
|
13204
|
+
contentType
|
|
13205
|
+
})
|
|
13206
|
+
};
|
|
13207
|
+
}
|
|
13208
|
+
return output;
|
|
13056
13209
|
}
|
|
13057
|
-
|
|
13058
|
-
// src/instrumentation/plugins/openai-channels.ts
|
|
13059
|
-
var openAIChannels = defineChannels(
|
|
13060
|
-
"openai",
|
|
13061
|
-
{
|
|
13062
|
-
chatCompletionsCreate: channel({
|
|
13063
|
-
channelName: "chat.completions.create",
|
|
13064
|
-
kind: "async"
|
|
13065
|
-
}),
|
|
13066
|
-
embeddingsCreate: channel({
|
|
13067
|
-
channelName: "embeddings.create",
|
|
13068
|
-
kind: "async"
|
|
13069
|
-
}),
|
|
13070
|
-
betaChatCompletionsParse: channel({
|
|
13071
|
-
channelName: "beta.chat.completions.parse",
|
|
13072
|
-
kind: "async"
|
|
13073
|
-
}),
|
|
13074
|
-
betaChatCompletionsStream: channel({
|
|
13075
|
-
channelName: "beta.chat.completions.stream",
|
|
13076
|
-
kind: "sync-stream"
|
|
13077
|
-
}),
|
|
13078
|
-
moderationsCreate: channel({
|
|
13079
|
-
channelName: "moderations.create",
|
|
13080
|
-
kind: "async"
|
|
13081
|
-
}),
|
|
13082
|
-
responsesCreate: channel({
|
|
13083
|
-
channelName: "responses.create",
|
|
13084
|
-
kind: "async"
|
|
13085
|
-
}),
|
|
13086
|
-
responsesStream: channel({
|
|
13087
|
-
channelName: "responses.stream",
|
|
13088
|
-
kind: "sync-stream"
|
|
13089
|
-
}),
|
|
13090
|
-
responsesParse: channel({
|
|
13091
|
-
channelName: "responses.parse",
|
|
13092
|
-
kind: "async"
|
|
13093
|
-
}),
|
|
13094
|
-
responsesCompact: channel({
|
|
13095
|
-
channelName: "responses.compact",
|
|
13096
|
-
kind: "async"
|
|
13097
|
-
})
|
|
13098
|
-
},
|
|
13099
|
-
{ instrumentationName: INSTRUMENTATION_NAMES.OPENAI }
|
|
13100
|
-
);
|
|
13101
13210
|
|
|
13102
13211
|
// src/openai-utils.ts
|
|
13103
13212
|
var BRAINTRUST_CACHED_STREAM_METRIC = "__braintrust_cached_metric";
|
|
@@ -13154,23 +13263,573 @@ function getCachedMetricFromHeaders(headers) {
|
|
|
13154
13263
|
return parseCachedHeader(headers.get(LEGACY_CACHED_HEADER));
|
|
13155
13264
|
}
|
|
13156
13265
|
|
|
13266
|
+
// src/instrumentation/plugins/openai-batch-instrumentation.ts
|
|
13267
|
+
var SUPPORTED_ENDPOINTS = /* @__PURE__ */ new Set(["/v1/chat/completions", "/v1/responses"]);
|
|
13268
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
13269
|
+
"completed",
|
|
13270
|
+
"failed",
|
|
13271
|
+
"expired",
|
|
13272
|
+
"cancelled"
|
|
13273
|
+
]);
|
|
13274
|
+
var pendingBatchTraces = /* @__PURE__ */ new Map();
|
|
13275
|
+
function read(value, key) {
|
|
13276
|
+
if (!isObject(value)) {
|
|
13277
|
+
return void 0;
|
|
13278
|
+
}
|
|
13279
|
+
try {
|
|
13280
|
+
return Reflect.get(value, key);
|
|
13281
|
+
} catch {
|
|
13282
|
+
return void 0;
|
|
13283
|
+
}
|
|
13284
|
+
}
|
|
13285
|
+
function isBatchRecordIterable(value) {
|
|
13286
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") {
|
|
13287
|
+
return false;
|
|
13288
|
+
}
|
|
13289
|
+
return typeof read(value, Symbol.iterator) === "function" || typeof read(value, Symbol.asyncIterator) === "function";
|
|
13290
|
+
}
|
|
13291
|
+
function validCustomId(value) {
|
|
13292
|
+
return typeof value === "string" && value.length > 0 && value.length <= 64;
|
|
13293
|
+
}
|
|
13294
|
+
function logBatchInstrumentationError(context, error) {
|
|
13295
|
+
debugLogger.debug(`OpenAI Batch instrumentation ${context}:`, error);
|
|
13296
|
+
}
|
|
13297
|
+
async function exportParent(parent) {
|
|
13298
|
+
if ("toStr" in parent && typeof parent.toStr === "function") {
|
|
13299
|
+
return parent.toStr();
|
|
13300
|
+
}
|
|
13301
|
+
if ("export" in parent && typeof parent.export === "function") {
|
|
13302
|
+
return await parent.export();
|
|
13303
|
+
}
|
|
13304
|
+
return void 0;
|
|
13305
|
+
}
|
|
13306
|
+
async function deterministicDigest(namespace, ...parts) {
|
|
13307
|
+
const encoded = new TextEncoder().encode(
|
|
13308
|
+
[namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
|
|
13309
|
+
);
|
|
13310
|
+
return new Uint8Array(
|
|
13311
|
+
await globalThis.crypto.subtle.digest("SHA-256", encoded)
|
|
13312
|
+
);
|
|
13313
|
+
}
|
|
13314
|
+
function digestHex(bytes, length) {
|
|
13315
|
+
return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
13316
|
+
}
|
|
13317
|
+
function digestUuid(bytes) {
|
|
13318
|
+
const hex = digestHex(bytes, 16);
|
|
13319
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
13320
|
+
}
|
|
13321
|
+
async function batchSpanIds(inputFileId) {
|
|
13322
|
+
const [row, span, root] = await Promise.all([
|
|
13323
|
+
deterministicDigest("openai:batch:row", inputFileId),
|
|
13324
|
+
deterministicDigest("openai:batch:span", inputFileId),
|
|
13325
|
+
deterministicDigest("openai:batch:root", inputFileId)
|
|
13326
|
+
]);
|
|
13327
|
+
return {
|
|
13328
|
+
rowId: digestUuid(row),
|
|
13329
|
+
spanId: digestHex(span, 8),
|
|
13330
|
+
rootSpanId: digestHex(root, 16)
|
|
13331
|
+
};
|
|
13332
|
+
}
|
|
13333
|
+
async function childSpanIds(inputFileId, customId) {
|
|
13334
|
+
const [row, span] = await Promise.all([
|
|
13335
|
+
deterministicDigest("openai:batch:child:row", inputFileId, customId),
|
|
13336
|
+
deterministicDigest("openai:batch:child:span", inputFileId, customId)
|
|
13337
|
+
]);
|
|
13338
|
+
return { rowId: digestUuid(row), spanId: digestHex(span, 8) };
|
|
13339
|
+
}
|
|
13340
|
+
async function startBatchSpan(context) {
|
|
13341
|
+
const ids = await batchSpanIds(context.inputFileId);
|
|
13342
|
+
const parent = SpanComponentsV4.fromStr(context.parent);
|
|
13343
|
+
const hasParentSpan = Boolean(
|
|
13344
|
+
parent.data.row_id && parent.data.span_id && parent.data.root_span_id
|
|
13345
|
+
);
|
|
13346
|
+
return withCurrent(
|
|
13347
|
+
NOOP_SPAN,
|
|
13348
|
+
() => _internalStartSpanWithInitialMergeAndParentSpanIds(
|
|
13349
|
+
withSpanInstrumentationName(
|
|
13350
|
+
{
|
|
13351
|
+
name: "openai.batch",
|
|
13352
|
+
type: "task" /* TASK */,
|
|
13353
|
+
parent: context.parent,
|
|
13354
|
+
...!hasParentSpan ? {
|
|
13355
|
+
parentSpanIds: {
|
|
13356
|
+
parentSpanIds: [],
|
|
13357
|
+
rootSpanId: ids.rootSpanId
|
|
13358
|
+
}
|
|
13359
|
+
} : {},
|
|
13360
|
+
spanId: ids.spanId,
|
|
13361
|
+
startTime: context.taskStartTime,
|
|
13362
|
+
event: {
|
|
13363
|
+
id: ids.rowId,
|
|
13364
|
+
metadata: {
|
|
13365
|
+
endpoint: context.endpoint,
|
|
13366
|
+
input_file_id: context.inputFileId,
|
|
13367
|
+
provider: "openai"
|
|
13368
|
+
}
|
|
13369
|
+
}
|
|
13370
|
+
},
|
|
13371
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
13372
|
+
)
|
|
13373
|
+
)
|
|
13374
|
+
);
|
|
13375
|
+
}
|
|
13376
|
+
async function startBatchChild(context, taskParent, input) {
|
|
13377
|
+
const ids = await childSpanIds(context.inputFileId, input.customId);
|
|
13378
|
+
return withCurrent(
|
|
13379
|
+
NOOP_SPAN,
|
|
13380
|
+
() => _internalStartSpanWithInitialMerge(
|
|
13381
|
+
withSpanInstrumentationName(
|
|
13382
|
+
{
|
|
13383
|
+
name: context.endpoint === "/v1/chat/completions" ? "Chat Completion" : "openai.responses.create",
|
|
13384
|
+
type: "llm" /* LLM */,
|
|
13385
|
+
parent: taskParent,
|
|
13386
|
+
spanId: ids.spanId,
|
|
13387
|
+
startTime: context.childStartTime,
|
|
13388
|
+
event: {
|
|
13389
|
+
id: ids.rowId,
|
|
13390
|
+
...input.spanData?.input !== void 0 ? { input: input.spanData.input } : {},
|
|
13391
|
+
metadata: {
|
|
13392
|
+
...input.spanData?.metadata,
|
|
13393
|
+
custom_id: input.customId,
|
|
13394
|
+
provider: "openai"
|
|
13395
|
+
}
|
|
13396
|
+
}
|
|
13397
|
+
},
|
|
13398
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
13399
|
+
)
|
|
13400
|
+
)
|
|
13401
|
+
);
|
|
13402
|
+
}
|
|
13403
|
+
async function* jsonlRecords(file, onIssue = () => {
|
|
13404
|
+
}) {
|
|
13405
|
+
const resolvedFile = await file;
|
|
13406
|
+
if (typeof resolvedFile === "string") {
|
|
13407
|
+
for (const line of resolvedFile.split("\n")) {
|
|
13408
|
+
if (!line.trim()) {
|
|
13409
|
+
continue;
|
|
13410
|
+
}
|
|
13411
|
+
try {
|
|
13412
|
+
yield JSON.parse(line.replace(/\r$/, ""));
|
|
13413
|
+
} catch (error) {
|
|
13414
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
13415
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
13416
|
+
}
|
|
13417
|
+
}
|
|
13418
|
+
return;
|
|
13419
|
+
}
|
|
13420
|
+
const body = read(resolvedFile, "body");
|
|
13421
|
+
const getReader = read(body, "getReader");
|
|
13422
|
+
if (isObject(body) && typeof getReader === "function") {
|
|
13423
|
+
let reader;
|
|
13424
|
+
try {
|
|
13425
|
+
reader = Reflect.apply(getReader, body, []);
|
|
13426
|
+
const decoder = new TextDecoder();
|
|
13427
|
+
let pending = "";
|
|
13428
|
+
while (true) {
|
|
13429
|
+
const readChunk = read(reader, "read");
|
|
13430
|
+
if (typeof readChunk !== "function") {
|
|
13431
|
+
throw new Error("Response body stream has no read method");
|
|
13432
|
+
}
|
|
13433
|
+
const chunk = await Reflect.apply(readChunk, reader, []);
|
|
13434
|
+
if (!isObject(chunk)) {
|
|
13435
|
+
throw new Error("Response body stream returned an invalid chunk");
|
|
13436
|
+
}
|
|
13437
|
+
if (chunk.done === true) {
|
|
13438
|
+
pending += decoder.decode();
|
|
13439
|
+
break;
|
|
13440
|
+
}
|
|
13441
|
+
if (!(chunk.value instanceof Uint8Array)) {
|
|
13442
|
+
throw new Error("Response body stream returned a non-byte chunk");
|
|
13443
|
+
}
|
|
13444
|
+
pending += decoder.decode(chunk.value, { stream: true });
|
|
13445
|
+
let newline = pending.indexOf("\n");
|
|
13446
|
+
while (newline !== -1) {
|
|
13447
|
+
const line = pending.slice(0, newline).replace(/\r$/, "");
|
|
13448
|
+
pending = pending.slice(newline + 1);
|
|
13449
|
+
if (line.trim()) {
|
|
13450
|
+
try {
|
|
13451
|
+
yield JSON.parse(line);
|
|
13452
|
+
} catch (error) {
|
|
13453
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
13454
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
13455
|
+
}
|
|
13456
|
+
}
|
|
13457
|
+
newline = pending.indexOf("\n");
|
|
13458
|
+
}
|
|
13459
|
+
}
|
|
13460
|
+
if (pending.trim()) {
|
|
13461
|
+
try {
|
|
13462
|
+
yield JSON.parse(pending.replace(/\r$/, ""));
|
|
13463
|
+
} catch (error) {
|
|
13464
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
13465
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
13466
|
+
}
|
|
13467
|
+
}
|
|
13468
|
+
} catch (error) {
|
|
13469
|
+
logBatchInstrumentationError("could not read JSONL response body", error);
|
|
13470
|
+
onIssue(new Error("OpenAI Batch response body could not be read"));
|
|
13471
|
+
} finally {
|
|
13472
|
+
const releaseLock = read(reader, "releaseLock");
|
|
13473
|
+
if (typeof releaseLock === "function") {
|
|
13474
|
+
try {
|
|
13475
|
+
Reflect.apply(releaseLock, reader, []);
|
|
13476
|
+
} catch (error) {
|
|
13477
|
+
logBatchInstrumentationError(
|
|
13478
|
+
"could not release stream reader",
|
|
13479
|
+
error
|
|
13480
|
+
);
|
|
13481
|
+
}
|
|
13482
|
+
}
|
|
13483
|
+
}
|
|
13484
|
+
return;
|
|
13485
|
+
}
|
|
13486
|
+
if (isBatchRecordIterable(resolvedFile)) {
|
|
13487
|
+
for await (const record of resolvedFile) {
|
|
13488
|
+
yield record;
|
|
13489
|
+
}
|
|
13490
|
+
return;
|
|
13491
|
+
}
|
|
13492
|
+
logBatchInstrumentationError("skipped invalid JSONL source", resolvedFile);
|
|
13493
|
+
onIssue(new Error("OpenAI Batch file source is invalid"));
|
|
13494
|
+
}
|
|
13495
|
+
async function readBatchInputs(file) {
|
|
13496
|
+
const inputs = /* @__PURE__ */ new Map();
|
|
13497
|
+
const issues = [];
|
|
13498
|
+
let endpoint;
|
|
13499
|
+
try {
|
|
13500
|
+
for await (const value of jsonlRecords(
|
|
13501
|
+
file,
|
|
13502
|
+
(issue) => issues.push(issue)
|
|
13503
|
+
)) {
|
|
13504
|
+
const customId = read(value, "custom_id");
|
|
13505
|
+
const url = read(value, "url");
|
|
13506
|
+
const body = read(value, "body");
|
|
13507
|
+
if (!validCustomId(customId) || inputs.has(customId) || read(value, "method") !== "POST" || typeof url !== "string" || !SUPPORTED_ENDPOINTS.has(url) || endpoint !== void 0 && endpoint !== url || !isObject(body)) {
|
|
13508
|
+
issues.push(new Error("OpenAI Batch input contains an invalid record"));
|
|
13509
|
+
continue;
|
|
13510
|
+
}
|
|
13511
|
+
endpoint = url;
|
|
13512
|
+
let spanData;
|
|
13513
|
+
try {
|
|
13514
|
+
spanData = extractOpenAIBatchInput(url, body);
|
|
13515
|
+
} catch (error) {
|
|
13516
|
+
logBatchInstrumentationError("could not extract batch input", error);
|
|
13517
|
+
}
|
|
13518
|
+
inputs.set(customId, { customId, spanData });
|
|
13519
|
+
}
|
|
13520
|
+
} catch (error) {
|
|
13521
|
+
logBatchInstrumentationError("could not process input file", error);
|
|
13522
|
+
issues.push(new Error("OpenAI Batch input file could not be processed"));
|
|
13523
|
+
}
|
|
13524
|
+
if (!endpoint || inputs.size === 0) {
|
|
13525
|
+
issues.push(new Error("OpenAI Batch input contains no supported records"));
|
|
13526
|
+
}
|
|
13527
|
+
return { endpoint, inputs, issues };
|
|
13528
|
+
}
|
|
13529
|
+
async function writePendingSpans(trace, endTime) {
|
|
13530
|
+
const task = await startBatchSpan(trace.context);
|
|
13531
|
+
const taskParent = await task.export();
|
|
13532
|
+
for (const input of trace.inputs.values()) {
|
|
13533
|
+
try {
|
|
13534
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
13535
|
+
if (endTime !== void 0) {
|
|
13536
|
+
child.end({ endTime });
|
|
13537
|
+
}
|
|
13538
|
+
} catch (error) {
|
|
13539
|
+
logBatchInstrumentationError("could not write batch request span", error);
|
|
13540
|
+
}
|
|
13541
|
+
}
|
|
13542
|
+
if (endTime !== void 0) {
|
|
13543
|
+
if (trace.status && trace.status !== "completed") {
|
|
13544
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
13545
|
+
}
|
|
13546
|
+
task.end({ endTime });
|
|
13547
|
+
}
|
|
13548
|
+
}
|
|
13549
|
+
var interceptOpenAIFilesCreateTraced = async (target, thisArg, args) => {
|
|
13550
|
+
const startTime = getCurrentUnixTimestamp();
|
|
13551
|
+
const inputPromise = readBatchInputs(args[0].inputFileContent);
|
|
13552
|
+
const parentPromise = exportParent(args[0].parent);
|
|
13553
|
+
const file = await Reflect.apply(target, thisArg, args);
|
|
13554
|
+
try {
|
|
13555
|
+
const inputFileId = read(file, "id");
|
|
13556
|
+
const [inputData, exportedParent2] = await Promise.all([
|
|
13557
|
+
inputPromise,
|
|
13558
|
+
parentPromise
|
|
13559
|
+
]);
|
|
13560
|
+
if (typeof inputFileId !== "string" || !exportedParent2 || !inputData.endpoint || inputData.issues.length > 0) {
|
|
13561
|
+
if (inputData.issues[0]) {
|
|
13562
|
+
logBatchInstrumentationError(
|
|
13563
|
+
"skipped invalid input file",
|
|
13564
|
+
inputData.issues[0]
|
|
13565
|
+
);
|
|
13566
|
+
}
|
|
13567
|
+
return file;
|
|
13568
|
+
}
|
|
13569
|
+
const trace = {
|
|
13570
|
+
context: {
|
|
13571
|
+
inputFileId,
|
|
13572
|
+
endpoint: inputData.endpoint,
|
|
13573
|
+
parent: exportedParent2,
|
|
13574
|
+
taskStartTime: startTime,
|
|
13575
|
+
childStartTime: startTime
|
|
13576
|
+
},
|
|
13577
|
+
inputs: inputData.inputs
|
|
13578
|
+
};
|
|
13579
|
+
pendingBatchTraces.set(inputFileId, trace);
|
|
13580
|
+
await writePendingSpans(trace);
|
|
13581
|
+
} catch (error) {
|
|
13582
|
+
logBatchInstrumentationError("could not start batch spans", error);
|
|
13583
|
+
}
|
|
13584
|
+
return file;
|
|
13585
|
+
};
|
|
13586
|
+
function validTimestamp(value) {
|
|
13587
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
13588
|
+
}
|
|
13589
|
+
function terminalEndTime(batch, startTime) {
|
|
13590
|
+
let timestamp;
|
|
13591
|
+
switch (batch.status) {
|
|
13592
|
+
case "completed":
|
|
13593
|
+
timestamp = batch.completed_at;
|
|
13594
|
+
break;
|
|
13595
|
+
case "failed":
|
|
13596
|
+
timestamp = batch.failed_at;
|
|
13597
|
+
break;
|
|
13598
|
+
case "expired":
|
|
13599
|
+
timestamp = batch.expired_at;
|
|
13600
|
+
break;
|
|
13601
|
+
default:
|
|
13602
|
+
timestamp = batch.cancelled_at;
|
|
13603
|
+
}
|
|
13604
|
+
return validTimestamp(timestamp) ? Math.max(timestamp, startTime) : Math.max(getCurrentUnixTimestamp(), startTime);
|
|
13605
|
+
}
|
|
13606
|
+
async function updateBatchTimestamps(batch) {
|
|
13607
|
+
const trace = pendingBatchTraces.get(batch.input_file_id);
|
|
13608
|
+
if (!trace || trace.context.endpoint !== batch.endpoint) {
|
|
13609
|
+
return;
|
|
13610
|
+
}
|
|
13611
|
+
if (validTimestamp(batch.created_at)) {
|
|
13612
|
+
trace.context.taskStartTime = batch.created_at;
|
|
13613
|
+
}
|
|
13614
|
+
trace.context.childStartTime = validTimestamp(batch.in_progress_at) ? Math.max(batch.in_progress_at, trace.context.taskStartTime) : trace.context.taskStartTime;
|
|
13615
|
+
trace.status = batch.status;
|
|
13616
|
+
if (TERMINAL_STATUSES.has(batch.status)) {
|
|
13617
|
+
trace.endTime = terminalEndTime(batch, trace.context.childStartTime);
|
|
13618
|
+
}
|
|
13619
|
+
await writePendingSpans(trace, trace.endTime);
|
|
13620
|
+
}
|
|
13621
|
+
var interceptOpenAIBatchesRetrieveTraced = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (batch) => {
|
|
13622
|
+
try {
|
|
13623
|
+
await updateBatchTimestamps(batch);
|
|
13624
|
+
} catch (error) {
|
|
13625
|
+
logBatchInstrumentationError("could not update batch timestamps", error);
|
|
13626
|
+
}
|
|
13627
|
+
return batch;
|
|
13628
|
+
});
|
|
13629
|
+
function errorFromResult(result) {
|
|
13630
|
+
const error = read(result.value, "error");
|
|
13631
|
+
if (isObject(error)) {
|
|
13632
|
+
const message = read(error, "message");
|
|
13633
|
+
return new Error(
|
|
13634
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
13635
|
+
);
|
|
13636
|
+
}
|
|
13637
|
+
const response = read(result.value, "response");
|
|
13638
|
+
const statusCode = read(response, "status_code");
|
|
13639
|
+
if (result.source === "error" || typeof statusCode === "number" && (statusCode < 200 || statusCode >= 300)) {
|
|
13640
|
+
const message = read(read(read(response, "body"), "error"), "message");
|
|
13641
|
+
return new Error(
|
|
13642
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
13643
|
+
);
|
|
13644
|
+
}
|
|
13645
|
+
return void 0;
|
|
13646
|
+
}
|
|
13647
|
+
async function completeBatchResult(context, taskParent, endTime, input, result) {
|
|
13648
|
+
const child = await startBatchChild(context, taskParent, input);
|
|
13649
|
+
try {
|
|
13650
|
+
const resultError = errorFromResult(result);
|
|
13651
|
+
const responseBody = read(read(result.value, "response"), "body");
|
|
13652
|
+
if (resultError) {
|
|
13653
|
+
child.log({ error: resultError });
|
|
13654
|
+
} else if (isObject(responseBody)) {
|
|
13655
|
+
const model = read(responseBody, "model");
|
|
13656
|
+
child.log({
|
|
13657
|
+
output: context.endpoint === "/v1/chat/completions" ? read(responseBody, "choices") : processImagesInOutput(read(responseBody, "output")),
|
|
13658
|
+
...typeof model === "string" ? { metadata: { model } } : {},
|
|
13659
|
+
metrics: parseMetricsFromUsage(read(responseBody, "usage"))
|
|
13660
|
+
});
|
|
13661
|
+
} else {
|
|
13662
|
+
child.log({ error: new Error("OpenAI Batch response body is missing") });
|
|
13663
|
+
}
|
|
13664
|
+
} catch (error) {
|
|
13665
|
+
child.log({ error });
|
|
13666
|
+
} finally {
|
|
13667
|
+
child.end({ endTime });
|
|
13668
|
+
}
|
|
13669
|
+
}
|
|
13670
|
+
async function completeResultFile({
|
|
13671
|
+
context,
|
|
13672
|
+
endTime,
|
|
13673
|
+
file,
|
|
13674
|
+
inputs,
|
|
13675
|
+
issues,
|
|
13676
|
+
seen,
|
|
13677
|
+
source,
|
|
13678
|
+
taskParent
|
|
13679
|
+
}) {
|
|
13680
|
+
if (file === void 0) {
|
|
13681
|
+
return;
|
|
13682
|
+
}
|
|
13683
|
+
for await (const value of jsonlRecords(file, (issue) => issues.push(issue))) {
|
|
13684
|
+
const customId = read(value, "custom_id");
|
|
13685
|
+
if (!validCustomId(customId) || !isObject(value)) {
|
|
13686
|
+
issues.push(
|
|
13687
|
+
new Error("OpenAI Batch result is missing a valid custom_id")
|
|
13688
|
+
);
|
|
13689
|
+
continue;
|
|
13690
|
+
}
|
|
13691
|
+
if (seen.has(customId)) {
|
|
13692
|
+
issues.push(new Error("OpenAI Batch result contains a duplicate"));
|
|
13693
|
+
continue;
|
|
13694
|
+
}
|
|
13695
|
+
const input = inputs.get(customId);
|
|
13696
|
+
if (!input) {
|
|
13697
|
+
issues.push(
|
|
13698
|
+
new Error("OpenAI Batch result does not match an input record")
|
|
13699
|
+
);
|
|
13700
|
+
continue;
|
|
13701
|
+
}
|
|
13702
|
+
seen.add(customId);
|
|
13703
|
+
await completeBatchResult(context, taskParent, endTime, input, {
|
|
13704
|
+
value,
|
|
13705
|
+
source
|
|
13706
|
+
});
|
|
13707
|
+
}
|
|
13708
|
+
}
|
|
13709
|
+
function sameInputs(first, second) {
|
|
13710
|
+
return first.size === second.size && [...first.keys()].every((customId) => second.has(customId));
|
|
13711
|
+
}
|
|
13712
|
+
async function contextForCompletion(inputFileId, inputData) {
|
|
13713
|
+
if (!inputData.endpoint || inputData.issues.length > 0) {
|
|
13714
|
+
return void 0;
|
|
13715
|
+
}
|
|
13716
|
+
const existing = pendingBatchTraces.get(inputFileId);
|
|
13717
|
+
if (existing) {
|
|
13718
|
+
if (existing.context.endpoint !== inputData.endpoint || !sameInputs(existing.inputs, inputData.inputs)) {
|
|
13719
|
+
return void 0;
|
|
13720
|
+
}
|
|
13721
|
+
return { ...existing, inputs: inputData.inputs };
|
|
13722
|
+
}
|
|
13723
|
+
const parent = await exportParent(getSpanParentObject());
|
|
13724
|
+
if (!parent) {
|
|
13725
|
+
return void 0;
|
|
13726
|
+
}
|
|
13727
|
+
const startTime = getCurrentUnixTimestamp();
|
|
13728
|
+
return {
|
|
13729
|
+
context: {
|
|
13730
|
+
inputFileId,
|
|
13731
|
+
endpoint: inputData.endpoint,
|
|
13732
|
+
parent,
|
|
13733
|
+
taskStartTime: startTime,
|
|
13734
|
+
childStartTime: startTime
|
|
13735
|
+
},
|
|
13736
|
+
inputs: inputData.inputs
|
|
13737
|
+
};
|
|
13738
|
+
}
|
|
13739
|
+
async function completeBatch(args) {
|
|
13740
|
+
const inputData = await readBatchInputs(args.inputFileContent);
|
|
13741
|
+
const trace = await contextForCompletion(args.inputFileId, inputData);
|
|
13742
|
+
if (!trace) {
|
|
13743
|
+
logBatchInstrumentationError(
|
|
13744
|
+
"left batch spans pending",
|
|
13745
|
+
inputData.issues[0] ?? new Error("OpenAI Batch input does not match")
|
|
13746
|
+
);
|
|
13747
|
+
return;
|
|
13748
|
+
}
|
|
13749
|
+
const endTime = trace.endTime ?? getCurrentUnixTimestamp();
|
|
13750
|
+
const task = await startBatchSpan(trace.context);
|
|
13751
|
+
const taskParent = await task.export();
|
|
13752
|
+
const issues = [];
|
|
13753
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13754
|
+
await Promise.all([
|
|
13755
|
+
completeResultFile({
|
|
13756
|
+
context: trace.context,
|
|
13757
|
+
endTime,
|
|
13758
|
+
file: args.outputFileContent,
|
|
13759
|
+
inputs: trace.inputs,
|
|
13760
|
+
issues,
|
|
13761
|
+
seen,
|
|
13762
|
+
source: "output",
|
|
13763
|
+
taskParent
|
|
13764
|
+
}),
|
|
13765
|
+
completeResultFile({
|
|
13766
|
+
context: trace.context,
|
|
13767
|
+
endTime,
|
|
13768
|
+
file: args.errorFileContent,
|
|
13769
|
+
inputs: trace.inputs,
|
|
13770
|
+
issues,
|
|
13771
|
+
seen,
|
|
13772
|
+
source: "error",
|
|
13773
|
+
taskParent
|
|
13774
|
+
})
|
|
13775
|
+
]);
|
|
13776
|
+
if (issues.length > 0) {
|
|
13777
|
+
logBatchInstrumentationError("left batch spans pending", issues[0]);
|
|
13778
|
+
return;
|
|
13779
|
+
}
|
|
13780
|
+
const missing = [...trace.inputs.values()].filter(
|
|
13781
|
+
({ customId }) => !seen.has(customId)
|
|
13782
|
+
);
|
|
13783
|
+
if (!trace.status || trace.status === "completed") {
|
|
13784
|
+
if (missing.length > 0) {
|
|
13785
|
+
logBatchInstrumentationError(
|
|
13786
|
+
"left batch spans pending",
|
|
13787
|
+
new Error("OpenAI Batch result files are incomplete")
|
|
13788
|
+
);
|
|
13789
|
+
return;
|
|
13790
|
+
}
|
|
13791
|
+
} else {
|
|
13792
|
+
for (const input of missing) {
|
|
13793
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
13794
|
+
child.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
13795
|
+
child.end({ endTime });
|
|
13796
|
+
}
|
|
13797
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
13798
|
+
}
|
|
13799
|
+
task.end({ endTime });
|
|
13800
|
+
pendingBatchTraces.delete(args.inputFileId);
|
|
13801
|
+
}
|
|
13802
|
+
var interceptOpenAIBatchTraceComplete = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (result) => {
|
|
13803
|
+
try {
|
|
13804
|
+
await completeBatch(args[0]);
|
|
13805
|
+
} catch (error) {
|
|
13806
|
+
logBatchInstrumentationError("could not complete batch", error);
|
|
13807
|
+
}
|
|
13808
|
+
return result;
|
|
13809
|
+
});
|
|
13810
|
+
|
|
13157
13811
|
// src/instrumentation/plugins/openai-plugin.ts
|
|
13158
13812
|
var OpenAIPlugin = class extends BasePlugin {
|
|
13159
13813
|
constructor() {
|
|
13160
13814
|
super();
|
|
13161
13815
|
}
|
|
13162
13816
|
onEnable() {
|
|
13817
|
+
this.unsubscribers.push(
|
|
13818
|
+
openAIChannels.filesCreateTraced.intercept(
|
|
13819
|
+
interceptOpenAIFilesCreateTraced
|
|
13820
|
+
),
|
|
13821
|
+
openAIChannels.batchesRetrieveTraced.intercept(
|
|
13822
|
+
interceptOpenAIBatchesRetrieveTraced
|
|
13823
|
+
),
|
|
13824
|
+
openAIChannels.batchesCompleteTrace.intercept(
|
|
13825
|
+
interceptOpenAIBatchTraceComplete
|
|
13826
|
+
)
|
|
13827
|
+
);
|
|
13163
13828
|
this.unsubscribers.push(
|
|
13164
13829
|
traceStreamingChannel(openAIChannels.chatCompletionsCreate, {
|
|
13165
13830
|
name: "Chat Completion",
|
|
13166
13831
|
type: "llm" /* LLM */,
|
|
13167
|
-
extractInput: ([params]) =>
|
|
13168
|
-
const { messages, ...metadata } = params;
|
|
13169
|
-
return {
|
|
13170
|
-
input: processInputAttachments(messages),
|
|
13171
|
-
metadata: { ...metadata, provider: "openai" }
|
|
13172
|
-
};
|
|
13173
|
-
},
|
|
13832
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
13174
13833
|
extractOutput: (result) => {
|
|
13175
13834
|
return result?.choices;
|
|
13176
13835
|
},
|
|
@@ -13216,13 +13875,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
13216
13875
|
traceStreamingChannel(openAIChannels.betaChatCompletionsParse, {
|
|
13217
13876
|
name: "Chat Completion",
|
|
13218
13877
|
type: "llm" /* LLM */,
|
|
13219
|
-
extractInput: ([params]) =>
|
|
13220
|
-
const { messages, ...metadata } = params;
|
|
13221
|
-
return {
|
|
13222
|
-
input: processInputAttachments(messages),
|
|
13223
|
-
metadata: { ...metadata, provider: "openai" }
|
|
13224
|
-
};
|
|
13225
|
-
},
|
|
13878
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
13226
13879
|
extractOutput: (result) => {
|
|
13227
13880
|
return result?.choices;
|
|
13228
13881
|
},
|
|
@@ -13244,13 +13897,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
13244
13897
|
traceSyncStreamChannel(openAIChannels.betaChatCompletionsStream, {
|
|
13245
13898
|
name: "Chat Completion",
|
|
13246
13899
|
type: "llm" /* LLM */,
|
|
13247
|
-
extractInput: ([params]) =>
|
|
13248
|
-
const { messages, ...metadata } = params;
|
|
13249
|
-
return {
|
|
13250
|
-
input: processInputAttachments(messages),
|
|
13251
|
-
metadata: { ...metadata, provider: "openai" }
|
|
13252
|
-
};
|
|
13253
|
-
}
|
|
13900
|
+
extractInput: ([params]) => extractOpenAIChatInput(params)
|
|
13254
13901
|
})
|
|
13255
13902
|
);
|
|
13256
13903
|
this.unsubscribers.push(
|
|
@@ -13280,23 +13927,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
13280
13927
|
traceStreamingChannel(openAIChannels.responsesCreate, {
|
|
13281
13928
|
name: "openai.responses.create",
|
|
13282
13929
|
type: "llm" /* LLM */,
|
|
13283
|
-
extractInput: ([params]) =>
|
|
13284
|
-
const { input, ...metadata } = params;
|
|
13285
|
-
return {
|
|
13286
|
-
input: processInputAttachments(input),
|
|
13287
|
-
metadata: { ...metadata, provider: "openai" }
|
|
13288
|
-
};
|
|
13289
|
-
},
|
|
13930
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
13290
13931
|
extractOutput: (result) => {
|
|
13291
13932
|
return processImagesInOutput(result?.output);
|
|
13292
13933
|
},
|
|
13293
|
-
extractMetadata: (result) =>
|
|
13294
|
-
if (!result) {
|
|
13295
|
-
return void 0;
|
|
13296
|
-
}
|
|
13297
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
13298
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
13299
|
-
},
|
|
13934
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
13300
13935
|
extractMetrics: (result, startTime, endEvent) => {
|
|
13301
13936
|
const metrics = withCachedMetric(
|
|
13302
13937
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -13315,13 +13950,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
13315
13950
|
traceSyncStreamChannel(openAIChannels.responsesStream, {
|
|
13316
13951
|
name: "openai.responses.create",
|
|
13317
13952
|
type: "llm" /* LLM */,
|
|
13318
|
-
extractInput: ([params]) =>
|
|
13319
|
-
const { input, ...metadata } = params;
|
|
13320
|
-
return {
|
|
13321
|
-
input: processInputAttachments(input),
|
|
13322
|
-
metadata: { ...metadata, provider: "openai" }
|
|
13323
|
-
};
|
|
13324
|
-
},
|
|
13953
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
13325
13954
|
extractFromEvent: (event) => {
|
|
13326
13955
|
if (event.type !== "response.completed" || !event.response) {
|
|
13327
13956
|
return {};
|
|
@@ -13344,23 +13973,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
13344
13973
|
traceStreamingChannel(openAIChannels.responsesParse, {
|
|
13345
13974
|
name: "openai.responses.parse",
|
|
13346
13975
|
type: "llm" /* LLM */,
|
|
13347
|
-
extractInput: ([params]) =>
|
|
13348
|
-
const { input, ...metadata } = params;
|
|
13349
|
-
return {
|
|
13350
|
-
input: processInputAttachments(input),
|
|
13351
|
-
metadata: { ...metadata, provider: "openai" }
|
|
13352
|
-
};
|
|
13353
|
-
},
|
|
13976
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
13354
13977
|
extractOutput: (result) => {
|
|
13355
13978
|
return processImagesInOutput(result?.output);
|
|
13356
13979
|
},
|
|
13357
|
-
extractMetadata: (result) =>
|
|
13358
|
-
if (!result) {
|
|
13359
|
-
return void 0;
|
|
13360
|
-
}
|
|
13361
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
13362
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
13363
|
-
},
|
|
13980
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
13364
13981
|
extractMetrics: (result, startTime, endEvent) => {
|
|
13365
13982
|
const metrics = withCachedMetric(
|
|
13366
13983
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -13379,23 +13996,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
13379
13996
|
traceAsyncChannel(openAIChannels.responsesCompact, {
|
|
13380
13997
|
name: "openai.responses.compact",
|
|
13381
13998
|
type: "llm" /* LLM */,
|
|
13382
|
-
extractInput: ([params]) =>
|
|
13383
|
-
const { input, ...metadata } = params;
|
|
13384
|
-
return {
|
|
13385
|
-
input: processInputAttachments(input),
|
|
13386
|
-
metadata: { ...metadata, provider: "openai" }
|
|
13387
|
-
};
|
|
13388
|
-
},
|
|
13999
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
13389
14000
|
extractOutput: (result) => {
|
|
13390
14001
|
return processImagesInOutput(result?.output);
|
|
13391
14002
|
},
|
|
13392
|
-
extractMetadata: (result) =>
|
|
13393
|
-
if (!result) {
|
|
13394
|
-
return void 0;
|
|
13395
|
-
}
|
|
13396
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
13397
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
13398
|
-
},
|
|
14003
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
13399
14004
|
extractMetrics: (result, startTime, endEvent) => {
|
|
13400
14005
|
const metrics = withCachedMetric(
|
|
13401
14006
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -13451,35 +14056,6 @@ function withCachedMetric(metrics, result, endEvent) {
|
|
|
13451
14056
|
cached
|
|
13452
14057
|
};
|
|
13453
14058
|
}
|
|
13454
|
-
function processImagesInOutput(output) {
|
|
13455
|
-
if (Array.isArray(output)) {
|
|
13456
|
-
return output.map(processImagesInOutput);
|
|
13457
|
-
}
|
|
13458
|
-
if (isObject(output)) {
|
|
13459
|
-
if (output.type === "image_generation_call" && output.result && typeof output.result === "string") {
|
|
13460
|
-
const fileExtension = output.output_format || "png";
|
|
13461
|
-
const contentType = `image/${fileExtension}`;
|
|
13462
|
-
const baseFilename = output.revised_prompt && typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
13463
|
-
const filename = `${baseFilename}.${fileExtension}`;
|
|
13464
|
-
const binaryString = atob(output.result);
|
|
13465
|
-
const bytes = new Uint8Array(binaryString.length);
|
|
13466
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
13467
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
13468
|
-
}
|
|
13469
|
-
const blob = new Blob([bytes], { type: contentType });
|
|
13470
|
-
const attachment = new Attachment({
|
|
13471
|
-
data: blob,
|
|
13472
|
-
filename,
|
|
13473
|
-
contentType
|
|
13474
|
-
});
|
|
13475
|
-
return {
|
|
13476
|
-
...output,
|
|
13477
|
-
result: attachment
|
|
13478
|
-
};
|
|
13479
|
-
}
|
|
13480
|
-
}
|
|
13481
|
-
return output;
|
|
13482
|
-
}
|
|
13483
14059
|
function mergeLogprobTokens(existing, incoming) {
|
|
13484
14060
|
if (incoming === void 0) {
|
|
13485
14061
|
return existing;
|
|
@@ -18623,6 +19199,12 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
|
|
|
18623
19199
|
if (!activeEntry) {
|
|
18624
19200
|
return result;
|
|
18625
19201
|
}
|
|
19202
|
+
const executionOptions = args[1];
|
|
19203
|
+
const toolCallId = isObject(executionOptions) ? executionOptions.toolCallId : void 0;
|
|
19204
|
+
const toolInput = {
|
|
19205
|
+
input: serializeToolExecutionInput(args),
|
|
19206
|
+
...typeof toolCallId === "string" ? { metadata: { toolCallId } } : {}
|
|
19207
|
+
};
|
|
18626
19208
|
if (isAsyncGenerator(result)) {
|
|
18627
19209
|
return (async function* () {
|
|
18628
19210
|
const span = activeEntry.parentSpan.startSpan(
|
|
@@ -18636,7 +19218,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
|
|
|
18636
19218
|
INSTRUMENTATION_NAMES.AI_SDK
|
|
18637
19219
|
)
|
|
18638
19220
|
);
|
|
18639
|
-
span.log(
|
|
19221
|
+
span.log(toolInput);
|
|
18640
19222
|
try {
|
|
18641
19223
|
let lastValue;
|
|
18642
19224
|
for await (const value of result) {
|
|
@@ -18654,7 +19236,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
|
|
|
18654
19236
|
}
|
|
18655
19237
|
return activeEntry.parentSpan.traced(
|
|
18656
19238
|
async (span) => {
|
|
18657
|
-
span.log(
|
|
19239
|
+
span.log(toolInput);
|
|
18658
19240
|
const awaitedResult = await result;
|
|
18659
19241
|
span.log({ output: awaitedResult });
|
|
18660
19242
|
return awaitedResult;
|
|
@@ -32776,14 +33358,17 @@ function getMetricsFromResponse(response) {
|
|
|
32776
33358
|
if (!isRecord(usageMetadata)) {
|
|
32777
33359
|
continue;
|
|
32778
33360
|
}
|
|
32779
|
-
const inputTokenDetails = usageMetadata.input_token_details;
|
|
33361
|
+
const inputTokenDetails = isRecord(usageMetadata.input_token_details) ? usageMetadata.input_token_details : {};
|
|
32780
33362
|
const outputTokenDetails = usageMetadata.output_token_details;
|
|
32781
33363
|
return normalizeTokenMetrics({
|
|
32782
33364
|
total_tokens: usageMetadata.total_tokens,
|
|
32783
33365
|
prompt_tokens: usageMetadata.input_tokens,
|
|
32784
33366
|
completion_tokens: usageMetadata.output_tokens,
|
|
32785
|
-
|
|
32786
|
-
|
|
33367
|
+
// Prefer TTL-specific cache writes over the aggregate when available.
|
|
33368
|
+
prompt_cache_creation_tokens: inputTokenDetails.ephemeral_5m_input_tokens == null && inputTokenDetails.ephemeral_1h_input_tokens == null ? inputTokenDetails.cache_creation : void 0,
|
|
33369
|
+
prompt_cache_creation_5m_tokens: inputTokenDetails.ephemeral_5m_input_tokens,
|
|
33370
|
+
prompt_cache_creation_1h_tokens: inputTokenDetails.ephemeral_1h_input_tokens,
|
|
33371
|
+
prompt_cached_tokens: inputTokenDetails.cache_read,
|
|
32787
33372
|
completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
|
|
32788
33373
|
});
|
|
32789
33374
|
}
|
|
@@ -33499,7 +34084,7 @@ function extractSession(event) {
|
|
|
33499
34084
|
return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
|
|
33500
34085
|
}
|
|
33501
34086
|
function isPiAgent(value) {
|
|
33502
|
-
return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
|
|
34087
|
+
return isObject(value) && (typeof value.streamFunction === "function" || typeof value.streamFn === "function") && typeof value.subscribe === "function";
|
|
33503
34088
|
}
|
|
33504
34089
|
function promptContextStore() {
|
|
33505
34090
|
piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
|
|
@@ -33509,17 +34094,21 @@ function currentPiPromptState() {
|
|
|
33509
34094
|
return promptContextStore().getStore();
|
|
33510
34095
|
}
|
|
33511
34096
|
function installPiAgentInstrumentation(agent) {
|
|
34097
|
+
const property = typeof agent.streamFunction === "function" ? "streamFunction" : "streamFn";
|
|
34098
|
+
const streamFunction = agent[property];
|
|
33512
34099
|
const existing = piAgentPatchStates.get(agent);
|
|
33513
|
-
if (!existing ||
|
|
34100
|
+
if (streamFunction && (!existing || existing.property !== property || streamFunction !== existing.wrappedStreamFunction)) {
|
|
33514
34101
|
const patchState = {
|
|
33515
|
-
|
|
33516
|
-
|
|
34102
|
+
originalStreamFunction: streamFunction,
|
|
34103
|
+
property,
|
|
34104
|
+
wrappedStreamFunction: streamFunction
|
|
33517
34105
|
};
|
|
33518
|
-
patchState.
|
|
34106
|
+
patchState.wrappedStreamFunction = makeInstrumentedStreamFunction(
|
|
33519
34107
|
agent,
|
|
33520
|
-
patchState.
|
|
34108
|
+
patchState.originalStreamFunction,
|
|
34109
|
+
property
|
|
33521
34110
|
);
|
|
33522
|
-
agent
|
|
34111
|
+
agent[property] = patchState.wrappedStreamFunction;
|
|
33523
34112
|
piAgentPatchStates.set(agent, patchState);
|
|
33524
34113
|
}
|
|
33525
34114
|
if (piAgentEventSubscriptions.has(agent)) {
|
|
@@ -33544,15 +34133,21 @@ function installPiAgentInstrumentation(agent) {
|
|
|
33544
34133
|
logInstrumentationError4("Pi Coding Agent event subscription", error);
|
|
33545
34134
|
}
|
|
33546
34135
|
}
|
|
33547
|
-
function
|
|
33548
|
-
return async function
|
|
33549
|
-
const invokeOriginal = () => Reflect.apply(
|
|
34136
|
+
function makeInstrumentedStreamFunction(agent, originalStreamFunction, property) {
|
|
34137
|
+
return async function instrumentedPiStreamFunction(model, context, options) {
|
|
34138
|
+
const invokeOriginal = () => Reflect.apply(originalStreamFunction, this, [model, context, options]);
|
|
33550
34139
|
const state = currentPiPromptState();
|
|
33551
34140
|
if (!state || state.agent !== agent || state.finalized) {
|
|
33552
34141
|
return invokeOriginal();
|
|
33553
34142
|
}
|
|
33554
34143
|
wrapPiToolExecutors(context.tools);
|
|
33555
|
-
const llmState = await startPiLlmSpan(
|
|
34144
|
+
const llmState = await startPiLlmSpan(
|
|
34145
|
+
state,
|
|
34146
|
+
model,
|
|
34147
|
+
context,
|
|
34148
|
+
property,
|
|
34149
|
+
options
|
|
34150
|
+
);
|
|
33556
34151
|
try {
|
|
33557
34152
|
const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
|
|
33558
34153
|
return patchAssistantMessageStream(stream, state, llmState);
|
|
@@ -33589,12 +34184,12 @@ function wrapPiToolExecutors(tools) {
|
|
|
33589
34184
|
}
|
|
33590
34185
|
}
|
|
33591
34186
|
}
|
|
33592
|
-
async function startPiLlmSpan(state, model, context, options) {
|
|
34187
|
+
async function startPiLlmSpan(state, model, context, property, options) {
|
|
33593
34188
|
const metadata = {
|
|
33594
34189
|
...extractModelMetadata2(model),
|
|
33595
34190
|
...extractStreamOptionsMetadata(options),
|
|
33596
34191
|
...extractToolMetadata(context.tools),
|
|
33597
|
-
"pi_coding_agent.operation":
|
|
34192
|
+
"pi_coding_agent.operation": `agent.${property}`
|
|
33598
34193
|
};
|
|
33599
34194
|
const span = startSpan(
|
|
33600
34195
|
withSpanInstrumentationName(
|
|
@@ -38787,19 +39382,29 @@ function buildSpanScores(results) {
|
|
|
38787
39382
|
function _internalPrepareEvaluatorScore(scoreValue, name) {
|
|
38788
39383
|
if (scoreValue === null) return { results: null };
|
|
38789
39384
|
if (Array.isArray(scoreValue)) {
|
|
39385
|
+
const names = /* @__PURE__ */ new Set();
|
|
38790
39386
|
for (const score of scoreValue) {
|
|
38791
39387
|
if (!(typeof score === "object" && !isEmpty2(score))) {
|
|
38792
39388
|
throw new Error(
|
|
38793
39389
|
`When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(score)}`
|
|
38794
39390
|
);
|
|
38795
39391
|
}
|
|
39392
|
+
if (typeof score.name !== "string") {
|
|
39393
|
+
throw new Error(
|
|
39394
|
+
`When returning an array of scores, each score must have a name. Got: ${JSON.stringify(score)}`
|
|
39395
|
+
);
|
|
39396
|
+
}
|
|
39397
|
+
if (names.has(score.name)) {
|
|
39398
|
+
throw new Error(`Duplicate score name '${score.name}' in score array`);
|
|
39399
|
+
}
|
|
39400
|
+
names.add(score.name);
|
|
38796
39401
|
}
|
|
38797
39402
|
}
|
|
38798
39403
|
let results;
|
|
38799
39404
|
if (Array.isArray(scoreValue)) {
|
|
38800
39405
|
results = scoreValue;
|
|
38801
39406
|
} else if (typeof scoreValue === "object" && !isEmpty2(scoreValue)) {
|
|
38802
|
-
results = [scoreValue];
|
|
39407
|
+
results = [{ ...scoreValue, name: scoreValue.name ?? name }];
|
|
38803
39408
|
} else {
|
|
38804
39409
|
results = [{ name, score: scoreValue }];
|
|
38805
39410
|
}
|