braintrust 3.7.0 → 3.7.1
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 +1859 -1338
- package/dev/dist/index.mjs +1774 -1253
- package/dist/auto-instrumentations/bundler/esbuild.cjs +12 -15
- package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
- package/dist/auto-instrumentations/bundler/rollup.cjs +12 -15
- package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
- package/dist/auto-instrumentations/bundler/vite.cjs +12 -15
- package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
- package/dist/auto-instrumentations/bundler/webpack-loader.cjs +12 -15
- package/dist/auto-instrumentations/bundler/webpack.cjs +12 -15
- package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
- package/dist/auto-instrumentations/{chunk-ZK2IYER2.mjs → chunk-NY4CGTN6.mjs} +1 -1
- package/dist/auto-instrumentations/{chunk-AKEXR4AL.mjs → chunk-YCKND42U.mjs} +12 -15
- package/dist/auto-instrumentations/hook.mjs +12 -15
- package/dist/auto-instrumentations/index.cjs +12 -15
- package/dist/auto-instrumentations/index.mjs +1 -1
- package/dist/browser.d.mts +8 -30
- package/dist/browser.d.ts +8 -30
- package/dist/browser.js +4836 -6828
- package/dist/browser.mjs +4836 -6828
- package/dist/cli.js +1507 -986
- package/dist/edge-light.js +9173 -11163
- package/dist/edge-light.mjs +9173 -11163
- package/dist/index.d.mts +8 -30
- package/dist/index.d.ts +8 -30
- package/dist/index.js +4747 -6739
- package/dist/index.mjs +4748 -6740
- package/dist/instrumentation/index.js +1735 -1236
- package/dist/instrumentation/index.mjs +1735 -1236
- package/dist/workerd.js +9173 -11163
- package/dist/workerd.mjs +9173 -11163
- package/package.json +2 -2
|
@@ -111,7 +111,7 @@ var DefaultTracingChannel = class {
|
|
|
111
111
|
}
|
|
112
112
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
113
113
|
tracePromise(fn, _message, thisArg, ...args) {
|
|
114
|
-
return
|
|
114
|
+
return fn.apply(thisArg, args);
|
|
115
115
|
}
|
|
116
116
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
117
117
|
traceCallback(fn, _position, _message, thisArg, ...args) {
|
|
@@ -131,6 +131,7 @@ var iso = {
|
|
|
131
131
|
processOn: (_0, _1) => {
|
|
132
132
|
},
|
|
133
133
|
basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
|
|
134
|
+
// eslint-disable-next-line no-restricted-properties -- preserving intentional console usage.
|
|
134
135
|
writeln: (text) => console.log(text)
|
|
135
136
|
};
|
|
136
137
|
var isomorph_default = iso;
|
|
@@ -166,7 +167,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
166
167
|
if (!completed) {
|
|
167
168
|
completed = true;
|
|
168
169
|
try {
|
|
169
|
-
options.onComplete(chunks);
|
|
170
|
+
await options.onComplete(chunks);
|
|
170
171
|
} catch (error) {
|
|
171
172
|
console.error("Error in stream onComplete handler:", error);
|
|
172
173
|
}
|
|
@@ -178,7 +179,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
178
179
|
chunks.push(chunk);
|
|
179
180
|
if (options.onChunk) {
|
|
180
181
|
try {
|
|
181
|
-
options.onChunk(chunk);
|
|
182
|
+
await options.onChunk(chunk);
|
|
182
183
|
} catch (error) {
|
|
183
184
|
console.error("Error in stream onChunk handler:", error);
|
|
184
185
|
}
|
|
@@ -191,7 +192,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
191
192
|
completed = true;
|
|
192
193
|
if (options.onError) {
|
|
193
194
|
try {
|
|
194
|
-
options.onError(
|
|
195
|
+
await options.onError(
|
|
195
196
|
error instanceof Error ? error : new Error(String(error)),
|
|
196
197
|
chunks
|
|
197
198
|
);
|
|
@@ -209,7 +210,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
209
210
|
if (!completed) {
|
|
210
211
|
completed = true;
|
|
211
212
|
try {
|
|
212
|
-
options.onComplete(chunks);
|
|
213
|
+
await options.onComplete(chunks);
|
|
213
214
|
} catch (error) {
|
|
214
215
|
console.error("Error in stream onComplete handler:", error);
|
|
215
216
|
}
|
|
@@ -226,7 +227,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
226
227
|
const error = rawError instanceof Error ? rawError : new Error(String(rawError));
|
|
227
228
|
if (options.onError) {
|
|
228
229
|
try {
|
|
229
|
-
options.onError(error, chunks);
|
|
230
|
+
await options.onError(error, chunks);
|
|
230
231
|
} catch (handlerError) {
|
|
231
232
|
console.error("Error in stream onError handler:", handlerError);
|
|
232
233
|
}
|
|
@@ -1578,6 +1579,15 @@ function addAzureBlobHeaders(headers, url) {
|
|
|
1578
1579
|
headers["x-ms-blob-type"] = "BlockBlob";
|
|
1579
1580
|
}
|
|
1580
1581
|
}
|
|
1582
|
+
function filterFrom(record, keys) {
|
|
1583
|
+
const out = {};
|
|
1584
|
+
for (const k of Object.keys(record)) {
|
|
1585
|
+
if (!keys.includes(k)) {
|
|
1586
|
+
out[k] = record[k];
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
return out;
|
|
1590
|
+
}
|
|
1581
1591
|
|
|
1582
1592
|
// src/generated_types.ts
|
|
1583
1593
|
var import_v36 = require("zod/v3");
|
|
@@ -8371,51 +8381,28 @@ function traceSyncStreamChannel(channel2, config) {
|
|
|
8371
8381
|
}
|
|
8372
8382
|
const { span, startTime } = spanData;
|
|
8373
8383
|
const endEvent = event;
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
return;
|
|
8388
|
-
}
|
|
8389
|
-
let first = true;
|
|
8390
|
-
stream.on("chunk", () => {
|
|
8391
|
-
if (first) {
|
|
8392
|
-
span.log({
|
|
8393
|
-
metrics: {
|
|
8394
|
-
time_to_first_token: getCurrentUnixTimestamp() - startTime
|
|
8395
|
-
}
|
|
8396
|
-
});
|
|
8397
|
-
first = false;
|
|
8398
|
-
}
|
|
8399
|
-
});
|
|
8400
|
-
stream.on("chatCompletion", (completion) => {
|
|
8401
|
-
try {
|
|
8402
|
-
if (hasChoices(completion)) {
|
|
8403
|
-
span.log({
|
|
8404
|
-
output: completion.choices
|
|
8405
|
-
});
|
|
8406
|
-
}
|
|
8407
|
-
} catch (error) {
|
|
8408
|
-
console.error(
|
|
8409
|
-
`Error extracting chatCompletion for ${channelName}:`,
|
|
8410
|
-
error
|
|
8411
|
-
);
|
|
8384
|
+
const handleResolvedResult = (result) => {
|
|
8385
|
+
const resolvedEndEvent = {
|
|
8386
|
+
...endEvent,
|
|
8387
|
+
result
|
|
8388
|
+
};
|
|
8389
|
+
if (config.patchResult?.({
|
|
8390
|
+
channelName,
|
|
8391
|
+
endEvent: resolvedEndEvent,
|
|
8392
|
+
result,
|
|
8393
|
+
span,
|
|
8394
|
+
startTime
|
|
8395
|
+
})) {
|
|
8396
|
+
return;
|
|
8412
8397
|
}
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8398
|
+
const stream = result;
|
|
8399
|
+
if (!isSyncStreamLike(stream)) {
|
|
8400
|
+
span.end();
|
|
8401
|
+
states.delete(event);
|
|
8416
8402
|
return;
|
|
8417
8403
|
}
|
|
8418
|
-
|
|
8404
|
+
let first = true;
|
|
8405
|
+
stream.on("chunk", () => {
|
|
8419
8406
|
if (first) {
|
|
8420
8407
|
span.log({
|
|
8421
8408
|
metrics: {
|
|
@@ -8424,25 +8411,55 @@ function traceSyncStreamChannel(channel2, config) {
|
|
|
8424
8411
|
});
|
|
8425
8412
|
first = false;
|
|
8426
8413
|
}
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8414
|
+
});
|
|
8415
|
+
stream.on("chatCompletion", (completion) => {
|
|
8416
|
+
try {
|
|
8417
|
+
if (hasChoices(completion)) {
|
|
8418
|
+
span.log({
|
|
8419
|
+
output: completion.choices
|
|
8420
|
+
});
|
|
8421
|
+
}
|
|
8422
|
+
} catch (error) {
|
|
8423
|
+
console.error(
|
|
8424
|
+
`Error extracting chatCompletion for ${channelName}:`,
|
|
8425
|
+
error
|
|
8426
|
+
);
|
|
8430
8427
|
}
|
|
8431
|
-
} catch (error) {
|
|
8432
|
-
console.error(`Error extracting event for ${channelName}:`, error);
|
|
8433
|
-
}
|
|
8434
|
-
});
|
|
8435
|
-
stream.on("end", () => {
|
|
8436
|
-
span.end();
|
|
8437
|
-
states.delete(event);
|
|
8438
|
-
});
|
|
8439
|
-
stream.on("error", (error) => {
|
|
8440
|
-
span.log({
|
|
8441
|
-
error: error.message
|
|
8442
8428
|
});
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8429
|
+
stream.on("event", (streamEvent) => {
|
|
8430
|
+
if (!config.extractFromEvent) {
|
|
8431
|
+
return;
|
|
8432
|
+
}
|
|
8433
|
+
try {
|
|
8434
|
+
if (first) {
|
|
8435
|
+
span.log({
|
|
8436
|
+
metrics: {
|
|
8437
|
+
time_to_first_token: getCurrentUnixTimestamp() - startTime
|
|
8438
|
+
}
|
|
8439
|
+
});
|
|
8440
|
+
first = false;
|
|
8441
|
+
}
|
|
8442
|
+
const extracted = config.extractFromEvent(streamEvent);
|
|
8443
|
+
if (extracted && Object.keys(extracted).length > 0) {
|
|
8444
|
+
span.log(extracted);
|
|
8445
|
+
}
|
|
8446
|
+
} catch (error) {
|
|
8447
|
+
console.error(`Error extracting event for ${channelName}:`, error);
|
|
8448
|
+
}
|
|
8449
|
+
});
|
|
8450
|
+
stream.on("end", () => {
|
|
8451
|
+
span.end();
|
|
8452
|
+
states.delete(event);
|
|
8453
|
+
});
|
|
8454
|
+
stream.on("error", (error) => {
|
|
8455
|
+
span.log({
|
|
8456
|
+
error: error.message
|
|
8457
|
+
});
|
|
8458
|
+
span.end();
|
|
8459
|
+
states.delete(event);
|
|
8460
|
+
});
|
|
8461
|
+
};
|
|
8462
|
+
handleResolvedResult(endEvent.result);
|
|
8446
8463
|
},
|
|
8447
8464
|
error: (event) => {
|
|
8448
8465
|
logErrorAndEnd(states, event);
|
|
@@ -9265,28 +9282,40 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
9265
9282
|
case "content_block_start":
|
|
9266
9283
|
if (event.content_block) {
|
|
9267
9284
|
contentBlocks[event.index] = event.content_block;
|
|
9268
|
-
contentBlockDeltas[event.index] = [];
|
|
9285
|
+
contentBlockDeltas[event.index] = { textDeltas: [], citations: [] };
|
|
9269
9286
|
}
|
|
9270
9287
|
break;
|
|
9271
|
-
case "content_block_delta":
|
|
9272
|
-
|
|
9273
|
-
|
|
9288
|
+
case "content_block_delta": {
|
|
9289
|
+
const acc = contentBlockDeltas[event.index];
|
|
9290
|
+
const delta = event.delta;
|
|
9291
|
+
if (!delta) break;
|
|
9292
|
+
if (delta.type === "text_delta" && "text" in delta) {
|
|
9293
|
+
const text = delta.text;
|
|
9274
9294
|
if (text) {
|
|
9275
|
-
if (
|
|
9276
|
-
|
|
9277
|
-
contentBlockDeltas[event.index].push(text);
|
|
9295
|
+
if (acc !== void 0) {
|
|
9296
|
+
acc.textDeltas.push(text);
|
|
9278
9297
|
} else {
|
|
9279
9298
|
fallbackTextDeltas.push(text);
|
|
9280
9299
|
}
|
|
9281
9300
|
}
|
|
9282
|
-
} else if (
|
|
9283
|
-
const partialJson =
|
|
9284
|
-
if (partialJson) {
|
|
9285
|
-
|
|
9286
|
-
|
|
9301
|
+
} else if (delta.type === "input_json_delta" && "partial_json" in delta) {
|
|
9302
|
+
const partialJson = delta.partial_json;
|
|
9303
|
+
if (partialJson && acc !== void 0) {
|
|
9304
|
+
acc.textDeltas.push(partialJson);
|
|
9305
|
+
}
|
|
9306
|
+
} else if (delta.type === "thinking_delta" && "thinking" in delta) {
|
|
9307
|
+
const thinking = delta.thinking;
|
|
9308
|
+
if (thinking && acc !== void 0) {
|
|
9309
|
+
acc.textDeltas.push(thinking);
|
|
9310
|
+
}
|
|
9311
|
+
} else if (delta.type === "citations_delta" && "citation" in delta) {
|
|
9312
|
+
const citation = delta.citation;
|
|
9313
|
+
if (citation && acc !== void 0) {
|
|
9314
|
+
acc.citations.push(citation);
|
|
9287
9315
|
}
|
|
9288
9316
|
}
|
|
9289
9317
|
break;
|
|
9318
|
+
}
|
|
9290
9319
|
case "content_block_stop":
|
|
9291
9320
|
finalizeContentBlock(
|
|
9292
9321
|
event.index,
|
|
@@ -9312,7 +9341,7 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
9312
9341
|
})).filter(({ block }) => block !== void 0).sort((left, right) => left.index - right.index).map(({ block }) => block);
|
|
9313
9342
|
let output = fallbackTextDeltas.join("");
|
|
9314
9343
|
if (orderedContent.length > 0) {
|
|
9315
|
-
if (orderedContent.every(isTextContentBlock)) {
|
|
9344
|
+
if (orderedContent.every(isTextContentBlock) && orderedContent.every((block) => !block.citations?.length)) {
|
|
9316
9345
|
output = orderedContent.map((block) => block.text).join("");
|
|
9317
9346
|
} else {
|
|
9318
9347
|
output = {
|
|
@@ -9338,7 +9367,8 @@ function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallback
|
|
|
9338
9367
|
if (!contentBlock) {
|
|
9339
9368
|
return;
|
|
9340
9369
|
}
|
|
9341
|
-
const
|
|
9370
|
+
const acc = contentBlockDeltas[index];
|
|
9371
|
+
const text = acc?.textDeltas.join("") ?? "";
|
|
9342
9372
|
if (isToolUseContentBlock(contentBlock)) {
|
|
9343
9373
|
if (!text) {
|
|
9344
9374
|
return;
|
|
@@ -9355,20 +9385,28 @@ function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallback
|
|
|
9355
9385
|
return;
|
|
9356
9386
|
}
|
|
9357
9387
|
if (isTextContentBlock(contentBlock)) {
|
|
9388
|
+
if (!text) {
|
|
9389
|
+
delete contentBlocks[index];
|
|
9390
|
+
return;
|
|
9391
|
+
}
|
|
9392
|
+
const updated = { ...contentBlock, text };
|
|
9393
|
+
if (acc?.citations.length) {
|
|
9394
|
+
updated.citations = acc.citations;
|
|
9395
|
+
}
|
|
9396
|
+
contentBlocks[index] = updated;
|
|
9397
|
+
return;
|
|
9398
|
+
}
|
|
9399
|
+
if (isThinkingContentBlock(contentBlock)) {
|
|
9358
9400
|
if (!text) {
|
|
9359
9401
|
delete contentBlocks[index];
|
|
9360
9402
|
return;
|
|
9361
9403
|
}
|
|
9362
9404
|
contentBlocks[index] = {
|
|
9363
9405
|
...contentBlock,
|
|
9364
|
-
text
|
|
9406
|
+
thinking: text
|
|
9365
9407
|
};
|
|
9366
9408
|
return;
|
|
9367
9409
|
}
|
|
9368
|
-
if (text) {
|
|
9369
|
-
fallbackTextDeltas.push(text);
|
|
9370
|
-
}
|
|
9371
|
-
delete contentBlocks[index];
|
|
9372
9410
|
}
|
|
9373
9411
|
function isTextContentBlock(contentBlock) {
|
|
9374
9412
|
return contentBlock.type === "text";
|
|
@@ -9376,6 +9414,9 @@ function isTextContentBlock(contentBlock) {
|
|
|
9376
9414
|
function isToolUseContentBlock(contentBlock) {
|
|
9377
9415
|
return contentBlock.type === "tool_use";
|
|
9378
9416
|
}
|
|
9417
|
+
function isThinkingContentBlock(contentBlock) {
|
|
9418
|
+
return contentBlock.type === "thinking";
|
|
9419
|
+
}
|
|
9379
9420
|
function isAnthropicBase64ContentBlock(input) {
|
|
9380
9421
|
return (input.type === "image" || input.type === "document") && isObject(input.source) && input.source.type === "base64";
|
|
9381
9422
|
}
|
|
@@ -9430,15 +9471,6 @@ function coalesceInput(messages, system) {
|
|
|
9430
9471
|
}
|
|
9431
9472
|
return input;
|
|
9432
9473
|
}
|
|
9433
|
-
function filterFrom(obj, fieldsToRemove) {
|
|
9434
|
-
const result = {};
|
|
9435
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
9436
|
-
if (!fieldsToRemove.includes(key)) {
|
|
9437
|
-
result[key] = value;
|
|
9438
|
-
}
|
|
9439
|
-
}
|
|
9440
|
-
return result;
|
|
9441
|
-
}
|
|
9442
9474
|
|
|
9443
9475
|
// src/wrappers/ai-sdk/normalize-logged-output.ts
|
|
9444
9476
|
var REMOVE_NORMALIZED_VALUE = Symbol("braintrust.ai-sdk.remove-normalized");
|
|
@@ -9552,10 +9584,6 @@ var aiSDKChannels = defineChannels("ai", {
|
|
|
9552
9584
|
channelName: "streamText",
|
|
9553
9585
|
kind: "async"
|
|
9554
9586
|
}),
|
|
9555
|
-
streamTextSync: channel({
|
|
9556
|
-
channelName: "streamText.sync",
|
|
9557
|
-
kind: "sync-stream"
|
|
9558
|
-
}),
|
|
9559
9587
|
generateObject: channel({
|
|
9560
9588
|
channelName: "generateObject",
|
|
9561
9589
|
kind: "async"
|
|
@@ -9564,10 +9592,6 @@ var aiSDKChannels = defineChannels("ai", {
|
|
|
9564
9592
|
channelName: "streamObject",
|
|
9565
9593
|
kind: "async"
|
|
9566
9594
|
}),
|
|
9567
|
-
streamObjectSync: channel({
|
|
9568
|
-
channelName: "streamObject.sync",
|
|
9569
|
-
kind: "sync-stream"
|
|
9570
|
-
}),
|
|
9571
9595
|
agentGenerate: channel({
|
|
9572
9596
|
channelName: "Agent.generate",
|
|
9573
9597
|
kind: "async"
|
|
@@ -9603,6 +9627,9 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
|
|
|
9603
9627
|
];
|
|
9604
9628
|
var AUTO_PATCHED_MODEL = Symbol.for("braintrust.ai-sdk.auto-patched-model");
|
|
9605
9629
|
var AUTO_PATCHED_TOOL = Symbol.for("braintrust.ai-sdk.auto-patched-tool");
|
|
9630
|
+
var RUNTIME_DENY_OUTPUT_PATHS = Symbol.for(
|
|
9631
|
+
"braintrust.ai-sdk.deny-output-paths"
|
|
9632
|
+
);
|
|
9606
9633
|
var AISDKPlugin = class extends BasePlugin {
|
|
9607
9634
|
config;
|
|
9608
9635
|
constructor(config = {}) {
|
|
@@ -9624,7 +9651,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9624
9651
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9625
9652
|
extractOutput: (result, endEvent) => {
|
|
9626
9653
|
finalizeAISDKChildTracing(endEvent);
|
|
9627
|
-
return processAISDKOutput(
|
|
9654
|
+
return processAISDKOutput(
|
|
9655
|
+
result,
|
|
9656
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9657
|
+
);
|
|
9628
9658
|
},
|
|
9629
9659
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9630
9660
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -9635,25 +9665,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9635
9665
|
name: "streamText",
|
|
9636
9666
|
type: "llm" /* LLM */,
|
|
9637
9667
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9638
|
-
extractOutput: (result) => processAISDKOutput(
|
|
9668
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
9669
|
+
result,
|
|
9670
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9671
|
+
),
|
|
9639
9672
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9640
9673
|
aggregateChunks: aggregateAISDKChunks,
|
|
9641
9674
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9642
|
-
denyOutputPaths,
|
|
9643
|
-
endEvent,
|
|
9644
|
-
result,
|
|
9645
|
-
span,
|
|
9646
|
-
startTime
|
|
9647
|
-
})
|
|
9648
|
-
})
|
|
9649
|
-
);
|
|
9650
|
-
this.unsubscribers.push(
|
|
9651
|
-
traceSyncStreamChannel(aiSDKChannels.streamTextSync, {
|
|
9652
|
-
name: "streamText",
|
|
9653
|
-
type: "llm" /* LLM */,
|
|
9654
|
-
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9655
|
-
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9656
|
-
denyOutputPaths,
|
|
9675
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
9657
9676
|
endEvent,
|
|
9658
9677
|
result,
|
|
9659
9678
|
span,
|
|
@@ -9668,7 +9687,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9668
9687
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9669
9688
|
extractOutput: (result, endEvent) => {
|
|
9670
9689
|
finalizeAISDKChildTracing(endEvent);
|
|
9671
|
-
return processAISDKOutput(
|
|
9690
|
+
return processAISDKOutput(
|
|
9691
|
+
result,
|
|
9692
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9693
|
+
);
|
|
9672
9694
|
},
|
|
9673
9695
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9674
9696
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -9679,25 +9701,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9679
9701
|
name: "streamObject",
|
|
9680
9702
|
type: "llm" /* LLM */,
|
|
9681
9703
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9682
|
-
extractOutput: (result) => processAISDKOutput(
|
|
9704
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
9705
|
+
result,
|
|
9706
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9707
|
+
),
|
|
9683
9708
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9684
9709
|
aggregateChunks: aggregateAISDKChunks,
|
|
9685
9710
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9686
|
-
denyOutputPaths,
|
|
9687
|
-
endEvent,
|
|
9688
|
-
result,
|
|
9689
|
-
span,
|
|
9690
|
-
startTime
|
|
9691
|
-
})
|
|
9692
|
-
})
|
|
9693
|
-
);
|
|
9694
|
-
this.unsubscribers.push(
|
|
9695
|
-
traceSyncStreamChannel(aiSDKChannels.streamObjectSync, {
|
|
9696
|
-
name: "streamObject",
|
|
9697
|
-
type: "llm" /* LLM */,
|
|
9698
|
-
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9699
|
-
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9700
|
-
denyOutputPaths,
|
|
9711
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
9701
9712
|
endEvent,
|
|
9702
9713
|
result,
|
|
9703
9714
|
span,
|
|
@@ -9712,7 +9723,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9712
9723
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9713
9724
|
extractOutput: (result, endEvent) => {
|
|
9714
9725
|
finalizeAISDKChildTracing(endEvent);
|
|
9715
|
-
return processAISDKOutput(
|
|
9726
|
+
return processAISDKOutput(
|
|
9727
|
+
result,
|
|
9728
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9729
|
+
);
|
|
9716
9730
|
},
|
|
9717
9731
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9718
9732
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -9723,11 +9737,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9723
9737
|
name: "Agent.stream",
|
|
9724
9738
|
type: "llm" /* LLM */,
|
|
9725
9739
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9726
|
-
extractOutput: (result) => processAISDKOutput(
|
|
9740
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
9741
|
+
result,
|
|
9742
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9743
|
+
),
|
|
9727
9744
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9728
9745
|
aggregateChunks: aggregateAISDKChunks,
|
|
9729
9746
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9730
|
-
denyOutputPaths,
|
|
9747
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
9731
9748
|
endEvent,
|
|
9732
9749
|
result,
|
|
9733
9750
|
span,
|
|
@@ -9742,7 +9759,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9742
9759
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9743
9760
|
extractOutput: (result, endEvent) => {
|
|
9744
9761
|
finalizeAISDKChildTracing(endEvent);
|
|
9745
|
-
return processAISDKOutput(
|
|
9762
|
+
return processAISDKOutput(
|
|
9763
|
+
result,
|
|
9764
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9765
|
+
);
|
|
9746
9766
|
},
|
|
9747
9767
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9748
9768
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -9753,11 +9773,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9753
9773
|
name: "ToolLoopAgent.stream",
|
|
9754
9774
|
type: "llm" /* LLM */,
|
|
9755
9775
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9756
|
-
extractOutput: (result) => processAISDKOutput(
|
|
9776
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
9777
|
+
result,
|
|
9778
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9779
|
+
),
|
|
9757
9780
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9758
9781
|
aggregateChunks: aggregateAISDKChunks,
|
|
9759
9782
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9760
|
-
denyOutputPaths,
|
|
9783
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
9761
9784
|
endEvent,
|
|
9762
9785
|
result,
|
|
9763
9786
|
span,
|
|
@@ -9767,132 +9790,435 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9767
9790
|
);
|
|
9768
9791
|
}
|
|
9769
9792
|
};
|
|
9770
|
-
function
|
|
9771
|
-
if (
|
|
9772
|
-
|
|
9773
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
9774
|
-
return input;
|
|
9793
|
+
function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
|
|
9794
|
+
if (Array.isArray(event?.denyOutputPaths)) {
|
|
9795
|
+
return event.denyOutputPaths;
|
|
9775
9796
|
}
|
|
9776
|
-
const
|
|
9777
|
-
|
|
9778
|
-
|
|
9779
|
-
function prepareAISDKInput(params, event, span, denyOutputPaths) {
|
|
9780
|
-
const input = processAISDKInput(params);
|
|
9781
|
-
const metadata = extractMetadataFromParams(params, event.self);
|
|
9782
|
-
const childTracing = prepareAISDKChildTracing(
|
|
9783
|
-
params,
|
|
9784
|
-
event.self,
|
|
9785
|
-
span,
|
|
9786
|
-
denyOutputPaths
|
|
9787
|
-
);
|
|
9788
|
-
event.__braintrust_ai_sdk_model_wrapped = childTracing.modelWrapped;
|
|
9789
|
-
if (childTracing.cleanup) {
|
|
9790
|
-
event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
|
|
9797
|
+
const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
|
|
9798
|
+
if (!firstArgument || typeof firstArgument !== "object") {
|
|
9799
|
+
return defaultDenyOutputPaths;
|
|
9791
9800
|
}
|
|
9792
|
-
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
};
|
|
9796
|
-
}
|
|
9797
|
-
function extractTopLevelAISDKMetrics(result, event, startTime) {
|
|
9798
|
-
const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
|
|
9799
|
-
if (startTime) {
|
|
9800
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
9801
|
+
const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
|
|
9802
|
+
if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path) => typeof path === "string")) {
|
|
9803
|
+
return runtimeDenyOutputPaths;
|
|
9801
9804
|
}
|
|
9802
|
-
return
|
|
9803
|
-
}
|
|
9804
|
-
function hasModelChildTracing(event) {
|
|
9805
|
-
return event?.__braintrust_ai_sdk_model_wrapped === true;
|
|
9805
|
+
return defaultDenyOutputPaths;
|
|
9806
9806
|
}
|
|
9807
|
-
|
|
9808
|
-
|
|
9809
|
-
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
|
-
}
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
if (model) {
|
|
9819
|
-
metadata.model = model;
|
|
9807
|
+
var isZodSchema2 = (value) => {
|
|
9808
|
+
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
9809
|
+
};
|
|
9810
|
+
var serializeZodSchema2 = (schema) => {
|
|
9811
|
+
try {
|
|
9812
|
+
return zodToJsonSchema(schema);
|
|
9813
|
+
} catch {
|
|
9814
|
+
return {
|
|
9815
|
+
type: "object",
|
|
9816
|
+
description: "Zod schema (conversion failed)"
|
|
9817
|
+
};
|
|
9820
9818
|
}
|
|
9821
|
-
|
|
9822
|
-
|
|
9819
|
+
};
|
|
9820
|
+
var isOutputObject = (value) => {
|
|
9821
|
+
if (value == null || typeof value !== "object") {
|
|
9822
|
+
return false;
|
|
9823
9823
|
}
|
|
9824
|
-
const
|
|
9825
|
-
if (
|
|
9826
|
-
|
|
9824
|
+
const output = value;
|
|
9825
|
+
if (!("responseFormat" in output)) {
|
|
9826
|
+
return false;
|
|
9827
9827
|
}
|
|
9828
|
-
|
|
9829
|
-
|
|
9830
|
-
|
|
9831
|
-
|
|
9832
|
-
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
9837
|
-
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
patchedModels.add(resolvedModel);
|
|
9841
|
-
resolvedModel[AUTO_PATCHED_MODEL] = true;
|
|
9842
|
-
modelWrapped = true;
|
|
9843
|
-
const originalDoGenerate = resolvedModel.doGenerate;
|
|
9844
|
-
const originalDoStream = resolvedModel.doStream;
|
|
9845
|
-
const baseMetadata = buildAISDKChildMetadata(resolvedModel);
|
|
9846
|
-
resolvedModel.doGenerate = async function doGeneratePatched(options) {
|
|
9847
|
-
return parentSpan.traced(
|
|
9848
|
-
async (span) => {
|
|
9849
|
-
const result = await Reflect.apply(
|
|
9850
|
-
originalDoGenerate,
|
|
9851
|
-
resolvedModel,
|
|
9852
|
-
[options]
|
|
9853
|
-
);
|
|
9854
|
-
span.log({
|
|
9855
|
-
output: processAISDKOutput(result, denyOutputPaths),
|
|
9856
|
-
metrics: extractTokenMetrics(result),
|
|
9857
|
-
...buildResolvedMetadataPayload(result)
|
|
9858
|
-
});
|
|
9859
|
-
return result;
|
|
9860
|
-
},
|
|
9861
|
-
{
|
|
9862
|
-
name: "doGenerate",
|
|
9863
|
-
spanAttributes: {
|
|
9864
|
-
type: "llm" /* LLM */
|
|
9865
|
-
},
|
|
9866
|
-
event: {
|
|
9867
|
-
input: processAISDKInput(options),
|
|
9868
|
-
metadata: baseMetadata
|
|
9869
|
-
}
|
|
9870
|
-
}
|
|
9871
|
-
);
|
|
9828
|
+
if (output.type === "object" || output.type === "text") {
|
|
9829
|
+
return true;
|
|
9830
|
+
}
|
|
9831
|
+
if (typeof output.responseFormat === "function" || typeof output.responseFormat === "object") {
|
|
9832
|
+
return true;
|
|
9833
|
+
}
|
|
9834
|
+
return false;
|
|
9835
|
+
};
|
|
9836
|
+
var serializeOutputObject = (output, model) => {
|
|
9837
|
+
try {
|
|
9838
|
+
const result = {
|
|
9839
|
+
response_format: null
|
|
9872
9840
|
};
|
|
9873
|
-
if (
|
|
9874
|
-
|
|
9875
|
-
|
|
9876
|
-
|
|
9877
|
-
|
|
9878
|
-
|
|
9879
|
-
|
|
9880
|
-
|
|
9881
|
-
|
|
9882
|
-
|
|
9841
|
+
if (output.type) {
|
|
9842
|
+
result.type = output.type;
|
|
9843
|
+
}
|
|
9844
|
+
let responseFormat;
|
|
9845
|
+
if (typeof output.responseFormat === "function") {
|
|
9846
|
+
const mockModelForSchema = {
|
|
9847
|
+
supportsStructuredOutputs: true,
|
|
9848
|
+
...model && typeof model === "object" ? model : {}
|
|
9849
|
+
};
|
|
9850
|
+
responseFormat = output.responseFormat({ model: mockModelForSchema });
|
|
9851
|
+
} else if (output.responseFormat != null && typeof output.responseFormat === "object") {
|
|
9852
|
+
responseFormat = output.responseFormat;
|
|
9853
|
+
}
|
|
9854
|
+
if (responseFormat) {
|
|
9855
|
+
if (typeof responseFormat.then === "function") {
|
|
9856
|
+
result.response_format = Promise.resolve(responseFormat).then(
|
|
9857
|
+
(resolved) => {
|
|
9858
|
+
if (resolved.schema && isZodSchema2(resolved.schema)) {
|
|
9859
|
+
return {
|
|
9860
|
+
...resolved,
|
|
9861
|
+
schema: serializeZodSchema2(resolved.schema)
|
|
9862
|
+
};
|
|
9863
|
+
}
|
|
9864
|
+
return resolved;
|
|
9883
9865
|
}
|
|
9884
|
-
});
|
|
9885
|
-
const result = await withCurrent(
|
|
9886
|
-
span,
|
|
9887
|
-
() => Reflect.apply(originalDoStream, resolvedModel, [options])
|
|
9888
9866
|
);
|
|
9889
|
-
|
|
9890
|
-
|
|
9891
|
-
|
|
9892
|
-
|
|
9867
|
+
} else {
|
|
9868
|
+
const syncResponseFormat = responseFormat;
|
|
9869
|
+
if (syncResponseFormat.schema && isZodSchema2(syncResponseFormat.schema)) {
|
|
9870
|
+
responseFormat = {
|
|
9871
|
+
...syncResponseFormat,
|
|
9872
|
+
schema: serializeZodSchema2(syncResponseFormat.schema)
|
|
9873
|
+
};
|
|
9874
|
+
}
|
|
9875
|
+
result.response_format = responseFormat;
|
|
9876
|
+
}
|
|
9877
|
+
}
|
|
9878
|
+
return result;
|
|
9879
|
+
} catch {
|
|
9880
|
+
return {
|
|
9881
|
+
response_format: null
|
|
9882
|
+
};
|
|
9883
|
+
}
|
|
9884
|
+
};
|
|
9885
|
+
var processInputAttachmentsSync = (input) => {
|
|
9886
|
+
if (!input) return { input };
|
|
9887
|
+
const processed = { ...input };
|
|
9888
|
+
if (input.messages && Array.isArray(input.messages)) {
|
|
9889
|
+
processed.messages = input.messages.map(processMessage);
|
|
9890
|
+
}
|
|
9891
|
+
if (input.prompt && typeof input.prompt === "object") {
|
|
9892
|
+
if (Array.isArray(input.prompt)) {
|
|
9893
|
+
processed.prompt = input.prompt.map(processMessage);
|
|
9894
|
+
} else {
|
|
9895
|
+
processed.prompt = processPromptContent(input.prompt);
|
|
9896
|
+
}
|
|
9897
|
+
}
|
|
9898
|
+
if (input.schema && isZodSchema2(input.schema)) {
|
|
9899
|
+
processed.schema = serializeZodSchema2(input.schema);
|
|
9900
|
+
}
|
|
9901
|
+
if (input.callOptionsSchema && isZodSchema2(input.callOptionsSchema)) {
|
|
9902
|
+
processed.callOptionsSchema = serializeZodSchema2(input.callOptionsSchema);
|
|
9903
|
+
}
|
|
9904
|
+
if (input.tools) {
|
|
9905
|
+
processed.tools = serializeAISDKToolsForLogging(input.tools);
|
|
9906
|
+
}
|
|
9907
|
+
let outputPromise;
|
|
9908
|
+
if (input.output && isOutputObject(input.output)) {
|
|
9909
|
+
const serialized = serializeOutputObject(input.output, input.model);
|
|
9910
|
+
if (serialized.response_format && typeof serialized.response_format.then === "function") {
|
|
9911
|
+
processed.output = { ...serialized, response_format: {} };
|
|
9912
|
+
outputPromise = serialized.response_format.then(
|
|
9913
|
+
(resolvedFormat) => ({
|
|
9914
|
+
output: { ...serialized, response_format: resolvedFormat }
|
|
9915
|
+
})
|
|
9916
|
+
);
|
|
9917
|
+
} else {
|
|
9918
|
+
processed.output = serialized;
|
|
9919
|
+
}
|
|
9920
|
+
}
|
|
9921
|
+
if ("prepareCall" in processed && typeof processed.prepareCall === "function") {
|
|
9922
|
+
processed.prepareCall = "[Function]";
|
|
9923
|
+
}
|
|
9924
|
+
return { input: processed, outputPromise };
|
|
9925
|
+
};
|
|
9926
|
+
var processMessage = (message) => {
|
|
9927
|
+
if (!message || typeof message !== "object") return message;
|
|
9928
|
+
if (Array.isArray(message.content)) {
|
|
9929
|
+
return {
|
|
9930
|
+
...message,
|
|
9931
|
+
content: message.content.map(processContentPart)
|
|
9932
|
+
};
|
|
9933
|
+
}
|
|
9934
|
+
if (typeof message.content === "object" && message.content !== null) {
|
|
9935
|
+
return {
|
|
9936
|
+
...message,
|
|
9937
|
+
content: processContentPart(message.content)
|
|
9938
|
+
};
|
|
9939
|
+
}
|
|
9940
|
+
return message;
|
|
9941
|
+
};
|
|
9942
|
+
var processPromptContent = (prompt) => {
|
|
9943
|
+
if (Array.isArray(prompt)) {
|
|
9944
|
+
return prompt.map(processContentPart);
|
|
9945
|
+
}
|
|
9946
|
+
if (prompt.content) {
|
|
9947
|
+
if (Array.isArray(prompt.content)) {
|
|
9948
|
+
return {
|
|
9949
|
+
...prompt,
|
|
9950
|
+
content: prompt.content.map(processContentPart)
|
|
9951
|
+
};
|
|
9952
|
+
} else if (typeof prompt.content === "object") {
|
|
9953
|
+
return {
|
|
9954
|
+
...prompt,
|
|
9955
|
+
content: processContentPart(prompt.content)
|
|
9956
|
+
};
|
|
9957
|
+
}
|
|
9958
|
+
}
|
|
9959
|
+
return prompt;
|
|
9960
|
+
};
|
|
9961
|
+
var processContentPart = (part) => {
|
|
9962
|
+
if (!part || typeof part !== "object") return part;
|
|
9963
|
+
try {
|
|
9964
|
+
if (part.type === "image" && part.image) {
|
|
9965
|
+
const imageAttachment = convertImageToAttachment(
|
|
9966
|
+
part.image,
|
|
9967
|
+
part.mimeType || part.mediaType
|
|
9968
|
+
);
|
|
9969
|
+
if (imageAttachment) {
|
|
9970
|
+
return {
|
|
9971
|
+
...part,
|
|
9972
|
+
image: imageAttachment
|
|
9973
|
+
};
|
|
9974
|
+
}
|
|
9975
|
+
}
|
|
9976
|
+
if (part.type === "file" && part.data && (part.mimeType || part.mediaType)) {
|
|
9977
|
+
const fileAttachment = convertDataToAttachment(
|
|
9978
|
+
part.data,
|
|
9979
|
+
part.mimeType || part.mediaType,
|
|
9980
|
+
part.name || part.filename
|
|
9981
|
+
);
|
|
9982
|
+
if (fileAttachment) {
|
|
9983
|
+
return {
|
|
9984
|
+
...part,
|
|
9985
|
+
data: fileAttachment
|
|
9986
|
+
};
|
|
9987
|
+
}
|
|
9988
|
+
}
|
|
9989
|
+
if (part.type === "image_url" && part.image_url) {
|
|
9990
|
+
if (typeof part.image_url === "object" && part.image_url.url) {
|
|
9991
|
+
const imageAttachment = convertImageToAttachment(part.image_url.url);
|
|
9992
|
+
if (imageAttachment) {
|
|
9993
|
+
return {
|
|
9994
|
+
...part,
|
|
9995
|
+
image_url: {
|
|
9996
|
+
...part.image_url,
|
|
9997
|
+
url: imageAttachment
|
|
9998
|
+
}
|
|
9999
|
+
};
|
|
10000
|
+
}
|
|
10001
|
+
}
|
|
10002
|
+
}
|
|
10003
|
+
} catch (error) {
|
|
10004
|
+
console.warn("Error processing content part:", error);
|
|
10005
|
+
}
|
|
10006
|
+
return part;
|
|
10007
|
+
};
|
|
10008
|
+
var convertImageToAttachment = (image, explicitMimeType) => {
|
|
10009
|
+
try {
|
|
10010
|
+
if (typeof image === "string" && image.startsWith("data:")) {
|
|
10011
|
+
const [mimeTypeSection, base64Data] = image.split(",");
|
|
10012
|
+
const mimeType = mimeTypeSection.match(/data:(.*?);/)?.[1];
|
|
10013
|
+
if (mimeType && base64Data) {
|
|
10014
|
+
const blob = convertDataToBlob(base64Data, mimeType);
|
|
10015
|
+
if (blob) {
|
|
10016
|
+
return new Attachment({
|
|
10017
|
+
data: blob,
|
|
10018
|
+
filename: `image.${getExtensionFromMediaType(mimeType)}`,
|
|
10019
|
+
contentType: mimeType
|
|
10020
|
+
});
|
|
10021
|
+
}
|
|
10022
|
+
}
|
|
10023
|
+
}
|
|
10024
|
+
if (explicitMimeType) {
|
|
10025
|
+
if (image instanceof Uint8Array) {
|
|
10026
|
+
return new Attachment({
|
|
10027
|
+
data: new Blob([image], { type: explicitMimeType }),
|
|
10028
|
+
filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
|
|
10029
|
+
contentType: explicitMimeType
|
|
10030
|
+
});
|
|
10031
|
+
}
|
|
10032
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
|
|
10033
|
+
return new Attachment({
|
|
10034
|
+
data: new Blob([image], { type: explicitMimeType }),
|
|
10035
|
+
filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
|
|
10036
|
+
contentType: explicitMimeType
|
|
10037
|
+
});
|
|
10038
|
+
}
|
|
10039
|
+
}
|
|
10040
|
+
if (image instanceof Blob && image.type) {
|
|
10041
|
+
return new Attachment({
|
|
10042
|
+
data: image,
|
|
10043
|
+
filename: `image.${getExtensionFromMediaType(image.type)}`,
|
|
10044
|
+
contentType: image.type
|
|
10045
|
+
});
|
|
10046
|
+
}
|
|
10047
|
+
if (image instanceof Attachment) {
|
|
10048
|
+
return image;
|
|
10049
|
+
}
|
|
10050
|
+
} catch (error) {
|
|
10051
|
+
console.warn("Error converting image to attachment:", error);
|
|
10052
|
+
}
|
|
10053
|
+
return null;
|
|
10054
|
+
};
|
|
10055
|
+
var convertDataToAttachment = (data, mimeType, filename) => {
|
|
10056
|
+
if (!mimeType) return null;
|
|
10057
|
+
try {
|
|
10058
|
+
let blob = null;
|
|
10059
|
+
if (typeof data === "string" && data.startsWith("data:")) {
|
|
10060
|
+
const [, base64Data] = data.split(",");
|
|
10061
|
+
if (base64Data) {
|
|
10062
|
+
blob = convertDataToBlob(base64Data, mimeType);
|
|
10063
|
+
}
|
|
10064
|
+
} else if (typeof data === "string" && data.length > 0) {
|
|
10065
|
+
blob = convertDataToBlob(data, mimeType);
|
|
10066
|
+
} else if (data instanceof Uint8Array) {
|
|
10067
|
+
blob = new Blob([data], { type: mimeType });
|
|
10068
|
+
} else if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
|
|
10069
|
+
blob = new Blob([data], { type: mimeType });
|
|
10070
|
+
} else if (data instanceof Blob) {
|
|
10071
|
+
blob = data;
|
|
10072
|
+
}
|
|
10073
|
+
if (blob) {
|
|
10074
|
+
return new Attachment({
|
|
10075
|
+
data: blob,
|
|
10076
|
+
filename: filename || `file.${getExtensionFromMediaType(mimeType)}`,
|
|
10077
|
+
contentType: mimeType
|
|
10078
|
+
});
|
|
10079
|
+
}
|
|
10080
|
+
} catch (error) {
|
|
10081
|
+
console.warn("Error converting data to attachment:", error);
|
|
10082
|
+
}
|
|
10083
|
+
return null;
|
|
10084
|
+
};
|
|
10085
|
+
function processAISDKInput(params) {
|
|
10086
|
+
return processInputAttachmentsSync(params);
|
|
10087
|
+
}
|
|
10088
|
+
function prepareAISDKInput(params, event, span, defaultDenyOutputPaths) {
|
|
10089
|
+
const { input, outputPromise } = processAISDKInput(params);
|
|
10090
|
+
if (outputPromise && input && typeof input === "object") {
|
|
10091
|
+
outputPromise.then((resolvedData) => {
|
|
10092
|
+
span.log({
|
|
10093
|
+
input: {
|
|
10094
|
+
...input,
|
|
10095
|
+
...resolvedData
|
|
10096
|
+
}
|
|
10097
|
+
});
|
|
10098
|
+
}).catch(() => {
|
|
10099
|
+
});
|
|
10100
|
+
}
|
|
10101
|
+
const metadata = extractMetadataFromParams(params, event.self);
|
|
10102
|
+
const childTracing = prepareAISDKChildTracing(
|
|
10103
|
+
params,
|
|
10104
|
+
event.self,
|
|
10105
|
+
span,
|
|
10106
|
+
defaultDenyOutputPaths,
|
|
10107
|
+
event.aiSDK
|
|
10108
|
+
);
|
|
10109
|
+
event.modelWrapped = childTracing.modelWrapped;
|
|
10110
|
+
if (childTracing.cleanup) {
|
|
10111
|
+
event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
|
|
10112
|
+
}
|
|
10113
|
+
return {
|
|
10114
|
+
input,
|
|
10115
|
+
metadata
|
|
10116
|
+
};
|
|
10117
|
+
}
|
|
10118
|
+
function extractTopLevelAISDKMetrics(result, event, startTime) {
|
|
10119
|
+
const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
|
|
10120
|
+
if (startTime) {
|
|
10121
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
10122
|
+
}
|
|
10123
|
+
return metrics;
|
|
10124
|
+
}
|
|
10125
|
+
function hasModelChildTracing(event) {
|
|
10126
|
+
return event?.modelWrapped === true || event?.__braintrust_ai_sdk_model_wrapped === true;
|
|
10127
|
+
}
|
|
10128
|
+
function extractMetadataFromParams(params, self) {
|
|
10129
|
+
const metadata = {
|
|
10130
|
+
braintrust: {
|
|
10131
|
+
integration_name: "ai-sdk",
|
|
10132
|
+
sdk_language: "typescript"
|
|
10133
|
+
}
|
|
10134
|
+
};
|
|
10135
|
+
const agentModel = self && typeof self === "object" && "model" in self && self.model ? self.model : self && typeof self === "object" && "settings" in self && self.settings?.model ? self.settings?.model : void 0;
|
|
10136
|
+
const { model, provider } = serializeModelWithProvider(
|
|
10137
|
+
params.model ?? agentModel
|
|
10138
|
+
);
|
|
10139
|
+
if (model) {
|
|
10140
|
+
metadata.model = model;
|
|
10141
|
+
}
|
|
10142
|
+
if (provider) {
|
|
10143
|
+
metadata.provider = provider;
|
|
10144
|
+
}
|
|
10145
|
+
const tools = serializeAISDKToolsForLogging(params.tools);
|
|
10146
|
+
if (tools) {
|
|
10147
|
+
metadata.tools = tools;
|
|
10148
|
+
}
|
|
10149
|
+
return metadata;
|
|
10150
|
+
}
|
|
10151
|
+
function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiSDK) {
|
|
10152
|
+
const cleanup = [];
|
|
10153
|
+
const patchedModels = /* @__PURE__ */ new WeakSet();
|
|
10154
|
+
const patchedTools = /* @__PURE__ */ new WeakSet();
|
|
10155
|
+
let modelWrapped = false;
|
|
10156
|
+
const patchModel = (model) => {
|
|
10157
|
+
const resolvedModel = resolveAISDKModel(model, aiSDK);
|
|
10158
|
+
if (!resolvedModel || typeof resolvedModel !== "object" || typeof resolvedModel.doGenerate !== "function" || patchedModels.has(resolvedModel) || resolvedModel[AUTO_PATCHED_MODEL]) {
|
|
10159
|
+
return resolvedModel;
|
|
10160
|
+
}
|
|
10161
|
+
patchedModels.add(resolvedModel);
|
|
10162
|
+
resolvedModel[AUTO_PATCHED_MODEL] = true;
|
|
10163
|
+
modelWrapped = true;
|
|
10164
|
+
const originalDoGenerate = resolvedModel.doGenerate;
|
|
10165
|
+
const originalDoStream = resolvedModel.doStream;
|
|
10166
|
+
const baseMetadata = buildAISDKChildMetadata(resolvedModel);
|
|
10167
|
+
resolvedModel.doGenerate = async function doGeneratePatched(options) {
|
|
10168
|
+
return parentSpan.traced(
|
|
10169
|
+
async (span) => {
|
|
10170
|
+
const result = await Reflect.apply(
|
|
10171
|
+
originalDoGenerate,
|
|
10172
|
+
resolvedModel,
|
|
10173
|
+
[options]
|
|
10174
|
+
);
|
|
10175
|
+
span.log({
|
|
10176
|
+
output: processAISDKOutput(result, denyOutputPaths),
|
|
10177
|
+
metrics: extractTokenMetrics(result),
|
|
10178
|
+
...buildResolvedMetadataPayload(result)
|
|
10179
|
+
});
|
|
10180
|
+
return result;
|
|
10181
|
+
},
|
|
10182
|
+
{
|
|
10183
|
+
name: "doGenerate",
|
|
10184
|
+
spanAttributes: {
|
|
10185
|
+
type: "llm" /* LLM */
|
|
10186
|
+
},
|
|
10187
|
+
event: {
|
|
10188
|
+
input: processAISDKInput(options).input,
|
|
10189
|
+
metadata: baseMetadata
|
|
10190
|
+
}
|
|
10191
|
+
}
|
|
10192
|
+
);
|
|
10193
|
+
};
|
|
10194
|
+
if (originalDoStream) {
|
|
10195
|
+
resolvedModel.doStream = async function doStreamPatched(options) {
|
|
10196
|
+
const span = parentSpan.startSpan({
|
|
10197
|
+
name: "doStream",
|
|
10198
|
+
spanAttributes: {
|
|
10199
|
+
type: "llm" /* LLM */
|
|
10200
|
+
},
|
|
10201
|
+
event: {
|
|
10202
|
+
input: processAISDKInput(options).input,
|
|
10203
|
+
metadata: baseMetadata
|
|
10204
|
+
}
|
|
10205
|
+
});
|
|
10206
|
+
const result = await withCurrent(
|
|
10207
|
+
span,
|
|
10208
|
+
() => Reflect.apply(originalDoStream, resolvedModel, [options])
|
|
10209
|
+
);
|
|
10210
|
+
const streamStartTime = getCurrentUnixTimestamp();
|
|
10211
|
+
let firstChunkTime;
|
|
10212
|
+
const output = {};
|
|
10213
|
+
let text = "";
|
|
10214
|
+
let reasoning = "";
|
|
10215
|
+
const toolCalls = [];
|
|
9893
10216
|
let object = void 0;
|
|
9894
10217
|
const transformStream = new TransformStream({
|
|
9895
10218
|
transform(chunk, controller) {
|
|
10219
|
+
if (firstChunkTime === void 0) {
|
|
10220
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
10221
|
+
}
|
|
9896
10222
|
switch (chunk.type) {
|
|
9897
10223
|
case "text-delta":
|
|
9898
10224
|
text += extractTextDelta(chunk);
|
|
@@ -9933,12 +10259,19 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
9933
10259
|
if (object !== void 0) {
|
|
9934
10260
|
output.object = object;
|
|
9935
10261
|
}
|
|
10262
|
+
const metrics = extractTokenMetrics(output);
|
|
10263
|
+
if (firstChunkTime !== void 0) {
|
|
10264
|
+
metrics.time_to_first_token = Math.max(
|
|
10265
|
+
firstChunkTime - streamStartTime,
|
|
10266
|
+
1e-6
|
|
10267
|
+
);
|
|
10268
|
+
}
|
|
9936
10269
|
span.log({
|
|
9937
10270
|
output: processAISDKOutput(
|
|
9938
10271
|
output,
|
|
9939
10272
|
denyOutputPaths
|
|
9940
10273
|
),
|
|
9941
|
-
metrics
|
|
10274
|
+
metrics,
|
|
9942
10275
|
...buildResolvedMetadataPayload(output)
|
|
9943
10276
|
});
|
|
9944
10277
|
span.end();
|
|
@@ -9960,6 +10293,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
9960
10293
|
}
|
|
9961
10294
|
delete resolvedModel[AUTO_PATCHED_MODEL];
|
|
9962
10295
|
});
|
|
10296
|
+
return resolvedModel;
|
|
9963
10297
|
};
|
|
9964
10298
|
const patchTool = (tool, name) => {
|
|
9965
10299
|
if (tool == null || typeof tool !== "object" || !("execute" in tool) || typeof tool.execute !== "function" || patchedTools.has(tool) || tool[AUTO_PATCHED_TOOL]) {
|
|
@@ -10032,17 +10366,26 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
10032
10366
|
}
|
|
10033
10367
|
};
|
|
10034
10368
|
if (params && typeof params === "object") {
|
|
10035
|
-
patchModel(params.model);
|
|
10369
|
+
const patchedParamModel = patchModel(params.model);
|
|
10370
|
+
if (typeof params.model === "string" && patchedParamModel && typeof patchedParamModel === "object") {
|
|
10371
|
+
params.model = patchedParamModel;
|
|
10372
|
+
}
|
|
10036
10373
|
patchTools(params.tools);
|
|
10037
10374
|
}
|
|
10038
10375
|
if (self && typeof self === "object") {
|
|
10039
10376
|
const selfRecord = self;
|
|
10040
10377
|
if (selfRecord.model !== void 0) {
|
|
10041
|
-
patchModel(selfRecord.model);
|
|
10378
|
+
const patchedSelfModel = patchModel(selfRecord.model);
|
|
10379
|
+
if (typeof selfRecord.model === "string" && patchedSelfModel && typeof patchedSelfModel === "object") {
|
|
10380
|
+
selfRecord.model = patchedSelfModel;
|
|
10381
|
+
}
|
|
10042
10382
|
}
|
|
10043
10383
|
if (selfRecord.settings && typeof selfRecord.settings === "object") {
|
|
10044
10384
|
if (selfRecord.settings.model !== void 0) {
|
|
10045
|
-
patchModel(selfRecord.settings.model);
|
|
10385
|
+
const patchedSettingsModel = patchModel(selfRecord.settings.model);
|
|
10386
|
+
if (typeof selfRecord.settings.model === "string" && patchedSettingsModel && typeof patchedSettingsModel === "object") {
|
|
10387
|
+
selfRecord.settings.model = patchedSettingsModel;
|
|
10388
|
+
}
|
|
10046
10389
|
}
|
|
10047
10390
|
if (selfRecord.settings.tools !== void 0) {
|
|
10048
10391
|
patchTools(selfRecord.settings.tools);
|
|
@@ -10066,63 +10409,173 @@ function finalizeAISDKChildTracing(event) {
|
|
|
10066
10409
|
}
|
|
10067
10410
|
}
|
|
10068
10411
|
function patchAISDKStreamingResult(args) {
|
|
10069
|
-
const {
|
|
10412
|
+
const { defaultDenyOutputPaths, endEvent, result, span, startTime } = args;
|
|
10070
10413
|
if (!result || typeof result !== "object") {
|
|
10071
10414
|
return false;
|
|
10072
10415
|
}
|
|
10073
10416
|
const resultRecord = result;
|
|
10074
|
-
|
|
10417
|
+
attachKnownResultPromiseHandlers(resultRecord);
|
|
10418
|
+
if (isReadableStreamLike(resultRecord.baseStream)) {
|
|
10419
|
+
let firstChunkTime2;
|
|
10420
|
+
const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
|
|
10421
|
+
new TransformStream({
|
|
10422
|
+
transform(chunk, controller) {
|
|
10423
|
+
if (firstChunkTime2 === void 0) {
|
|
10424
|
+
firstChunkTime2 = getCurrentUnixTimestamp();
|
|
10425
|
+
}
|
|
10426
|
+
controller.enqueue(chunk);
|
|
10427
|
+
},
|
|
10428
|
+
async flush() {
|
|
10429
|
+
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
10430
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime2 !== void 0) {
|
|
10431
|
+
metrics.time_to_first_token = firstChunkTime2 - startTime;
|
|
10432
|
+
}
|
|
10433
|
+
const output = await processAISDKStreamingOutput(
|
|
10434
|
+
result,
|
|
10435
|
+
resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
|
|
10436
|
+
);
|
|
10437
|
+
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
10438
|
+
span.log({
|
|
10439
|
+
output,
|
|
10440
|
+
...metadata ? { metadata } : {},
|
|
10441
|
+
metrics
|
|
10442
|
+
});
|
|
10443
|
+
finalizeAISDKChildTracing(endEvent);
|
|
10444
|
+
span.end();
|
|
10445
|
+
}
|
|
10446
|
+
})
|
|
10447
|
+
);
|
|
10448
|
+
Object.defineProperty(resultRecord, "baseStream", {
|
|
10449
|
+
configurable: true,
|
|
10450
|
+
enumerable: true,
|
|
10451
|
+
value: wrappedBaseStream,
|
|
10452
|
+
writable: true
|
|
10453
|
+
});
|
|
10454
|
+
return true;
|
|
10455
|
+
}
|
|
10456
|
+
const streamField = findAsyncIterableField(resultRecord, [
|
|
10457
|
+
"partialObjectStream",
|
|
10458
|
+
"textStream",
|
|
10459
|
+
"fullStream",
|
|
10460
|
+
"stream"
|
|
10461
|
+
]);
|
|
10462
|
+
if (!streamField) {
|
|
10075
10463
|
return false;
|
|
10076
10464
|
}
|
|
10077
10465
|
let firstChunkTime;
|
|
10078
|
-
const
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
10082
|
-
firstChunkTime = getCurrentUnixTimestamp();
|
|
10083
|
-
}
|
|
10084
|
-
controller.enqueue(chunk);
|
|
10085
|
-
},
|
|
10086
|
-
async flush() {
|
|
10087
|
-
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
10088
|
-
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
10089
|
-
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
10090
|
-
}
|
|
10091
|
-
const output = await processAISDKStreamingOutput(
|
|
10092
|
-
result,
|
|
10093
|
-
denyOutputPaths
|
|
10094
|
-
);
|
|
10095
|
-
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
10096
|
-
span.log({
|
|
10097
|
-
output,
|
|
10098
|
-
...metadata ? { metadata } : {},
|
|
10099
|
-
metrics
|
|
10100
|
-
});
|
|
10101
|
-
finalizeAISDKChildTracing(endEvent);
|
|
10102
|
-
span.end();
|
|
10466
|
+
const wrappedStream = createPatchedAsyncIterable(streamField.stream, {
|
|
10467
|
+
onChunk: () => {
|
|
10468
|
+
if (firstChunkTime === void 0) {
|
|
10469
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
10103
10470
|
}
|
|
10104
|
-
}
|
|
10105
|
-
|
|
10106
|
-
|
|
10471
|
+
},
|
|
10472
|
+
onComplete: async () => {
|
|
10473
|
+
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
10474
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
10475
|
+
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
10476
|
+
}
|
|
10477
|
+
const output = await processAISDKStreamingOutput(
|
|
10478
|
+
result,
|
|
10479
|
+
resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
|
|
10480
|
+
);
|
|
10481
|
+
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
10482
|
+
span.log({
|
|
10483
|
+
output,
|
|
10484
|
+
...metadata ? { metadata } : {},
|
|
10485
|
+
metrics
|
|
10486
|
+
});
|
|
10487
|
+
finalizeAISDKChildTracing(endEvent);
|
|
10488
|
+
span.end();
|
|
10489
|
+
},
|
|
10490
|
+
onError: (error) => {
|
|
10491
|
+
span.log({
|
|
10492
|
+
error: error.message
|
|
10493
|
+
});
|
|
10494
|
+
finalizeAISDKChildTracing(endEvent);
|
|
10495
|
+
span.end();
|
|
10496
|
+
}
|
|
10497
|
+
});
|
|
10498
|
+
Object.defineProperty(resultRecord, streamField.field, {
|
|
10107
10499
|
configurable: true,
|
|
10108
10500
|
enumerable: true,
|
|
10109
|
-
value:
|
|
10501
|
+
value: wrappedStream,
|
|
10110
10502
|
writable: true
|
|
10111
10503
|
});
|
|
10112
10504
|
return true;
|
|
10113
10505
|
}
|
|
10114
|
-
function
|
|
10115
|
-
|
|
10116
|
-
|
|
10117
|
-
|
|
10118
|
-
|
|
10119
|
-
|
|
10506
|
+
function attachKnownResultPromiseHandlers(result) {
|
|
10507
|
+
const promiseLikeFields = [
|
|
10508
|
+
"content",
|
|
10509
|
+
"text",
|
|
10510
|
+
"object",
|
|
10511
|
+
"finishReason",
|
|
10512
|
+
"usage",
|
|
10513
|
+
"totalUsage",
|
|
10514
|
+
"steps"
|
|
10515
|
+
];
|
|
10516
|
+
for (const field of promiseLikeFields) {
|
|
10517
|
+
try {
|
|
10518
|
+
if (!(field in result)) {
|
|
10519
|
+
continue;
|
|
10520
|
+
}
|
|
10521
|
+
const value = result[field];
|
|
10522
|
+
if (isPromiseLike(value)) {
|
|
10523
|
+
void Promise.resolve(value).catch(() => {
|
|
10524
|
+
});
|
|
10525
|
+
}
|
|
10526
|
+
} catch {
|
|
10527
|
+
}
|
|
10528
|
+
}
|
|
10529
|
+
}
|
|
10530
|
+
function isReadableStreamLike(value) {
|
|
10531
|
+
return value != null && typeof value === "object" && typeof value.pipeThrough === "function";
|
|
10532
|
+
}
|
|
10533
|
+
function isAsyncIterableLike(value) {
|
|
10534
|
+
return value != null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
|
|
10535
|
+
}
|
|
10536
|
+
function findAsyncIterableField(result, candidateFields) {
|
|
10537
|
+
for (const field of candidateFields) {
|
|
10538
|
+
try {
|
|
10539
|
+
const stream = result[field];
|
|
10540
|
+
if (isAsyncIterableLike(stream)) {
|
|
10541
|
+
return { field, stream };
|
|
10542
|
+
}
|
|
10543
|
+
} catch {
|
|
10544
|
+
}
|
|
10545
|
+
}
|
|
10546
|
+
return null;
|
|
10547
|
+
}
|
|
10548
|
+
function createPatchedAsyncIterable(stream, hooks) {
|
|
10549
|
+
return {
|
|
10550
|
+
async *[Symbol.asyncIterator]() {
|
|
10551
|
+
try {
|
|
10552
|
+
for await (const chunk of stream) {
|
|
10553
|
+
hooks.onChunk(chunk);
|
|
10554
|
+
yield chunk;
|
|
10555
|
+
}
|
|
10556
|
+
await hooks.onComplete();
|
|
10557
|
+
} catch (error) {
|
|
10558
|
+
hooks.onError(
|
|
10559
|
+
error instanceof Error ? error : new Error(String(error))
|
|
10560
|
+
);
|
|
10561
|
+
throw error;
|
|
10562
|
+
}
|
|
10563
|
+
}
|
|
10564
|
+
};
|
|
10565
|
+
}
|
|
10566
|
+
async function processAISDKStreamingOutput(result, denyOutputPaths) {
|
|
10567
|
+
const output = processAISDKOutput(result, denyOutputPaths);
|
|
10568
|
+
if (!output || typeof output !== "object") {
|
|
10120
10569
|
return output;
|
|
10121
10570
|
}
|
|
10122
10571
|
const outputRecord = output;
|
|
10572
|
+
const isObjectStreamingResult = result != null && typeof result === "object" && "partialObjectStream" in result;
|
|
10123
10573
|
try {
|
|
10124
|
-
if ("text" in result
|
|
10125
|
-
|
|
10574
|
+
if (!isObjectStreamingResult && "text" in result) {
|
|
10575
|
+
const resolvedText = await Promise.resolve(result.text);
|
|
10576
|
+
if (typeof resolvedText === "string") {
|
|
10577
|
+
outputRecord.text = resolvedText;
|
|
10578
|
+
}
|
|
10126
10579
|
}
|
|
10127
10580
|
} catch {
|
|
10128
10581
|
}
|
|
@@ -10135,6 +10588,15 @@ async function processAISDKStreamingOutput(result, denyOutputPaths) {
|
|
|
10135
10588
|
}
|
|
10136
10589
|
} catch {
|
|
10137
10590
|
}
|
|
10591
|
+
try {
|
|
10592
|
+
if ("finishReason" in result) {
|
|
10593
|
+
const resolvedFinishReason = await Promise.resolve(result.finishReason);
|
|
10594
|
+
if (resolvedFinishReason !== void 0) {
|
|
10595
|
+
outputRecord.finishReason = resolvedFinishReason;
|
|
10596
|
+
}
|
|
10597
|
+
}
|
|
10598
|
+
} catch {
|
|
10599
|
+
}
|
|
10138
10600
|
return outputRecord;
|
|
10139
10601
|
}
|
|
10140
10602
|
function buildAISDKChildMetadata(model) {
|
|
@@ -10157,16 +10619,25 @@ function buildResolvedMetadataPayload(result) {
|
|
|
10157
10619
|
if (gatewayInfo?.model) {
|
|
10158
10620
|
metadata.model = gatewayInfo.model;
|
|
10159
10621
|
}
|
|
10160
|
-
|
|
10161
|
-
|
|
10622
|
+
let finishReason;
|
|
10623
|
+
try {
|
|
10624
|
+
finishReason = result.finishReason;
|
|
10625
|
+
} catch {
|
|
10626
|
+
finishReason = void 0;
|
|
10627
|
+
}
|
|
10628
|
+
if (isPromiseLike(finishReason)) {
|
|
10629
|
+
void Promise.resolve(finishReason).catch(() => {
|
|
10630
|
+
});
|
|
10631
|
+
} else if (finishReason !== void 0) {
|
|
10632
|
+
metadata.finish_reason = finishReason;
|
|
10162
10633
|
}
|
|
10163
10634
|
return Object.keys(metadata).length > 0 ? { metadata } : {};
|
|
10164
10635
|
}
|
|
10165
|
-
function resolveAISDKModel(model) {
|
|
10636
|
+
function resolveAISDKModel(model, aiSDK) {
|
|
10166
10637
|
if (typeof model !== "string") {
|
|
10167
10638
|
return model;
|
|
10168
10639
|
}
|
|
10169
|
-
const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? null;
|
|
10640
|
+
const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? aiSDK?.gateway ?? null;
|
|
10170
10641
|
if (provider && typeof provider.languageModel === "function") {
|
|
10171
10642
|
return provider.languageModel(model);
|
|
10172
10643
|
}
|
|
@@ -10189,15 +10660,15 @@ function processAISDKOutput(output, denyOutputPaths) {
|
|
|
10189
10660
|
}
|
|
10190
10661
|
function extractTokenMetrics(result) {
|
|
10191
10662
|
const metrics = {};
|
|
10192
|
-
let usage
|
|
10193
|
-
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
|
|
10663
|
+
let usage;
|
|
10664
|
+
const totalUsageValue = safeResultFieldRead(result, "totalUsage");
|
|
10665
|
+
if (totalUsageValue !== void 0 && !isPromiseLike(totalUsageValue)) {
|
|
10666
|
+
usage = totalUsageValue;
|
|
10667
|
+
}
|
|
10668
|
+
if (!usage) {
|
|
10669
|
+
const usageValue = safeResultFieldRead(result, "usage");
|
|
10670
|
+
if (usageValue !== void 0 && !isPromiseLike(usageValue)) {
|
|
10671
|
+
usage = usageValue;
|
|
10201
10672
|
}
|
|
10202
10673
|
}
|
|
10203
10674
|
if (!usage) {
|
|
@@ -10235,6 +10706,22 @@ function extractTokenMetrics(result) {
|
|
|
10235
10706
|
}
|
|
10236
10707
|
return metrics;
|
|
10237
10708
|
}
|
|
10709
|
+
function safeResultFieldRead(result, field) {
|
|
10710
|
+
return safeSerializableFieldRead(result, field);
|
|
10711
|
+
}
|
|
10712
|
+
function safeSerializableFieldRead(obj, field) {
|
|
10713
|
+
try {
|
|
10714
|
+
const value = obj?.[field];
|
|
10715
|
+
if (isPromiseLike(value)) {
|
|
10716
|
+
void Promise.resolve(value).catch(() => {
|
|
10717
|
+
});
|
|
10718
|
+
return void 0;
|
|
10719
|
+
}
|
|
10720
|
+
return value;
|
|
10721
|
+
} catch {
|
|
10722
|
+
return void 0;
|
|
10723
|
+
}
|
|
10724
|
+
}
|
|
10238
10725
|
function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
10239
10726
|
const lastChunk = chunks[chunks.length - 1];
|
|
10240
10727
|
const output = {};
|
|
@@ -10243,17 +10730,21 @@ function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
|
10243
10730
|
if (lastChunk) {
|
|
10244
10731
|
metrics = hasModelChildTracing(endEvent) ? {} : extractTokenMetrics(lastChunk);
|
|
10245
10732
|
metadata = buildResolvedMetadataPayload(lastChunk).metadata;
|
|
10246
|
-
|
|
10247
|
-
|
|
10733
|
+
const text = safeSerializableFieldRead(lastChunk, "text");
|
|
10734
|
+
if (text !== void 0) {
|
|
10735
|
+
output.text = text;
|
|
10248
10736
|
}
|
|
10249
|
-
|
|
10250
|
-
|
|
10737
|
+
const objectValue = safeSerializableFieldRead(lastChunk, "object");
|
|
10738
|
+
if (objectValue !== void 0) {
|
|
10739
|
+
output.object = objectValue;
|
|
10251
10740
|
}
|
|
10252
|
-
|
|
10253
|
-
|
|
10741
|
+
const finishReason = safeSerializableFieldRead(lastChunk, "finishReason");
|
|
10742
|
+
if (finishReason !== void 0) {
|
|
10743
|
+
output.finishReason = finishReason;
|
|
10254
10744
|
}
|
|
10255
|
-
|
|
10256
|
-
|
|
10745
|
+
const toolCalls = safeSerializableFieldRead(lastChunk, "toolCalls");
|
|
10746
|
+
if (toolCalls !== void 0) {
|
|
10747
|
+
output.toolCalls = toolCalls;
|
|
10257
10748
|
}
|
|
10258
10749
|
}
|
|
10259
10750
|
finalizeAISDKChildTracing(endEvent);
|
|
@@ -10262,6 +10753,7 @@ function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
|
10262
10753
|
function extractGetterValues(obj) {
|
|
10263
10754
|
const getterValues = {};
|
|
10264
10755
|
const getterNames = [
|
|
10756
|
+
"content",
|
|
10265
10757
|
"text",
|
|
10266
10758
|
"object",
|
|
10267
10759
|
"finishReason",
|
|
@@ -10277,8 +10769,17 @@ function extractGetterValues(obj) {
|
|
|
10277
10769
|
];
|
|
10278
10770
|
for (const name of getterNames) {
|
|
10279
10771
|
try {
|
|
10280
|
-
if (obj
|
|
10281
|
-
|
|
10772
|
+
if (!obj || !(name in obj)) {
|
|
10773
|
+
continue;
|
|
10774
|
+
}
|
|
10775
|
+
const value = obj[name];
|
|
10776
|
+
if (isPromiseLike(value)) {
|
|
10777
|
+
void Promise.resolve(value).catch(() => {
|
|
10778
|
+
});
|
|
10779
|
+
continue;
|
|
10780
|
+
}
|
|
10781
|
+
if (isSerializableOutputValue(value)) {
|
|
10782
|
+
getterValues[name] = value;
|
|
10282
10783
|
}
|
|
10283
10784
|
} catch {
|
|
10284
10785
|
}
|
|
@@ -10300,6 +10801,11 @@ function extractSerializableOutputFields(output) {
|
|
|
10300
10801
|
for (const name of directFieldNames) {
|
|
10301
10802
|
try {
|
|
10302
10803
|
const value = output?.[name];
|
|
10804
|
+
if (isPromiseLike(value)) {
|
|
10805
|
+
void Promise.resolve(value).catch(() => {
|
|
10806
|
+
});
|
|
10807
|
+
continue;
|
|
10808
|
+
}
|
|
10303
10809
|
if (isSerializableOutputValue(value)) {
|
|
10304
10810
|
serialized[name] = value;
|
|
10305
10811
|
}
|
|
@@ -10311,6 +10817,9 @@ function extractSerializableOutputFields(output) {
|
|
|
10311
10817
|
...extractGetterValues(output)
|
|
10312
10818
|
};
|
|
10313
10819
|
}
|
|
10820
|
+
function isPromiseLike(value) {
|
|
10821
|
+
return value != null && typeof value === "object" && typeof value.then === "function";
|
|
10822
|
+
}
|
|
10314
10823
|
function isSerializableOutputValue(value) {
|
|
10315
10824
|
if (typeof value === "function") {
|
|
10316
10825
|
return false;
|
|
@@ -10352,8 +10861,9 @@ function parseGatewayModelString(modelString) {
|
|
|
10352
10861
|
return { model: modelString };
|
|
10353
10862
|
}
|
|
10354
10863
|
function extractGatewayRoutingInfo(result) {
|
|
10355
|
-
|
|
10356
|
-
|
|
10864
|
+
const steps = safeSerializableFieldRead(result, "steps");
|
|
10865
|
+
if (Array.isArray(steps) && steps.length > 0) {
|
|
10866
|
+
const routing2 = steps[0]?.providerMetadata?.gateway?.routing;
|
|
10357
10867
|
if (routing2) {
|
|
10358
10868
|
return {
|
|
10359
10869
|
provider: routing2.resolvedProvider || routing2.finalProvider,
|
|
@@ -10361,7 +10871,11 @@ function extractGatewayRoutingInfo(result) {
|
|
|
10361
10871
|
};
|
|
10362
10872
|
}
|
|
10363
10873
|
}
|
|
10364
|
-
const
|
|
10874
|
+
const providerMetadata = safeSerializableFieldRead(
|
|
10875
|
+
result,
|
|
10876
|
+
"providerMetadata"
|
|
10877
|
+
);
|
|
10878
|
+
const routing = providerMetadata?.gateway?.routing;
|
|
10365
10879
|
if (routing) {
|
|
10366
10880
|
return {
|
|
10367
10881
|
provider: routing.resolvedProvider || routing.finalProvider,
|
|
@@ -10371,10 +10885,11 @@ function extractGatewayRoutingInfo(result) {
|
|
|
10371
10885
|
return null;
|
|
10372
10886
|
}
|
|
10373
10887
|
function extractCostFromResult(result) {
|
|
10374
|
-
|
|
10888
|
+
const steps = safeSerializableFieldRead(result, "steps");
|
|
10889
|
+
if (Array.isArray(steps) && steps.length > 0) {
|
|
10375
10890
|
let totalCost = 0;
|
|
10376
10891
|
let foundCost = false;
|
|
10377
|
-
for (const step of
|
|
10892
|
+
for (const step of steps) {
|
|
10378
10893
|
const gateway2 = step?.providerMetadata?.gateway;
|
|
10379
10894
|
const stepCost = parseGatewayCost(gateway2?.cost) || parseGatewayCost(gateway2?.marketCost);
|
|
10380
10895
|
if (stepCost !== void 0 && stepCost > 0) {
|
|
@@ -10386,7 +10901,11 @@ function extractCostFromResult(result) {
|
|
|
10386
10901
|
return totalCost;
|
|
10387
10902
|
}
|
|
10388
10903
|
}
|
|
10389
|
-
const
|
|
10904
|
+
const providerMetadata = safeSerializableFieldRead(
|
|
10905
|
+
result,
|
|
10906
|
+
"providerMetadata"
|
|
10907
|
+
);
|
|
10908
|
+
const gateway = providerMetadata?.gateway;
|
|
10390
10909
|
const directCost = parseGatewayCost(gateway?.cost) || parseGatewayCost(gateway?.marketCost);
|
|
10391
10910
|
if (directCost !== void 0 && directCost > 0) {
|
|
10392
10911
|
return directCost;
|
|
@@ -11087,20 +11606,16 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
11087
11606
|
);
|
|
11088
11607
|
});
|
|
11089
11608
|
},
|
|
11090
|
-
onComplete: () => {
|
|
11091
|
-
|
|
11092
|
-
|
|
11093
|
-
|
|
11094
|
-
|
|
11095
|
-
|
|
11096
|
-
void state.processing.then(() => {
|
|
11097
|
-
state.span.log({
|
|
11098
|
-
error: error.message
|
|
11099
|
-
});
|
|
11100
|
-
}).then(() => finalizeQuerySpan(state)).finally(() => {
|
|
11101
|
-
spans.delete(event);
|
|
11609
|
+
onComplete: () => state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
|
|
11610
|
+
spans.delete(event);
|
|
11611
|
+
}),
|
|
11612
|
+
onError: (error) => state.processing.then(() => {
|
|
11613
|
+
state.span.log({
|
|
11614
|
+
error: error.message
|
|
11102
11615
|
});
|
|
11103
|
-
}
|
|
11616
|
+
}).then(() => finalizeQuerySpan(state)).finally(() => {
|
|
11617
|
+
spans.delete(event);
|
|
11618
|
+
})
|
|
11104
11619
|
});
|
|
11105
11620
|
return;
|
|
11106
11621
|
}
|
|
@@ -11248,12 +11763,14 @@ var GoogleGenAIPlugin = class extends BasePlugin {
|
|
|
11248
11763
|
const params = event.arguments[0];
|
|
11249
11764
|
streamEvent.googleGenAIInput = serializeInput(params);
|
|
11250
11765
|
streamEvent.googleGenAIMetadata = extractMetadata(params);
|
|
11766
|
+
streamEvent.googleGenAIStartTime = getCurrentUnixTimestamp();
|
|
11251
11767
|
},
|
|
11252
11768
|
asyncEnd: (event) => {
|
|
11253
11769
|
const streamEvent = event;
|
|
11254
11770
|
patchGoogleGenAIStreamingResult({
|
|
11255
11771
|
input: streamEvent.googleGenAIInput,
|
|
11256
11772
|
metadata: streamEvent.googleGenAIMetadata,
|
|
11773
|
+
startTime: streamEvent.googleGenAIStartTime,
|
|
11257
11774
|
result: streamEvent.result
|
|
11258
11775
|
});
|
|
11259
11776
|
},
|
|
@@ -11306,7 +11823,7 @@ function logErrorAndEndSpan(states, event) {
|
|
|
11306
11823
|
states.delete(event);
|
|
11307
11824
|
}
|
|
11308
11825
|
function patchGoogleGenAIStreamingResult(args) {
|
|
11309
|
-
const { input, metadata, result } = args;
|
|
11826
|
+
const { input, metadata, result, startTime } = args;
|
|
11310
11827
|
if (!input || !metadata || !result || typeof result !== "object" || typeof result.next !== "function") {
|
|
11311
11828
|
return false;
|
|
11312
11829
|
}
|
|
@@ -11314,7 +11831,7 @@ function patchGoogleGenAIStreamingResult(args) {
|
|
|
11314
11831
|
let firstTokenTime = null;
|
|
11315
11832
|
let finalized = false;
|
|
11316
11833
|
let span = null;
|
|
11317
|
-
|
|
11834
|
+
const requestStartTime = startTime ?? getCurrentUnixTimestamp();
|
|
11318
11835
|
const ensureSpan = () => {
|
|
11319
11836
|
if (!span) {
|
|
11320
11837
|
span = startSpan({
|
|
@@ -11327,7 +11844,6 @@ function patchGoogleGenAIStreamingResult(args) {
|
|
|
11327
11844
|
metadata
|
|
11328
11845
|
}
|
|
11329
11846
|
});
|
|
11330
|
-
startTime = getCurrentUnixTimestamp();
|
|
11331
11847
|
}
|
|
11332
11848
|
return span;
|
|
11333
11849
|
};
|
|
@@ -11381,11 +11897,11 @@ function patchGoogleGenAIStreamingResult(args) {
|
|
|
11381
11897
|
}
|
|
11382
11898
|
chunks.push(nextResult.value);
|
|
11383
11899
|
}
|
|
11384
|
-
if (nextResult.done
|
|
11900
|
+
if (nextResult.done) {
|
|
11385
11901
|
finalize({
|
|
11386
11902
|
result: aggregateGenerateContentChunks(
|
|
11387
11903
|
chunks,
|
|
11388
|
-
|
|
11904
|
+
requestStartTime,
|
|
11389
11905
|
firstTokenTime
|
|
11390
11906
|
)
|
|
11391
11907
|
});
|
|
@@ -11405,13 +11921,13 @@ function patchGoogleGenAIStreamingResult(args) {
|
|
|
11405
11921
|
...returnArgs
|
|
11406
11922
|
);
|
|
11407
11923
|
} finally {
|
|
11408
|
-
if (
|
|
11924
|
+
if (chunks.length > 0) {
|
|
11409
11925
|
finalize({
|
|
11410
|
-
result:
|
|
11926
|
+
result: aggregateGenerateContentChunks(
|
|
11411
11927
|
chunks,
|
|
11412
|
-
|
|
11928
|
+
requestStartTime,
|
|
11413
11929
|
firstTokenTime
|
|
11414
|
-
)
|
|
11930
|
+
)
|
|
11415
11931
|
});
|
|
11416
11932
|
} else {
|
|
11417
11933
|
finalize({});
|
|
@@ -11703,500 +12219,488 @@ var openRouterChannels = defineChannels("@openrouter/sdk", {
|
|
|
11703
12219
|
channelName: "callModel",
|
|
11704
12220
|
kind: "sync-stream"
|
|
11705
12221
|
}),
|
|
12222
|
+
callModelTurn: channel({
|
|
12223
|
+
channelName: "callModel.turn",
|
|
12224
|
+
kind: "async"
|
|
12225
|
+
}),
|
|
11706
12226
|
toolExecute: channel({
|
|
11707
12227
|
channelName: "tool.execute",
|
|
11708
12228
|
kind: "async"
|
|
11709
12229
|
})
|
|
11710
12230
|
});
|
|
11711
12231
|
|
|
11712
|
-
// src/openrouter-
|
|
11713
|
-
var
|
|
11714
|
-
|
|
11715
|
-
|
|
11716
|
-
completionTokens: "completion_tokens",
|
|
11717
|
-
outputTokens: "completion_tokens",
|
|
11718
|
-
totalTokens: "tokens",
|
|
11719
|
-
prompt_tokens: "prompt_tokens",
|
|
11720
|
-
input_tokens: "prompt_tokens",
|
|
11721
|
-
completion_tokens: "completion_tokens",
|
|
11722
|
-
output_tokens: "completion_tokens",
|
|
11723
|
-
total_tokens: "tokens"
|
|
11724
|
-
};
|
|
11725
|
-
var TOKEN_DETAIL_PREFIX_MAP = {
|
|
11726
|
-
promptTokensDetails: "prompt",
|
|
11727
|
-
inputTokensDetails: "prompt",
|
|
11728
|
-
completionTokensDetails: "completion",
|
|
11729
|
-
outputTokensDetails: "completion",
|
|
11730
|
-
costDetails: "cost",
|
|
11731
|
-
prompt_tokens_details: "prompt",
|
|
11732
|
-
input_tokens_details: "prompt",
|
|
11733
|
-
completion_tokens_details: "completion",
|
|
11734
|
-
output_tokens_details: "completion",
|
|
11735
|
-
cost_details: "cost"
|
|
11736
|
-
};
|
|
11737
|
-
function camelToSnake(value) {
|
|
11738
|
-
return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
|
|
11739
|
-
}
|
|
11740
|
-
function parseOpenRouterMetricsFromUsage(usage) {
|
|
11741
|
-
if (!isObject(usage)) {
|
|
11742
|
-
return {};
|
|
11743
|
-
}
|
|
11744
|
-
const metrics = {};
|
|
11745
|
-
for (const [name, value] of Object.entries(usage)) {
|
|
11746
|
-
if (typeof value === "number") {
|
|
11747
|
-
metrics[TOKEN_NAME_MAP2[name] || camelToSnake(name)] = value;
|
|
11748
|
-
continue;
|
|
11749
|
-
}
|
|
11750
|
-
if (!isObject(value)) {
|
|
11751
|
-
continue;
|
|
11752
|
-
}
|
|
11753
|
-
const prefix = TOKEN_DETAIL_PREFIX_MAP[name];
|
|
11754
|
-
if (!prefix) {
|
|
11755
|
-
continue;
|
|
11756
|
-
}
|
|
11757
|
-
for (const [nestedName, nestedValue] of Object.entries(value)) {
|
|
11758
|
-
if (typeof nestedValue !== "number") {
|
|
11759
|
-
continue;
|
|
11760
|
-
}
|
|
11761
|
-
metrics[`${prefix}_${camelToSnake(nestedName)}`] = nestedValue;
|
|
11762
|
-
}
|
|
11763
|
-
}
|
|
11764
|
-
return metrics;
|
|
11765
|
-
}
|
|
11766
|
-
function extractOpenRouterUsageMetadata(usage) {
|
|
11767
|
-
if (!isObject(usage)) {
|
|
11768
|
-
return void 0;
|
|
11769
|
-
}
|
|
11770
|
-
const metadata = {};
|
|
11771
|
-
if (typeof usage.isByok === "boolean") {
|
|
11772
|
-
metadata.is_byok = usage.isByok;
|
|
11773
|
-
} else if (typeof usage.is_byok === "boolean") {
|
|
11774
|
-
metadata.is_byok = usage.is_byok;
|
|
11775
|
-
}
|
|
11776
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
11777
|
-
}
|
|
11778
|
-
|
|
11779
|
-
// src/openrouter-logging.ts
|
|
11780
|
-
var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
|
|
11781
|
-
"execute",
|
|
11782
|
-
"render",
|
|
11783
|
-
"nextTurnParams",
|
|
11784
|
-
"requireApproval"
|
|
11785
|
-
]);
|
|
11786
|
-
function parseOpenRouterModelString(model) {
|
|
11787
|
-
if (typeof model !== "string") {
|
|
11788
|
-
return { model };
|
|
11789
|
-
}
|
|
11790
|
-
const slashIndex = model.indexOf("/");
|
|
11791
|
-
if (slashIndex > 0 && slashIndex < model.length - 1) {
|
|
11792
|
-
return {
|
|
11793
|
-
provider: model.substring(0, slashIndex),
|
|
11794
|
-
model: model.substring(slashIndex + 1)
|
|
11795
|
-
};
|
|
11796
|
-
}
|
|
11797
|
-
return { model };
|
|
11798
|
-
}
|
|
11799
|
-
function isZodSchema2(value) {
|
|
11800
|
-
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
11801
|
-
}
|
|
11802
|
-
function serializeZodSchema2(schema) {
|
|
11803
|
-
try {
|
|
11804
|
-
return zodToJsonSchema(schema);
|
|
11805
|
-
} catch {
|
|
11806
|
-
return {
|
|
11807
|
-
type: "object",
|
|
11808
|
-
description: "Zod schema (conversion failed)"
|
|
11809
|
-
};
|
|
11810
|
-
}
|
|
11811
|
-
}
|
|
11812
|
-
function serializeOpenRouterTool(tool) {
|
|
11813
|
-
if (!isObject(tool)) {
|
|
11814
|
-
return tool;
|
|
11815
|
-
}
|
|
11816
|
-
const serialized = {};
|
|
11817
|
-
for (const [key, value] of Object.entries(tool)) {
|
|
11818
|
-
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
11819
|
-
continue;
|
|
11820
|
-
}
|
|
11821
|
-
if (key === "function" && isObject(value)) {
|
|
11822
|
-
serialized.function = sanitizeOpenRouterLoggedValue(value);
|
|
11823
|
-
continue;
|
|
11824
|
-
}
|
|
11825
|
-
serialized[key] = sanitizeOpenRouterLoggedValue(value);
|
|
11826
|
-
}
|
|
11827
|
-
return serialized;
|
|
11828
|
-
}
|
|
11829
|
-
function serializeOpenRouterToolsForLogging(tools) {
|
|
11830
|
-
if (!Array.isArray(tools)) {
|
|
11831
|
-
return void 0;
|
|
11832
|
-
}
|
|
11833
|
-
return tools.map((tool) => serializeOpenRouterTool(tool));
|
|
11834
|
-
}
|
|
11835
|
-
function sanitizeOpenRouterLoggedValue(value) {
|
|
11836
|
-
if (isZodSchema2(value)) {
|
|
11837
|
-
return serializeZodSchema2(value);
|
|
11838
|
-
}
|
|
11839
|
-
if (typeof value === "function") {
|
|
11840
|
-
return "[Function]";
|
|
11841
|
-
}
|
|
11842
|
-
if (Array.isArray(value)) {
|
|
11843
|
-
return value.map((entry) => sanitizeOpenRouterLoggedValue(entry));
|
|
11844
|
-
}
|
|
11845
|
-
if (!isObject(value)) {
|
|
11846
|
-
return value;
|
|
12232
|
+
// src/instrumentation/plugins/openrouter-plugin.ts
|
|
12233
|
+
var OpenRouterPlugin = class extends BasePlugin {
|
|
12234
|
+
onEnable() {
|
|
12235
|
+
this.subscribeToOpenRouterChannels();
|
|
11847
12236
|
}
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
11851
|
-
continue;
|
|
11852
|
-
}
|
|
11853
|
-
if (key === "tools" && Array.isArray(entry)) {
|
|
11854
|
-
sanitized.tools = serializeOpenRouterToolsForLogging(entry);
|
|
11855
|
-
continue;
|
|
11856
|
-
}
|
|
11857
|
-
sanitized[key] = sanitizeOpenRouterLoggedValue(entry);
|
|
12237
|
+
onDisable() {
|
|
12238
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
11858
12239
|
}
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
|
|
11864
|
-
|
|
11865
|
-
|
|
11866
|
-
|
|
11867
|
-
|
|
11868
|
-
|
|
11869
|
-
|
|
11870
|
-
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
|
|
11874
|
-
}
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
11884
|
-
}
|
|
11885
|
-
|
|
11886
|
-
|
|
11887
|
-
|
|
11888
|
-
|
|
11889
|
-
|
|
11890
|
-
|
|
11891
|
-
|
|
11892
|
-
|
|
11893
|
-
|
|
11894
|
-
|
|
12240
|
+
subscribeToOpenRouterChannels() {
|
|
12241
|
+
this.unsubscribers.push(
|
|
12242
|
+
traceStreamingChannel(openRouterChannels.chatSend, {
|
|
12243
|
+
name: "openrouter.chat.send",
|
|
12244
|
+
type: "llm" /* LLM */,
|
|
12245
|
+
extractInput: (args) => {
|
|
12246
|
+
const request = getOpenRouterRequestArg(args);
|
|
12247
|
+
const chatGenerationParams = isObject(request?.chatGenerationParams) ? request.chatGenerationParams : {};
|
|
12248
|
+
const httpReferer = request?.httpReferer;
|
|
12249
|
+
const xTitle = request?.xTitle;
|
|
12250
|
+
const { messages, ...metadata } = chatGenerationParams;
|
|
12251
|
+
return {
|
|
12252
|
+
input: messages,
|
|
12253
|
+
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
12254
|
+
};
|
|
12255
|
+
},
|
|
12256
|
+
extractOutput: (result) => {
|
|
12257
|
+
return isObject(result) ? result.choices : void 0;
|
|
12258
|
+
},
|
|
12259
|
+
extractMetrics: (result, startTime) => {
|
|
12260
|
+
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
12261
|
+
if (startTime) {
|
|
12262
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
12263
|
+
}
|
|
12264
|
+
return metrics;
|
|
12265
|
+
},
|
|
12266
|
+
aggregateChunks: aggregateOpenRouterChatChunks
|
|
12267
|
+
})
|
|
12268
|
+
);
|
|
12269
|
+
this.unsubscribers.push(
|
|
12270
|
+
traceAsyncChannel(openRouterChannels.embeddingsGenerate, {
|
|
12271
|
+
name: "openrouter.embeddings.generate",
|
|
12272
|
+
type: "llm" /* LLM */,
|
|
12273
|
+
extractInput: (args) => {
|
|
12274
|
+
const request = getOpenRouterRequestArg(args);
|
|
12275
|
+
const requestBody = isObject(request?.requestBody) ? request.requestBody : {};
|
|
12276
|
+
const httpReferer = request?.httpReferer;
|
|
12277
|
+
const xTitle = request?.xTitle;
|
|
12278
|
+
const { input, ...metadata } = requestBody;
|
|
12279
|
+
return {
|
|
12280
|
+
input,
|
|
12281
|
+
metadata: buildOpenRouterEmbeddingMetadata(
|
|
12282
|
+
metadata,
|
|
12283
|
+
httpReferer,
|
|
12284
|
+
xTitle
|
|
12285
|
+
)
|
|
12286
|
+
};
|
|
12287
|
+
},
|
|
12288
|
+
extractOutput: (result) => {
|
|
12289
|
+
if (!isObject(result)) {
|
|
12290
|
+
return void 0;
|
|
12291
|
+
}
|
|
12292
|
+
const embedding = result.data?.[0]?.embedding;
|
|
12293
|
+
return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
|
|
12294
|
+
},
|
|
12295
|
+
extractMetadata: (result) => {
|
|
12296
|
+
if (!isObject(result)) {
|
|
12297
|
+
return void 0;
|
|
12298
|
+
}
|
|
12299
|
+
return extractOpenRouterResponseMetadata(result);
|
|
12300
|
+
},
|
|
12301
|
+
extractMetrics: (result) => {
|
|
12302
|
+
return isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {};
|
|
12303
|
+
}
|
|
12304
|
+
})
|
|
12305
|
+
);
|
|
12306
|
+
this.unsubscribers.push(
|
|
12307
|
+
traceStreamingChannel(openRouterChannels.betaResponsesSend, {
|
|
12308
|
+
name: "openrouter.beta.responses.send",
|
|
12309
|
+
type: "llm" /* LLM */,
|
|
12310
|
+
extractInput: (args) => {
|
|
12311
|
+
const request = getOpenRouterRequestArg(args);
|
|
12312
|
+
const openResponsesRequest = isObject(request?.openResponsesRequest) ? request.openResponsesRequest : {};
|
|
12313
|
+
const httpReferer = request?.httpReferer;
|
|
12314
|
+
const xTitle = request?.xTitle;
|
|
12315
|
+
const { input, ...metadata } = openResponsesRequest;
|
|
12316
|
+
return {
|
|
12317
|
+
input,
|
|
12318
|
+
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
12319
|
+
};
|
|
12320
|
+
},
|
|
12321
|
+
extractOutput: (result) => extractOpenRouterResponseOutput(result),
|
|
12322
|
+
extractMetadata: (result) => extractOpenRouterResponseMetadata(result),
|
|
12323
|
+
extractMetrics: (result, startTime) => {
|
|
12324
|
+
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
12325
|
+
if (startTime) {
|
|
12326
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
12327
|
+
}
|
|
12328
|
+
return metrics;
|
|
12329
|
+
},
|
|
12330
|
+
aggregateChunks: aggregateOpenRouterResponseStreamEvents
|
|
12331
|
+
})
|
|
12332
|
+
);
|
|
12333
|
+
this.unsubscribers.push(
|
|
12334
|
+
traceSyncStreamChannel(openRouterChannels.callModel, {
|
|
12335
|
+
name: "openrouter.callModel",
|
|
12336
|
+
type: "llm" /* LLM */,
|
|
12337
|
+
extractInput: (args) => {
|
|
12338
|
+
const request = getOpenRouterCallModelRequestArg(args);
|
|
12339
|
+
return {
|
|
12340
|
+
input: request ? extractOpenRouterCallModelInput(request) : void 0,
|
|
12341
|
+
metadata: request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" }
|
|
12342
|
+
};
|
|
12343
|
+
},
|
|
12344
|
+
patchResult: ({ endEvent, result, span }) => {
|
|
12345
|
+
return patchOpenRouterCallModelResult({
|
|
12346
|
+
request: getOpenRouterCallModelRequestArg(endEvent.arguments),
|
|
12347
|
+
result,
|
|
12348
|
+
span
|
|
12349
|
+
});
|
|
12350
|
+
}
|
|
12351
|
+
})
|
|
12352
|
+
);
|
|
12353
|
+
this.unsubscribers.push(
|
|
12354
|
+
traceAsyncChannel(openRouterChannels.callModelTurn, {
|
|
12355
|
+
name: "openrouter.beta.responses.send",
|
|
12356
|
+
type: "llm" /* LLM */,
|
|
12357
|
+
extractInput: (args, event) => {
|
|
12358
|
+
const request = getOpenRouterCallModelRequestArg(args);
|
|
12359
|
+
const metadata = request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" };
|
|
12360
|
+
if (isObject(metadata) && "tools" in metadata) {
|
|
12361
|
+
delete metadata.tools;
|
|
12362
|
+
}
|
|
12363
|
+
return {
|
|
12364
|
+
input: request ? extractOpenRouterCallModelInput(request) : void 0,
|
|
12365
|
+
metadata: {
|
|
12366
|
+
...metadata,
|
|
12367
|
+
step: event.step,
|
|
12368
|
+
step_type: event.stepType
|
|
12369
|
+
}
|
|
12370
|
+
};
|
|
12371
|
+
},
|
|
12372
|
+
extractOutput: (result) => extractOpenRouterResponseOutput(result),
|
|
12373
|
+
extractMetadata: (result, event) => {
|
|
12374
|
+
if (!isObject(result)) {
|
|
12375
|
+
return {
|
|
12376
|
+
step: event?.step,
|
|
12377
|
+
step_type: event?.stepType
|
|
12378
|
+
};
|
|
12379
|
+
}
|
|
12380
|
+
return {
|
|
12381
|
+
...extractOpenRouterResponseMetadata(result) || {},
|
|
12382
|
+
...event?.step !== void 0 ? { step: event.step } : {},
|
|
12383
|
+
...event?.stepType ? { step_type: event.stepType } : {}
|
|
12384
|
+
};
|
|
12385
|
+
},
|
|
12386
|
+
extractMetrics: (result) => isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {}
|
|
12387
|
+
})
|
|
12388
|
+
);
|
|
12389
|
+
this.unsubscribers.push(
|
|
12390
|
+
traceStreamingChannel(openRouterChannels.toolExecute, {
|
|
12391
|
+
name: "openrouter.tool",
|
|
12392
|
+
type: "tool" /* TOOL */,
|
|
12393
|
+
extractInput: (args, event) => ({
|
|
12394
|
+
input: args[0],
|
|
12395
|
+
metadata: {
|
|
12396
|
+
provider: "openrouter",
|
|
12397
|
+
tool_name: event.toolName,
|
|
12398
|
+
...event.toolCallId ? { tool_call_id: event.toolCallId } : {}
|
|
12399
|
+
}
|
|
12400
|
+
}),
|
|
12401
|
+
extractOutput: (result) => result,
|
|
12402
|
+
extractMetrics: () => ({}),
|
|
12403
|
+
aggregateChunks: (chunks) => ({
|
|
12404
|
+
output: chunks.length > 0 ? chunks[chunks.length - 1] : void 0,
|
|
12405
|
+
metrics: {}
|
|
12406
|
+
})
|
|
12407
|
+
})
|
|
12408
|
+
);
|
|
12409
|
+
const callModelChannel = openRouterChannels.callModel.tracingChannel();
|
|
12410
|
+
const callModelHandlers = {
|
|
12411
|
+
start: (event) => {
|
|
12412
|
+
const request = getOpenRouterCallModelRequestArg(event.arguments);
|
|
12413
|
+
if (!request) {
|
|
12414
|
+
return;
|
|
12415
|
+
}
|
|
12416
|
+
patchOpenRouterCallModelRequestTools(request);
|
|
12417
|
+
}
|
|
12418
|
+
};
|
|
12419
|
+
callModelChannel.subscribe(callModelHandlers);
|
|
12420
|
+
this.unsubscribers.push(() => {
|
|
12421
|
+
callModelChannel.unsubscribe(callModelHandlers);
|
|
12422
|
+
});
|
|
11895
12423
|
}
|
|
11896
|
-
|
|
11897
|
-
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
const normalizedModel = parseOpenRouterModelString(model);
|
|
11901
|
-
const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
|
|
11902
|
-
const usageMetadata = extractOpenRouterUsageMetadata(usage);
|
|
11903
|
-
const combined = {
|
|
11904
|
-
...rest,
|
|
11905
|
-
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
11906
|
-
...usageMetadata || {},
|
|
11907
|
-
...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
|
|
11908
|
-
};
|
|
11909
|
-
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
11910
|
-
}
|
|
11911
|
-
function extractOpenRouterResponseOutput(response, fallbackOutput) {
|
|
11912
|
-
if (isObject(response) && "output" in response && response.output !== void 0) {
|
|
11913
|
-
return sanitizeOpenRouterLoggedValue(response.output);
|
|
12424
|
+
};
|
|
12425
|
+
function normalizeArgs(args) {
|
|
12426
|
+
if (Array.isArray(args)) {
|
|
12427
|
+
return args;
|
|
11914
12428
|
}
|
|
11915
|
-
if (
|
|
11916
|
-
return
|
|
12429
|
+
if (isArrayLike(args)) {
|
|
12430
|
+
return Array.from(args);
|
|
11917
12431
|
}
|
|
11918
|
-
return
|
|
12432
|
+
return [args];
|
|
11919
12433
|
}
|
|
11920
|
-
|
|
11921
|
-
|
|
11922
|
-
|
|
11923
|
-
|
|
11924
|
-
|
|
11925
|
-
|
|
11926
|
-
|
|
11927
|
-
"getFullResponsesStream",
|
|
11928
|
-
"getItemsStream",
|
|
11929
|
-
"getNewMessagesStream",
|
|
11930
|
-
"getReasoningStream",
|
|
11931
|
-
"getTextStream",
|
|
11932
|
-
"getToolCallsStream",
|
|
11933
|
-
"getToolStream"
|
|
11934
|
-
];
|
|
11935
|
-
var OPENROUTER_CALL_MODEL_CONTEXT_METHODS = [
|
|
11936
|
-
"cancel",
|
|
11937
|
-
"getPendingToolCalls",
|
|
11938
|
-
"getState",
|
|
11939
|
-
"getToolCalls",
|
|
11940
|
-
"requiresApproval"
|
|
11941
|
-
];
|
|
11942
|
-
function patchOpenRouterCallModelRequestTools(request) {
|
|
11943
|
-
if (!Array.isArray(request.tools) || request.tools.length === 0) {
|
|
11944
|
-
return void 0;
|
|
11945
|
-
}
|
|
11946
|
-
const originalTools = request.tools;
|
|
11947
|
-
const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
|
|
11948
|
-
const didPatch = wrappedTools.some(
|
|
11949
|
-
(tool, index) => tool !== originalTools[index]
|
|
12434
|
+
function isArrayLike(value) {
|
|
12435
|
+
return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
|
|
12436
|
+
}
|
|
12437
|
+
function getOpenRouterRequestArg(args) {
|
|
12438
|
+
const normalizedArgs = normalizeArgs(args);
|
|
12439
|
+
const keyedCandidate = normalizedArgs.find(
|
|
12440
|
+
(arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
|
|
11950
12441
|
);
|
|
11951
|
-
if (
|
|
11952
|
-
return
|
|
12442
|
+
if (isObject(keyedCandidate)) {
|
|
12443
|
+
return keyedCandidate;
|
|
11953
12444
|
}
|
|
11954
|
-
|
|
11955
|
-
return ()
|
|
11956
|
-
request.tools = originalTools;
|
|
11957
|
-
};
|
|
12445
|
+
const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
|
|
12446
|
+
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
11958
12447
|
}
|
|
11959
|
-
function
|
|
11960
|
-
|
|
11961
|
-
|
|
11962
|
-
|
|
11963
|
-
|
|
11964
|
-
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
|
|
11968
|
-
|
|
12448
|
+
function getOpenRouterCallModelRequestArg(args) {
|
|
12449
|
+
const firstObjectArg = normalizeArgs(args).find((arg) => isObject(arg));
|
|
12450
|
+
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
12451
|
+
}
|
|
12452
|
+
var TOKEN_NAME_MAP2 = {
|
|
12453
|
+
promptTokens: "prompt_tokens",
|
|
12454
|
+
inputTokens: "prompt_tokens",
|
|
12455
|
+
completionTokens: "completion_tokens",
|
|
12456
|
+
outputTokens: "completion_tokens",
|
|
12457
|
+
totalTokens: "tokens",
|
|
12458
|
+
prompt_tokens: "prompt_tokens",
|
|
12459
|
+
input_tokens: "prompt_tokens",
|
|
12460
|
+
completion_tokens: "completion_tokens",
|
|
12461
|
+
output_tokens: "completion_tokens",
|
|
12462
|
+
total_tokens: "tokens"
|
|
12463
|
+
};
|
|
12464
|
+
var TOKEN_DETAIL_PREFIX_MAP = {
|
|
12465
|
+
promptTokensDetails: "prompt",
|
|
12466
|
+
inputTokensDetails: "prompt",
|
|
12467
|
+
completionTokensDetails: "completion",
|
|
12468
|
+
outputTokensDetails: "completion",
|
|
12469
|
+
costDetails: "cost",
|
|
12470
|
+
prompt_tokens_details: "prompt",
|
|
12471
|
+
input_tokens_details: "prompt",
|
|
12472
|
+
completion_tokens_details: "completion",
|
|
12473
|
+
output_tokens_details: "completion",
|
|
12474
|
+
cost_details: "cost"
|
|
12475
|
+
};
|
|
12476
|
+
function camelToSnake(value) {
|
|
12477
|
+
return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
|
|
12478
|
+
}
|
|
12479
|
+
function parseOpenRouterMetricsFromUsage(usage) {
|
|
12480
|
+
if (!isObject(usage)) {
|
|
12481
|
+
return {};
|
|
11969
12482
|
}
|
|
11970
|
-
|
|
11971
|
-
|
|
11972
|
-
|
|
11973
|
-
|
|
11974
|
-
|
|
11975
|
-
const originalGetResponse = typeof resultLike.getResponse === "function" ? resultLike.getResponse.bind(resultLike) : void 0;
|
|
11976
|
-
const originalGetInitialResponse = typeof resultLike.getInitialResponse === "function" ? resultLike.getInitialResponse.bind(resultLike) : void 0;
|
|
11977
|
-
const originalMakeFollowupRequest = typeof resultLike.makeFollowupRequest === "function" ? resultLike.makeFollowupRequest.bind(resultLike) : void 0;
|
|
11978
|
-
let ended = false;
|
|
11979
|
-
let tracedTurnCount = 0;
|
|
11980
|
-
const endSpanWithResult = async (response, fallbackOutput) => {
|
|
11981
|
-
if (ended) {
|
|
11982
|
-
return;
|
|
11983
|
-
}
|
|
11984
|
-
ended = true;
|
|
11985
|
-
const finalResponse = getFinalOpenRouterCallModelResponse(
|
|
11986
|
-
resultLike,
|
|
11987
|
-
response
|
|
11988
|
-
);
|
|
11989
|
-
if (finalResponse) {
|
|
11990
|
-
const rounds = getOpenRouterCallModelRounds(resultLike);
|
|
11991
|
-
const metadata = extractOpenRouterCallModelResultMetadata(
|
|
11992
|
-
finalResponse,
|
|
11993
|
-
rounds.length + 1
|
|
11994
|
-
);
|
|
11995
|
-
span.log({
|
|
11996
|
-
output: extractOpenRouterResponseOutput(finalResponse, fallbackOutput),
|
|
11997
|
-
...metadata ? { metadata } : {},
|
|
11998
|
-
metrics: aggregateOpenRouterCallModelMetrics(rounds, finalResponse)
|
|
11999
|
-
});
|
|
12000
|
-
span.end();
|
|
12001
|
-
return;
|
|
12002
|
-
}
|
|
12003
|
-
if (fallbackOutput !== void 0) {
|
|
12004
|
-
span.log({
|
|
12005
|
-
output: fallbackOutput
|
|
12006
|
-
});
|
|
12483
|
+
const metrics = {};
|
|
12484
|
+
for (const [name, value] of Object.entries(usage)) {
|
|
12485
|
+
if (typeof value === "number") {
|
|
12486
|
+
metrics[TOKEN_NAME_MAP2[name] || camelToSnake(name)] = value;
|
|
12487
|
+
continue;
|
|
12007
12488
|
}
|
|
12008
|
-
|
|
12009
|
-
|
|
12010
|
-
const endSpanWithError = (error) => {
|
|
12011
|
-
if (ended) {
|
|
12012
|
-
return;
|
|
12489
|
+
if (!isObject(value)) {
|
|
12490
|
+
continue;
|
|
12013
12491
|
}
|
|
12014
|
-
|
|
12015
|
-
|
|
12016
|
-
|
|
12017
|
-
});
|
|
12018
|
-
span.end();
|
|
12019
|
-
};
|
|
12020
|
-
const finalizeFromResponse = async (fallbackOutput) => {
|
|
12021
|
-
if (!originalGetResponse) {
|
|
12022
|
-
await endSpanWithResult(void 0, fallbackOutput);
|
|
12023
|
-
return;
|
|
12492
|
+
const prefix = TOKEN_DETAIL_PREFIX_MAP[name];
|
|
12493
|
+
if (!prefix) {
|
|
12494
|
+
continue;
|
|
12024
12495
|
}
|
|
12025
|
-
|
|
12026
|
-
|
|
12027
|
-
|
|
12028
|
-
|
|
12496
|
+
for (const [nestedName, nestedValue] of Object.entries(value)) {
|
|
12497
|
+
if (typeof nestedValue !== "number") {
|
|
12498
|
+
continue;
|
|
12499
|
+
}
|
|
12500
|
+
metrics[`${prefix}_${camelToSnake(nestedName)}`] = nestedValue;
|
|
12029
12501
|
}
|
|
12030
|
-
};
|
|
12031
|
-
if (originalGetResponse) {
|
|
12032
|
-
resultLike.getResponse = async (...args) => {
|
|
12033
|
-
return await withCurrent(span, async () => {
|
|
12034
|
-
try {
|
|
12035
|
-
const response = await originalGetResponse(...args);
|
|
12036
|
-
await endSpanWithResult(response);
|
|
12037
|
-
return response;
|
|
12038
|
-
} catch (error) {
|
|
12039
|
-
endSpanWithError(error);
|
|
12040
|
-
throw error;
|
|
12041
|
-
}
|
|
12042
|
-
});
|
|
12043
|
-
};
|
|
12044
12502
|
}
|
|
12045
|
-
|
|
12046
|
-
|
|
12047
|
-
|
|
12048
|
-
|
|
12049
|
-
|
|
12050
|
-
const text = await originalGetText(...args);
|
|
12051
|
-
await finalizeFromResponse(text);
|
|
12052
|
-
return text;
|
|
12053
|
-
} catch (error) {
|
|
12054
|
-
endSpanWithError(error);
|
|
12055
|
-
throw error;
|
|
12056
|
-
}
|
|
12057
|
-
});
|
|
12058
|
-
};
|
|
12503
|
+
return metrics;
|
|
12504
|
+
}
|
|
12505
|
+
function extractOpenRouterUsageMetadata(usage) {
|
|
12506
|
+
if (!isObject(usage)) {
|
|
12507
|
+
return void 0;
|
|
12059
12508
|
}
|
|
12060
|
-
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
|
|
12064
|
-
|
|
12065
|
-
resultLike[methodName] = async (...args) => {
|
|
12066
|
-
return await withCurrent(span, async () => {
|
|
12067
|
-
return await originalMethod.apply(resultLike, args);
|
|
12068
|
-
});
|
|
12069
|
-
};
|
|
12509
|
+
const metadata = {};
|
|
12510
|
+
if (typeof usage.isByok === "boolean") {
|
|
12511
|
+
metadata.is_byok = usage.isByok;
|
|
12512
|
+
} else if (typeof usage.is_byok === "boolean") {
|
|
12513
|
+
metadata.is_byok = usage.is_byok;
|
|
12070
12514
|
}
|
|
12071
|
-
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
|
|
12077
|
-
|
|
12078
|
-
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
return stream;
|
|
12083
|
-
}
|
|
12084
|
-
return wrapAsyncIterableWithSpan({
|
|
12085
|
-
finalize: finalizeFromResponse,
|
|
12086
|
-
iteratorFactory: () => stream[Symbol.asyncIterator](),
|
|
12087
|
-
onError: endSpanWithError,
|
|
12088
|
-
span
|
|
12089
|
-
});
|
|
12090
|
-
};
|
|
12515
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
12516
|
+
}
|
|
12517
|
+
var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
|
|
12518
|
+
"execute",
|
|
12519
|
+
"render",
|
|
12520
|
+
"nextTurnParams",
|
|
12521
|
+
"requireApproval"
|
|
12522
|
+
]);
|
|
12523
|
+
function parseOpenRouterModelString(model) {
|
|
12524
|
+
if (typeof model !== "string") {
|
|
12525
|
+
return { model };
|
|
12091
12526
|
}
|
|
12092
|
-
|
|
12093
|
-
|
|
12094
|
-
|
|
12095
|
-
|
|
12096
|
-
|
|
12097
|
-
return await originalGetInitialResponse(...args);
|
|
12098
|
-
});
|
|
12099
|
-
}
|
|
12100
|
-
initialTurnTraced = true;
|
|
12101
|
-
const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
|
|
12102
|
-
const childSpan = startOpenRouterCallModelTurnSpan({
|
|
12103
|
-
request: resolvedRequest,
|
|
12104
|
-
step: tracedTurnCount + 1,
|
|
12105
|
-
stepType: tracedTurnCount === 0 ? "initial" : "continue"
|
|
12106
|
-
});
|
|
12107
|
-
return await withCurrent(childSpan, async () => {
|
|
12108
|
-
try {
|
|
12109
|
-
const response = await originalGetInitialResponse(...args);
|
|
12110
|
-
tracedTurnCount++;
|
|
12111
|
-
finishOpenRouterCallModelTurnSpan({
|
|
12112
|
-
response,
|
|
12113
|
-
step: tracedTurnCount,
|
|
12114
|
-
stepType: tracedTurnCount === 1 ? "initial" : "continue",
|
|
12115
|
-
span: childSpan
|
|
12116
|
-
});
|
|
12117
|
-
return response;
|
|
12118
|
-
} catch (error) {
|
|
12119
|
-
childSpan.log({
|
|
12120
|
-
error: normalizeError(error).message
|
|
12121
|
-
});
|
|
12122
|
-
childSpan.end();
|
|
12123
|
-
throw error;
|
|
12124
|
-
}
|
|
12125
|
-
});
|
|
12527
|
+
const slashIndex = model.indexOf("/");
|
|
12528
|
+
if (slashIndex > 0 && slashIndex < model.length - 1) {
|
|
12529
|
+
return {
|
|
12530
|
+
provider: model.substring(0, slashIndex),
|
|
12531
|
+
model: model.substring(slashIndex + 1)
|
|
12126
12532
|
};
|
|
12127
12533
|
}
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
step: tracedTurnCount + 1,
|
|
12141
|
-
stepType: "continue"
|
|
12142
|
-
});
|
|
12143
|
-
return await withCurrent(childSpan, async () => {
|
|
12144
|
-
try {
|
|
12145
|
-
const response = await originalMakeFollowupRequest(...args);
|
|
12146
|
-
tracedTurnCount++;
|
|
12147
|
-
finishOpenRouterCallModelTurnSpan({
|
|
12148
|
-
response,
|
|
12149
|
-
step: tracedTurnCount,
|
|
12150
|
-
stepType: "continue",
|
|
12151
|
-
span: childSpan
|
|
12152
|
-
});
|
|
12153
|
-
return response;
|
|
12154
|
-
} catch (error) {
|
|
12155
|
-
childSpan.log({
|
|
12156
|
-
error: normalizeError(error).message
|
|
12157
|
-
});
|
|
12158
|
-
childSpan.end();
|
|
12159
|
-
throw error;
|
|
12160
|
-
}
|
|
12161
|
-
});
|
|
12534
|
+
return { model };
|
|
12535
|
+
}
|
|
12536
|
+
function isZodSchema3(value) {
|
|
12537
|
+
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
12538
|
+
}
|
|
12539
|
+
function serializeZodSchema3(schema) {
|
|
12540
|
+
try {
|
|
12541
|
+
return zodToJsonSchema(schema);
|
|
12542
|
+
} catch {
|
|
12543
|
+
return {
|
|
12544
|
+
type: "object",
|
|
12545
|
+
description: "Zod schema (conversion failed)"
|
|
12162
12546
|
};
|
|
12163
12547
|
}
|
|
12164
|
-
return true;
|
|
12165
12548
|
}
|
|
12166
|
-
function
|
|
12167
|
-
if (
|
|
12549
|
+
function serializeOpenRouterTool(tool) {
|
|
12550
|
+
if (!isObject(tool)) {
|
|
12168
12551
|
return tool;
|
|
12169
12552
|
}
|
|
12170
|
-
const
|
|
12171
|
-
const
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
function: {
|
|
12175
|
-
...tool.function,
|
|
12176
|
-
execute(...args) {
|
|
12177
|
-
return traceToolExecution({
|
|
12178
|
-
args,
|
|
12179
|
-
execute: () => Reflect.apply(originalExecute, this, args),
|
|
12180
|
-
toolCallId: getToolCallId(args[1]),
|
|
12181
|
-
toolName
|
|
12182
|
-
});
|
|
12183
|
-
}
|
|
12553
|
+
const serialized = {};
|
|
12554
|
+
for (const [key, value] of Object.entries(tool)) {
|
|
12555
|
+
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
12556
|
+
continue;
|
|
12184
12557
|
}
|
|
12185
|
-
|
|
12186
|
-
|
|
12187
|
-
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
}
|
|
12191
|
-
return
|
|
12192
|
-
}
|
|
12193
|
-
function isWrappedTool(tool) {
|
|
12194
|
-
return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
|
|
12558
|
+
if (key === "function" && isObject(value)) {
|
|
12559
|
+
serialized.function = sanitizeOpenRouterLoggedValue(value);
|
|
12560
|
+
continue;
|
|
12561
|
+
}
|
|
12562
|
+
serialized[key] = sanitizeOpenRouterLoggedValue(value);
|
|
12563
|
+
}
|
|
12564
|
+
return serialized;
|
|
12195
12565
|
}
|
|
12196
|
-
function
|
|
12197
|
-
|
|
12198
|
-
|
|
12566
|
+
function serializeOpenRouterToolsForLogging(tools) {
|
|
12567
|
+
if (!Array.isArray(tools)) {
|
|
12568
|
+
return void 0;
|
|
12569
|
+
}
|
|
12570
|
+
return tools.map((tool) => serializeOpenRouterTool(tool));
|
|
12571
|
+
}
|
|
12572
|
+
function sanitizeOpenRouterLoggedValue(value) {
|
|
12573
|
+
if (isZodSchema3(value)) {
|
|
12574
|
+
return serializeZodSchema3(value);
|
|
12575
|
+
}
|
|
12576
|
+
if (typeof value === "function") {
|
|
12577
|
+
return "[Function]";
|
|
12578
|
+
}
|
|
12579
|
+
if (Array.isArray(value)) {
|
|
12580
|
+
return value.map((entry) => sanitizeOpenRouterLoggedValue(entry));
|
|
12581
|
+
}
|
|
12582
|
+
if (!isObject(value)) {
|
|
12583
|
+
return value;
|
|
12584
|
+
}
|
|
12585
|
+
const sanitized = {};
|
|
12586
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
12587
|
+
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
12588
|
+
continue;
|
|
12589
|
+
}
|
|
12590
|
+
if (key === "tools" && Array.isArray(entry)) {
|
|
12591
|
+
sanitized.tools = serializeOpenRouterToolsForLogging(entry);
|
|
12592
|
+
continue;
|
|
12593
|
+
}
|
|
12594
|
+
sanitized[key] = sanitizeOpenRouterLoggedValue(entry);
|
|
12595
|
+
}
|
|
12596
|
+
return sanitized;
|
|
12597
|
+
}
|
|
12598
|
+
function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
|
|
12599
|
+
const sanitized = sanitizeOpenRouterLoggedValue(metadata);
|
|
12600
|
+
const metadataRecord = isObject(sanitized) ? sanitized : {};
|
|
12601
|
+
const { model, provider: providerRouting, ...rest } = metadataRecord;
|
|
12602
|
+
const normalizedModel = parseOpenRouterModelString(model);
|
|
12603
|
+
return {
|
|
12604
|
+
...rest,
|
|
12605
|
+
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
12606
|
+
...providerRouting !== void 0 ? { providerRouting } : {},
|
|
12607
|
+
...httpReferer !== void 0 ? { httpReferer } : {},
|
|
12608
|
+
...xTitle !== void 0 ? { xTitle } : {},
|
|
12609
|
+
provider: normalizedModel.provider || "openrouter"
|
|
12610
|
+
};
|
|
12611
|
+
}
|
|
12612
|
+
function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
|
|
12613
|
+
const normalized = buildOpenRouterMetadata(metadata, httpReferer, xTitle);
|
|
12614
|
+
return typeof normalized.model === "string" ? {
|
|
12615
|
+
...normalized,
|
|
12616
|
+
embedding_model: normalized.model
|
|
12617
|
+
} : normalized;
|
|
12618
|
+
}
|
|
12619
|
+
function extractOpenRouterCallModelInput(request) {
|
|
12620
|
+
return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue(request.input) : void 0;
|
|
12621
|
+
}
|
|
12622
|
+
function extractOpenRouterCallModelMetadata(request) {
|
|
12623
|
+
if (!isObject(request)) {
|
|
12624
|
+
return { provider: "openrouter" };
|
|
12625
|
+
}
|
|
12626
|
+
const { input: _input, ...metadata } = request;
|
|
12627
|
+
return buildOpenRouterMetadata(metadata, void 0, void 0);
|
|
12628
|
+
}
|
|
12629
|
+
function extractOpenRouterResponseMetadata(result) {
|
|
12630
|
+
if (!isObject(result)) {
|
|
12631
|
+
return void 0;
|
|
12632
|
+
}
|
|
12633
|
+
const { output: _output, data: _data, usage, ...metadata } = result;
|
|
12634
|
+
const sanitized = sanitizeOpenRouterLoggedValue(metadata);
|
|
12635
|
+
const metadataRecord = isObject(sanitized) ? sanitized : {};
|
|
12636
|
+
const { model, provider, ...rest } = metadataRecord;
|
|
12637
|
+
const normalizedModel = parseOpenRouterModelString(model);
|
|
12638
|
+
const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
|
|
12639
|
+
const usageMetadata = extractOpenRouterUsageMetadata(usage);
|
|
12640
|
+
const combined = {
|
|
12641
|
+
...rest,
|
|
12642
|
+
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
12643
|
+
...usageMetadata || {},
|
|
12644
|
+
...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
|
|
12645
|
+
};
|
|
12646
|
+
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
12647
|
+
}
|
|
12648
|
+
function extractOpenRouterResponseOutput(response, fallbackOutput) {
|
|
12649
|
+
if (isObject(response) && "output" in response && response.output !== void 0) {
|
|
12650
|
+
return sanitizeOpenRouterLoggedValue(response.output);
|
|
12651
|
+
}
|
|
12652
|
+
if (fallbackOutput !== void 0) {
|
|
12653
|
+
return sanitizeOpenRouterLoggedValue(fallbackOutput);
|
|
12654
|
+
}
|
|
12655
|
+
return void 0;
|
|
12656
|
+
}
|
|
12657
|
+
var OPENROUTER_WRAPPED_TOOL = Symbol("braintrust.openrouter.wrappedTool");
|
|
12658
|
+
function patchOpenRouterCallModelRequestTools(request) {
|
|
12659
|
+
if (!Array.isArray(request.tools) || request.tools.length === 0) {
|
|
12660
|
+
return void 0;
|
|
12661
|
+
}
|
|
12662
|
+
const originalTools = request.tools;
|
|
12663
|
+
const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
|
|
12664
|
+
const didPatch = wrappedTools.some(
|
|
12665
|
+
(tool, index) => tool !== originalTools[index]
|
|
12199
12666
|
);
|
|
12667
|
+
if (!didPatch) {
|
|
12668
|
+
return void 0;
|
|
12669
|
+
}
|
|
12670
|
+
request.tools = wrappedTools;
|
|
12671
|
+
return () => {
|
|
12672
|
+
request.tools = originalTools;
|
|
12673
|
+
};
|
|
12674
|
+
}
|
|
12675
|
+
function wrapOpenRouterTool(tool) {
|
|
12676
|
+
if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
|
|
12677
|
+
return tool;
|
|
12678
|
+
}
|
|
12679
|
+
const toolName = tool.function.name || "tool";
|
|
12680
|
+
const originalExecute = tool.function.execute;
|
|
12681
|
+
const wrappedTool = {
|
|
12682
|
+
...tool,
|
|
12683
|
+
function: {
|
|
12684
|
+
...tool.function,
|
|
12685
|
+
execute(...args) {
|
|
12686
|
+
return traceToolExecution({
|
|
12687
|
+
args,
|
|
12688
|
+
execute: () => Reflect.apply(originalExecute, this, args),
|
|
12689
|
+
toolCallId: getToolCallId(args[1]),
|
|
12690
|
+
toolName
|
|
12691
|
+
});
|
|
12692
|
+
}
|
|
12693
|
+
}
|
|
12694
|
+
};
|
|
12695
|
+
Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL, {
|
|
12696
|
+
value: true,
|
|
12697
|
+
enumerable: false,
|
|
12698
|
+
configurable: false
|
|
12699
|
+
});
|
|
12700
|
+
return wrappedTool;
|
|
12701
|
+
}
|
|
12702
|
+
function isWrappedTool(tool) {
|
|
12703
|
+
return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
|
|
12200
12704
|
}
|
|
12201
12705
|
function traceToolExecution(args) {
|
|
12202
12706
|
const tracingChannel = openRouterChannels.toolExecute.tracingChannel();
|
|
@@ -12220,7 +12724,7 @@ function traceToolExecution(args) {
|
|
|
12220
12724
|
}
|
|
12221
12725
|
}
|
|
12222
12726
|
function publishToolResult(tracingChannel, event, result) {
|
|
12223
|
-
if (
|
|
12727
|
+
if (isPromiseLike2(result)) {
|
|
12224
12728
|
return result.then(
|
|
12225
12729
|
(resolved) => {
|
|
12226
12730
|
event.result = resolved;
|
|
@@ -12242,465 +12746,460 @@ function getToolCallId(context) {
|
|
|
12242
12746
|
const toolContext = context;
|
|
12243
12747
|
return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
|
|
12244
12748
|
}
|
|
12245
|
-
function
|
|
12246
|
-
|
|
12247
|
-
...extractOpenRouterResponseMetadata(response) || {},
|
|
12248
|
-
...turnCount !== void 0 ? { turn_count: turnCount } : {}
|
|
12249
|
-
};
|
|
12250
|
-
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
12251
|
-
}
|
|
12252
|
-
function getFinalOpenRouterCallModelResponse(result, response) {
|
|
12253
|
-
if (isObject(response)) {
|
|
12254
|
-
return response;
|
|
12255
|
-
}
|
|
12256
|
-
return isObject(result.finalResponse) ? result.finalResponse : void 0;
|
|
12257
|
-
}
|
|
12258
|
-
function getOpenRouterCallModelRounds(result) {
|
|
12259
|
-
if (!Array.isArray(result.allToolExecutionRounds)) {
|
|
12260
|
-
return [];
|
|
12261
|
-
}
|
|
12262
|
-
return result.allToolExecutionRounds.filter((round) => isObject(round)).map((round) => ({
|
|
12263
|
-
response: isObject(round.response) ? round.response : void 0,
|
|
12264
|
-
round: typeof round.round === "number" ? round.round : void 0,
|
|
12265
|
-
toolResults: Array.isArray(round.toolResults) ? round.toolResults : []
|
|
12266
|
-
})).filter((round) => round.response !== void 0);
|
|
12267
|
-
}
|
|
12268
|
-
function aggregateOpenRouterCallModelMetrics(rounds, finalResponse) {
|
|
12269
|
-
const metrics = {};
|
|
12270
|
-
const responses = [
|
|
12271
|
-
...rounds.map((round) => round.response).filter(isObject),
|
|
12272
|
-
finalResponse
|
|
12273
|
-
];
|
|
12274
|
-
for (const response of responses) {
|
|
12275
|
-
const responseMetrics = parseOpenRouterMetricsFromUsage(response.usage);
|
|
12276
|
-
for (const [name, value] of Object.entries(responseMetrics)) {
|
|
12277
|
-
metrics[name] = (metrics[name] || 0) + value;
|
|
12278
|
-
}
|
|
12279
|
-
}
|
|
12280
|
-
return metrics;
|
|
12281
|
-
}
|
|
12282
|
-
function buildNextOpenRouterCallModelInput(currentInput, response, toolResults) {
|
|
12283
|
-
const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
|
|
12284
|
-
const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
|
|
12285
|
-
return [...normalizedInput, ...responseOutput, ...toolResults].map(
|
|
12286
|
-
(entry) => sanitizeOpenRouterLoggedValue(entry)
|
|
12287
|
-
);
|
|
12749
|
+
function isPromiseLike2(value) {
|
|
12750
|
+
return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
|
|
12288
12751
|
}
|
|
12289
|
-
function
|
|
12290
|
-
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
}
|
|
12295
|
-
|
|
12296
|
-
|
|
12297
|
-
|
|
12298
|
-
|
|
12299
|
-
}
|
|
12300
|
-
|
|
12301
|
-
|
|
12302
|
-
|
|
12303
|
-
|
|
12304
|
-
|
|
12305
|
-
step_type: args.stepType
|
|
12752
|
+
function aggregateOpenRouterChatChunks(chunks) {
|
|
12753
|
+
let role;
|
|
12754
|
+
let content = "";
|
|
12755
|
+
let toolCalls;
|
|
12756
|
+
let finishReason;
|
|
12757
|
+
let metrics = {};
|
|
12758
|
+
for (const chunk of chunks) {
|
|
12759
|
+
metrics = {
|
|
12760
|
+
...metrics,
|
|
12761
|
+
...parseOpenRouterMetricsFromUsage(chunk?.usage)
|
|
12762
|
+
};
|
|
12763
|
+
const choice = chunk?.choices?.[0];
|
|
12764
|
+
const delta = choice?.delta;
|
|
12765
|
+
if (!delta) {
|
|
12766
|
+
if (choice?.finish_reason !== void 0) {
|
|
12767
|
+
finishReason = choice.finish_reason;
|
|
12306
12768
|
}
|
|
12769
|
+
continue;
|
|
12307
12770
|
}
|
|
12308
|
-
|
|
12309
|
-
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
|
|
12318
|
-
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
|
|
12771
|
+
if (!role && delta.role) {
|
|
12772
|
+
role = delta.role;
|
|
12773
|
+
}
|
|
12774
|
+
if (typeof delta.content === "string") {
|
|
12775
|
+
content += delta.content;
|
|
12776
|
+
}
|
|
12777
|
+
const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
|
|
12778
|
+
const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
|
|
12779
|
+
if (choiceFinishReason !== void 0) {
|
|
12780
|
+
finishReason = choiceFinishReason;
|
|
12781
|
+
} else if (deltaFinishReason !== void 0) {
|
|
12782
|
+
finishReason = deltaFinishReason;
|
|
12783
|
+
}
|
|
12784
|
+
const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
|
|
12785
|
+
if (!toolCallDeltas) {
|
|
12786
|
+
continue;
|
|
12787
|
+
}
|
|
12788
|
+
for (const toolDelta of toolCallDeltas) {
|
|
12789
|
+
if (!toolDelta?.function) {
|
|
12790
|
+
continue;
|
|
12322
12791
|
}
|
|
12323
|
-
|
|
12324
|
-
|
|
12325
|
-
|
|
12326
|
-
|
|
12327
|
-
|
|
12328
|
-
|
|
12329
|
-
|
|
12330
|
-
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
function buildOpenRouterFollowupRequest(request, currentResponse, toolResults) {
|
|
12335
|
-
if (!request) {
|
|
12336
|
-
return void 0;
|
|
12337
|
-
}
|
|
12338
|
-
return {
|
|
12339
|
-
...request,
|
|
12340
|
-
input: buildNextOpenRouterCallModelInput(
|
|
12341
|
-
extractOpenRouterCallModelInput(request),
|
|
12342
|
-
isObject(currentResponse) ? currentResponse : {},
|
|
12343
|
-
toolResults
|
|
12344
|
-
),
|
|
12345
|
-
stream: false
|
|
12346
|
-
};
|
|
12347
|
-
}
|
|
12348
|
-
function wrapAsyncIterableWithSpan(args) {
|
|
12349
|
-
return {
|
|
12350
|
-
[Symbol.asyncIterator]() {
|
|
12351
|
-
const iterator = args.iteratorFactory();
|
|
12352
|
-
return {
|
|
12353
|
-
next(value) {
|
|
12354
|
-
return withCurrent(
|
|
12355
|
-
args.span,
|
|
12356
|
-
() => value === void 0 ? iterator.next() : iterator.next(value)
|
|
12357
|
-
).then(
|
|
12358
|
-
async (result) => {
|
|
12359
|
-
if (result.done) {
|
|
12360
|
-
await args.finalize();
|
|
12361
|
-
}
|
|
12362
|
-
return result;
|
|
12363
|
-
},
|
|
12364
|
-
(error) => {
|
|
12365
|
-
args.onError(error);
|
|
12366
|
-
throw error;
|
|
12367
|
-
}
|
|
12368
|
-
);
|
|
12369
|
-
},
|
|
12370
|
-
return(value) {
|
|
12371
|
-
if (typeof iterator.return !== "function") {
|
|
12372
|
-
return args.finalize().then(() => ({
|
|
12373
|
-
done: true,
|
|
12374
|
-
value
|
|
12375
|
-
}));
|
|
12376
|
-
}
|
|
12377
|
-
return withCurrent(args.span, () => iterator.return(value)).then(
|
|
12378
|
-
async (result) => {
|
|
12379
|
-
await args.finalize();
|
|
12380
|
-
return result;
|
|
12381
|
-
},
|
|
12382
|
-
(error) => {
|
|
12383
|
-
args.onError(error);
|
|
12384
|
-
throw error;
|
|
12385
|
-
}
|
|
12386
|
-
);
|
|
12387
|
-
},
|
|
12388
|
-
throw(error) {
|
|
12389
|
-
args.onError(error);
|
|
12390
|
-
if (typeof iterator.throw !== "function") {
|
|
12391
|
-
return Promise.reject(error);
|
|
12792
|
+
const toolIndex = toolDelta.index ?? 0;
|
|
12793
|
+
const existingToolCall = toolCalls?.[toolIndex];
|
|
12794
|
+
if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
|
|
12795
|
+
const nextToolCalls = [...toolCalls || []];
|
|
12796
|
+
nextToolCalls[toolIndex] = {
|
|
12797
|
+
index: toolIndex,
|
|
12798
|
+
id: toolDelta.id,
|
|
12799
|
+
type: toolDelta.type,
|
|
12800
|
+
function: {
|
|
12801
|
+
name: toolDelta.function.name,
|
|
12802
|
+
arguments: toolDelta.function.arguments || ""
|
|
12392
12803
|
}
|
|
12393
|
-
|
|
12394
|
-
|
|
12395
|
-
|
|
12396
|
-
|
|
12397
|
-
|
|
12398
|
-
|
|
12804
|
+
};
|
|
12805
|
+
toolCalls = nextToolCalls;
|
|
12806
|
+
continue;
|
|
12807
|
+
}
|
|
12808
|
+
const current = existingToolCall;
|
|
12809
|
+
if (toolDelta.id && !current.id) {
|
|
12810
|
+
current.id = toolDelta.id;
|
|
12811
|
+
}
|
|
12812
|
+
if (toolDelta.type && !current.type) {
|
|
12813
|
+
current.type = toolDelta.type;
|
|
12814
|
+
}
|
|
12815
|
+
if (toolDelta.function.name && !current.function.name) {
|
|
12816
|
+
current.function.name = toolDelta.function.name;
|
|
12817
|
+
}
|
|
12818
|
+
current.function.arguments += toolDelta.function.arguments || "";
|
|
12399
12819
|
}
|
|
12820
|
+
}
|
|
12821
|
+
return {
|
|
12822
|
+
output: [
|
|
12823
|
+
{
|
|
12824
|
+
index: 0,
|
|
12825
|
+
message: {
|
|
12826
|
+
role,
|
|
12827
|
+
content: content || void 0,
|
|
12828
|
+
...toolCalls ? { tool_calls: toolCalls } : {}
|
|
12829
|
+
},
|
|
12830
|
+
logprobs: null,
|
|
12831
|
+
finish_reason: finishReason
|
|
12832
|
+
}
|
|
12833
|
+
],
|
|
12834
|
+
metrics
|
|
12400
12835
|
};
|
|
12401
12836
|
}
|
|
12402
|
-
function
|
|
12403
|
-
|
|
12404
|
-
|
|
12405
|
-
|
|
12406
|
-
|
|
12407
|
-
|
|
12408
|
-
|
|
12409
|
-
|
|
12837
|
+
function aggregateOpenRouterResponseStreamEvents(chunks) {
|
|
12838
|
+
let finalResponse;
|
|
12839
|
+
for (const chunk of chunks) {
|
|
12840
|
+
const response = chunk?.response;
|
|
12841
|
+
if (!response) {
|
|
12842
|
+
continue;
|
|
12843
|
+
}
|
|
12844
|
+
if (chunk.type === "response.completed" || chunk.type === "response.incomplete" || chunk.type === "response.failed") {
|
|
12845
|
+
finalResponse = response;
|
|
12846
|
+
}
|
|
12847
|
+
}
|
|
12848
|
+
if (!finalResponse) {
|
|
12849
|
+
return {
|
|
12850
|
+
output: void 0,
|
|
12851
|
+
metrics: {}
|
|
12852
|
+
};
|
|
12853
|
+
}
|
|
12854
|
+
return {
|
|
12855
|
+
output: extractOpenRouterResponseOutput(finalResponse),
|
|
12856
|
+
metrics: parseOpenRouterMetricsFromUsage(finalResponse.usage),
|
|
12857
|
+
...extractOpenRouterResponseMetadata(finalResponse) ? { metadata: extractOpenRouterResponseMetadata(finalResponse) } : {}
|
|
12858
|
+
};
|
|
12410
12859
|
}
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
|
|
12415
|
-
|
|
12860
|
+
var OPENROUTER_WRAPPED_CALL_MODEL_RESULT = Symbol(
|
|
12861
|
+
"braintrust.openrouter.wrappedCallModelResult"
|
|
12862
|
+
);
|
|
12863
|
+
var OPENROUTER_CALL_MODEL_STREAM_METHODS = [
|
|
12864
|
+
"getFullResponsesStream",
|
|
12865
|
+
"getItemsStream",
|
|
12866
|
+
"getNewMessagesStream",
|
|
12867
|
+
"getReasoningStream",
|
|
12868
|
+
"getTextStream",
|
|
12869
|
+
"getToolCallsStream",
|
|
12870
|
+
"getToolStream"
|
|
12871
|
+
];
|
|
12872
|
+
var OPENROUTER_CALL_MODEL_CONTEXT_METHODS = [
|
|
12873
|
+
"cancel",
|
|
12874
|
+
"getPendingToolCalls",
|
|
12875
|
+
"getState",
|
|
12876
|
+
"getToolCalls",
|
|
12877
|
+
"requiresApproval"
|
|
12878
|
+
];
|
|
12879
|
+
function patchOpenRouterCallModelResult(args) {
|
|
12880
|
+
const { request, result, span } = args;
|
|
12881
|
+
if (!isObject(result) || isWrappedCallModelResult(result)) {
|
|
12882
|
+
return false;
|
|
12416
12883
|
}
|
|
12417
|
-
|
|
12418
|
-
|
|
12884
|
+
const resultLike = result;
|
|
12885
|
+
const hasInstrumentableMethod = typeof resultLike.getResponse === "function" || typeof resultLike.getText === "function" || OPENROUTER_CALL_MODEL_STREAM_METHODS.some(
|
|
12886
|
+
(methodName) => typeof resultLike[methodName] === "function"
|
|
12887
|
+
);
|
|
12888
|
+
if (!hasInstrumentableMethod) {
|
|
12889
|
+
return false;
|
|
12419
12890
|
}
|
|
12420
|
-
|
|
12421
|
-
|
|
12422
|
-
|
|
12423
|
-
|
|
12424
|
-
|
|
12425
|
-
|
|
12426
|
-
|
|
12427
|
-
|
|
12428
|
-
|
|
12429
|
-
|
|
12430
|
-
|
|
12431
|
-
|
|
12432
|
-
|
|
12433
|
-
|
|
12434
|
-
|
|
12435
|
-
|
|
12436
|
-
|
|
12437
|
-
|
|
12438
|
-
},
|
|
12439
|
-
extractMetrics: (result, startTime) => {
|
|
12440
|
-
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
12441
|
-
if (startTime) {
|
|
12442
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
12443
|
-
}
|
|
12444
|
-
return metrics;
|
|
12445
|
-
},
|
|
12446
|
-
aggregateChunks: aggregateOpenRouterChatChunks
|
|
12447
|
-
})
|
|
12448
|
-
);
|
|
12449
|
-
this.unsubscribers.push(
|
|
12450
|
-
traceAsyncChannel(openRouterChannels.embeddingsGenerate, {
|
|
12451
|
-
name: "openrouter.embeddings.generate",
|
|
12452
|
-
type: "llm" /* LLM */,
|
|
12453
|
-
extractInput: (args) => {
|
|
12454
|
-
const request = getOpenRouterRequestArg(args);
|
|
12455
|
-
const requestBody = isObject(request?.requestBody) ? request.requestBody : {};
|
|
12456
|
-
const httpReferer = request?.httpReferer;
|
|
12457
|
-
const xTitle = request?.xTitle;
|
|
12458
|
-
const { input, ...metadata } = requestBody;
|
|
12459
|
-
return {
|
|
12460
|
-
input,
|
|
12461
|
-
metadata: buildOpenRouterEmbeddingMetadata(
|
|
12462
|
-
metadata,
|
|
12463
|
-
httpReferer,
|
|
12464
|
-
xTitle
|
|
12465
|
-
)
|
|
12466
|
-
};
|
|
12467
|
-
},
|
|
12468
|
-
extractOutput: (result) => {
|
|
12469
|
-
if (!isObject(result)) {
|
|
12470
|
-
return void 0;
|
|
12471
|
-
}
|
|
12472
|
-
const embedding = result.data?.[0]?.embedding;
|
|
12473
|
-
return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
|
|
12474
|
-
},
|
|
12475
|
-
extractMetadata: (result) => {
|
|
12476
|
-
if (!isObject(result)) {
|
|
12477
|
-
return void 0;
|
|
12478
|
-
}
|
|
12479
|
-
return extractOpenRouterResponseMetadata(result);
|
|
12480
|
-
},
|
|
12481
|
-
extractMetrics: (result) => {
|
|
12482
|
-
return isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {};
|
|
12483
|
-
}
|
|
12484
|
-
})
|
|
12485
|
-
);
|
|
12486
|
-
this.unsubscribers.push(
|
|
12487
|
-
traceStreamingChannel(openRouterChannels.betaResponsesSend, {
|
|
12488
|
-
name: "openrouter.beta.responses.send",
|
|
12489
|
-
type: "llm" /* LLM */,
|
|
12490
|
-
extractInput: (args) => {
|
|
12491
|
-
const request = getOpenRouterRequestArg(args);
|
|
12492
|
-
const openResponsesRequest = isObject(request?.openResponsesRequest) ? request.openResponsesRequest : {};
|
|
12493
|
-
const httpReferer = request?.httpReferer;
|
|
12494
|
-
const xTitle = request?.xTitle;
|
|
12495
|
-
const { input, ...metadata } = openResponsesRequest;
|
|
12496
|
-
return {
|
|
12497
|
-
input,
|
|
12498
|
-
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
12499
|
-
};
|
|
12500
|
-
},
|
|
12501
|
-
extractOutput: (result) => extractOpenRouterResponseOutput(result),
|
|
12502
|
-
extractMetadata: (result) => extractOpenRouterResponseMetadata(result),
|
|
12503
|
-
extractMetrics: (result, startTime) => {
|
|
12504
|
-
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
12505
|
-
if (startTime) {
|
|
12506
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
12507
|
-
}
|
|
12508
|
-
return metrics;
|
|
12509
|
-
},
|
|
12510
|
-
aggregateChunks: aggregateOpenRouterResponseStreamEvents
|
|
12511
|
-
})
|
|
12891
|
+
Object.defineProperty(resultLike, OPENROUTER_WRAPPED_CALL_MODEL_RESULT, {
|
|
12892
|
+
value: true,
|
|
12893
|
+
enumerable: false,
|
|
12894
|
+
configurable: false
|
|
12895
|
+
});
|
|
12896
|
+
const originalGetResponse = typeof resultLike.getResponse === "function" ? resultLike.getResponse.bind(resultLike) : void 0;
|
|
12897
|
+
const originalGetInitialResponse = typeof resultLike.getInitialResponse === "function" ? resultLike.getInitialResponse.bind(resultLike) : void 0;
|
|
12898
|
+
const originalMakeFollowupRequest = typeof resultLike.makeFollowupRequest === "function" ? resultLike.makeFollowupRequest.bind(resultLike) : void 0;
|
|
12899
|
+
let ended = false;
|
|
12900
|
+
let tracedTurnCount = 0;
|
|
12901
|
+
const endSpanWithResult = async (response, fallbackOutput) => {
|
|
12902
|
+
if (ended) {
|
|
12903
|
+
return;
|
|
12904
|
+
}
|
|
12905
|
+
ended = true;
|
|
12906
|
+
const finalResponse = getFinalOpenRouterCallModelResponse(
|
|
12907
|
+
resultLike,
|
|
12908
|
+
response
|
|
12512
12909
|
);
|
|
12513
|
-
|
|
12514
|
-
|
|
12515
|
-
|
|
12516
|
-
|
|
12517
|
-
|
|
12518
|
-
|
|
12519
|
-
|
|
12520
|
-
|
|
12521
|
-
|
|
12522
|
-
|
|
12523
|
-
|
|
12524
|
-
|
|
12525
|
-
|
|
12526
|
-
|
|
12527
|
-
|
|
12528
|
-
|
|
12529
|
-
|
|
12910
|
+
if (finalResponse) {
|
|
12911
|
+
const rounds = getOpenRouterCallModelRounds(resultLike);
|
|
12912
|
+
const metadata = extractOpenRouterCallModelResultMetadata(
|
|
12913
|
+
finalResponse,
|
|
12914
|
+
rounds.length + 1
|
|
12915
|
+
);
|
|
12916
|
+
span.log({
|
|
12917
|
+
output: extractOpenRouterResponseOutput(finalResponse, fallbackOutput),
|
|
12918
|
+
...metadata ? { metadata } : {},
|
|
12919
|
+
metrics: aggregateOpenRouterCallModelMetrics(rounds, finalResponse)
|
|
12920
|
+
});
|
|
12921
|
+
span.end();
|
|
12922
|
+
return;
|
|
12923
|
+
}
|
|
12924
|
+
if (fallbackOutput !== void 0) {
|
|
12925
|
+
span.log({
|
|
12926
|
+
output: fallbackOutput
|
|
12927
|
+
});
|
|
12928
|
+
}
|
|
12929
|
+
span.end();
|
|
12930
|
+
};
|
|
12931
|
+
const endSpanWithError = (error) => {
|
|
12932
|
+
if (ended) {
|
|
12933
|
+
return;
|
|
12934
|
+
}
|
|
12935
|
+
ended = true;
|
|
12936
|
+
span.log({
|
|
12937
|
+
error: normalizeError(error).message
|
|
12938
|
+
});
|
|
12939
|
+
span.end();
|
|
12940
|
+
};
|
|
12941
|
+
const finalizeFromResponse = async (fallbackOutput) => {
|
|
12942
|
+
if (!originalGetResponse) {
|
|
12943
|
+
await endSpanWithResult(void 0, fallbackOutput);
|
|
12944
|
+
return;
|
|
12945
|
+
}
|
|
12946
|
+
try {
|
|
12947
|
+
await endSpanWithResult(await originalGetResponse(), fallbackOutput);
|
|
12948
|
+
} catch {
|
|
12949
|
+
await endSpanWithResult(void 0, fallbackOutput);
|
|
12950
|
+
}
|
|
12951
|
+
};
|
|
12952
|
+
if (originalGetResponse) {
|
|
12953
|
+
resultLike.getResponse = async (...args2) => {
|
|
12954
|
+
return await withCurrent(span, async () => {
|
|
12955
|
+
try {
|
|
12956
|
+
const response = await originalGetResponse(...args2);
|
|
12957
|
+
await endSpanWithResult(response);
|
|
12958
|
+
return response;
|
|
12959
|
+
} catch (error) {
|
|
12960
|
+
endSpanWithError(error);
|
|
12961
|
+
throw error;
|
|
12530
12962
|
}
|
|
12531
|
-
})
|
|
12532
|
-
|
|
12533
|
-
|
|
12534
|
-
|
|
12535
|
-
|
|
12536
|
-
|
|
12537
|
-
|
|
12538
|
-
|
|
12539
|
-
|
|
12540
|
-
|
|
12541
|
-
|
|
12542
|
-
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
extractOutput: (result) => result,
|
|
12546
|
-
extractMetrics: () => ({}),
|
|
12547
|
-
aggregateChunks: (chunks) => ({
|
|
12548
|
-
output: chunks.length > 0 ? chunks[chunks.length - 1] : void 0,
|
|
12549
|
-
metrics: {}
|
|
12550
|
-
})
|
|
12551
|
-
})
|
|
12552
|
-
);
|
|
12553
|
-
const callModelChannel = openRouterChannels.callModel.tracingChannel();
|
|
12554
|
-
const callModelHandlers = {
|
|
12555
|
-
start: (event) => {
|
|
12556
|
-
const request = getOpenRouterCallModelRequestArg(event.arguments);
|
|
12557
|
-
if (!request) {
|
|
12558
|
-
return;
|
|
12963
|
+
});
|
|
12964
|
+
};
|
|
12965
|
+
}
|
|
12966
|
+
if (typeof resultLike.getText === "function") {
|
|
12967
|
+
const originalGetText = resultLike.getText.bind(resultLike);
|
|
12968
|
+
resultLike.getText = async (...args2) => {
|
|
12969
|
+
return await withCurrent(span, async () => {
|
|
12970
|
+
try {
|
|
12971
|
+
const text = await originalGetText(...args2);
|
|
12972
|
+
await finalizeFromResponse(text);
|
|
12973
|
+
return text;
|
|
12974
|
+
} catch (error) {
|
|
12975
|
+
endSpanWithError(error);
|
|
12976
|
+
throw error;
|
|
12559
12977
|
}
|
|
12560
|
-
|
|
12978
|
+
});
|
|
12979
|
+
};
|
|
12980
|
+
}
|
|
12981
|
+
for (const methodName of OPENROUTER_CALL_MODEL_CONTEXT_METHODS) {
|
|
12982
|
+
if (typeof resultLike[methodName] !== "function") {
|
|
12983
|
+
continue;
|
|
12984
|
+
}
|
|
12985
|
+
const originalMethod = resultLike[methodName];
|
|
12986
|
+
resultLike[methodName] = async (...args2) => {
|
|
12987
|
+
return await withCurrent(span, async () => {
|
|
12988
|
+
return await originalMethod.apply(resultLike, args2);
|
|
12989
|
+
});
|
|
12990
|
+
};
|
|
12991
|
+
}
|
|
12992
|
+
for (const methodName of OPENROUTER_CALL_MODEL_STREAM_METHODS) {
|
|
12993
|
+
if (typeof resultLike[methodName] !== "function") {
|
|
12994
|
+
continue;
|
|
12995
|
+
}
|
|
12996
|
+
const originalMethod = resultLike[methodName];
|
|
12997
|
+
resultLike[methodName] = (...args2) => {
|
|
12998
|
+
const stream = withCurrent(
|
|
12999
|
+
span,
|
|
13000
|
+
() => originalMethod.apply(resultLike, args2)
|
|
13001
|
+
);
|
|
13002
|
+
if (!isAsyncIterable2(stream)) {
|
|
13003
|
+
return stream;
|
|
13004
|
+
}
|
|
13005
|
+
return wrapAsyncIterableWithSpan({
|
|
13006
|
+
finalize: finalizeFromResponse,
|
|
13007
|
+
iteratorFactory: () => stream[Symbol.asyncIterator](),
|
|
13008
|
+
onError: endSpanWithError,
|
|
13009
|
+
span
|
|
13010
|
+
});
|
|
13011
|
+
};
|
|
13012
|
+
}
|
|
13013
|
+
if (originalGetInitialResponse) {
|
|
13014
|
+
let initialTurnTraced = false;
|
|
13015
|
+
resultLike.getInitialResponse = async (...args2) => {
|
|
13016
|
+
if (initialTurnTraced) {
|
|
13017
|
+
return await withCurrent(span, async () => {
|
|
13018
|
+
return await originalGetInitialResponse(...args2);
|
|
13019
|
+
});
|
|
12561
13020
|
}
|
|
13021
|
+
initialTurnTraced = true;
|
|
13022
|
+
const step = tracedTurnCount + 1;
|
|
13023
|
+
const stepType = tracedTurnCount === 0 ? "initial" : "continue";
|
|
13024
|
+
const response = await traceOpenRouterCallModelTurn({
|
|
13025
|
+
fn: async () => {
|
|
13026
|
+
const nextResponse = await originalGetInitialResponse(...args2);
|
|
13027
|
+
tracedTurnCount++;
|
|
13028
|
+
return nextResponse;
|
|
13029
|
+
},
|
|
13030
|
+
parentSpan: span,
|
|
13031
|
+
request: getOpenRouterResolvedRequest(resultLike, request),
|
|
13032
|
+
step,
|
|
13033
|
+
stepType
|
|
13034
|
+
});
|
|
13035
|
+
return response;
|
|
12562
13036
|
};
|
|
12563
|
-
callModelChannel.subscribe(callModelHandlers);
|
|
12564
|
-
this.unsubscribers.push(() => {
|
|
12565
|
-
callModelChannel.unsubscribe(callModelHandlers);
|
|
12566
|
-
});
|
|
12567
|
-
}
|
|
12568
|
-
};
|
|
12569
|
-
function normalizeArgs(args) {
|
|
12570
|
-
if (Array.isArray(args)) {
|
|
12571
|
-
return args;
|
|
12572
13037
|
}
|
|
12573
|
-
if (
|
|
12574
|
-
|
|
13038
|
+
if (originalMakeFollowupRequest) {
|
|
13039
|
+
resultLike.makeFollowupRequest = async (...args2) => {
|
|
13040
|
+
const currentResponse = args2[0];
|
|
13041
|
+
const toolResults = Array.isArray(args2[1]) ? args2[1] : [];
|
|
13042
|
+
const step = tracedTurnCount + 1;
|
|
13043
|
+
const response = await traceOpenRouterCallModelTurn({
|
|
13044
|
+
fn: async () => {
|
|
13045
|
+
const nextResponse = await originalMakeFollowupRequest(...args2);
|
|
13046
|
+
tracedTurnCount++;
|
|
13047
|
+
return nextResponse;
|
|
13048
|
+
},
|
|
13049
|
+
parentSpan: span,
|
|
13050
|
+
request: buildOpenRouterFollowupRequest(
|
|
13051
|
+
getOpenRouterResolvedRequest(resultLike, request),
|
|
13052
|
+
currentResponse,
|
|
13053
|
+
toolResults
|
|
13054
|
+
),
|
|
13055
|
+
step,
|
|
13056
|
+
stepType: "continue"
|
|
13057
|
+
});
|
|
13058
|
+
return response;
|
|
13059
|
+
};
|
|
12575
13060
|
}
|
|
12576
|
-
return
|
|
13061
|
+
return true;
|
|
12577
13062
|
}
|
|
12578
|
-
function
|
|
12579
|
-
|
|
13063
|
+
async function traceOpenRouterCallModelTurn(args) {
|
|
13064
|
+
const context = {
|
|
13065
|
+
arguments: [args.request],
|
|
13066
|
+
step: args.step,
|
|
13067
|
+
stepType: args.stepType
|
|
13068
|
+
};
|
|
13069
|
+
return await withCurrent(
|
|
13070
|
+
args.parentSpan,
|
|
13071
|
+
() => openRouterChannels.callModelTurn.tracePromise(args.fn, context)
|
|
13072
|
+
);
|
|
12580
13073
|
}
|
|
12581
|
-
function
|
|
12582
|
-
|
|
12583
|
-
|
|
12584
|
-
(arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
|
|
13074
|
+
function isWrappedCallModelResult(value) {
|
|
13075
|
+
return Boolean(
|
|
13076
|
+
isObject(value) && value[OPENROUTER_WRAPPED_CALL_MODEL_RESULT]
|
|
12585
13077
|
);
|
|
12586
|
-
|
|
12587
|
-
|
|
13078
|
+
}
|
|
13079
|
+
function extractOpenRouterCallModelResultMetadata(response, turnCount) {
|
|
13080
|
+
const combined = {
|
|
13081
|
+
...extractOpenRouterResponseMetadata(response) || {},
|
|
13082
|
+
...turnCount !== void 0 ? { turn_count: turnCount } : {}
|
|
13083
|
+
};
|
|
13084
|
+
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
13085
|
+
}
|
|
13086
|
+
function getFinalOpenRouterCallModelResponse(result, response) {
|
|
13087
|
+
if (isObject(response)) {
|
|
13088
|
+
return response;
|
|
12588
13089
|
}
|
|
12589
|
-
|
|
12590
|
-
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
13090
|
+
return isObject(result.finalResponse) ? result.finalResponse : void 0;
|
|
12591
13091
|
}
|
|
12592
|
-
function
|
|
12593
|
-
|
|
12594
|
-
|
|
13092
|
+
function getOpenRouterCallModelRounds(result) {
|
|
13093
|
+
if (!Array.isArray(result.allToolExecutionRounds)) {
|
|
13094
|
+
return [];
|
|
13095
|
+
}
|
|
13096
|
+
return result.allToolExecutionRounds.filter((round) => isObject(round)).map((round) => ({
|
|
13097
|
+
response: isObject(round.response) ? round.response : void 0,
|
|
13098
|
+
round: typeof round.round === "number" ? round.round : void 0,
|
|
13099
|
+
toolResults: Array.isArray(round.toolResults) ? round.toolResults : []
|
|
13100
|
+
})).filter((round) => round.response !== void 0);
|
|
12595
13101
|
}
|
|
12596
|
-
function
|
|
12597
|
-
|
|
12598
|
-
|
|
12599
|
-
|
|
12600
|
-
|
|
12601
|
-
|
|
12602
|
-
for (const
|
|
12603
|
-
|
|
12604
|
-
|
|
12605
|
-
|
|
12606
|
-
};
|
|
12607
|
-
const choice = chunk?.choices?.[0];
|
|
12608
|
-
const delta = choice?.delta;
|
|
12609
|
-
if (!delta) {
|
|
12610
|
-
if (choice?.finish_reason !== void 0) {
|
|
12611
|
-
finishReason = choice.finish_reason;
|
|
12612
|
-
}
|
|
12613
|
-
continue;
|
|
12614
|
-
}
|
|
12615
|
-
if (!role && delta.role) {
|
|
12616
|
-
role = delta.role;
|
|
12617
|
-
}
|
|
12618
|
-
if (typeof delta.content === "string") {
|
|
12619
|
-
content += delta.content;
|
|
12620
|
-
}
|
|
12621
|
-
const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
|
|
12622
|
-
const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
|
|
12623
|
-
if (choiceFinishReason !== void 0) {
|
|
12624
|
-
finishReason = choiceFinishReason;
|
|
12625
|
-
} else if (deltaFinishReason !== void 0) {
|
|
12626
|
-
finishReason = deltaFinishReason;
|
|
12627
|
-
}
|
|
12628
|
-
const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
|
|
12629
|
-
if (!toolCallDeltas) {
|
|
12630
|
-
continue;
|
|
12631
|
-
}
|
|
12632
|
-
for (const toolDelta of toolCallDeltas) {
|
|
12633
|
-
if (!toolDelta?.function) {
|
|
12634
|
-
continue;
|
|
12635
|
-
}
|
|
12636
|
-
const toolIndex = toolDelta.index ?? 0;
|
|
12637
|
-
const existingToolCall = toolCalls?.[toolIndex];
|
|
12638
|
-
if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
|
|
12639
|
-
const nextToolCalls = [...toolCalls || []];
|
|
12640
|
-
nextToolCalls[toolIndex] = {
|
|
12641
|
-
index: toolIndex,
|
|
12642
|
-
id: toolDelta.id,
|
|
12643
|
-
type: toolDelta.type,
|
|
12644
|
-
function: {
|
|
12645
|
-
name: toolDelta.function.name,
|
|
12646
|
-
arguments: toolDelta.function.arguments || ""
|
|
12647
|
-
}
|
|
12648
|
-
};
|
|
12649
|
-
toolCalls = nextToolCalls;
|
|
12650
|
-
continue;
|
|
12651
|
-
}
|
|
12652
|
-
const current = existingToolCall;
|
|
12653
|
-
if (toolDelta.id && !current.id) {
|
|
12654
|
-
current.id = toolDelta.id;
|
|
12655
|
-
}
|
|
12656
|
-
if (toolDelta.type && !current.type) {
|
|
12657
|
-
current.type = toolDelta.type;
|
|
12658
|
-
}
|
|
12659
|
-
if (toolDelta.function.name && !current.function.name) {
|
|
12660
|
-
current.function.name = toolDelta.function.name;
|
|
12661
|
-
}
|
|
12662
|
-
current.function.arguments += toolDelta.function.arguments || "";
|
|
13102
|
+
function aggregateOpenRouterCallModelMetrics(rounds, finalResponse) {
|
|
13103
|
+
const metrics = {};
|
|
13104
|
+
const responses = [
|
|
13105
|
+
...rounds.map((round) => round.response).filter(isObject),
|
|
13106
|
+
finalResponse
|
|
13107
|
+
];
|
|
13108
|
+
for (const response of responses) {
|
|
13109
|
+
const responseMetrics = parseOpenRouterMetricsFromUsage(response.usage);
|
|
13110
|
+
for (const [name, value] of Object.entries(responseMetrics)) {
|
|
13111
|
+
metrics[name] = (metrics[name] || 0) + value;
|
|
12663
13112
|
}
|
|
12664
13113
|
}
|
|
12665
|
-
return
|
|
12666
|
-
output: [
|
|
12667
|
-
{
|
|
12668
|
-
index: 0,
|
|
12669
|
-
message: {
|
|
12670
|
-
role,
|
|
12671
|
-
content: content || void 0,
|
|
12672
|
-
...toolCalls ? { tool_calls: toolCalls } : {}
|
|
12673
|
-
},
|
|
12674
|
-
logprobs: null,
|
|
12675
|
-
finish_reason: finishReason
|
|
12676
|
-
}
|
|
12677
|
-
],
|
|
12678
|
-
metrics
|
|
12679
|
-
};
|
|
13114
|
+
return metrics;
|
|
12680
13115
|
}
|
|
12681
|
-
function
|
|
12682
|
-
|
|
12683
|
-
|
|
12684
|
-
|
|
12685
|
-
|
|
12686
|
-
|
|
12687
|
-
|
|
12688
|
-
|
|
12689
|
-
|
|
12690
|
-
|
|
13116
|
+
function buildNextOpenRouterCallModelInput(currentInput, response, toolResults) {
|
|
13117
|
+
const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
|
|
13118
|
+
const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
|
|
13119
|
+
return [...normalizedInput, ...responseOutput, ...toolResults].map(
|
|
13120
|
+
(entry) => sanitizeOpenRouterLoggedValue(entry)
|
|
13121
|
+
);
|
|
13122
|
+
}
|
|
13123
|
+
function getOpenRouterResolvedRequest(result, request) {
|
|
13124
|
+
if (isObject(result.resolvedRequest)) {
|
|
13125
|
+
return result.resolvedRequest;
|
|
12691
13126
|
}
|
|
12692
|
-
|
|
12693
|
-
|
|
12694
|
-
|
|
12695
|
-
|
|
12696
|
-
|
|
13127
|
+
return request;
|
|
13128
|
+
}
|
|
13129
|
+
function buildOpenRouterFollowupRequest(request, currentResponse, toolResults) {
|
|
13130
|
+
if (!request) {
|
|
13131
|
+
return void 0;
|
|
12697
13132
|
}
|
|
12698
13133
|
return {
|
|
12699
|
-
|
|
12700
|
-
|
|
12701
|
-
|
|
13134
|
+
...request,
|
|
13135
|
+
input: buildNextOpenRouterCallModelInput(
|
|
13136
|
+
extractOpenRouterCallModelInput(request),
|
|
13137
|
+
isObject(currentResponse) ? currentResponse : {},
|
|
13138
|
+
toolResults
|
|
13139
|
+
),
|
|
13140
|
+
stream: false
|
|
13141
|
+
};
|
|
13142
|
+
}
|
|
13143
|
+
function wrapAsyncIterableWithSpan(args) {
|
|
13144
|
+
return {
|
|
13145
|
+
[Symbol.asyncIterator]() {
|
|
13146
|
+
const iterator = args.iteratorFactory();
|
|
13147
|
+
return {
|
|
13148
|
+
next(value) {
|
|
13149
|
+
return withCurrent(
|
|
13150
|
+
args.span,
|
|
13151
|
+
() => value === void 0 ? iterator.next() : iterator.next(value)
|
|
13152
|
+
).then(
|
|
13153
|
+
async (result) => {
|
|
13154
|
+
if (result.done) {
|
|
13155
|
+
await args.finalize();
|
|
13156
|
+
}
|
|
13157
|
+
return result;
|
|
13158
|
+
},
|
|
13159
|
+
(error) => {
|
|
13160
|
+
args.onError(error);
|
|
13161
|
+
throw error;
|
|
13162
|
+
}
|
|
13163
|
+
);
|
|
13164
|
+
},
|
|
13165
|
+
return(value) {
|
|
13166
|
+
if (typeof iterator.return !== "function") {
|
|
13167
|
+
return args.finalize().then(() => ({
|
|
13168
|
+
done: true,
|
|
13169
|
+
value
|
|
13170
|
+
}));
|
|
13171
|
+
}
|
|
13172
|
+
return withCurrent(args.span, () => iterator.return(value)).then(
|
|
13173
|
+
async (result) => {
|
|
13174
|
+
await args.finalize();
|
|
13175
|
+
return result;
|
|
13176
|
+
},
|
|
13177
|
+
(error) => {
|
|
13178
|
+
args.onError(error);
|
|
13179
|
+
throw error;
|
|
13180
|
+
}
|
|
13181
|
+
);
|
|
13182
|
+
},
|
|
13183
|
+
throw(error) {
|
|
13184
|
+
args.onError(error);
|
|
13185
|
+
if (typeof iterator.throw !== "function") {
|
|
13186
|
+
return Promise.reject(error);
|
|
13187
|
+
}
|
|
13188
|
+
return withCurrent(args.span, () => iterator.throw(error));
|
|
13189
|
+
},
|
|
13190
|
+
[Symbol.asyncIterator]() {
|
|
13191
|
+
return this;
|
|
13192
|
+
}
|
|
13193
|
+
};
|
|
13194
|
+
}
|
|
12702
13195
|
};
|
|
12703
13196
|
}
|
|
13197
|
+
function isAsyncIterable2(value) {
|
|
13198
|
+
return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
13199
|
+
}
|
|
13200
|
+
function normalizeError(error) {
|
|
13201
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
13202
|
+
}
|
|
12704
13203
|
|
|
12705
13204
|
// src/instrumentation/braintrust-plugin.ts
|
|
12706
13205
|
var BraintrustPlugin = class extends BasePlugin {
|