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
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
strandsAgentSDKChannels,
|
|
53
53
|
voyageAIChannels,
|
|
54
54
|
withSpanInstrumentationName
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-CE3BLB2L.mjs";
|
|
56
56
|
|
|
57
57
|
// src/id-gen.ts
|
|
58
58
|
import { v4 as uuidv4 } from "uuid";
|
|
@@ -3016,6 +3016,7 @@ var ProjectSettings = z6.union([
|
|
|
3016
3016
|
]),
|
|
3017
3017
|
disable_realtime_queries: z6.union([z6.boolean(), z6.null()]),
|
|
3018
3018
|
monitor_charts_use_metrics_start: z6.union([z6.boolean(), z6.null()]),
|
|
3019
|
+
blind_reviews: z6.union([z6.boolean(), z6.null()]),
|
|
3019
3020
|
default_preprocessor: NullableSavedFunctionId
|
|
3020
3021
|
}).partial(),
|
|
3021
3022
|
z6.null()
|
|
@@ -3077,6 +3078,7 @@ var WindowedAutomationConfig = z6.object({
|
|
|
3077
3078
|
auto_approve_tools: z6.array(z6.string().min(1)).optional().default([]),
|
|
3078
3079
|
harness: z6.enum(["native", "codex", "claude-code"]).optional(),
|
|
3079
3080
|
model: z6.string().min(1).optional(),
|
|
3081
|
+
endpoint_name: z6.string().min(1).optional(),
|
|
3080
3082
|
reasoning_effort: z6.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional()
|
|
3081
3083
|
}).optional(),
|
|
3082
3084
|
actions: z6.array(
|
|
@@ -9030,6 +9032,15 @@ function _internalStartSpanWithInitialMerge(args) {
|
|
|
9030
9032
|
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
9031
9033
|
}).span;
|
|
9032
9034
|
}
|
|
9035
|
+
function _internalStartSpanWithInitialMergeAndParentSpanIds(args) {
|
|
9036
|
+
return startSpanAndIsLogger(
|
|
9037
|
+
{
|
|
9038
|
+
...args,
|
|
9039
|
+
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
9040
|
+
},
|
|
9041
|
+
{ useParentSpanIdsForObjectParent: true }
|
|
9042
|
+
).span;
|
|
9043
|
+
}
|
|
9033
9044
|
function _internalStartSpanWithContext(args, context) {
|
|
9034
9045
|
return startSpanAndIsLogger({
|
|
9035
9046
|
...args,
|
|
@@ -9043,7 +9054,7 @@ async function flush(options) {
|
|
|
9043
9054
|
function setFetch(fetch2) {
|
|
9044
9055
|
_internalGetGlobalState().setFetch(fetch2);
|
|
9045
9056
|
}
|
|
9046
|
-
function startSpanAndIsLogger(args) {
|
|
9057
|
+
function startSpanAndIsLogger(args, internalOptions) {
|
|
9047
9058
|
const state = args?.state ?? _globalState;
|
|
9048
9059
|
const { parentObject, propagatedState } = getSpanParentObjectAndPropagatedState({
|
|
9049
9060
|
asyncFlush: args?.asyncFlush,
|
|
@@ -9057,7 +9068,7 @@ function startSpanAndIsLogger(args) {
|
|
|
9057
9068
|
) ? {
|
|
9058
9069
|
spanId: parentObject.data.span_id,
|
|
9059
9070
|
rootSpanId: parentObject.data.root_span_id
|
|
9060
|
-
} : void 0;
|
|
9071
|
+
} : internalOptions?.useParentSpanIdsForObjectParent ? args?.parentSpanIds : void 0;
|
|
9061
9072
|
const { parent: _ignoredParent, ...spanArgs } = args ?? {};
|
|
9062
9073
|
const span = new SpanImpl({
|
|
9063
9074
|
state,
|
|
@@ -14978,6 +14989,12 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
|
|
|
14978
14989
|
if (!activeEntry) {
|
|
14979
14990
|
return result;
|
|
14980
14991
|
}
|
|
14992
|
+
const executionOptions = args[1];
|
|
14993
|
+
const toolCallId = isObject(executionOptions) ? executionOptions.toolCallId : void 0;
|
|
14994
|
+
const toolInput = {
|
|
14995
|
+
input: serializeToolExecutionInput(args),
|
|
14996
|
+
...typeof toolCallId === "string" ? { metadata: { toolCallId } } : {}
|
|
14997
|
+
};
|
|
14981
14998
|
if (isAsyncGenerator(result)) {
|
|
14982
14999
|
return (async function* () {
|
|
14983
15000
|
const span = activeEntry.parentSpan.startSpan(
|
|
@@ -14991,7 +15008,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
|
|
|
14991
15008
|
INSTRUMENTATION_NAMES.AI_SDK
|
|
14992
15009
|
)
|
|
14993
15010
|
);
|
|
14994
|
-
span.log(
|
|
15011
|
+
span.log(toolInput);
|
|
14995
15012
|
try {
|
|
14996
15013
|
let lastValue;
|
|
14997
15014
|
for await (const value of result) {
|
|
@@ -15009,7 +15026,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
|
|
|
15009
15026
|
}
|
|
15010
15027
|
return activeEntry.parentSpan.traced(
|
|
15011
15028
|
async (span) => {
|
|
15012
|
-
span.log(
|
|
15029
|
+
span.log(toolInput);
|
|
15013
15030
|
const awaitedResult = await result;
|
|
15014
15031
|
span.log({ output: awaitedResult });
|
|
15015
15032
|
return awaitedResult;
|
|
@@ -18563,14 +18580,17 @@ function getMetricsFromResponse(response) {
|
|
|
18563
18580
|
if (!isRecord(usageMetadata)) {
|
|
18564
18581
|
continue;
|
|
18565
18582
|
}
|
|
18566
|
-
const inputTokenDetails = usageMetadata.input_token_details;
|
|
18583
|
+
const inputTokenDetails = isRecord(usageMetadata.input_token_details) ? usageMetadata.input_token_details : {};
|
|
18567
18584
|
const outputTokenDetails = usageMetadata.output_token_details;
|
|
18568
18585
|
return normalizeTokenMetrics({
|
|
18569
18586
|
total_tokens: usageMetadata.total_tokens,
|
|
18570
18587
|
prompt_tokens: usageMetadata.input_tokens,
|
|
18571
18588
|
completion_tokens: usageMetadata.output_tokens,
|
|
18572
|
-
|
|
18573
|
-
|
|
18589
|
+
// Prefer TTL-specific cache writes over the aggregate when available.
|
|
18590
|
+
prompt_cache_creation_tokens: inputTokenDetails.ephemeral_5m_input_tokens == null && inputTokenDetails.ephemeral_1h_input_tokens == null ? inputTokenDetails.cache_creation : void 0,
|
|
18591
|
+
prompt_cache_creation_5m_tokens: inputTokenDetails.ephemeral_5m_input_tokens,
|
|
18592
|
+
prompt_cache_creation_1h_tokens: inputTokenDetails.ephemeral_1h_input_tokens,
|
|
18593
|
+
prompt_cached_tokens: inputTokenDetails.cache_read,
|
|
18574
18594
|
completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
|
|
18575
18595
|
});
|
|
18576
18596
|
}
|
|
@@ -18593,23 +18613,659 @@ function isRecord(value) {
|
|
|
18593
18613
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18594
18614
|
}
|
|
18595
18615
|
|
|
18616
|
+
// src/instrumentation/plugins/openai-span-data.ts
|
|
18617
|
+
var OPENAI_METADATA_KEYS = [
|
|
18618
|
+
"model",
|
|
18619
|
+
"temperature",
|
|
18620
|
+
"top_p",
|
|
18621
|
+
"max_tokens",
|
|
18622
|
+
"frequency_penalty",
|
|
18623
|
+
"presence_penalty",
|
|
18624
|
+
"stop",
|
|
18625
|
+
"response_format",
|
|
18626
|
+
"tools",
|
|
18627
|
+
"tool_choice",
|
|
18628
|
+
"parallel_tool_calls",
|
|
18629
|
+
"max_tool_calls"
|
|
18630
|
+
];
|
|
18631
|
+
function batchMetadata(params) {
|
|
18632
|
+
const metadata = { provider: "openai" };
|
|
18633
|
+
for (const key of OPENAI_METADATA_KEYS) {
|
|
18634
|
+
try {
|
|
18635
|
+
const value = Reflect.get(params, key);
|
|
18636
|
+
if (value !== void 0) {
|
|
18637
|
+
metadata[key] = value;
|
|
18638
|
+
}
|
|
18639
|
+
} catch {
|
|
18640
|
+
}
|
|
18641
|
+
}
|
|
18642
|
+
return metadata;
|
|
18643
|
+
}
|
|
18644
|
+
function extractOpenAIBatchInput(endpoint, params) {
|
|
18645
|
+
const input = endpoint === "/v1/chat/completions" ? params.messages : params.input;
|
|
18646
|
+
return {
|
|
18647
|
+
input: processInputAttachments(input),
|
|
18648
|
+
metadata: batchMetadata(params)
|
|
18649
|
+
};
|
|
18650
|
+
}
|
|
18651
|
+
function extractOpenAIChatInput(params) {
|
|
18652
|
+
const { messages, ...metadata } = params;
|
|
18653
|
+
return {
|
|
18654
|
+
input: processInputAttachments(messages),
|
|
18655
|
+
metadata: { ...metadata, provider: "openai" }
|
|
18656
|
+
};
|
|
18657
|
+
}
|
|
18658
|
+
function extractOpenAIResponsesInput(params) {
|
|
18659
|
+
const { input, ...metadata } = params;
|
|
18660
|
+
return {
|
|
18661
|
+
input: processInputAttachments(input),
|
|
18662
|
+
metadata: { ...metadata, provider: "openai" }
|
|
18663
|
+
};
|
|
18664
|
+
}
|
|
18665
|
+
function extractOpenAIResponsesMetadata(result) {
|
|
18666
|
+
if (!result) {
|
|
18667
|
+
return void 0;
|
|
18668
|
+
}
|
|
18669
|
+
const { output: _output, usage: _usage, ...metadata } = result;
|
|
18670
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
18671
|
+
}
|
|
18672
|
+
function processImagesInOutput(output) {
|
|
18673
|
+
if (Array.isArray(output)) {
|
|
18674
|
+
return output.map(processImagesInOutput);
|
|
18675
|
+
}
|
|
18676
|
+
if (isObject(output) && output.type === "image_generation_call" && typeof output.result === "string" && output.result) {
|
|
18677
|
+
const fileExtension = output.output_format || "png";
|
|
18678
|
+
const contentType = `image/${fileExtension}`;
|
|
18679
|
+
const baseFilename = typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
18680
|
+
let binaryString;
|
|
18681
|
+
try {
|
|
18682
|
+
binaryString = atob(output.result);
|
|
18683
|
+
} catch {
|
|
18684
|
+
return output;
|
|
18685
|
+
}
|
|
18686
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
18687
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
18688
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
18689
|
+
}
|
|
18690
|
+
return {
|
|
18691
|
+
...output,
|
|
18692
|
+
result: new Attachment({
|
|
18693
|
+
data: new Blob([bytes], { type: contentType }),
|
|
18694
|
+
filename: `${baseFilename}.${fileExtension}`,
|
|
18695
|
+
contentType
|
|
18696
|
+
})
|
|
18697
|
+
};
|
|
18698
|
+
}
|
|
18699
|
+
return output;
|
|
18700
|
+
}
|
|
18701
|
+
|
|
18702
|
+
// src/instrumentation/plugins/openai-batch-instrumentation.ts
|
|
18703
|
+
var SUPPORTED_ENDPOINTS = /* @__PURE__ */ new Set(["/v1/chat/completions", "/v1/responses"]);
|
|
18704
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
18705
|
+
"completed",
|
|
18706
|
+
"failed",
|
|
18707
|
+
"expired",
|
|
18708
|
+
"cancelled"
|
|
18709
|
+
]);
|
|
18710
|
+
var pendingBatchTraces = /* @__PURE__ */ new Map();
|
|
18711
|
+
function read(value, key) {
|
|
18712
|
+
if (!isObject(value)) {
|
|
18713
|
+
return void 0;
|
|
18714
|
+
}
|
|
18715
|
+
try {
|
|
18716
|
+
return Reflect.get(value, key);
|
|
18717
|
+
} catch {
|
|
18718
|
+
return void 0;
|
|
18719
|
+
}
|
|
18720
|
+
}
|
|
18721
|
+
function isBatchRecordIterable(value) {
|
|
18722
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") {
|
|
18723
|
+
return false;
|
|
18724
|
+
}
|
|
18725
|
+
return typeof read(value, Symbol.iterator) === "function" || typeof read(value, Symbol.asyncIterator) === "function";
|
|
18726
|
+
}
|
|
18727
|
+
function validCustomId(value) {
|
|
18728
|
+
return typeof value === "string" && value.length > 0 && value.length <= 64;
|
|
18729
|
+
}
|
|
18730
|
+
function logBatchInstrumentationError(context, error) {
|
|
18731
|
+
debugLogger.debug(`OpenAI Batch instrumentation ${context}:`, error);
|
|
18732
|
+
}
|
|
18733
|
+
async function exportParent(parent) {
|
|
18734
|
+
if ("toStr" in parent && typeof parent.toStr === "function") {
|
|
18735
|
+
return parent.toStr();
|
|
18736
|
+
}
|
|
18737
|
+
if ("export" in parent && typeof parent.export === "function") {
|
|
18738
|
+
return await parent.export();
|
|
18739
|
+
}
|
|
18740
|
+
return void 0;
|
|
18741
|
+
}
|
|
18742
|
+
async function deterministicDigest(namespace, ...parts) {
|
|
18743
|
+
const encoded = new TextEncoder().encode(
|
|
18744
|
+
[namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
|
|
18745
|
+
);
|
|
18746
|
+
return new Uint8Array(
|
|
18747
|
+
await globalThis.crypto.subtle.digest("SHA-256", encoded)
|
|
18748
|
+
);
|
|
18749
|
+
}
|
|
18750
|
+
function digestHex(bytes, length) {
|
|
18751
|
+
return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
18752
|
+
}
|
|
18753
|
+
function digestUuid(bytes) {
|
|
18754
|
+
const hex = digestHex(bytes, 16);
|
|
18755
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
18756
|
+
}
|
|
18757
|
+
async function batchSpanIds(inputFileId) {
|
|
18758
|
+
const [row, span, root] = await Promise.all([
|
|
18759
|
+
deterministicDigest("openai:batch:row", inputFileId),
|
|
18760
|
+
deterministicDigest("openai:batch:span", inputFileId),
|
|
18761
|
+
deterministicDigest("openai:batch:root", inputFileId)
|
|
18762
|
+
]);
|
|
18763
|
+
return {
|
|
18764
|
+
rowId: digestUuid(row),
|
|
18765
|
+
spanId: digestHex(span, 8),
|
|
18766
|
+
rootSpanId: digestHex(root, 16)
|
|
18767
|
+
};
|
|
18768
|
+
}
|
|
18769
|
+
async function childSpanIds(inputFileId, customId) {
|
|
18770
|
+
const [row, span] = await Promise.all([
|
|
18771
|
+
deterministicDigest("openai:batch:child:row", inputFileId, customId),
|
|
18772
|
+
deterministicDigest("openai:batch:child:span", inputFileId, customId)
|
|
18773
|
+
]);
|
|
18774
|
+
return { rowId: digestUuid(row), spanId: digestHex(span, 8) };
|
|
18775
|
+
}
|
|
18776
|
+
async function startBatchSpan(context) {
|
|
18777
|
+
const ids = await batchSpanIds(context.inputFileId);
|
|
18778
|
+
const parent = SpanComponentsV4.fromStr(context.parent);
|
|
18779
|
+
const hasParentSpan = Boolean(
|
|
18780
|
+
parent.data.row_id && parent.data.span_id && parent.data.root_span_id
|
|
18781
|
+
);
|
|
18782
|
+
return withCurrent(
|
|
18783
|
+
NOOP_SPAN,
|
|
18784
|
+
() => _internalStartSpanWithInitialMergeAndParentSpanIds(
|
|
18785
|
+
withSpanInstrumentationName(
|
|
18786
|
+
{
|
|
18787
|
+
name: "openai.batch",
|
|
18788
|
+
type: "task" /* TASK */,
|
|
18789
|
+
parent: context.parent,
|
|
18790
|
+
...!hasParentSpan ? {
|
|
18791
|
+
parentSpanIds: {
|
|
18792
|
+
parentSpanIds: [],
|
|
18793
|
+
rootSpanId: ids.rootSpanId
|
|
18794
|
+
}
|
|
18795
|
+
} : {},
|
|
18796
|
+
spanId: ids.spanId,
|
|
18797
|
+
startTime: context.taskStartTime,
|
|
18798
|
+
event: {
|
|
18799
|
+
id: ids.rowId,
|
|
18800
|
+
metadata: {
|
|
18801
|
+
endpoint: context.endpoint,
|
|
18802
|
+
input_file_id: context.inputFileId,
|
|
18803
|
+
provider: "openai"
|
|
18804
|
+
}
|
|
18805
|
+
}
|
|
18806
|
+
},
|
|
18807
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
18808
|
+
)
|
|
18809
|
+
)
|
|
18810
|
+
);
|
|
18811
|
+
}
|
|
18812
|
+
async function startBatchChild(context, taskParent, input) {
|
|
18813
|
+
const ids = await childSpanIds(context.inputFileId, input.customId);
|
|
18814
|
+
return withCurrent(
|
|
18815
|
+
NOOP_SPAN,
|
|
18816
|
+
() => _internalStartSpanWithInitialMerge(
|
|
18817
|
+
withSpanInstrumentationName(
|
|
18818
|
+
{
|
|
18819
|
+
name: context.endpoint === "/v1/chat/completions" ? "Chat Completion" : "openai.responses.create",
|
|
18820
|
+
type: "llm" /* LLM */,
|
|
18821
|
+
parent: taskParent,
|
|
18822
|
+
spanId: ids.spanId,
|
|
18823
|
+
startTime: context.childStartTime,
|
|
18824
|
+
event: {
|
|
18825
|
+
id: ids.rowId,
|
|
18826
|
+
...input.spanData?.input !== void 0 ? { input: input.spanData.input } : {},
|
|
18827
|
+
metadata: {
|
|
18828
|
+
...input.spanData?.metadata,
|
|
18829
|
+
custom_id: input.customId,
|
|
18830
|
+
provider: "openai"
|
|
18831
|
+
}
|
|
18832
|
+
}
|
|
18833
|
+
},
|
|
18834
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
18835
|
+
)
|
|
18836
|
+
)
|
|
18837
|
+
);
|
|
18838
|
+
}
|
|
18839
|
+
async function* jsonlRecords(file, onIssue = () => {
|
|
18840
|
+
}) {
|
|
18841
|
+
const resolvedFile = await file;
|
|
18842
|
+
if (typeof resolvedFile === "string") {
|
|
18843
|
+
for (const line of resolvedFile.split("\n")) {
|
|
18844
|
+
if (!line.trim()) {
|
|
18845
|
+
continue;
|
|
18846
|
+
}
|
|
18847
|
+
try {
|
|
18848
|
+
yield JSON.parse(line.replace(/\r$/, ""));
|
|
18849
|
+
} catch (error) {
|
|
18850
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
18851
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
18852
|
+
}
|
|
18853
|
+
}
|
|
18854
|
+
return;
|
|
18855
|
+
}
|
|
18856
|
+
const body = read(resolvedFile, "body");
|
|
18857
|
+
const getReader = read(body, "getReader");
|
|
18858
|
+
if (isObject(body) && typeof getReader === "function") {
|
|
18859
|
+
let reader;
|
|
18860
|
+
try {
|
|
18861
|
+
reader = Reflect.apply(getReader, body, []);
|
|
18862
|
+
const decoder = new TextDecoder();
|
|
18863
|
+
let pending = "";
|
|
18864
|
+
while (true) {
|
|
18865
|
+
const readChunk = read(reader, "read");
|
|
18866
|
+
if (typeof readChunk !== "function") {
|
|
18867
|
+
throw new Error("Response body stream has no read method");
|
|
18868
|
+
}
|
|
18869
|
+
const chunk = await Reflect.apply(readChunk, reader, []);
|
|
18870
|
+
if (!isObject(chunk)) {
|
|
18871
|
+
throw new Error("Response body stream returned an invalid chunk");
|
|
18872
|
+
}
|
|
18873
|
+
if (chunk.done === true) {
|
|
18874
|
+
pending += decoder.decode();
|
|
18875
|
+
break;
|
|
18876
|
+
}
|
|
18877
|
+
if (!(chunk.value instanceof Uint8Array)) {
|
|
18878
|
+
throw new Error("Response body stream returned a non-byte chunk");
|
|
18879
|
+
}
|
|
18880
|
+
pending += decoder.decode(chunk.value, { stream: true });
|
|
18881
|
+
let newline = pending.indexOf("\n");
|
|
18882
|
+
while (newline !== -1) {
|
|
18883
|
+
const line = pending.slice(0, newline).replace(/\r$/, "");
|
|
18884
|
+
pending = pending.slice(newline + 1);
|
|
18885
|
+
if (line.trim()) {
|
|
18886
|
+
try {
|
|
18887
|
+
yield JSON.parse(line);
|
|
18888
|
+
} catch (error) {
|
|
18889
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
18890
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
18891
|
+
}
|
|
18892
|
+
}
|
|
18893
|
+
newline = pending.indexOf("\n");
|
|
18894
|
+
}
|
|
18895
|
+
}
|
|
18896
|
+
if (pending.trim()) {
|
|
18897
|
+
try {
|
|
18898
|
+
yield JSON.parse(pending.replace(/\r$/, ""));
|
|
18899
|
+
} catch (error) {
|
|
18900
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
18901
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
18902
|
+
}
|
|
18903
|
+
}
|
|
18904
|
+
} catch (error) {
|
|
18905
|
+
logBatchInstrumentationError("could not read JSONL response body", error);
|
|
18906
|
+
onIssue(new Error("OpenAI Batch response body could not be read"));
|
|
18907
|
+
} finally {
|
|
18908
|
+
const releaseLock = read(reader, "releaseLock");
|
|
18909
|
+
if (typeof releaseLock === "function") {
|
|
18910
|
+
try {
|
|
18911
|
+
Reflect.apply(releaseLock, reader, []);
|
|
18912
|
+
} catch (error) {
|
|
18913
|
+
logBatchInstrumentationError(
|
|
18914
|
+
"could not release stream reader",
|
|
18915
|
+
error
|
|
18916
|
+
);
|
|
18917
|
+
}
|
|
18918
|
+
}
|
|
18919
|
+
}
|
|
18920
|
+
return;
|
|
18921
|
+
}
|
|
18922
|
+
if (isBatchRecordIterable(resolvedFile)) {
|
|
18923
|
+
for await (const record of resolvedFile) {
|
|
18924
|
+
yield record;
|
|
18925
|
+
}
|
|
18926
|
+
return;
|
|
18927
|
+
}
|
|
18928
|
+
logBatchInstrumentationError("skipped invalid JSONL source", resolvedFile);
|
|
18929
|
+
onIssue(new Error("OpenAI Batch file source is invalid"));
|
|
18930
|
+
}
|
|
18931
|
+
async function readBatchInputs(file) {
|
|
18932
|
+
const inputs = /* @__PURE__ */ new Map();
|
|
18933
|
+
const issues = [];
|
|
18934
|
+
let endpoint;
|
|
18935
|
+
try {
|
|
18936
|
+
for await (const value of jsonlRecords(
|
|
18937
|
+
file,
|
|
18938
|
+
(issue) => issues.push(issue)
|
|
18939
|
+
)) {
|
|
18940
|
+
const customId = read(value, "custom_id");
|
|
18941
|
+
const url = read(value, "url");
|
|
18942
|
+
const body = read(value, "body");
|
|
18943
|
+
if (!validCustomId(customId) || inputs.has(customId) || read(value, "method") !== "POST" || typeof url !== "string" || !SUPPORTED_ENDPOINTS.has(url) || endpoint !== void 0 && endpoint !== url || !isObject(body)) {
|
|
18944
|
+
issues.push(new Error("OpenAI Batch input contains an invalid record"));
|
|
18945
|
+
continue;
|
|
18946
|
+
}
|
|
18947
|
+
endpoint = url;
|
|
18948
|
+
let spanData;
|
|
18949
|
+
try {
|
|
18950
|
+
spanData = extractOpenAIBatchInput(url, body);
|
|
18951
|
+
} catch (error) {
|
|
18952
|
+
logBatchInstrumentationError("could not extract batch input", error);
|
|
18953
|
+
}
|
|
18954
|
+
inputs.set(customId, { customId, spanData });
|
|
18955
|
+
}
|
|
18956
|
+
} catch (error) {
|
|
18957
|
+
logBatchInstrumentationError("could not process input file", error);
|
|
18958
|
+
issues.push(new Error("OpenAI Batch input file could not be processed"));
|
|
18959
|
+
}
|
|
18960
|
+
if (!endpoint || inputs.size === 0) {
|
|
18961
|
+
issues.push(new Error("OpenAI Batch input contains no supported records"));
|
|
18962
|
+
}
|
|
18963
|
+
return { endpoint, inputs, issues };
|
|
18964
|
+
}
|
|
18965
|
+
async function writePendingSpans(trace, endTime) {
|
|
18966
|
+
const task = await startBatchSpan(trace.context);
|
|
18967
|
+
const taskParent = await task.export();
|
|
18968
|
+
for (const input of trace.inputs.values()) {
|
|
18969
|
+
try {
|
|
18970
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
18971
|
+
if (endTime !== void 0) {
|
|
18972
|
+
child.end({ endTime });
|
|
18973
|
+
}
|
|
18974
|
+
} catch (error) {
|
|
18975
|
+
logBatchInstrumentationError("could not write batch request span", error);
|
|
18976
|
+
}
|
|
18977
|
+
}
|
|
18978
|
+
if (endTime !== void 0) {
|
|
18979
|
+
if (trace.status && trace.status !== "completed") {
|
|
18980
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
18981
|
+
}
|
|
18982
|
+
task.end({ endTime });
|
|
18983
|
+
}
|
|
18984
|
+
}
|
|
18985
|
+
var interceptOpenAIFilesCreateTraced = async (target, thisArg, args) => {
|
|
18986
|
+
const startTime = getCurrentUnixTimestamp();
|
|
18987
|
+
const inputPromise = readBatchInputs(args[0].inputFileContent);
|
|
18988
|
+
const parentPromise = exportParent(args[0].parent);
|
|
18989
|
+
const file = await Reflect.apply(target, thisArg, args);
|
|
18990
|
+
try {
|
|
18991
|
+
const inputFileId = read(file, "id");
|
|
18992
|
+
const [inputData, exportedParent2] = await Promise.all([
|
|
18993
|
+
inputPromise,
|
|
18994
|
+
parentPromise
|
|
18995
|
+
]);
|
|
18996
|
+
if (typeof inputFileId !== "string" || !exportedParent2 || !inputData.endpoint || inputData.issues.length > 0) {
|
|
18997
|
+
if (inputData.issues[0]) {
|
|
18998
|
+
logBatchInstrumentationError(
|
|
18999
|
+
"skipped invalid input file",
|
|
19000
|
+
inputData.issues[0]
|
|
19001
|
+
);
|
|
19002
|
+
}
|
|
19003
|
+
return file;
|
|
19004
|
+
}
|
|
19005
|
+
const trace = {
|
|
19006
|
+
context: {
|
|
19007
|
+
inputFileId,
|
|
19008
|
+
endpoint: inputData.endpoint,
|
|
19009
|
+
parent: exportedParent2,
|
|
19010
|
+
taskStartTime: startTime,
|
|
19011
|
+
childStartTime: startTime
|
|
19012
|
+
},
|
|
19013
|
+
inputs: inputData.inputs
|
|
19014
|
+
};
|
|
19015
|
+
pendingBatchTraces.set(inputFileId, trace);
|
|
19016
|
+
await writePendingSpans(trace);
|
|
19017
|
+
} catch (error) {
|
|
19018
|
+
logBatchInstrumentationError("could not start batch spans", error);
|
|
19019
|
+
}
|
|
19020
|
+
return file;
|
|
19021
|
+
};
|
|
19022
|
+
function validTimestamp(value) {
|
|
19023
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
19024
|
+
}
|
|
19025
|
+
function terminalEndTime(batch, startTime) {
|
|
19026
|
+
let timestamp;
|
|
19027
|
+
switch (batch.status) {
|
|
19028
|
+
case "completed":
|
|
19029
|
+
timestamp = batch.completed_at;
|
|
19030
|
+
break;
|
|
19031
|
+
case "failed":
|
|
19032
|
+
timestamp = batch.failed_at;
|
|
19033
|
+
break;
|
|
19034
|
+
case "expired":
|
|
19035
|
+
timestamp = batch.expired_at;
|
|
19036
|
+
break;
|
|
19037
|
+
default:
|
|
19038
|
+
timestamp = batch.cancelled_at;
|
|
19039
|
+
}
|
|
19040
|
+
return validTimestamp(timestamp) ? Math.max(timestamp, startTime) : Math.max(getCurrentUnixTimestamp(), startTime);
|
|
19041
|
+
}
|
|
19042
|
+
async function updateBatchTimestamps(batch) {
|
|
19043
|
+
const trace = pendingBatchTraces.get(batch.input_file_id);
|
|
19044
|
+
if (!trace || trace.context.endpoint !== batch.endpoint) {
|
|
19045
|
+
return;
|
|
19046
|
+
}
|
|
19047
|
+
if (validTimestamp(batch.created_at)) {
|
|
19048
|
+
trace.context.taskStartTime = batch.created_at;
|
|
19049
|
+
}
|
|
19050
|
+
trace.context.childStartTime = validTimestamp(batch.in_progress_at) ? Math.max(batch.in_progress_at, trace.context.taskStartTime) : trace.context.taskStartTime;
|
|
19051
|
+
trace.status = batch.status;
|
|
19052
|
+
if (TERMINAL_STATUSES.has(batch.status)) {
|
|
19053
|
+
trace.endTime = terminalEndTime(batch, trace.context.childStartTime);
|
|
19054
|
+
}
|
|
19055
|
+
await writePendingSpans(trace, trace.endTime);
|
|
19056
|
+
}
|
|
19057
|
+
var interceptOpenAIBatchesRetrieveTraced = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (batch) => {
|
|
19058
|
+
try {
|
|
19059
|
+
await updateBatchTimestamps(batch);
|
|
19060
|
+
} catch (error) {
|
|
19061
|
+
logBatchInstrumentationError("could not update batch timestamps", error);
|
|
19062
|
+
}
|
|
19063
|
+
return batch;
|
|
19064
|
+
});
|
|
19065
|
+
function errorFromResult(result) {
|
|
19066
|
+
const error = read(result.value, "error");
|
|
19067
|
+
if (isObject(error)) {
|
|
19068
|
+
const message = read(error, "message");
|
|
19069
|
+
return new Error(
|
|
19070
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
19071
|
+
);
|
|
19072
|
+
}
|
|
19073
|
+
const response = read(result.value, "response");
|
|
19074
|
+
const statusCode = read(response, "status_code");
|
|
19075
|
+
if (result.source === "error" || typeof statusCode === "number" && (statusCode < 200 || statusCode >= 300)) {
|
|
19076
|
+
const message = read(read(read(response, "body"), "error"), "message");
|
|
19077
|
+
return new Error(
|
|
19078
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
19079
|
+
);
|
|
19080
|
+
}
|
|
19081
|
+
return void 0;
|
|
19082
|
+
}
|
|
19083
|
+
async function completeBatchResult(context, taskParent, endTime, input, result) {
|
|
19084
|
+
const child = await startBatchChild(context, taskParent, input);
|
|
19085
|
+
try {
|
|
19086
|
+
const resultError = errorFromResult(result);
|
|
19087
|
+
const responseBody = read(read(result.value, "response"), "body");
|
|
19088
|
+
if (resultError) {
|
|
19089
|
+
child.log({ error: resultError });
|
|
19090
|
+
} else if (isObject(responseBody)) {
|
|
19091
|
+
const model = read(responseBody, "model");
|
|
19092
|
+
child.log({
|
|
19093
|
+
output: context.endpoint === "/v1/chat/completions" ? read(responseBody, "choices") : processImagesInOutput(read(responseBody, "output")),
|
|
19094
|
+
...typeof model === "string" ? { metadata: { model } } : {},
|
|
19095
|
+
metrics: parseMetricsFromUsage(read(responseBody, "usage"))
|
|
19096
|
+
});
|
|
19097
|
+
} else {
|
|
19098
|
+
child.log({ error: new Error("OpenAI Batch response body is missing") });
|
|
19099
|
+
}
|
|
19100
|
+
} catch (error) {
|
|
19101
|
+
child.log({ error });
|
|
19102
|
+
} finally {
|
|
19103
|
+
child.end({ endTime });
|
|
19104
|
+
}
|
|
19105
|
+
}
|
|
19106
|
+
async function completeResultFile({
|
|
19107
|
+
context,
|
|
19108
|
+
endTime,
|
|
19109
|
+
file,
|
|
19110
|
+
inputs,
|
|
19111
|
+
issues,
|
|
19112
|
+
seen,
|
|
19113
|
+
source,
|
|
19114
|
+
taskParent
|
|
19115
|
+
}) {
|
|
19116
|
+
if (file === void 0) {
|
|
19117
|
+
return;
|
|
19118
|
+
}
|
|
19119
|
+
for await (const value of jsonlRecords(file, (issue) => issues.push(issue))) {
|
|
19120
|
+
const customId = read(value, "custom_id");
|
|
19121
|
+
if (!validCustomId(customId) || !isObject(value)) {
|
|
19122
|
+
issues.push(
|
|
19123
|
+
new Error("OpenAI Batch result is missing a valid custom_id")
|
|
19124
|
+
);
|
|
19125
|
+
continue;
|
|
19126
|
+
}
|
|
19127
|
+
if (seen.has(customId)) {
|
|
19128
|
+
issues.push(new Error("OpenAI Batch result contains a duplicate"));
|
|
19129
|
+
continue;
|
|
19130
|
+
}
|
|
19131
|
+
const input = inputs.get(customId);
|
|
19132
|
+
if (!input) {
|
|
19133
|
+
issues.push(
|
|
19134
|
+
new Error("OpenAI Batch result does not match an input record")
|
|
19135
|
+
);
|
|
19136
|
+
continue;
|
|
19137
|
+
}
|
|
19138
|
+
seen.add(customId);
|
|
19139
|
+
await completeBatchResult(context, taskParent, endTime, input, {
|
|
19140
|
+
value,
|
|
19141
|
+
source
|
|
19142
|
+
});
|
|
19143
|
+
}
|
|
19144
|
+
}
|
|
19145
|
+
function sameInputs(first, second) {
|
|
19146
|
+
return first.size === second.size && [...first.keys()].every((customId) => second.has(customId));
|
|
19147
|
+
}
|
|
19148
|
+
async function contextForCompletion(inputFileId, inputData) {
|
|
19149
|
+
if (!inputData.endpoint || inputData.issues.length > 0) {
|
|
19150
|
+
return void 0;
|
|
19151
|
+
}
|
|
19152
|
+
const existing = pendingBatchTraces.get(inputFileId);
|
|
19153
|
+
if (existing) {
|
|
19154
|
+
if (existing.context.endpoint !== inputData.endpoint || !sameInputs(existing.inputs, inputData.inputs)) {
|
|
19155
|
+
return void 0;
|
|
19156
|
+
}
|
|
19157
|
+
return { ...existing, inputs: inputData.inputs };
|
|
19158
|
+
}
|
|
19159
|
+
const parent = await exportParent(getSpanParentObject());
|
|
19160
|
+
if (!parent) {
|
|
19161
|
+
return void 0;
|
|
19162
|
+
}
|
|
19163
|
+
const startTime = getCurrentUnixTimestamp();
|
|
19164
|
+
return {
|
|
19165
|
+
context: {
|
|
19166
|
+
inputFileId,
|
|
19167
|
+
endpoint: inputData.endpoint,
|
|
19168
|
+
parent,
|
|
19169
|
+
taskStartTime: startTime,
|
|
19170
|
+
childStartTime: startTime
|
|
19171
|
+
},
|
|
19172
|
+
inputs: inputData.inputs
|
|
19173
|
+
};
|
|
19174
|
+
}
|
|
19175
|
+
async function completeBatch(args) {
|
|
19176
|
+
const inputData = await readBatchInputs(args.inputFileContent);
|
|
19177
|
+
const trace = await contextForCompletion(args.inputFileId, inputData);
|
|
19178
|
+
if (!trace) {
|
|
19179
|
+
logBatchInstrumentationError(
|
|
19180
|
+
"left batch spans pending",
|
|
19181
|
+
inputData.issues[0] ?? new Error("OpenAI Batch input does not match")
|
|
19182
|
+
);
|
|
19183
|
+
return;
|
|
19184
|
+
}
|
|
19185
|
+
const endTime = trace.endTime ?? getCurrentUnixTimestamp();
|
|
19186
|
+
const task = await startBatchSpan(trace.context);
|
|
19187
|
+
const taskParent = await task.export();
|
|
19188
|
+
const issues = [];
|
|
19189
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19190
|
+
await Promise.all([
|
|
19191
|
+
completeResultFile({
|
|
19192
|
+
context: trace.context,
|
|
19193
|
+
endTime,
|
|
19194
|
+
file: args.outputFileContent,
|
|
19195
|
+
inputs: trace.inputs,
|
|
19196
|
+
issues,
|
|
19197
|
+
seen,
|
|
19198
|
+
source: "output",
|
|
19199
|
+
taskParent
|
|
19200
|
+
}),
|
|
19201
|
+
completeResultFile({
|
|
19202
|
+
context: trace.context,
|
|
19203
|
+
endTime,
|
|
19204
|
+
file: args.errorFileContent,
|
|
19205
|
+
inputs: trace.inputs,
|
|
19206
|
+
issues,
|
|
19207
|
+
seen,
|
|
19208
|
+
source: "error",
|
|
19209
|
+
taskParent
|
|
19210
|
+
})
|
|
19211
|
+
]);
|
|
19212
|
+
if (issues.length > 0) {
|
|
19213
|
+
logBatchInstrumentationError("left batch spans pending", issues[0]);
|
|
19214
|
+
return;
|
|
19215
|
+
}
|
|
19216
|
+
const missing = [...trace.inputs.values()].filter(
|
|
19217
|
+
({ customId }) => !seen.has(customId)
|
|
19218
|
+
);
|
|
19219
|
+
if (!trace.status || trace.status === "completed") {
|
|
19220
|
+
if (missing.length > 0) {
|
|
19221
|
+
logBatchInstrumentationError(
|
|
19222
|
+
"left batch spans pending",
|
|
19223
|
+
new Error("OpenAI Batch result files are incomplete")
|
|
19224
|
+
);
|
|
19225
|
+
return;
|
|
19226
|
+
}
|
|
19227
|
+
} else {
|
|
19228
|
+
for (const input of missing) {
|
|
19229
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
19230
|
+
child.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
19231
|
+
child.end({ endTime });
|
|
19232
|
+
}
|
|
19233
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
19234
|
+
}
|
|
19235
|
+
task.end({ endTime });
|
|
19236
|
+
pendingBatchTraces.delete(args.inputFileId);
|
|
19237
|
+
}
|
|
19238
|
+
var interceptOpenAIBatchTraceComplete = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (result) => {
|
|
19239
|
+
try {
|
|
19240
|
+
await completeBatch(args[0]);
|
|
19241
|
+
} catch (error) {
|
|
19242
|
+
logBatchInstrumentationError("could not complete batch", error);
|
|
19243
|
+
}
|
|
19244
|
+
return result;
|
|
19245
|
+
});
|
|
19246
|
+
|
|
18596
19247
|
// src/instrumentation/plugins/openai-plugin.ts
|
|
18597
19248
|
var OpenAIPlugin = class extends BasePlugin {
|
|
18598
19249
|
constructor() {
|
|
18599
19250
|
super();
|
|
18600
19251
|
}
|
|
18601
19252
|
onEnable() {
|
|
19253
|
+
this.unsubscribers.push(
|
|
19254
|
+
openAIChannels.filesCreateTraced.intercept(
|
|
19255
|
+
interceptOpenAIFilesCreateTraced
|
|
19256
|
+
),
|
|
19257
|
+
openAIChannels.batchesRetrieveTraced.intercept(
|
|
19258
|
+
interceptOpenAIBatchesRetrieveTraced
|
|
19259
|
+
),
|
|
19260
|
+
openAIChannels.batchesCompleteTrace.intercept(
|
|
19261
|
+
interceptOpenAIBatchTraceComplete
|
|
19262
|
+
)
|
|
19263
|
+
);
|
|
18602
19264
|
this.unsubscribers.push(
|
|
18603
19265
|
traceStreamingChannel(openAIChannels.chatCompletionsCreate, {
|
|
18604
19266
|
name: "Chat Completion",
|
|
18605
19267
|
type: "llm" /* LLM */,
|
|
18606
|
-
extractInput: ([params]) =>
|
|
18607
|
-
const { messages, ...metadata } = params;
|
|
18608
|
-
return {
|
|
18609
|
-
input: processInputAttachments(messages),
|
|
18610
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18611
|
-
};
|
|
18612
|
-
},
|
|
19268
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
18613
19269
|
extractOutput: (result) => {
|
|
18614
19270
|
return result?.choices;
|
|
18615
19271
|
},
|
|
@@ -18655,13 +19311,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
18655
19311
|
traceStreamingChannel(openAIChannels.betaChatCompletionsParse, {
|
|
18656
19312
|
name: "Chat Completion",
|
|
18657
19313
|
type: "llm" /* LLM */,
|
|
18658
|
-
extractInput: ([params]) =>
|
|
18659
|
-
const { messages, ...metadata } = params;
|
|
18660
|
-
return {
|
|
18661
|
-
input: processInputAttachments(messages),
|
|
18662
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18663
|
-
};
|
|
18664
|
-
},
|
|
19314
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
18665
19315
|
extractOutput: (result) => {
|
|
18666
19316
|
return result?.choices;
|
|
18667
19317
|
},
|
|
@@ -18683,13 +19333,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
18683
19333
|
traceSyncStreamChannel(openAIChannels.betaChatCompletionsStream, {
|
|
18684
19334
|
name: "Chat Completion",
|
|
18685
19335
|
type: "llm" /* LLM */,
|
|
18686
|
-
extractInput: ([params]) =>
|
|
18687
|
-
const { messages, ...metadata } = params;
|
|
18688
|
-
return {
|
|
18689
|
-
input: processInputAttachments(messages),
|
|
18690
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18691
|
-
};
|
|
18692
|
-
}
|
|
19336
|
+
extractInput: ([params]) => extractOpenAIChatInput(params)
|
|
18693
19337
|
})
|
|
18694
19338
|
);
|
|
18695
19339
|
this.unsubscribers.push(
|
|
@@ -18719,23 +19363,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
18719
19363
|
traceStreamingChannel(openAIChannels.responsesCreate, {
|
|
18720
19364
|
name: "openai.responses.create",
|
|
18721
19365
|
type: "llm" /* LLM */,
|
|
18722
|
-
extractInput: ([params]) =>
|
|
18723
|
-
const { input, ...metadata } = params;
|
|
18724
|
-
return {
|
|
18725
|
-
input: processInputAttachments(input),
|
|
18726
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18727
|
-
};
|
|
18728
|
-
},
|
|
19366
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
18729
19367
|
extractOutput: (result) => {
|
|
18730
19368
|
return processImagesInOutput(result?.output);
|
|
18731
19369
|
},
|
|
18732
|
-
extractMetadata: (result) =>
|
|
18733
|
-
if (!result) {
|
|
18734
|
-
return void 0;
|
|
18735
|
-
}
|
|
18736
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
18737
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
18738
|
-
},
|
|
19370
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
18739
19371
|
extractMetrics: (result, startTime, endEvent) => {
|
|
18740
19372
|
const metrics = withCachedMetric(
|
|
18741
19373
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -18754,13 +19386,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
18754
19386
|
traceSyncStreamChannel(openAIChannels.responsesStream, {
|
|
18755
19387
|
name: "openai.responses.create",
|
|
18756
19388
|
type: "llm" /* LLM */,
|
|
18757
|
-
extractInput: ([params]) =>
|
|
18758
|
-
const { input, ...metadata } = params;
|
|
18759
|
-
return {
|
|
18760
|
-
input: processInputAttachments(input),
|
|
18761
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18762
|
-
};
|
|
18763
|
-
},
|
|
19389
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
18764
19390
|
extractFromEvent: (event) => {
|
|
18765
19391
|
if (event.type !== "response.completed" || !event.response) {
|
|
18766
19392
|
return {};
|
|
@@ -18783,23 +19409,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
18783
19409
|
traceStreamingChannel(openAIChannels.responsesParse, {
|
|
18784
19410
|
name: "openai.responses.parse",
|
|
18785
19411
|
type: "llm" /* LLM */,
|
|
18786
|
-
extractInput: ([params]) =>
|
|
18787
|
-
const { input, ...metadata } = params;
|
|
18788
|
-
return {
|
|
18789
|
-
input: processInputAttachments(input),
|
|
18790
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18791
|
-
};
|
|
18792
|
-
},
|
|
19412
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
18793
19413
|
extractOutput: (result) => {
|
|
18794
19414
|
return processImagesInOutput(result?.output);
|
|
18795
19415
|
},
|
|
18796
|
-
extractMetadata: (result) =>
|
|
18797
|
-
if (!result) {
|
|
18798
|
-
return void 0;
|
|
18799
|
-
}
|
|
18800
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
18801
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
18802
|
-
},
|
|
19416
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
18803
19417
|
extractMetrics: (result, startTime, endEvent) => {
|
|
18804
19418
|
const metrics = withCachedMetric(
|
|
18805
19419
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -18818,23 +19432,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
18818
19432
|
traceAsyncChannel(openAIChannels.responsesCompact, {
|
|
18819
19433
|
name: "openai.responses.compact",
|
|
18820
19434
|
type: "llm" /* LLM */,
|
|
18821
|
-
extractInput: ([params]) =>
|
|
18822
|
-
const { input, ...metadata } = params;
|
|
18823
|
-
return {
|
|
18824
|
-
input: processInputAttachments(input),
|
|
18825
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18826
|
-
};
|
|
18827
|
-
},
|
|
19435
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
18828
19436
|
extractOutput: (result) => {
|
|
18829
19437
|
return processImagesInOutput(result?.output);
|
|
18830
19438
|
},
|
|
18831
|
-
extractMetadata: (result) =>
|
|
18832
|
-
if (!result) {
|
|
18833
|
-
return void 0;
|
|
18834
|
-
}
|
|
18835
|
-
const { output: _output, usage: _usage, ...metadata } = result;
|
|
18836
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
18837
|
-
},
|
|
19439
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
18838
19440
|
extractMetrics: (result, startTime, endEvent) => {
|
|
18839
19441
|
const metrics = withCachedMetric(
|
|
18840
19442
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -18890,35 +19492,6 @@ function withCachedMetric(metrics, result, endEvent) {
|
|
|
18890
19492
|
cached
|
|
18891
19493
|
};
|
|
18892
19494
|
}
|
|
18893
|
-
function processImagesInOutput(output) {
|
|
18894
|
-
if (Array.isArray(output)) {
|
|
18895
|
-
return output.map(processImagesInOutput);
|
|
18896
|
-
}
|
|
18897
|
-
if (isObject(output)) {
|
|
18898
|
-
if (output.type === "image_generation_call" && output.result && typeof output.result === "string") {
|
|
18899
|
-
const fileExtension = output.output_format || "png";
|
|
18900
|
-
const contentType = `image/${fileExtension}`;
|
|
18901
|
-
const baseFilename = output.revised_prompt && typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
18902
|
-
const filename = `${baseFilename}.${fileExtension}`;
|
|
18903
|
-
const binaryString = atob(output.result);
|
|
18904
|
-
const bytes = new Uint8Array(binaryString.length);
|
|
18905
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
18906
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
18907
|
-
}
|
|
18908
|
-
const blob = new Blob([bytes], { type: contentType });
|
|
18909
|
-
const attachment = new Attachment({
|
|
18910
|
-
data: blob,
|
|
18911
|
-
filename,
|
|
18912
|
-
contentType
|
|
18913
|
-
});
|
|
18914
|
-
return {
|
|
18915
|
-
...output,
|
|
18916
|
-
result: attachment
|
|
18917
|
-
};
|
|
18918
|
-
}
|
|
18919
|
-
}
|
|
18920
|
-
return output;
|
|
18921
|
-
}
|
|
18922
19495
|
function mergeLogprobTokens(existing, incoming) {
|
|
18923
19496
|
if (incoming === void 0) {
|
|
18924
19497
|
return existing;
|
|
@@ -32442,7 +33015,7 @@ function extractSession(event) {
|
|
|
32442
33015
|
return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
|
|
32443
33016
|
}
|
|
32444
33017
|
function isPiAgent(value) {
|
|
32445
|
-
return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
|
|
33018
|
+
return isObject(value) && (typeof value.streamFunction === "function" || typeof value.streamFn === "function") && typeof value.subscribe === "function";
|
|
32446
33019
|
}
|
|
32447
33020
|
function promptContextStore() {
|
|
32448
33021
|
piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
|
|
@@ -32452,17 +33025,21 @@ function currentPiPromptState() {
|
|
|
32452
33025
|
return promptContextStore().getStore();
|
|
32453
33026
|
}
|
|
32454
33027
|
function installPiAgentInstrumentation(agent) {
|
|
33028
|
+
const property = typeof agent.streamFunction === "function" ? "streamFunction" : "streamFn";
|
|
33029
|
+
const streamFunction = agent[property];
|
|
32455
33030
|
const existing = piAgentPatchStates.get(agent);
|
|
32456
|
-
if (!existing ||
|
|
33031
|
+
if (streamFunction && (!existing || existing.property !== property || streamFunction !== existing.wrappedStreamFunction)) {
|
|
32457
33032
|
const patchState = {
|
|
32458
|
-
|
|
32459
|
-
|
|
33033
|
+
originalStreamFunction: streamFunction,
|
|
33034
|
+
property,
|
|
33035
|
+
wrappedStreamFunction: streamFunction
|
|
32460
33036
|
};
|
|
32461
|
-
patchState.
|
|
33037
|
+
patchState.wrappedStreamFunction = makeInstrumentedStreamFunction(
|
|
32462
33038
|
agent,
|
|
32463
|
-
patchState.
|
|
33039
|
+
patchState.originalStreamFunction,
|
|
33040
|
+
property
|
|
32464
33041
|
);
|
|
32465
|
-
agent
|
|
33042
|
+
agent[property] = patchState.wrappedStreamFunction;
|
|
32466
33043
|
piAgentPatchStates.set(agent, patchState);
|
|
32467
33044
|
}
|
|
32468
33045
|
if (piAgentEventSubscriptions.has(agent)) {
|
|
@@ -32487,15 +33064,21 @@ function installPiAgentInstrumentation(agent) {
|
|
|
32487
33064
|
logInstrumentationError4("Pi Coding Agent event subscription", error);
|
|
32488
33065
|
}
|
|
32489
33066
|
}
|
|
32490
|
-
function
|
|
32491
|
-
return async function
|
|
32492
|
-
const invokeOriginal = () => Reflect.apply(
|
|
33067
|
+
function makeInstrumentedStreamFunction(agent, originalStreamFunction, property) {
|
|
33068
|
+
return async function instrumentedPiStreamFunction(model, context, options) {
|
|
33069
|
+
const invokeOriginal = () => Reflect.apply(originalStreamFunction, this, [model, context, options]);
|
|
32493
33070
|
const state = currentPiPromptState();
|
|
32494
33071
|
if (!state || state.agent !== agent || state.finalized) {
|
|
32495
33072
|
return invokeOriginal();
|
|
32496
33073
|
}
|
|
32497
33074
|
wrapPiToolExecutors(context.tools);
|
|
32498
|
-
const llmState = await startPiLlmSpan(
|
|
33075
|
+
const llmState = await startPiLlmSpan(
|
|
33076
|
+
state,
|
|
33077
|
+
model,
|
|
33078
|
+
context,
|
|
33079
|
+
property,
|
|
33080
|
+
options
|
|
33081
|
+
);
|
|
32499
33082
|
try {
|
|
32500
33083
|
const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
|
|
32501
33084
|
return patchAssistantMessageStream(stream, state, llmState);
|
|
@@ -32532,12 +33115,12 @@ function wrapPiToolExecutors(tools) {
|
|
|
32532
33115
|
}
|
|
32533
33116
|
}
|
|
32534
33117
|
}
|
|
32535
|
-
async function startPiLlmSpan(state, model, context, options) {
|
|
33118
|
+
async function startPiLlmSpan(state, model, context, property, options) {
|
|
32536
33119
|
const metadata = {
|
|
32537
33120
|
...extractModelMetadata2(model),
|
|
32538
33121
|
...extractStreamOptionsMetadata(options),
|
|
32539
33122
|
...extractToolMetadata(context.tools),
|
|
32540
|
-
"pi_coding_agent.operation":
|
|
33123
|
+
"pi_coding_agent.operation": `agent.${property}`
|
|
32541
33124
|
};
|
|
32542
33125
|
const span = startSpan(
|
|
32543
33126
|
withSpanInstrumentationName(
|