braintrust 3.29.0 → 3.30.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.js +1465 -881
- package/dev/dist/index.mjs +846 -262
- 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 +13 -1
- package/dist/auto-instrumentations/bundler/next.mjs +3 -3
- 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 +16 -4
- package/dist/auto-instrumentations/index.cjs +13 -1
- package/dist/auto-instrumentations/index.mjs +1 -1
- package/dist/browser.d.mts +133 -2
- package/dist/browser.d.ts +133 -2
- package/dist/browser.js +1143 -297
- package/dist/browser.mjs +1143 -297
- package/dist/{chunk-6Z5S7VOU.js → chunk-2XDW3UCG.js} +13 -1
- package/dist/{chunk-M6XPNJC4.mjs → chunk-BU6SM54N.mjs} +687 -115
- package/dist/{chunk-7FA6VP2S.mjs → chunk-N3JKQ3D3.mjs} +13 -1
- package/dist/{chunk-XLLGRXGR.js → chunk-TWCDSYJN.js} +1803 -1231
- package/dist/cli.js +819 -235
- package/dist/edge-light.d.mts +1 -1
- package/dist/edge-light.d.ts +1 -1
- package/dist/edge-light.js +1143 -297
- package/dist/edge-light.mjs +1143 -297
- package/dist/index.d.mts +133 -2
- package/dist/index.d.ts +133 -2
- package/dist/index.js +902 -640
- package/dist/index.mjs +336 -74
- package/dist/instrumentation/index.d.mts +15 -0
- package/dist/instrumentation/index.d.ts +15 -0
- package/dist/instrumentation/index.js +857 -262
- package/dist/instrumentation/index.mjs +857 -262
- 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 +1143 -297
- package/dist/workerd.mjs +1143 -297
- 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-N3JKQ3D3.mjs";
|
|
56
56
|
|
|
57
57
|
// src/id-gen.ts
|
|
58
58
|
import { v4 as uuidv4 } from "uuid";
|
|
@@ -9030,6 +9030,15 @@ function _internalStartSpanWithInitialMerge(args) {
|
|
|
9030
9030
|
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
9031
9031
|
}).span;
|
|
9032
9032
|
}
|
|
9033
|
+
function _internalStartSpanWithInitialMergeAndParentSpanIds(args) {
|
|
9034
|
+
return startSpanAndIsLogger(
|
|
9035
|
+
{
|
|
9036
|
+
...args,
|
|
9037
|
+
[INITIAL_SPAN_WRITE_AS_MERGE]: true
|
|
9038
|
+
},
|
|
9039
|
+
{ useParentSpanIdsForObjectParent: true }
|
|
9040
|
+
).span;
|
|
9041
|
+
}
|
|
9033
9042
|
function _internalStartSpanWithContext(args, context) {
|
|
9034
9043
|
return startSpanAndIsLogger({
|
|
9035
9044
|
...args,
|
|
@@ -9043,7 +9052,7 @@ async function flush(options) {
|
|
|
9043
9052
|
function setFetch(fetch2) {
|
|
9044
9053
|
_internalGetGlobalState().setFetch(fetch2);
|
|
9045
9054
|
}
|
|
9046
|
-
function startSpanAndIsLogger(args) {
|
|
9055
|
+
function startSpanAndIsLogger(args, internalOptions) {
|
|
9047
9056
|
const state = args?.state ?? _globalState;
|
|
9048
9057
|
const { parentObject, propagatedState } = getSpanParentObjectAndPropagatedState({
|
|
9049
9058
|
asyncFlush: args?.asyncFlush,
|
|
@@ -9057,7 +9066,7 @@ function startSpanAndIsLogger(args) {
|
|
|
9057
9066
|
) ? {
|
|
9058
9067
|
spanId: parentObject.data.span_id,
|
|
9059
9068
|
rootSpanId: parentObject.data.root_span_id
|
|
9060
|
-
} : void 0;
|
|
9069
|
+
} : internalOptions?.useParentSpanIdsForObjectParent ? args?.parentSpanIds : void 0;
|
|
9061
9070
|
const { parent: _ignoredParent, ...spanArgs } = args ?? {};
|
|
9062
9071
|
const span = new SpanImpl({
|
|
9063
9072
|
state,
|
|
@@ -18593,23 +18602,659 @@ function isRecord(value) {
|
|
|
18593
18602
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18594
18603
|
}
|
|
18595
18604
|
|
|
18605
|
+
// src/instrumentation/plugins/openai-span-data.ts
|
|
18606
|
+
var OPENAI_METADATA_KEYS = [
|
|
18607
|
+
"model",
|
|
18608
|
+
"temperature",
|
|
18609
|
+
"top_p",
|
|
18610
|
+
"max_tokens",
|
|
18611
|
+
"frequency_penalty",
|
|
18612
|
+
"presence_penalty",
|
|
18613
|
+
"stop",
|
|
18614
|
+
"response_format",
|
|
18615
|
+
"tools",
|
|
18616
|
+
"tool_choice",
|
|
18617
|
+
"parallel_tool_calls",
|
|
18618
|
+
"max_tool_calls"
|
|
18619
|
+
];
|
|
18620
|
+
function batchMetadata(params) {
|
|
18621
|
+
const metadata = { provider: "openai" };
|
|
18622
|
+
for (const key of OPENAI_METADATA_KEYS) {
|
|
18623
|
+
try {
|
|
18624
|
+
const value = Reflect.get(params, key);
|
|
18625
|
+
if (value !== void 0) {
|
|
18626
|
+
metadata[key] = value;
|
|
18627
|
+
}
|
|
18628
|
+
} catch {
|
|
18629
|
+
}
|
|
18630
|
+
}
|
|
18631
|
+
return metadata;
|
|
18632
|
+
}
|
|
18633
|
+
function extractOpenAIBatchInput(endpoint, params) {
|
|
18634
|
+
const input = endpoint === "/v1/chat/completions" ? params.messages : params.input;
|
|
18635
|
+
return {
|
|
18636
|
+
input: processInputAttachments(input),
|
|
18637
|
+
metadata: batchMetadata(params)
|
|
18638
|
+
};
|
|
18639
|
+
}
|
|
18640
|
+
function extractOpenAIChatInput(params) {
|
|
18641
|
+
const { messages, ...metadata } = params;
|
|
18642
|
+
return {
|
|
18643
|
+
input: processInputAttachments(messages),
|
|
18644
|
+
metadata: { ...metadata, provider: "openai" }
|
|
18645
|
+
};
|
|
18646
|
+
}
|
|
18647
|
+
function extractOpenAIResponsesInput(params) {
|
|
18648
|
+
const { input, ...metadata } = params;
|
|
18649
|
+
return {
|
|
18650
|
+
input: processInputAttachments(input),
|
|
18651
|
+
metadata: { ...metadata, provider: "openai" }
|
|
18652
|
+
};
|
|
18653
|
+
}
|
|
18654
|
+
function extractOpenAIResponsesMetadata(result) {
|
|
18655
|
+
if (!result) {
|
|
18656
|
+
return void 0;
|
|
18657
|
+
}
|
|
18658
|
+
const { output: _output, usage: _usage, ...metadata } = result;
|
|
18659
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
18660
|
+
}
|
|
18661
|
+
function processImagesInOutput(output) {
|
|
18662
|
+
if (Array.isArray(output)) {
|
|
18663
|
+
return output.map(processImagesInOutput);
|
|
18664
|
+
}
|
|
18665
|
+
if (isObject(output) && output.type === "image_generation_call" && typeof output.result === "string" && output.result) {
|
|
18666
|
+
const fileExtension = output.output_format || "png";
|
|
18667
|
+
const contentType = `image/${fileExtension}`;
|
|
18668
|
+
const baseFilename = typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
|
|
18669
|
+
let binaryString;
|
|
18670
|
+
try {
|
|
18671
|
+
binaryString = atob(output.result);
|
|
18672
|
+
} catch {
|
|
18673
|
+
return output;
|
|
18674
|
+
}
|
|
18675
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
18676
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
18677
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
18678
|
+
}
|
|
18679
|
+
return {
|
|
18680
|
+
...output,
|
|
18681
|
+
result: new Attachment({
|
|
18682
|
+
data: new Blob([bytes], { type: contentType }),
|
|
18683
|
+
filename: `${baseFilename}.${fileExtension}`,
|
|
18684
|
+
contentType
|
|
18685
|
+
})
|
|
18686
|
+
};
|
|
18687
|
+
}
|
|
18688
|
+
return output;
|
|
18689
|
+
}
|
|
18690
|
+
|
|
18691
|
+
// src/instrumentation/plugins/openai-batch-instrumentation.ts
|
|
18692
|
+
var SUPPORTED_ENDPOINTS = /* @__PURE__ */ new Set(["/v1/chat/completions", "/v1/responses"]);
|
|
18693
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
18694
|
+
"completed",
|
|
18695
|
+
"failed",
|
|
18696
|
+
"expired",
|
|
18697
|
+
"cancelled"
|
|
18698
|
+
]);
|
|
18699
|
+
var pendingBatchTraces = /* @__PURE__ */ new Map();
|
|
18700
|
+
function read(value, key) {
|
|
18701
|
+
if (!isObject(value)) {
|
|
18702
|
+
return void 0;
|
|
18703
|
+
}
|
|
18704
|
+
try {
|
|
18705
|
+
return Reflect.get(value, key);
|
|
18706
|
+
} catch {
|
|
18707
|
+
return void 0;
|
|
18708
|
+
}
|
|
18709
|
+
}
|
|
18710
|
+
function isBatchRecordIterable(value) {
|
|
18711
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") {
|
|
18712
|
+
return false;
|
|
18713
|
+
}
|
|
18714
|
+
return typeof read(value, Symbol.iterator) === "function" || typeof read(value, Symbol.asyncIterator) === "function";
|
|
18715
|
+
}
|
|
18716
|
+
function validCustomId(value) {
|
|
18717
|
+
return typeof value === "string" && value.length > 0 && value.length <= 64;
|
|
18718
|
+
}
|
|
18719
|
+
function logBatchInstrumentationError(context, error) {
|
|
18720
|
+
debugLogger.debug(`OpenAI Batch instrumentation ${context}:`, error);
|
|
18721
|
+
}
|
|
18722
|
+
async function exportParent(parent) {
|
|
18723
|
+
if ("toStr" in parent && typeof parent.toStr === "function") {
|
|
18724
|
+
return parent.toStr();
|
|
18725
|
+
}
|
|
18726
|
+
if ("export" in parent && typeof parent.export === "function") {
|
|
18727
|
+
return await parent.export();
|
|
18728
|
+
}
|
|
18729
|
+
return void 0;
|
|
18730
|
+
}
|
|
18731
|
+
async function deterministicDigest(namespace, ...parts) {
|
|
18732
|
+
const encoded = new TextEncoder().encode(
|
|
18733
|
+
[namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
|
|
18734
|
+
);
|
|
18735
|
+
return new Uint8Array(
|
|
18736
|
+
await globalThis.crypto.subtle.digest("SHA-256", encoded)
|
|
18737
|
+
);
|
|
18738
|
+
}
|
|
18739
|
+
function digestHex(bytes, length) {
|
|
18740
|
+
return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
18741
|
+
}
|
|
18742
|
+
function digestUuid(bytes) {
|
|
18743
|
+
const hex = digestHex(bytes, 16);
|
|
18744
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
18745
|
+
}
|
|
18746
|
+
async function batchSpanIds(inputFileId) {
|
|
18747
|
+
const [row, span, root] = await Promise.all([
|
|
18748
|
+
deterministicDigest("openai:batch:row", inputFileId),
|
|
18749
|
+
deterministicDigest("openai:batch:span", inputFileId),
|
|
18750
|
+
deterministicDigest("openai:batch:root", inputFileId)
|
|
18751
|
+
]);
|
|
18752
|
+
return {
|
|
18753
|
+
rowId: digestUuid(row),
|
|
18754
|
+
spanId: digestHex(span, 8),
|
|
18755
|
+
rootSpanId: digestHex(root, 16)
|
|
18756
|
+
};
|
|
18757
|
+
}
|
|
18758
|
+
async function childSpanIds(inputFileId, customId) {
|
|
18759
|
+
const [row, span] = await Promise.all([
|
|
18760
|
+
deterministicDigest("openai:batch:child:row", inputFileId, customId),
|
|
18761
|
+
deterministicDigest("openai:batch:child:span", inputFileId, customId)
|
|
18762
|
+
]);
|
|
18763
|
+
return { rowId: digestUuid(row), spanId: digestHex(span, 8) };
|
|
18764
|
+
}
|
|
18765
|
+
async function startBatchSpan(context) {
|
|
18766
|
+
const ids = await batchSpanIds(context.inputFileId);
|
|
18767
|
+
const parent = SpanComponentsV4.fromStr(context.parent);
|
|
18768
|
+
const hasParentSpan = Boolean(
|
|
18769
|
+
parent.data.row_id && parent.data.span_id && parent.data.root_span_id
|
|
18770
|
+
);
|
|
18771
|
+
return withCurrent(
|
|
18772
|
+
NOOP_SPAN,
|
|
18773
|
+
() => _internalStartSpanWithInitialMergeAndParentSpanIds(
|
|
18774
|
+
withSpanInstrumentationName(
|
|
18775
|
+
{
|
|
18776
|
+
name: "openai.batch",
|
|
18777
|
+
type: "task" /* TASK */,
|
|
18778
|
+
parent: context.parent,
|
|
18779
|
+
...!hasParentSpan ? {
|
|
18780
|
+
parentSpanIds: {
|
|
18781
|
+
parentSpanIds: [],
|
|
18782
|
+
rootSpanId: ids.rootSpanId
|
|
18783
|
+
}
|
|
18784
|
+
} : {},
|
|
18785
|
+
spanId: ids.spanId,
|
|
18786
|
+
startTime: context.taskStartTime,
|
|
18787
|
+
event: {
|
|
18788
|
+
id: ids.rowId,
|
|
18789
|
+
metadata: {
|
|
18790
|
+
endpoint: context.endpoint,
|
|
18791
|
+
input_file_id: context.inputFileId,
|
|
18792
|
+
provider: "openai"
|
|
18793
|
+
}
|
|
18794
|
+
}
|
|
18795
|
+
},
|
|
18796
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
18797
|
+
)
|
|
18798
|
+
)
|
|
18799
|
+
);
|
|
18800
|
+
}
|
|
18801
|
+
async function startBatchChild(context, taskParent, input) {
|
|
18802
|
+
const ids = await childSpanIds(context.inputFileId, input.customId);
|
|
18803
|
+
return withCurrent(
|
|
18804
|
+
NOOP_SPAN,
|
|
18805
|
+
() => _internalStartSpanWithInitialMerge(
|
|
18806
|
+
withSpanInstrumentationName(
|
|
18807
|
+
{
|
|
18808
|
+
name: context.endpoint === "/v1/chat/completions" ? "Chat Completion" : "openai.responses.create",
|
|
18809
|
+
type: "llm" /* LLM */,
|
|
18810
|
+
parent: taskParent,
|
|
18811
|
+
spanId: ids.spanId,
|
|
18812
|
+
startTime: context.childStartTime,
|
|
18813
|
+
event: {
|
|
18814
|
+
id: ids.rowId,
|
|
18815
|
+
...input.spanData?.input !== void 0 ? { input: input.spanData.input } : {},
|
|
18816
|
+
metadata: {
|
|
18817
|
+
...input.spanData?.metadata,
|
|
18818
|
+
custom_id: input.customId,
|
|
18819
|
+
provider: "openai"
|
|
18820
|
+
}
|
|
18821
|
+
}
|
|
18822
|
+
},
|
|
18823
|
+
INSTRUMENTATION_NAMES.OPENAI
|
|
18824
|
+
)
|
|
18825
|
+
)
|
|
18826
|
+
);
|
|
18827
|
+
}
|
|
18828
|
+
async function* jsonlRecords(file, onIssue = () => {
|
|
18829
|
+
}) {
|
|
18830
|
+
const resolvedFile = await file;
|
|
18831
|
+
if (typeof resolvedFile === "string") {
|
|
18832
|
+
for (const line of resolvedFile.split("\n")) {
|
|
18833
|
+
if (!line.trim()) {
|
|
18834
|
+
continue;
|
|
18835
|
+
}
|
|
18836
|
+
try {
|
|
18837
|
+
yield JSON.parse(line.replace(/\r$/, ""));
|
|
18838
|
+
} catch (error) {
|
|
18839
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
18840
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
18841
|
+
}
|
|
18842
|
+
}
|
|
18843
|
+
return;
|
|
18844
|
+
}
|
|
18845
|
+
const body = read(resolvedFile, "body");
|
|
18846
|
+
const getReader = read(body, "getReader");
|
|
18847
|
+
if (isObject(body) && typeof getReader === "function") {
|
|
18848
|
+
let reader;
|
|
18849
|
+
try {
|
|
18850
|
+
reader = Reflect.apply(getReader, body, []);
|
|
18851
|
+
const decoder = new TextDecoder();
|
|
18852
|
+
let pending = "";
|
|
18853
|
+
while (true) {
|
|
18854
|
+
const readChunk = read(reader, "read");
|
|
18855
|
+
if (typeof readChunk !== "function") {
|
|
18856
|
+
throw new Error("Response body stream has no read method");
|
|
18857
|
+
}
|
|
18858
|
+
const chunk = await Reflect.apply(readChunk, reader, []);
|
|
18859
|
+
if (!isObject(chunk)) {
|
|
18860
|
+
throw new Error("Response body stream returned an invalid chunk");
|
|
18861
|
+
}
|
|
18862
|
+
if (chunk.done === true) {
|
|
18863
|
+
pending += decoder.decode();
|
|
18864
|
+
break;
|
|
18865
|
+
}
|
|
18866
|
+
if (!(chunk.value instanceof Uint8Array)) {
|
|
18867
|
+
throw new Error("Response body stream returned a non-byte chunk");
|
|
18868
|
+
}
|
|
18869
|
+
pending += decoder.decode(chunk.value, { stream: true });
|
|
18870
|
+
let newline = pending.indexOf("\n");
|
|
18871
|
+
while (newline !== -1) {
|
|
18872
|
+
const line = pending.slice(0, newline).replace(/\r$/, "");
|
|
18873
|
+
pending = pending.slice(newline + 1);
|
|
18874
|
+
if (line.trim()) {
|
|
18875
|
+
try {
|
|
18876
|
+
yield JSON.parse(line);
|
|
18877
|
+
} catch (error) {
|
|
18878
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
18879
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
18880
|
+
}
|
|
18881
|
+
}
|
|
18882
|
+
newline = pending.indexOf("\n");
|
|
18883
|
+
}
|
|
18884
|
+
}
|
|
18885
|
+
if (pending.trim()) {
|
|
18886
|
+
try {
|
|
18887
|
+
yield JSON.parse(pending.replace(/\r$/, ""));
|
|
18888
|
+
} catch (error) {
|
|
18889
|
+
logBatchInstrumentationError("skipped malformed JSONL", error);
|
|
18890
|
+
onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
|
|
18891
|
+
}
|
|
18892
|
+
}
|
|
18893
|
+
} catch (error) {
|
|
18894
|
+
logBatchInstrumentationError("could not read JSONL response body", error);
|
|
18895
|
+
onIssue(new Error("OpenAI Batch response body could not be read"));
|
|
18896
|
+
} finally {
|
|
18897
|
+
const releaseLock = read(reader, "releaseLock");
|
|
18898
|
+
if (typeof releaseLock === "function") {
|
|
18899
|
+
try {
|
|
18900
|
+
Reflect.apply(releaseLock, reader, []);
|
|
18901
|
+
} catch (error) {
|
|
18902
|
+
logBatchInstrumentationError(
|
|
18903
|
+
"could not release stream reader",
|
|
18904
|
+
error
|
|
18905
|
+
);
|
|
18906
|
+
}
|
|
18907
|
+
}
|
|
18908
|
+
}
|
|
18909
|
+
return;
|
|
18910
|
+
}
|
|
18911
|
+
if (isBatchRecordIterable(resolvedFile)) {
|
|
18912
|
+
for await (const record of resolvedFile) {
|
|
18913
|
+
yield record;
|
|
18914
|
+
}
|
|
18915
|
+
return;
|
|
18916
|
+
}
|
|
18917
|
+
logBatchInstrumentationError("skipped invalid JSONL source", resolvedFile);
|
|
18918
|
+
onIssue(new Error("OpenAI Batch file source is invalid"));
|
|
18919
|
+
}
|
|
18920
|
+
async function readBatchInputs(file) {
|
|
18921
|
+
const inputs = /* @__PURE__ */ new Map();
|
|
18922
|
+
const issues = [];
|
|
18923
|
+
let endpoint;
|
|
18924
|
+
try {
|
|
18925
|
+
for await (const value of jsonlRecords(
|
|
18926
|
+
file,
|
|
18927
|
+
(issue) => issues.push(issue)
|
|
18928
|
+
)) {
|
|
18929
|
+
const customId = read(value, "custom_id");
|
|
18930
|
+
const url = read(value, "url");
|
|
18931
|
+
const body = read(value, "body");
|
|
18932
|
+
if (!validCustomId(customId) || inputs.has(customId) || read(value, "method") !== "POST" || typeof url !== "string" || !SUPPORTED_ENDPOINTS.has(url) || endpoint !== void 0 && endpoint !== url || !isObject(body)) {
|
|
18933
|
+
issues.push(new Error("OpenAI Batch input contains an invalid record"));
|
|
18934
|
+
continue;
|
|
18935
|
+
}
|
|
18936
|
+
endpoint = url;
|
|
18937
|
+
let spanData;
|
|
18938
|
+
try {
|
|
18939
|
+
spanData = extractOpenAIBatchInput(url, body);
|
|
18940
|
+
} catch (error) {
|
|
18941
|
+
logBatchInstrumentationError("could not extract batch input", error);
|
|
18942
|
+
}
|
|
18943
|
+
inputs.set(customId, { customId, spanData });
|
|
18944
|
+
}
|
|
18945
|
+
} catch (error) {
|
|
18946
|
+
logBatchInstrumentationError("could not process input file", error);
|
|
18947
|
+
issues.push(new Error("OpenAI Batch input file could not be processed"));
|
|
18948
|
+
}
|
|
18949
|
+
if (!endpoint || inputs.size === 0) {
|
|
18950
|
+
issues.push(new Error("OpenAI Batch input contains no supported records"));
|
|
18951
|
+
}
|
|
18952
|
+
return { endpoint, inputs, issues };
|
|
18953
|
+
}
|
|
18954
|
+
async function writePendingSpans(trace, endTime) {
|
|
18955
|
+
const task = await startBatchSpan(trace.context);
|
|
18956
|
+
const taskParent = await task.export();
|
|
18957
|
+
for (const input of trace.inputs.values()) {
|
|
18958
|
+
try {
|
|
18959
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
18960
|
+
if (endTime !== void 0) {
|
|
18961
|
+
child.end({ endTime });
|
|
18962
|
+
}
|
|
18963
|
+
} catch (error) {
|
|
18964
|
+
logBatchInstrumentationError("could not write batch request span", error);
|
|
18965
|
+
}
|
|
18966
|
+
}
|
|
18967
|
+
if (endTime !== void 0) {
|
|
18968
|
+
if (trace.status && trace.status !== "completed") {
|
|
18969
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
18970
|
+
}
|
|
18971
|
+
task.end({ endTime });
|
|
18972
|
+
}
|
|
18973
|
+
}
|
|
18974
|
+
var interceptOpenAIFilesCreateTraced = async (target, thisArg, args) => {
|
|
18975
|
+
const startTime = getCurrentUnixTimestamp();
|
|
18976
|
+
const inputPromise = readBatchInputs(args[0].inputFileContent);
|
|
18977
|
+
const parentPromise = exportParent(args[0].parent);
|
|
18978
|
+
const file = await Reflect.apply(target, thisArg, args);
|
|
18979
|
+
try {
|
|
18980
|
+
const inputFileId = read(file, "id");
|
|
18981
|
+
const [inputData, exportedParent2] = await Promise.all([
|
|
18982
|
+
inputPromise,
|
|
18983
|
+
parentPromise
|
|
18984
|
+
]);
|
|
18985
|
+
if (typeof inputFileId !== "string" || !exportedParent2 || !inputData.endpoint || inputData.issues.length > 0) {
|
|
18986
|
+
if (inputData.issues[0]) {
|
|
18987
|
+
logBatchInstrumentationError(
|
|
18988
|
+
"skipped invalid input file",
|
|
18989
|
+
inputData.issues[0]
|
|
18990
|
+
);
|
|
18991
|
+
}
|
|
18992
|
+
return file;
|
|
18993
|
+
}
|
|
18994
|
+
const trace = {
|
|
18995
|
+
context: {
|
|
18996
|
+
inputFileId,
|
|
18997
|
+
endpoint: inputData.endpoint,
|
|
18998
|
+
parent: exportedParent2,
|
|
18999
|
+
taskStartTime: startTime,
|
|
19000
|
+
childStartTime: startTime
|
|
19001
|
+
},
|
|
19002
|
+
inputs: inputData.inputs
|
|
19003
|
+
};
|
|
19004
|
+
pendingBatchTraces.set(inputFileId, trace);
|
|
19005
|
+
await writePendingSpans(trace);
|
|
19006
|
+
} catch (error) {
|
|
19007
|
+
logBatchInstrumentationError("could not start batch spans", error);
|
|
19008
|
+
}
|
|
19009
|
+
return file;
|
|
19010
|
+
};
|
|
19011
|
+
function validTimestamp(value) {
|
|
19012
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
19013
|
+
}
|
|
19014
|
+
function terminalEndTime(batch, startTime) {
|
|
19015
|
+
let timestamp;
|
|
19016
|
+
switch (batch.status) {
|
|
19017
|
+
case "completed":
|
|
19018
|
+
timestamp = batch.completed_at;
|
|
19019
|
+
break;
|
|
19020
|
+
case "failed":
|
|
19021
|
+
timestamp = batch.failed_at;
|
|
19022
|
+
break;
|
|
19023
|
+
case "expired":
|
|
19024
|
+
timestamp = batch.expired_at;
|
|
19025
|
+
break;
|
|
19026
|
+
default:
|
|
19027
|
+
timestamp = batch.cancelled_at;
|
|
19028
|
+
}
|
|
19029
|
+
return validTimestamp(timestamp) ? Math.max(timestamp, startTime) : Math.max(getCurrentUnixTimestamp(), startTime);
|
|
19030
|
+
}
|
|
19031
|
+
async function updateBatchTimestamps(batch) {
|
|
19032
|
+
const trace = pendingBatchTraces.get(batch.input_file_id);
|
|
19033
|
+
if (!trace || trace.context.endpoint !== batch.endpoint) {
|
|
19034
|
+
return;
|
|
19035
|
+
}
|
|
19036
|
+
if (validTimestamp(batch.created_at)) {
|
|
19037
|
+
trace.context.taskStartTime = batch.created_at;
|
|
19038
|
+
}
|
|
19039
|
+
trace.context.childStartTime = validTimestamp(batch.in_progress_at) ? Math.max(batch.in_progress_at, trace.context.taskStartTime) : trace.context.taskStartTime;
|
|
19040
|
+
trace.status = batch.status;
|
|
19041
|
+
if (TERMINAL_STATUSES.has(batch.status)) {
|
|
19042
|
+
trace.endTime = terminalEndTime(batch, trace.context.childStartTime);
|
|
19043
|
+
}
|
|
19044
|
+
await writePendingSpans(trace, trace.endTime);
|
|
19045
|
+
}
|
|
19046
|
+
var interceptOpenAIBatchesRetrieveTraced = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (batch) => {
|
|
19047
|
+
try {
|
|
19048
|
+
await updateBatchTimestamps(batch);
|
|
19049
|
+
} catch (error) {
|
|
19050
|
+
logBatchInstrumentationError("could not update batch timestamps", error);
|
|
19051
|
+
}
|
|
19052
|
+
return batch;
|
|
19053
|
+
});
|
|
19054
|
+
function errorFromResult(result) {
|
|
19055
|
+
const error = read(result.value, "error");
|
|
19056
|
+
if (isObject(error)) {
|
|
19057
|
+
const message = read(error, "message");
|
|
19058
|
+
return new Error(
|
|
19059
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
19060
|
+
);
|
|
19061
|
+
}
|
|
19062
|
+
const response = read(result.value, "response");
|
|
19063
|
+
const statusCode = read(response, "status_code");
|
|
19064
|
+
if (result.source === "error" || typeof statusCode === "number" && (statusCode < 200 || statusCode >= 300)) {
|
|
19065
|
+
const message = read(read(read(response, "body"), "error"), "message");
|
|
19066
|
+
return new Error(
|
|
19067
|
+
typeof message === "string" ? message : "OpenAI Batch request failed"
|
|
19068
|
+
);
|
|
19069
|
+
}
|
|
19070
|
+
return void 0;
|
|
19071
|
+
}
|
|
19072
|
+
async function completeBatchResult(context, taskParent, endTime, input, result) {
|
|
19073
|
+
const child = await startBatchChild(context, taskParent, input);
|
|
19074
|
+
try {
|
|
19075
|
+
const resultError = errorFromResult(result);
|
|
19076
|
+
const responseBody = read(read(result.value, "response"), "body");
|
|
19077
|
+
if (resultError) {
|
|
19078
|
+
child.log({ error: resultError });
|
|
19079
|
+
} else if (isObject(responseBody)) {
|
|
19080
|
+
const model = read(responseBody, "model");
|
|
19081
|
+
child.log({
|
|
19082
|
+
output: context.endpoint === "/v1/chat/completions" ? read(responseBody, "choices") : processImagesInOutput(read(responseBody, "output")),
|
|
19083
|
+
...typeof model === "string" ? { metadata: { model } } : {},
|
|
19084
|
+
metrics: parseMetricsFromUsage(read(responseBody, "usage"))
|
|
19085
|
+
});
|
|
19086
|
+
} else {
|
|
19087
|
+
child.log({ error: new Error("OpenAI Batch response body is missing") });
|
|
19088
|
+
}
|
|
19089
|
+
} catch (error) {
|
|
19090
|
+
child.log({ error });
|
|
19091
|
+
} finally {
|
|
19092
|
+
child.end({ endTime });
|
|
19093
|
+
}
|
|
19094
|
+
}
|
|
19095
|
+
async function completeResultFile({
|
|
19096
|
+
context,
|
|
19097
|
+
endTime,
|
|
19098
|
+
file,
|
|
19099
|
+
inputs,
|
|
19100
|
+
issues,
|
|
19101
|
+
seen,
|
|
19102
|
+
source,
|
|
19103
|
+
taskParent
|
|
19104
|
+
}) {
|
|
19105
|
+
if (file === void 0) {
|
|
19106
|
+
return;
|
|
19107
|
+
}
|
|
19108
|
+
for await (const value of jsonlRecords(file, (issue) => issues.push(issue))) {
|
|
19109
|
+
const customId = read(value, "custom_id");
|
|
19110
|
+
if (!validCustomId(customId) || !isObject(value)) {
|
|
19111
|
+
issues.push(
|
|
19112
|
+
new Error("OpenAI Batch result is missing a valid custom_id")
|
|
19113
|
+
);
|
|
19114
|
+
continue;
|
|
19115
|
+
}
|
|
19116
|
+
if (seen.has(customId)) {
|
|
19117
|
+
issues.push(new Error("OpenAI Batch result contains a duplicate"));
|
|
19118
|
+
continue;
|
|
19119
|
+
}
|
|
19120
|
+
const input = inputs.get(customId);
|
|
19121
|
+
if (!input) {
|
|
19122
|
+
issues.push(
|
|
19123
|
+
new Error("OpenAI Batch result does not match an input record")
|
|
19124
|
+
);
|
|
19125
|
+
continue;
|
|
19126
|
+
}
|
|
19127
|
+
seen.add(customId);
|
|
19128
|
+
await completeBatchResult(context, taskParent, endTime, input, {
|
|
19129
|
+
value,
|
|
19130
|
+
source
|
|
19131
|
+
});
|
|
19132
|
+
}
|
|
19133
|
+
}
|
|
19134
|
+
function sameInputs(first, second) {
|
|
19135
|
+
return first.size === second.size && [...first.keys()].every((customId) => second.has(customId));
|
|
19136
|
+
}
|
|
19137
|
+
async function contextForCompletion(inputFileId, inputData) {
|
|
19138
|
+
if (!inputData.endpoint || inputData.issues.length > 0) {
|
|
19139
|
+
return void 0;
|
|
19140
|
+
}
|
|
19141
|
+
const existing = pendingBatchTraces.get(inputFileId);
|
|
19142
|
+
if (existing) {
|
|
19143
|
+
if (existing.context.endpoint !== inputData.endpoint || !sameInputs(existing.inputs, inputData.inputs)) {
|
|
19144
|
+
return void 0;
|
|
19145
|
+
}
|
|
19146
|
+
return { ...existing, inputs: inputData.inputs };
|
|
19147
|
+
}
|
|
19148
|
+
const parent = await exportParent(getSpanParentObject());
|
|
19149
|
+
if (!parent) {
|
|
19150
|
+
return void 0;
|
|
19151
|
+
}
|
|
19152
|
+
const startTime = getCurrentUnixTimestamp();
|
|
19153
|
+
return {
|
|
19154
|
+
context: {
|
|
19155
|
+
inputFileId,
|
|
19156
|
+
endpoint: inputData.endpoint,
|
|
19157
|
+
parent,
|
|
19158
|
+
taskStartTime: startTime,
|
|
19159
|
+
childStartTime: startTime
|
|
19160
|
+
},
|
|
19161
|
+
inputs: inputData.inputs
|
|
19162
|
+
};
|
|
19163
|
+
}
|
|
19164
|
+
async function completeBatch(args) {
|
|
19165
|
+
const inputData = await readBatchInputs(args.inputFileContent);
|
|
19166
|
+
const trace = await contextForCompletion(args.inputFileId, inputData);
|
|
19167
|
+
if (!trace) {
|
|
19168
|
+
logBatchInstrumentationError(
|
|
19169
|
+
"left batch spans pending",
|
|
19170
|
+
inputData.issues[0] ?? new Error("OpenAI Batch input does not match")
|
|
19171
|
+
);
|
|
19172
|
+
return;
|
|
19173
|
+
}
|
|
19174
|
+
const endTime = trace.endTime ?? getCurrentUnixTimestamp();
|
|
19175
|
+
const task = await startBatchSpan(trace.context);
|
|
19176
|
+
const taskParent = await task.export();
|
|
19177
|
+
const issues = [];
|
|
19178
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19179
|
+
await Promise.all([
|
|
19180
|
+
completeResultFile({
|
|
19181
|
+
context: trace.context,
|
|
19182
|
+
endTime,
|
|
19183
|
+
file: args.outputFileContent,
|
|
19184
|
+
inputs: trace.inputs,
|
|
19185
|
+
issues,
|
|
19186
|
+
seen,
|
|
19187
|
+
source: "output",
|
|
19188
|
+
taskParent
|
|
19189
|
+
}),
|
|
19190
|
+
completeResultFile({
|
|
19191
|
+
context: trace.context,
|
|
19192
|
+
endTime,
|
|
19193
|
+
file: args.errorFileContent,
|
|
19194
|
+
inputs: trace.inputs,
|
|
19195
|
+
issues,
|
|
19196
|
+
seen,
|
|
19197
|
+
source: "error",
|
|
19198
|
+
taskParent
|
|
19199
|
+
})
|
|
19200
|
+
]);
|
|
19201
|
+
if (issues.length > 0) {
|
|
19202
|
+
logBatchInstrumentationError("left batch spans pending", issues[0]);
|
|
19203
|
+
return;
|
|
19204
|
+
}
|
|
19205
|
+
const missing = [...trace.inputs.values()].filter(
|
|
19206
|
+
({ customId }) => !seen.has(customId)
|
|
19207
|
+
);
|
|
19208
|
+
if (!trace.status || trace.status === "completed") {
|
|
19209
|
+
if (missing.length > 0) {
|
|
19210
|
+
logBatchInstrumentationError(
|
|
19211
|
+
"left batch spans pending",
|
|
19212
|
+
new Error("OpenAI Batch result files are incomplete")
|
|
19213
|
+
);
|
|
19214
|
+
return;
|
|
19215
|
+
}
|
|
19216
|
+
} else {
|
|
19217
|
+
for (const input of missing) {
|
|
19218
|
+
const child = await startBatchChild(trace.context, taskParent, input);
|
|
19219
|
+
child.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
19220
|
+
child.end({ endTime });
|
|
19221
|
+
}
|
|
19222
|
+
task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
|
|
19223
|
+
}
|
|
19224
|
+
task.end({ endTime });
|
|
19225
|
+
pendingBatchTraces.delete(args.inputFileId);
|
|
19226
|
+
}
|
|
19227
|
+
var interceptOpenAIBatchTraceComplete = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (result) => {
|
|
19228
|
+
try {
|
|
19229
|
+
await completeBatch(args[0]);
|
|
19230
|
+
} catch (error) {
|
|
19231
|
+
logBatchInstrumentationError("could not complete batch", error);
|
|
19232
|
+
}
|
|
19233
|
+
return result;
|
|
19234
|
+
});
|
|
19235
|
+
|
|
18596
19236
|
// src/instrumentation/plugins/openai-plugin.ts
|
|
18597
19237
|
var OpenAIPlugin = class extends BasePlugin {
|
|
18598
19238
|
constructor() {
|
|
18599
19239
|
super();
|
|
18600
19240
|
}
|
|
18601
19241
|
onEnable() {
|
|
19242
|
+
this.unsubscribers.push(
|
|
19243
|
+
openAIChannels.filesCreateTraced.intercept(
|
|
19244
|
+
interceptOpenAIFilesCreateTraced
|
|
19245
|
+
),
|
|
19246
|
+
openAIChannels.batchesRetrieveTraced.intercept(
|
|
19247
|
+
interceptOpenAIBatchesRetrieveTraced
|
|
19248
|
+
),
|
|
19249
|
+
openAIChannels.batchesCompleteTrace.intercept(
|
|
19250
|
+
interceptOpenAIBatchTraceComplete
|
|
19251
|
+
)
|
|
19252
|
+
);
|
|
18602
19253
|
this.unsubscribers.push(
|
|
18603
19254
|
traceStreamingChannel(openAIChannels.chatCompletionsCreate, {
|
|
18604
19255
|
name: "Chat Completion",
|
|
18605
19256
|
type: "llm" /* LLM */,
|
|
18606
|
-
extractInput: ([params]) =>
|
|
18607
|
-
const { messages, ...metadata } = params;
|
|
18608
|
-
return {
|
|
18609
|
-
input: processInputAttachments(messages),
|
|
18610
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18611
|
-
};
|
|
18612
|
-
},
|
|
19257
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
18613
19258
|
extractOutput: (result) => {
|
|
18614
19259
|
return result?.choices;
|
|
18615
19260
|
},
|
|
@@ -18655,13 +19300,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
18655
19300
|
traceStreamingChannel(openAIChannels.betaChatCompletionsParse, {
|
|
18656
19301
|
name: "Chat Completion",
|
|
18657
19302
|
type: "llm" /* LLM */,
|
|
18658
|
-
extractInput: ([params]) =>
|
|
18659
|
-
const { messages, ...metadata } = params;
|
|
18660
|
-
return {
|
|
18661
|
-
input: processInputAttachments(messages),
|
|
18662
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18663
|
-
};
|
|
18664
|
-
},
|
|
19303
|
+
extractInput: ([params]) => extractOpenAIChatInput(params),
|
|
18665
19304
|
extractOutput: (result) => {
|
|
18666
19305
|
return result?.choices;
|
|
18667
19306
|
},
|
|
@@ -18683,13 +19322,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
18683
19322
|
traceSyncStreamChannel(openAIChannels.betaChatCompletionsStream, {
|
|
18684
19323
|
name: "Chat Completion",
|
|
18685
19324
|
type: "llm" /* LLM */,
|
|
18686
|
-
extractInput: ([params]) =>
|
|
18687
|
-
const { messages, ...metadata } = params;
|
|
18688
|
-
return {
|
|
18689
|
-
input: processInputAttachments(messages),
|
|
18690
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18691
|
-
};
|
|
18692
|
-
}
|
|
19325
|
+
extractInput: ([params]) => extractOpenAIChatInput(params)
|
|
18693
19326
|
})
|
|
18694
19327
|
);
|
|
18695
19328
|
this.unsubscribers.push(
|
|
@@ -18719,23 +19352,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
18719
19352
|
traceStreamingChannel(openAIChannels.responsesCreate, {
|
|
18720
19353
|
name: "openai.responses.create",
|
|
18721
19354
|
type: "llm" /* LLM */,
|
|
18722
|
-
extractInput: ([params]) =>
|
|
18723
|
-
const { input, ...metadata } = params;
|
|
18724
|
-
return {
|
|
18725
|
-
input: processInputAttachments(input),
|
|
18726
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18727
|
-
};
|
|
18728
|
-
},
|
|
19355
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
18729
19356
|
extractOutput: (result) => {
|
|
18730
19357
|
return processImagesInOutput(result?.output);
|
|
18731
19358
|
},
|
|
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
|
-
},
|
|
19359
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
18739
19360
|
extractMetrics: (result, startTime, endEvent) => {
|
|
18740
19361
|
const metrics = withCachedMetric(
|
|
18741
19362
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -18754,13 +19375,7 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
18754
19375
|
traceSyncStreamChannel(openAIChannels.responsesStream, {
|
|
18755
19376
|
name: "openai.responses.create",
|
|
18756
19377
|
type: "llm" /* LLM */,
|
|
18757
|
-
extractInput: ([params]) =>
|
|
18758
|
-
const { input, ...metadata } = params;
|
|
18759
|
-
return {
|
|
18760
|
-
input: processInputAttachments(input),
|
|
18761
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18762
|
-
};
|
|
18763
|
-
},
|
|
19378
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
18764
19379
|
extractFromEvent: (event) => {
|
|
18765
19380
|
if (event.type !== "response.completed" || !event.response) {
|
|
18766
19381
|
return {};
|
|
@@ -18783,23 +19398,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
18783
19398
|
traceStreamingChannel(openAIChannels.responsesParse, {
|
|
18784
19399
|
name: "openai.responses.parse",
|
|
18785
19400
|
type: "llm" /* LLM */,
|
|
18786
|
-
extractInput: ([params]) =>
|
|
18787
|
-
const { input, ...metadata } = params;
|
|
18788
|
-
return {
|
|
18789
|
-
input: processInputAttachments(input),
|
|
18790
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18791
|
-
};
|
|
18792
|
-
},
|
|
19401
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
18793
19402
|
extractOutput: (result) => {
|
|
18794
19403
|
return processImagesInOutput(result?.output);
|
|
18795
19404
|
},
|
|
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
|
-
},
|
|
19405
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
18803
19406
|
extractMetrics: (result, startTime, endEvent) => {
|
|
18804
19407
|
const metrics = withCachedMetric(
|
|
18805
19408
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -18818,23 +19421,11 @@ var OpenAIPlugin = class extends BasePlugin {
|
|
|
18818
19421
|
traceAsyncChannel(openAIChannels.responsesCompact, {
|
|
18819
19422
|
name: "openai.responses.compact",
|
|
18820
19423
|
type: "llm" /* LLM */,
|
|
18821
|
-
extractInput: ([params]) =>
|
|
18822
|
-
const { input, ...metadata } = params;
|
|
18823
|
-
return {
|
|
18824
|
-
input: processInputAttachments(input),
|
|
18825
|
-
metadata: { ...metadata, provider: "openai" }
|
|
18826
|
-
};
|
|
18827
|
-
},
|
|
19424
|
+
extractInput: ([params]) => extractOpenAIResponsesInput(params),
|
|
18828
19425
|
extractOutput: (result) => {
|
|
18829
19426
|
return processImagesInOutput(result?.output);
|
|
18830
19427
|
},
|
|
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
|
-
},
|
|
19428
|
+
extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
|
|
18838
19429
|
extractMetrics: (result, startTime, endEvent) => {
|
|
18839
19430
|
const metrics = withCachedMetric(
|
|
18840
19431
|
parseMetricsFromUsage(result?.usage),
|
|
@@ -18890,35 +19481,6 @@ function withCachedMetric(metrics, result, endEvent) {
|
|
|
18890
19481
|
cached
|
|
18891
19482
|
};
|
|
18892
19483
|
}
|
|
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
19484
|
function mergeLogprobTokens(existing, incoming) {
|
|
18923
19485
|
if (incoming === void 0) {
|
|
18924
19486
|
return existing;
|
|
@@ -32442,7 +33004,7 @@ function extractSession(event) {
|
|
|
32442
33004
|
return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
|
|
32443
33005
|
}
|
|
32444
33006
|
function isPiAgent(value) {
|
|
32445
|
-
return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
|
|
33007
|
+
return isObject(value) && (typeof value.streamFunction === "function" || typeof value.streamFn === "function") && typeof value.subscribe === "function";
|
|
32446
33008
|
}
|
|
32447
33009
|
function promptContextStore() {
|
|
32448
33010
|
piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
|
|
@@ -32452,17 +33014,21 @@ function currentPiPromptState() {
|
|
|
32452
33014
|
return promptContextStore().getStore();
|
|
32453
33015
|
}
|
|
32454
33016
|
function installPiAgentInstrumentation(agent) {
|
|
33017
|
+
const property = typeof agent.streamFunction === "function" ? "streamFunction" : "streamFn";
|
|
33018
|
+
const streamFunction = agent[property];
|
|
32455
33019
|
const existing = piAgentPatchStates.get(agent);
|
|
32456
|
-
if (!existing ||
|
|
33020
|
+
if (streamFunction && (!existing || existing.property !== property || streamFunction !== existing.wrappedStreamFunction)) {
|
|
32457
33021
|
const patchState = {
|
|
32458
|
-
|
|
32459
|
-
|
|
33022
|
+
originalStreamFunction: streamFunction,
|
|
33023
|
+
property,
|
|
33024
|
+
wrappedStreamFunction: streamFunction
|
|
32460
33025
|
};
|
|
32461
|
-
patchState.
|
|
33026
|
+
patchState.wrappedStreamFunction = makeInstrumentedStreamFunction(
|
|
32462
33027
|
agent,
|
|
32463
|
-
patchState.
|
|
33028
|
+
patchState.originalStreamFunction,
|
|
33029
|
+
property
|
|
32464
33030
|
);
|
|
32465
|
-
agent
|
|
33031
|
+
agent[property] = patchState.wrappedStreamFunction;
|
|
32466
33032
|
piAgentPatchStates.set(agent, patchState);
|
|
32467
33033
|
}
|
|
32468
33034
|
if (piAgentEventSubscriptions.has(agent)) {
|
|
@@ -32487,15 +33053,21 @@ function installPiAgentInstrumentation(agent) {
|
|
|
32487
33053
|
logInstrumentationError4("Pi Coding Agent event subscription", error);
|
|
32488
33054
|
}
|
|
32489
33055
|
}
|
|
32490
|
-
function
|
|
32491
|
-
return async function
|
|
32492
|
-
const invokeOriginal = () => Reflect.apply(
|
|
33056
|
+
function makeInstrumentedStreamFunction(agent, originalStreamFunction, property) {
|
|
33057
|
+
return async function instrumentedPiStreamFunction(model, context, options) {
|
|
33058
|
+
const invokeOriginal = () => Reflect.apply(originalStreamFunction, this, [model, context, options]);
|
|
32493
33059
|
const state = currentPiPromptState();
|
|
32494
33060
|
if (!state || state.agent !== agent || state.finalized) {
|
|
32495
33061
|
return invokeOriginal();
|
|
32496
33062
|
}
|
|
32497
33063
|
wrapPiToolExecutors(context.tools);
|
|
32498
|
-
const llmState = await startPiLlmSpan(
|
|
33064
|
+
const llmState = await startPiLlmSpan(
|
|
33065
|
+
state,
|
|
33066
|
+
model,
|
|
33067
|
+
context,
|
|
33068
|
+
property,
|
|
33069
|
+
options
|
|
33070
|
+
);
|
|
32499
33071
|
try {
|
|
32500
33072
|
const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
|
|
32501
33073
|
return patchAssistantMessageStream(stream, state, llmState);
|
|
@@ -32532,12 +33104,12 @@ function wrapPiToolExecutors(tools) {
|
|
|
32532
33104
|
}
|
|
32533
33105
|
}
|
|
32534
33106
|
}
|
|
32535
|
-
async function startPiLlmSpan(state, model, context, options) {
|
|
33107
|
+
async function startPiLlmSpan(state, model, context, property, options) {
|
|
32536
33108
|
const metadata = {
|
|
32537
33109
|
...extractModelMetadata2(model),
|
|
32538
33110
|
...extractStreamOptionsMetadata(options),
|
|
32539
33111
|
...extractToolMetadata(context.tools),
|
|
32540
|
-
"pi_coding_agent.operation":
|
|
33112
|
+
"pi_coding_agent.operation": `agent.${property}`
|
|
32541
33113
|
};
|
|
32542
33114
|
const span = startSpan(
|
|
32543
33115
|
withSpanInstrumentationName(
|