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
|
@@ -70,7 +70,7 @@ var DefaultTracingChannel = class {
|
|
|
70
70
|
}
|
|
71
71
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
72
|
tracePromise(fn, _message, thisArg, ...args) {
|
|
73
|
-
return
|
|
73
|
+
return fn.apply(thisArg, args);
|
|
74
74
|
}
|
|
75
75
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
76
76
|
traceCallback(fn, _position, _message, thisArg, ...args) {
|
|
@@ -90,6 +90,7 @@ var iso = {
|
|
|
90
90
|
processOn: (_0, _1) => {
|
|
91
91
|
},
|
|
92
92
|
basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
|
|
93
|
+
// eslint-disable-next-line no-restricted-properties -- preserving intentional console usage.
|
|
93
94
|
writeln: (text) => console.log(text)
|
|
94
95
|
};
|
|
95
96
|
var isomorph_default = iso;
|
|
@@ -125,7 +126,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
125
126
|
if (!completed) {
|
|
126
127
|
completed = true;
|
|
127
128
|
try {
|
|
128
|
-
options.onComplete(chunks);
|
|
129
|
+
await options.onComplete(chunks);
|
|
129
130
|
} catch (error) {
|
|
130
131
|
console.error("Error in stream onComplete handler:", error);
|
|
131
132
|
}
|
|
@@ -137,7 +138,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
137
138
|
chunks.push(chunk);
|
|
138
139
|
if (options.onChunk) {
|
|
139
140
|
try {
|
|
140
|
-
options.onChunk(chunk);
|
|
141
|
+
await options.onChunk(chunk);
|
|
141
142
|
} catch (error) {
|
|
142
143
|
console.error("Error in stream onChunk handler:", error);
|
|
143
144
|
}
|
|
@@ -150,7 +151,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
150
151
|
completed = true;
|
|
151
152
|
if (options.onError) {
|
|
152
153
|
try {
|
|
153
|
-
options.onError(
|
|
154
|
+
await options.onError(
|
|
154
155
|
error instanceof Error ? error : new Error(String(error)),
|
|
155
156
|
chunks
|
|
156
157
|
);
|
|
@@ -168,7 +169,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
168
169
|
if (!completed) {
|
|
169
170
|
completed = true;
|
|
170
171
|
try {
|
|
171
|
-
options.onComplete(chunks);
|
|
172
|
+
await options.onComplete(chunks);
|
|
172
173
|
} catch (error) {
|
|
173
174
|
console.error("Error in stream onComplete handler:", error);
|
|
174
175
|
}
|
|
@@ -185,7 +186,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
185
186
|
const error = rawError instanceof Error ? rawError : new Error(String(rawError));
|
|
186
187
|
if (options.onError) {
|
|
187
188
|
try {
|
|
188
|
-
options.onError(error, chunks);
|
|
189
|
+
await options.onError(error, chunks);
|
|
189
190
|
} catch (handlerError) {
|
|
190
191
|
console.error("Error in stream onError handler:", handlerError);
|
|
191
192
|
}
|
|
@@ -1537,6 +1538,15 @@ function addAzureBlobHeaders(headers, url) {
|
|
|
1537
1538
|
headers["x-ms-blob-type"] = "BlockBlob";
|
|
1538
1539
|
}
|
|
1539
1540
|
}
|
|
1541
|
+
function filterFrom(record, keys) {
|
|
1542
|
+
const out = {};
|
|
1543
|
+
for (const k of Object.keys(record)) {
|
|
1544
|
+
if (!keys.includes(k)) {
|
|
1545
|
+
out[k] = record[k];
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
return out;
|
|
1549
|
+
}
|
|
1540
1550
|
|
|
1541
1551
|
// src/generated_types.ts
|
|
1542
1552
|
import { z as z6 } from "zod/v3";
|
|
@@ -8332,51 +8342,28 @@ function traceSyncStreamChannel(channel2, config) {
|
|
|
8332
8342
|
}
|
|
8333
8343
|
const { span, startTime } = spanData;
|
|
8334
8344
|
const endEvent = event;
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
|
|
8348
|
-
return;
|
|
8349
|
-
}
|
|
8350
|
-
let first = true;
|
|
8351
|
-
stream.on("chunk", () => {
|
|
8352
|
-
if (first) {
|
|
8353
|
-
span.log({
|
|
8354
|
-
metrics: {
|
|
8355
|
-
time_to_first_token: getCurrentUnixTimestamp() - startTime
|
|
8356
|
-
}
|
|
8357
|
-
});
|
|
8358
|
-
first = false;
|
|
8359
|
-
}
|
|
8360
|
-
});
|
|
8361
|
-
stream.on("chatCompletion", (completion) => {
|
|
8362
|
-
try {
|
|
8363
|
-
if (hasChoices(completion)) {
|
|
8364
|
-
span.log({
|
|
8365
|
-
output: completion.choices
|
|
8366
|
-
});
|
|
8367
|
-
}
|
|
8368
|
-
} catch (error) {
|
|
8369
|
-
console.error(
|
|
8370
|
-
`Error extracting chatCompletion for ${channelName}:`,
|
|
8371
|
-
error
|
|
8372
|
-
);
|
|
8345
|
+
const handleResolvedResult = (result) => {
|
|
8346
|
+
const resolvedEndEvent = {
|
|
8347
|
+
...endEvent,
|
|
8348
|
+
result
|
|
8349
|
+
};
|
|
8350
|
+
if (config.patchResult?.({
|
|
8351
|
+
channelName,
|
|
8352
|
+
endEvent: resolvedEndEvent,
|
|
8353
|
+
result,
|
|
8354
|
+
span,
|
|
8355
|
+
startTime
|
|
8356
|
+
})) {
|
|
8357
|
+
return;
|
|
8373
8358
|
}
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8359
|
+
const stream = result;
|
|
8360
|
+
if (!isSyncStreamLike(stream)) {
|
|
8361
|
+
span.end();
|
|
8362
|
+
states.delete(event);
|
|
8377
8363
|
return;
|
|
8378
8364
|
}
|
|
8379
|
-
|
|
8365
|
+
let first = true;
|
|
8366
|
+
stream.on("chunk", () => {
|
|
8380
8367
|
if (first) {
|
|
8381
8368
|
span.log({
|
|
8382
8369
|
metrics: {
|
|
@@ -8385,25 +8372,55 @@ function traceSyncStreamChannel(channel2, config) {
|
|
|
8385
8372
|
});
|
|
8386
8373
|
first = false;
|
|
8387
8374
|
}
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8375
|
+
});
|
|
8376
|
+
stream.on("chatCompletion", (completion) => {
|
|
8377
|
+
try {
|
|
8378
|
+
if (hasChoices(completion)) {
|
|
8379
|
+
span.log({
|
|
8380
|
+
output: completion.choices
|
|
8381
|
+
});
|
|
8382
|
+
}
|
|
8383
|
+
} catch (error) {
|
|
8384
|
+
console.error(
|
|
8385
|
+
`Error extracting chatCompletion for ${channelName}:`,
|
|
8386
|
+
error
|
|
8387
|
+
);
|
|
8391
8388
|
}
|
|
8392
|
-
} catch (error) {
|
|
8393
|
-
console.error(`Error extracting event for ${channelName}:`, error);
|
|
8394
|
-
}
|
|
8395
|
-
});
|
|
8396
|
-
stream.on("end", () => {
|
|
8397
|
-
span.end();
|
|
8398
|
-
states.delete(event);
|
|
8399
|
-
});
|
|
8400
|
-
stream.on("error", (error) => {
|
|
8401
|
-
span.log({
|
|
8402
|
-
error: error.message
|
|
8403
8389
|
});
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8390
|
+
stream.on("event", (streamEvent) => {
|
|
8391
|
+
if (!config.extractFromEvent) {
|
|
8392
|
+
return;
|
|
8393
|
+
}
|
|
8394
|
+
try {
|
|
8395
|
+
if (first) {
|
|
8396
|
+
span.log({
|
|
8397
|
+
metrics: {
|
|
8398
|
+
time_to_first_token: getCurrentUnixTimestamp() - startTime
|
|
8399
|
+
}
|
|
8400
|
+
});
|
|
8401
|
+
first = false;
|
|
8402
|
+
}
|
|
8403
|
+
const extracted = config.extractFromEvent(streamEvent);
|
|
8404
|
+
if (extracted && Object.keys(extracted).length > 0) {
|
|
8405
|
+
span.log(extracted);
|
|
8406
|
+
}
|
|
8407
|
+
} catch (error) {
|
|
8408
|
+
console.error(`Error extracting event for ${channelName}:`, error);
|
|
8409
|
+
}
|
|
8410
|
+
});
|
|
8411
|
+
stream.on("end", () => {
|
|
8412
|
+
span.end();
|
|
8413
|
+
states.delete(event);
|
|
8414
|
+
});
|
|
8415
|
+
stream.on("error", (error) => {
|
|
8416
|
+
span.log({
|
|
8417
|
+
error: error.message
|
|
8418
|
+
});
|
|
8419
|
+
span.end();
|
|
8420
|
+
states.delete(event);
|
|
8421
|
+
});
|
|
8422
|
+
};
|
|
8423
|
+
handleResolvedResult(endEvent.result);
|
|
8407
8424
|
},
|
|
8408
8425
|
error: (event) => {
|
|
8409
8426
|
logErrorAndEnd(states, event);
|
|
@@ -9226,28 +9243,40 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
9226
9243
|
case "content_block_start":
|
|
9227
9244
|
if (event.content_block) {
|
|
9228
9245
|
contentBlocks[event.index] = event.content_block;
|
|
9229
|
-
contentBlockDeltas[event.index] = [];
|
|
9246
|
+
contentBlockDeltas[event.index] = { textDeltas: [], citations: [] };
|
|
9230
9247
|
}
|
|
9231
9248
|
break;
|
|
9232
|
-
case "content_block_delta":
|
|
9233
|
-
|
|
9234
|
-
|
|
9249
|
+
case "content_block_delta": {
|
|
9250
|
+
const acc = contentBlockDeltas[event.index];
|
|
9251
|
+
const delta = event.delta;
|
|
9252
|
+
if (!delta) break;
|
|
9253
|
+
if (delta.type === "text_delta" && "text" in delta) {
|
|
9254
|
+
const text = delta.text;
|
|
9235
9255
|
if (text) {
|
|
9236
|
-
if (
|
|
9237
|
-
|
|
9238
|
-
contentBlockDeltas[event.index].push(text);
|
|
9256
|
+
if (acc !== void 0) {
|
|
9257
|
+
acc.textDeltas.push(text);
|
|
9239
9258
|
} else {
|
|
9240
9259
|
fallbackTextDeltas.push(text);
|
|
9241
9260
|
}
|
|
9242
9261
|
}
|
|
9243
|
-
} else if (
|
|
9244
|
-
const partialJson =
|
|
9245
|
-
if (partialJson) {
|
|
9246
|
-
|
|
9247
|
-
|
|
9262
|
+
} else if (delta.type === "input_json_delta" && "partial_json" in delta) {
|
|
9263
|
+
const partialJson = delta.partial_json;
|
|
9264
|
+
if (partialJson && acc !== void 0) {
|
|
9265
|
+
acc.textDeltas.push(partialJson);
|
|
9266
|
+
}
|
|
9267
|
+
} else if (delta.type === "thinking_delta" && "thinking" in delta) {
|
|
9268
|
+
const thinking = delta.thinking;
|
|
9269
|
+
if (thinking && acc !== void 0) {
|
|
9270
|
+
acc.textDeltas.push(thinking);
|
|
9271
|
+
}
|
|
9272
|
+
} else if (delta.type === "citations_delta" && "citation" in delta) {
|
|
9273
|
+
const citation = delta.citation;
|
|
9274
|
+
if (citation && acc !== void 0) {
|
|
9275
|
+
acc.citations.push(citation);
|
|
9248
9276
|
}
|
|
9249
9277
|
}
|
|
9250
9278
|
break;
|
|
9279
|
+
}
|
|
9251
9280
|
case "content_block_stop":
|
|
9252
9281
|
finalizeContentBlock(
|
|
9253
9282
|
event.index,
|
|
@@ -9273,7 +9302,7 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
9273
9302
|
})).filter(({ block }) => block !== void 0).sort((left, right) => left.index - right.index).map(({ block }) => block);
|
|
9274
9303
|
let output = fallbackTextDeltas.join("");
|
|
9275
9304
|
if (orderedContent.length > 0) {
|
|
9276
|
-
if (orderedContent.every(isTextContentBlock)) {
|
|
9305
|
+
if (orderedContent.every(isTextContentBlock) && orderedContent.every((block) => !block.citations?.length)) {
|
|
9277
9306
|
output = orderedContent.map((block) => block.text).join("");
|
|
9278
9307
|
} else {
|
|
9279
9308
|
output = {
|
|
@@ -9299,7 +9328,8 @@ function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallback
|
|
|
9299
9328
|
if (!contentBlock) {
|
|
9300
9329
|
return;
|
|
9301
9330
|
}
|
|
9302
|
-
const
|
|
9331
|
+
const acc = contentBlockDeltas[index];
|
|
9332
|
+
const text = acc?.textDeltas.join("") ?? "";
|
|
9303
9333
|
if (isToolUseContentBlock(contentBlock)) {
|
|
9304
9334
|
if (!text) {
|
|
9305
9335
|
return;
|
|
@@ -9316,20 +9346,28 @@ function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallback
|
|
|
9316
9346
|
return;
|
|
9317
9347
|
}
|
|
9318
9348
|
if (isTextContentBlock(contentBlock)) {
|
|
9349
|
+
if (!text) {
|
|
9350
|
+
delete contentBlocks[index];
|
|
9351
|
+
return;
|
|
9352
|
+
}
|
|
9353
|
+
const updated = { ...contentBlock, text };
|
|
9354
|
+
if (acc?.citations.length) {
|
|
9355
|
+
updated.citations = acc.citations;
|
|
9356
|
+
}
|
|
9357
|
+
contentBlocks[index] = updated;
|
|
9358
|
+
return;
|
|
9359
|
+
}
|
|
9360
|
+
if (isThinkingContentBlock(contentBlock)) {
|
|
9319
9361
|
if (!text) {
|
|
9320
9362
|
delete contentBlocks[index];
|
|
9321
9363
|
return;
|
|
9322
9364
|
}
|
|
9323
9365
|
contentBlocks[index] = {
|
|
9324
9366
|
...contentBlock,
|
|
9325
|
-
text
|
|
9367
|
+
thinking: text
|
|
9326
9368
|
};
|
|
9327
9369
|
return;
|
|
9328
9370
|
}
|
|
9329
|
-
if (text) {
|
|
9330
|
-
fallbackTextDeltas.push(text);
|
|
9331
|
-
}
|
|
9332
|
-
delete contentBlocks[index];
|
|
9333
9371
|
}
|
|
9334
9372
|
function isTextContentBlock(contentBlock) {
|
|
9335
9373
|
return contentBlock.type === "text";
|
|
@@ -9337,6 +9375,9 @@ function isTextContentBlock(contentBlock) {
|
|
|
9337
9375
|
function isToolUseContentBlock(contentBlock) {
|
|
9338
9376
|
return contentBlock.type === "tool_use";
|
|
9339
9377
|
}
|
|
9378
|
+
function isThinkingContentBlock(contentBlock) {
|
|
9379
|
+
return contentBlock.type === "thinking";
|
|
9380
|
+
}
|
|
9340
9381
|
function isAnthropicBase64ContentBlock(input) {
|
|
9341
9382
|
return (input.type === "image" || input.type === "document") && isObject(input.source) && input.source.type === "base64";
|
|
9342
9383
|
}
|
|
@@ -9391,15 +9432,6 @@ function coalesceInput(messages, system) {
|
|
|
9391
9432
|
}
|
|
9392
9433
|
return input;
|
|
9393
9434
|
}
|
|
9394
|
-
function filterFrom(obj, fieldsToRemove) {
|
|
9395
|
-
const result = {};
|
|
9396
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
9397
|
-
if (!fieldsToRemove.includes(key)) {
|
|
9398
|
-
result[key] = value;
|
|
9399
|
-
}
|
|
9400
|
-
}
|
|
9401
|
-
return result;
|
|
9402
|
-
}
|
|
9403
9435
|
|
|
9404
9436
|
// src/wrappers/ai-sdk/normalize-logged-output.ts
|
|
9405
9437
|
var REMOVE_NORMALIZED_VALUE = Symbol("braintrust.ai-sdk.remove-normalized");
|
|
@@ -9513,10 +9545,6 @@ var aiSDKChannels = defineChannels("ai", {
|
|
|
9513
9545
|
channelName: "streamText",
|
|
9514
9546
|
kind: "async"
|
|
9515
9547
|
}),
|
|
9516
|
-
streamTextSync: channel({
|
|
9517
|
-
channelName: "streamText.sync",
|
|
9518
|
-
kind: "sync-stream"
|
|
9519
|
-
}),
|
|
9520
9548
|
generateObject: channel({
|
|
9521
9549
|
channelName: "generateObject",
|
|
9522
9550
|
kind: "async"
|
|
@@ -9525,10 +9553,6 @@ var aiSDKChannels = defineChannels("ai", {
|
|
|
9525
9553
|
channelName: "streamObject",
|
|
9526
9554
|
kind: "async"
|
|
9527
9555
|
}),
|
|
9528
|
-
streamObjectSync: channel({
|
|
9529
|
-
channelName: "streamObject.sync",
|
|
9530
|
-
kind: "sync-stream"
|
|
9531
|
-
}),
|
|
9532
9556
|
agentGenerate: channel({
|
|
9533
9557
|
channelName: "Agent.generate",
|
|
9534
9558
|
kind: "async"
|
|
@@ -9564,6 +9588,9 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
|
|
|
9564
9588
|
];
|
|
9565
9589
|
var AUTO_PATCHED_MODEL = Symbol.for("braintrust.ai-sdk.auto-patched-model");
|
|
9566
9590
|
var AUTO_PATCHED_TOOL = Symbol.for("braintrust.ai-sdk.auto-patched-tool");
|
|
9591
|
+
var RUNTIME_DENY_OUTPUT_PATHS = Symbol.for(
|
|
9592
|
+
"braintrust.ai-sdk.deny-output-paths"
|
|
9593
|
+
);
|
|
9567
9594
|
var AISDKPlugin = class extends BasePlugin {
|
|
9568
9595
|
config;
|
|
9569
9596
|
constructor(config = {}) {
|
|
@@ -9585,7 +9612,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9585
9612
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9586
9613
|
extractOutput: (result, endEvent) => {
|
|
9587
9614
|
finalizeAISDKChildTracing(endEvent);
|
|
9588
|
-
return processAISDKOutput(
|
|
9615
|
+
return processAISDKOutput(
|
|
9616
|
+
result,
|
|
9617
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9618
|
+
);
|
|
9589
9619
|
},
|
|
9590
9620
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9591
9621
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -9596,25 +9626,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9596
9626
|
name: "streamText",
|
|
9597
9627
|
type: "llm" /* LLM */,
|
|
9598
9628
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9599
|
-
extractOutput: (result) => processAISDKOutput(
|
|
9629
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
9630
|
+
result,
|
|
9631
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9632
|
+
),
|
|
9600
9633
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9601
9634
|
aggregateChunks: aggregateAISDKChunks,
|
|
9602
9635
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9603
|
-
denyOutputPaths,
|
|
9604
|
-
endEvent,
|
|
9605
|
-
result,
|
|
9606
|
-
span,
|
|
9607
|
-
startTime
|
|
9608
|
-
})
|
|
9609
|
-
})
|
|
9610
|
-
);
|
|
9611
|
-
this.unsubscribers.push(
|
|
9612
|
-
traceSyncStreamChannel(aiSDKChannels.streamTextSync, {
|
|
9613
|
-
name: "streamText",
|
|
9614
|
-
type: "llm" /* LLM */,
|
|
9615
|
-
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9616
|
-
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9617
|
-
denyOutputPaths,
|
|
9636
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
9618
9637
|
endEvent,
|
|
9619
9638
|
result,
|
|
9620
9639
|
span,
|
|
@@ -9629,7 +9648,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9629
9648
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9630
9649
|
extractOutput: (result, endEvent) => {
|
|
9631
9650
|
finalizeAISDKChildTracing(endEvent);
|
|
9632
|
-
return processAISDKOutput(
|
|
9651
|
+
return processAISDKOutput(
|
|
9652
|
+
result,
|
|
9653
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9654
|
+
);
|
|
9633
9655
|
},
|
|
9634
9656
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9635
9657
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -9640,25 +9662,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9640
9662
|
name: "streamObject",
|
|
9641
9663
|
type: "llm" /* LLM */,
|
|
9642
9664
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9643
|
-
extractOutput: (result) => processAISDKOutput(
|
|
9665
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
9666
|
+
result,
|
|
9667
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9668
|
+
),
|
|
9644
9669
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9645
9670
|
aggregateChunks: aggregateAISDKChunks,
|
|
9646
9671
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9647
|
-
denyOutputPaths,
|
|
9648
|
-
endEvent,
|
|
9649
|
-
result,
|
|
9650
|
-
span,
|
|
9651
|
-
startTime
|
|
9652
|
-
})
|
|
9653
|
-
})
|
|
9654
|
-
);
|
|
9655
|
-
this.unsubscribers.push(
|
|
9656
|
-
traceSyncStreamChannel(aiSDKChannels.streamObjectSync, {
|
|
9657
|
-
name: "streamObject",
|
|
9658
|
-
type: "llm" /* LLM */,
|
|
9659
|
-
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9660
|
-
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9661
|
-
denyOutputPaths,
|
|
9672
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
9662
9673
|
endEvent,
|
|
9663
9674
|
result,
|
|
9664
9675
|
span,
|
|
@@ -9673,7 +9684,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9673
9684
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9674
9685
|
extractOutput: (result, endEvent) => {
|
|
9675
9686
|
finalizeAISDKChildTracing(endEvent);
|
|
9676
|
-
return processAISDKOutput(
|
|
9687
|
+
return processAISDKOutput(
|
|
9688
|
+
result,
|
|
9689
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9690
|
+
);
|
|
9677
9691
|
},
|
|
9678
9692
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9679
9693
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -9684,11 +9698,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9684
9698
|
name: "Agent.stream",
|
|
9685
9699
|
type: "llm" /* LLM */,
|
|
9686
9700
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9687
|
-
extractOutput: (result) => processAISDKOutput(
|
|
9701
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
9702
|
+
result,
|
|
9703
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9704
|
+
),
|
|
9688
9705
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9689
9706
|
aggregateChunks: aggregateAISDKChunks,
|
|
9690
9707
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9691
|
-
denyOutputPaths,
|
|
9708
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
9692
9709
|
endEvent,
|
|
9693
9710
|
result,
|
|
9694
9711
|
span,
|
|
@@ -9703,7 +9720,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9703
9720
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9704
9721
|
extractOutput: (result, endEvent) => {
|
|
9705
9722
|
finalizeAISDKChildTracing(endEvent);
|
|
9706
|
-
return processAISDKOutput(
|
|
9723
|
+
return processAISDKOutput(
|
|
9724
|
+
result,
|
|
9725
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9726
|
+
);
|
|
9707
9727
|
},
|
|
9708
9728
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9709
9729
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -9714,11 +9734,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9714
9734
|
name: "ToolLoopAgent.stream",
|
|
9715
9735
|
type: "llm" /* LLM */,
|
|
9716
9736
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9717
|
-
extractOutput: (result) => processAISDKOutput(
|
|
9737
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
9738
|
+
result,
|
|
9739
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9740
|
+
),
|
|
9718
9741
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9719
9742
|
aggregateChunks: aggregateAISDKChunks,
|
|
9720
9743
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9721
|
-
denyOutputPaths,
|
|
9744
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
9722
9745
|
endEvent,
|
|
9723
9746
|
result,
|
|
9724
9747
|
span,
|
|
@@ -9728,132 +9751,435 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9728
9751
|
);
|
|
9729
9752
|
}
|
|
9730
9753
|
};
|
|
9731
|
-
function
|
|
9732
|
-
if (
|
|
9733
|
-
|
|
9734
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
9735
|
-
return input;
|
|
9754
|
+
function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
|
|
9755
|
+
if (Array.isArray(event?.denyOutputPaths)) {
|
|
9756
|
+
return event.denyOutputPaths;
|
|
9736
9757
|
}
|
|
9737
|
-
const
|
|
9738
|
-
|
|
9739
|
-
|
|
9740
|
-
function prepareAISDKInput(params, event, span, denyOutputPaths) {
|
|
9741
|
-
const input = processAISDKInput(params);
|
|
9742
|
-
const metadata = extractMetadataFromParams(params, event.self);
|
|
9743
|
-
const childTracing = prepareAISDKChildTracing(
|
|
9744
|
-
params,
|
|
9745
|
-
event.self,
|
|
9746
|
-
span,
|
|
9747
|
-
denyOutputPaths
|
|
9748
|
-
);
|
|
9749
|
-
event.__braintrust_ai_sdk_model_wrapped = childTracing.modelWrapped;
|
|
9750
|
-
if (childTracing.cleanup) {
|
|
9751
|
-
event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
|
|
9758
|
+
const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
|
|
9759
|
+
if (!firstArgument || typeof firstArgument !== "object") {
|
|
9760
|
+
return defaultDenyOutputPaths;
|
|
9752
9761
|
}
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9756
|
-
};
|
|
9757
|
-
}
|
|
9758
|
-
function extractTopLevelAISDKMetrics(result, event, startTime) {
|
|
9759
|
-
const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
|
|
9760
|
-
if (startTime) {
|
|
9761
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
9762
|
+
const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
|
|
9763
|
+
if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path) => typeof path === "string")) {
|
|
9764
|
+
return runtimeDenyOutputPaths;
|
|
9762
9765
|
}
|
|
9763
|
-
return
|
|
9764
|
-
}
|
|
9765
|
-
function hasModelChildTracing(event) {
|
|
9766
|
-
return event?.__braintrust_ai_sdk_model_wrapped === true;
|
|
9766
|
+
return defaultDenyOutputPaths;
|
|
9767
9767
|
}
|
|
9768
|
-
|
|
9769
|
-
|
|
9770
|
-
|
|
9771
|
-
|
|
9772
|
-
|
|
9773
|
-
|
|
9774
|
-
}
|
|
9775
|
-
|
|
9776
|
-
|
|
9777
|
-
|
|
9778
|
-
|
|
9779
|
-
if (model) {
|
|
9780
|
-
metadata.model = model;
|
|
9768
|
+
var isZodSchema2 = (value) => {
|
|
9769
|
+
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
9770
|
+
};
|
|
9771
|
+
var serializeZodSchema2 = (schema) => {
|
|
9772
|
+
try {
|
|
9773
|
+
return zodToJsonSchema(schema);
|
|
9774
|
+
} catch {
|
|
9775
|
+
return {
|
|
9776
|
+
type: "object",
|
|
9777
|
+
description: "Zod schema (conversion failed)"
|
|
9778
|
+
};
|
|
9781
9779
|
}
|
|
9782
|
-
|
|
9783
|
-
|
|
9780
|
+
};
|
|
9781
|
+
var isOutputObject = (value) => {
|
|
9782
|
+
if (value == null || typeof value !== "object") {
|
|
9783
|
+
return false;
|
|
9784
9784
|
}
|
|
9785
|
-
const
|
|
9786
|
-
if (
|
|
9787
|
-
|
|
9785
|
+
const output = value;
|
|
9786
|
+
if (!("responseFormat" in output)) {
|
|
9787
|
+
return false;
|
|
9788
9788
|
}
|
|
9789
|
-
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
|
|
9796
|
-
|
|
9797
|
-
|
|
9798
|
-
|
|
9799
|
-
|
|
9800
|
-
|
|
9801
|
-
patchedModels.add(resolvedModel);
|
|
9802
|
-
resolvedModel[AUTO_PATCHED_MODEL] = true;
|
|
9803
|
-
modelWrapped = true;
|
|
9804
|
-
const originalDoGenerate = resolvedModel.doGenerate;
|
|
9805
|
-
const originalDoStream = resolvedModel.doStream;
|
|
9806
|
-
const baseMetadata = buildAISDKChildMetadata(resolvedModel);
|
|
9807
|
-
resolvedModel.doGenerate = async function doGeneratePatched(options) {
|
|
9808
|
-
return parentSpan.traced(
|
|
9809
|
-
async (span) => {
|
|
9810
|
-
const result = await Reflect.apply(
|
|
9811
|
-
originalDoGenerate,
|
|
9812
|
-
resolvedModel,
|
|
9813
|
-
[options]
|
|
9814
|
-
);
|
|
9815
|
-
span.log({
|
|
9816
|
-
output: processAISDKOutput(result, denyOutputPaths),
|
|
9817
|
-
metrics: extractTokenMetrics(result),
|
|
9818
|
-
...buildResolvedMetadataPayload(result)
|
|
9819
|
-
});
|
|
9820
|
-
return result;
|
|
9821
|
-
},
|
|
9822
|
-
{
|
|
9823
|
-
name: "doGenerate",
|
|
9824
|
-
spanAttributes: {
|
|
9825
|
-
type: "llm" /* LLM */
|
|
9826
|
-
},
|
|
9827
|
-
event: {
|
|
9828
|
-
input: processAISDKInput(options),
|
|
9829
|
-
metadata: baseMetadata
|
|
9830
|
-
}
|
|
9831
|
-
}
|
|
9832
|
-
);
|
|
9789
|
+
if (output.type === "object" || output.type === "text") {
|
|
9790
|
+
return true;
|
|
9791
|
+
}
|
|
9792
|
+
if (typeof output.responseFormat === "function" || typeof output.responseFormat === "object") {
|
|
9793
|
+
return true;
|
|
9794
|
+
}
|
|
9795
|
+
return false;
|
|
9796
|
+
};
|
|
9797
|
+
var serializeOutputObject = (output, model) => {
|
|
9798
|
+
try {
|
|
9799
|
+
const result = {
|
|
9800
|
+
response_format: null
|
|
9833
9801
|
};
|
|
9834
|
-
if (
|
|
9835
|
-
|
|
9836
|
-
|
|
9837
|
-
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
|
|
9802
|
+
if (output.type) {
|
|
9803
|
+
result.type = output.type;
|
|
9804
|
+
}
|
|
9805
|
+
let responseFormat;
|
|
9806
|
+
if (typeof output.responseFormat === "function") {
|
|
9807
|
+
const mockModelForSchema = {
|
|
9808
|
+
supportsStructuredOutputs: true,
|
|
9809
|
+
...model && typeof model === "object" ? model : {}
|
|
9810
|
+
};
|
|
9811
|
+
responseFormat = output.responseFormat({ model: mockModelForSchema });
|
|
9812
|
+
} else if (output.responseFormat != null && typeof output.responseFormat === "object") {
|
|
9813
|
+
responseFormat = output.responseFormat;
|
|
9814
|
+
}
|
|
9815
|
+
if (responseFormat) {
|
|
9816
|
+
if (typeof responseFormat.then === "function") {
|
|
9817
|
+
result.response_format = Promise.resolve(responseFormat).then(
|
|
9818
|
+
(resolved) => {
|
|
9819
|
+
if (resolved.schema && isZodSchema2(resolved.schema)) {
|
|
9820
|
+
return {
|
|
9821
|
+
...resolved,
|
|
9822
|
+
schema: serializeZodSchema2(resolved.schema)
|
|
9823
|
+
};
|
|
9824
|
+
}
|
|
9825
|
+
return resolved;
|
|
9844
9826
|
}
|
|
9845
|
-
});
|
|
9846
|
-
const result = await withCurrent(
|
|
9847
|
-
span,
|
|
9848
|
-
() => Reflect.apply(originalDoStream, resolvedModel, [options])
|
|
9849
9827
|
);
|
|
9850
|
-
|
|
9851
|
-
|
|
9852
|
-
|
|
9853
|
-
|
|
9828
|
+
} else {
|
|
9829
|
+
const syncResponseFormat = responseFormat;
|
|
9830
|
+
if (syncResponseFormat.schema && isZodSchema2(syncResponseFormat.schema)) {
|
|
9831
|
+
responseFormat = {
|
|
9832
|
+
...syncResponseFormat,
|
|
9833
|
+
schema: serializeZodSchema2(syncResponseFormat.schema)
|
|
9834
|
+
};
|
|
9835
|
+
}
|
|
9836
|
+
result.response_format = responseFormat;
|
|
9837
|
+
}
|
|
9838
|
+
}
|
|
9839
|
+
return result;
|
|
9840
|
+
} catch {
|
|
9841
|
+
return {
|
|
9842
|
+
response_format: null
|
|
9843
|
+
};
|
|
9844
|
+
}
|
|
9845
|
+
};
|
|
9846
|
+
var processInputAttachmentsSync = (input) => {
|
|
9847
|
+
if (!input) return { input };
|
|
9848
|
+
const processed = { ...input };
|
|
9849
|
+
if (input.messages && Array.isArray(input.messages)) {
|
|
9850
|
+
processed.messages = input.messages.map(processMessage);
|
|
9851
|
+
}
|
|
9852
|
+
if (input.prompt && typeof input.prompt === "object") {
|
|
9853
|
+
if (Array.isArray(input.prompt)) {
|
|
9854
|
+
processed.prompt = input.prompt.map(processMessage);
|
|
9855
|
+
} else {
|
|
9856
|
+
processed.prompt = processPromptContent(input.prompt);
|
|
9857
|
+
}
|
|
9858
|
+
}
|
|
9859
|
+
if (input.schema && isZodSchema2(input.schema)) {
|
|
9860
|
+
processed.schema = serializeZodSchema2(input.schema);
|
|
9861
|
+
}
|
|
9862
|
+
if (input.callOptionsSchema && isZodSchema2(input.callOptionsSchema)) {
|
|
9863
|
+
processed.callOptionsSchema = serializeZodSchema2(input.callOptionsSchema);
|
|
9864
|
+
}
|
|
9865
|
+
if (input.tools) {
|
|
9866
|
+
processed.tools = serializeAISDKToolsForLogging(input.tools);
|
|
9867
|
+
}
|
|
9868
|
+
let outputPromise;
|
|
9869
|
+
if (input.output && isOutputObject(input.output)) {
|
|
9870
|
+
const serialized = serializeOutputObject(input.output, input.model);
|
|
9871
|
+
if (serialized.response_format && typeof serialized.response_format.then === "function") {
|
|
9872
|
+
processed.output = { ...serialized, response_format: {} };
|
|
9873
|
+
outputPromise = serialized.response_format.then(
|
|
9874
|
+
(resolvedFormat) => ({
|
|
9875
|
+
output: { ...serialized, response_format: resolvedFormat }
|
|
9876
|
+
})
|
|
9877
|
+
);
|
|
9878
|
+
} else {
|
|
9879
|
+
processed.output = serialized;
|
|
9880
|
+
}
|
|
9881
|
+
}
|
|
9882
|
+
if ("prepareCall" in processed && typeof processed.prepareCall === "function") {
|
|
9883
|
+
processed.prepareCall = "[Function]";
|
|
9884
|
+
}
|
|
9885
|
+
return { input: processed, outputPromise };
|
|
9886
|
+
};
|
|
9887
|
+
var processMessage = (message) => {
|
|
9888
|
+
if (!message || typeof message !== "object") return message;
|
|
9889
|
+
if (Array.isArray(message.content)) {
|
|
9890
|
+
return {
|
|
9891
|
+
...message,
|
|
9892
|
+
content: message.content.map(processContentPart)
|
|
9893
|
+
};
|
|
9894
|
+
}
|
|
9895
|
+
if (typeof message.content === "object" && message.content !== null) {
|
|
9896
|
+
return {
|
|
9897
|
+
...message,
|
|
9898
|
+
content: processContentPart(message.content)
|
|
9899
|
+
};
|
|
9900
|
+
}
|
|
9901
|
+
return message;
|
|
9902
|
+
};
|
|
9903
|
+
var processPromptContent = (prompt) => {
|
|
9904
|
+
if (Array.isArray(prompt)) {
|
|
9905
|
+
return prompt.map(processContentPart);
|
|
9906
|
+
}
|
|
9907
|
+
if (prompt.content) {
|
|
9908
|
+
if (Array.isArray(prompt.content)) {
|
|
9909
|
+
return {
|
|
9910
|
+
...prompt,
|
|
9911
|
+
content: prompt.content.map(processContentPart)
|
|
9912
|
+
};
|
|
9913
|
+
} else if (typeof prompt.content === "object") {
|
|
9914
|
+
return {
|
|
9915
|
+
...prompt,
|
|
9916
|
+
content: processContentPart(prompt.content)
|
|
9917
|
+
};
|
|
9918
|
+
}
|
|
9919
|
+
}
|
|
9920
|
+
return prompt;
|
|
9921
|
+
};
|
|
9922
|
+
var processContentPart = (part) => {
|
|
9923
|
+
if (!part || typeof part !== "object") return part;
|
|
9924
|
+
try {
|
|
9925
|
+
if (part.type === "image" && part.image) {
|
|
9926
|
+
const imageAttachment = convertImageToAttachment(
|
|
9927
|
+
part.image,
|
|
9928
|
+
part.mimeType || part.mediaType
|
|
9929
|
+
);
|
|
9930
|
+
if (imageAttachment) {
|
|
9931
|
+
return {
|
|
9932
|
+
...part,
|
|
9933
|
+
image: imageAttachment
|
|
9934
|
+
};
|
|
9935
|
+
}
|
|
9936
|
+
}
|
|
9937
|
+
if (part.type === "file" && part.data && (part.mimeType || part.mediaType)) {
|
|
9938
|
+
const fileAttachment = convertDataToAttachment(
|
|
9939
|
+
part.data,
|
|
9940
|
+
part.mimeType || part.mediaType,
|
|
9941
|
+
part.name || part.filename
|
|
9942
|
+
);
|
|
9943
|
+
if (fileAttachment) {
|
|
9944
|
+
return {
|
|
9945
|
+
...part,
|
|
9946
|
+
data: fileAttachment
|
|
9947
|
+
};
|
|
9948
|
+
}
|
|
9949
|
+
}
|
|
9950
|
+
if (part.type === "image_url" && part.image_url) {
|
|
9951
|
+
if (typeof part.image_url === "object" && part.image_url.url) {
|
|
9952
|
+
const imageAttachment = convertImageToAttachment(part.image_url.url);
|
|
9953
|
+
if (imageAttachment) {
|
|
9954
|
+
return {
|
|
9955
|
+
...part,
|
|
9956
|
+
image_url: {
|
|
9957
|
+
...part.image_url,
|
|
9958
|
+
url: imageAttachment
|
|
9959
|
+
}
|
|
9960
|
+
};
|
|
9961
|
+
}
|
|
9962
|
+
}
|
|
9963
|
+
}
|
|
9964
|
+
} catch (error) {
|
|
9965
|
+
console.warn("Error processing content part:", error);
|
|
9966
|
+
}
|
|
9967
|
+
return part;
|
|
9968
|
+
};
|
|
9969
|
+
var convertImageToAttachment = (image, explicitMimeType) => {
|
|
9970
|
+
try {
|
|
9971
|
+
if (typeof image === "string" && image.startsWith("data:")) {
|
|
9972
|
+
const [mimeTypeSection, base64Data] = image.split(",");
|
|
9973
|
+
const mimeType = mimeTypeSection.match(/data:(.*?);/)?.[1];
|
|
9974
|
+
if (mimeType && base64Data) {
|
|
9975
|
+
const blob = convertDataToBlob(base64Data, mimeType);
|
|
9976
|
+
if (blob) {
|
|
9977
|
+
return new Attachment({
|
|
9978
|
+
data: blob,
|
|
9979
|
+
filename: `image.${getExtensionFromMediaType(mimeType)}`,
|
|
9980
|
+
contentType: mimeType
|
|
9981
|
+
});
|
|
9982
|
+
}
|
|
9983
|
+
}
|
|
9984
|
+
}
|
|
9985
|
+
if (explicitMimeType) {
|
|
9986
|
+
if (image instanceof Uint8Array) {
|
|
9987
|
+
return new Attachment({
|
|
9988
|
+
data: new Blob([image], { type: explicitMimeType }),
|
|
9989
|
+
filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
|
|
9990
|
+
contentType: explicitMimeType
|
|
9991
|
+
});
|
|
9992
|
+
}
|
|
9993
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
|
|
9994
|
+
return new Attachment({
|
|
9995
|
+
data: new Blob([image], { type: explicitMimeType }),
|
|
9996
|
+
filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
|
|
9997
|
+
contentType: explicitMimeType
|
|
9998
|
+
});
|
|
9999
|
+
}
|
|
10000
|
+
}
|
|
10001
|
+
if (image instanceof Blob && image.type) {
|
|
10002
|
+
return new Attachment({
|
|
10003
|
+
data: image,
|
|
10004
|
+
filename: `image.${getExtensionFromMediaType(image.type)}`,
|
|
10005
|
+
contentType: image.type
|
|
10006
|
+
});
|
|
10007
|
+
}
|
|
10008
|
+
if (image instanceof Attachment) {
|
|
10009
|
+
return image;
|
|
10010
|
+
}
|
|
10011
|
+
} catch (error) {
|
|
10012
|
+
console.warn("Error converting image to attachment:", error);
|
|
10013
|
+
}
|
|
10014
|
+
return null;
|
|
10015
|
+
};
|
|
10016
|
+
var convertDataToAttachment = (data, mimeType, filename) => {
|
|
10017
|
+
if (!mimeType) return null;
|
|
10018
|
+
try {
|
|
10019
|
+
let blob = null;
|
|
10020
|
+
if (typeof data === "string" && data.startsWith("data:")) {
|
|
10021
|
+
const [, base64Data] = data.split(",");
|
|
10022
|
+
if (base64Data) {
|
|
10023
|
+
blob = convertDataToBlob(base64Data, mimeType);
|
|
10024
|
+
}
|
|
10025
|
+
} else if (typeof data === "string" && data.length > 0) {
|
|
10026
|
+
blob = convertDataToBlob(data, mimeType);
|
|
10027
|
+
} else if (data instanceof Uint8Array) {
|
|
10028
|
+
blob = new Blob([data], { type: mimeType });
|
|
10029
|
+
} else if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
|
|
10030
|
+
blob = new Blob([data], { type: mimeType });
|
|
10031
|
+
} else if (data instanceof Blob) {
|
|
10032
|
+
blob = data;
|
|
10033
|
+
}
|
|
10034
|
+
if (blob) {
|
|
10035
|
+
return new Attachment({
|
|
10036
|
+
data: blob,
|
|
10037
|
+
filename: filename || `file.${getExtensionFromMediaType(mimeType)}`,
|
|
10038
|
+
contentType: mimeType
|
|
10039
|
+
});
|
|
10040
|
+
}
|
|
10041
|
+
} catch (error) {
|
|
10042
|
+
console.warn("Error converting data to attachment:", error);
|
|
10043
|
+
}
|
|
10044
|
+
return null;
|
|
10045
|
+
};
|
|
10046
|
+
function processAISDKInput(params) {
|
|
10047
|
+
return processInputAttachmentsSync(params);
|
|
10048
|
+
}
|
|
10049
|
+
function prepareAISDKInput(params, event, span, defaultDenyOutputPaths) {
|
|
10050
|
+
const { input, outputPromise } = processAISDKInput(params);
|
|
10051
|
+
if (outputPromise && input && typeof input === "object") {
|
|
10052
|
+
outputPromise.then((resolvedData) => {
|
|
10053
|
+
span.log({
|
|
10054
|
+
input: {
|
|
10055
|
+
...input,
|
|
10056
|
+
...resolvedData
|
|
10057
|
+
}
|
|
10058
|
+
});
|
|
10059
|
+
}).catch(() => {
|
|
10060
|
+
});
|
|
10061
|
+
}
|
|
10062
|
+
const metadata = extractMetadataFromParams(params, event.self);
|
|
10063
|
+
const childTracing = prepareAISDKChildTracing(
|
|
10064
|
+
params,
|
|
10065
|
+
event.self,
|
|
10066
|
+
span,
|
|
10067
|
+
defaultDenyOutputPaths,
|
|
10068
|
+
event.aiSDK
|
|
10069
|
+
);
|
|
10070
|
+
event.modelWrapped = childTracing.modelWrapped;
|
|
10071
|
+
if (childTracing.cleanup) {
|
|
10072
|
+
event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
|
|
10073
|
+
}
|
|
10074
|
+
return {
|
|
10075
|
+
input,
|
|
10076
|
+
metadata
|
|
10077
|
+
};
|
|
10078
|
+
}
|
|
10079
|
+
function extractTopLevelAISDKMetrics(result, event, startTime) {
|
|
10080
|
+
const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
|
|
10081
|
+
if (startTime) {
|
|
10082
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
10083
|
+
}
|
|
10084
|
+
return metrics;
|
|
10085
|
+
}
|
|
10086
|
+
function hasModelChildTracing(event) {
|
|
10087
|
+
return event?.modelWrapped === true || event?.__braintrust_ai_sdk_model_wrapped === true;
|
|
10088
|
+
}
|
|
10089
|
+
function extractMetadataFromParams(params, self) {
|
|
10090
|
+
const metadata = {
|
|
10091
|
+
braintrust: {
|
|
10092
|
+
integration_name: "ai-sdk",
|
|
10093
|
+
sdk_language: "typescript"
|
|
10094
|
+
}
|
|
10095
|
+
};
|
|
10096
|
+
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;
|
|
10097
|
+
const { model, provider } = serializeModelWithProvider(
|
|
10098
|
+
params.model ?? agentModel
|
|
10099
|
+
);
|
|
10100
|
+
if (model) {
|
|
10101
|
+
metadata.model = model;
|
|
10102
|
+
}
|
|
10103
|
+
if (provider) {
|
|
10104
|
+
metadata.provider = provider;
|
|
10105
|
+
}
|
|
10106
|
+
const tools = serializeAISDKToolsForLogging(params.tools);
|
|
10107
|
+
if (tools) {
|
|
10108
|
+
metadata.tools = tools;
|
|
10109
|
+
}
|
|
10110
|
+
return metadata;
|
|
10111
|
+
}
|
|
10112
|
+
function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiSDK) {
|
|
10113
|
+
const cleanup = [];
|
|
10114
|
+
const patchedModels = /* @__PURE__ */ new WeakSet();
|
|
10115
|
+
const patchedTools = /* @__PURE__ */ new WeakSet();
|
|
10116
|
+
let modelWrapped = false;
|
|
10117
|
+
const patchModel = (model) => {
|
|
10118
|
+
const resolvedModel = resolveAISDKModel(model, aiSDK);
|
|
10119
|
+
if (!resolvedModel || typeof resolvedModel !== "object" || typeof resolvedModel.doGenerate !== "function" || patchedModels.has(resolvedModel) || resolvedModel[AUTO_PATCHED_MODEL]) {
|
|
10120
|
+
return resolvedModel;
|
|
10121
|
+
}
|
|
10122
|
+
patchedModels.add(resolvedModel);
|
|
10123
|
+
resolvedModel[AUTO_PATCHED_MODEL] = true;
|
|
10124
|
+
modelWrapped = true;
|
|
10125
|
+
const originalDoGenerate = resolvedModel.doGenerate;
|
|
10126
|
+
const originalDoStream = resolvedModel.doStream;
|
|
10127
|
+
const baseMetadata = buildAISDKChildMetadata(resolvedModel);
|
|
10128
|
+
resolvedModel.doGenerate = async function doGeneratePatched(options) {
|
|
10129
|
+
return parentSpan.traced(
|
|
10130
|
+
async (span) => {
|
|
10131
|
+
const result = await Reflect.apply(
|
|
10132
|
+
originalDoGenerate,
|
|
10133
|
+
resolvedModel,
|
|
10134
|
+
[options]
|
|
10135
|
+
);
|
|
10136
|
+
span.log({
|
|
10137
|
+
output: processAISDKOutput(result, denyOutputPaths),
|
|
10138
|
+
metrics: extractTokenMetrics(result),
|
|
10139
|
+
...buildResolvedMetadataPayload(result)
|
|
10140
|
+
});
|
|
10141
|
+
return result;
|
|
10142
|
+
},
|
|
10143
|
+
{
|
|
10144
|
+
name: "doGenerate",
|
|
10145
|
+
spanAttributes: {
|
|
10146
|
+
type: "llm" /* LLM */
|
|
10147
|
+
},
|
|
10148
|
+
event: {
|
|
10149
|
+
input: processAISDKInput(options).input,
|
|
10150
|
+
metadata: baseMetadata
|
|
10151
|
+
}
|
|
10152
|
+
}
|
|
10153
|
+
);
|
|
10154
|
+
};
|
|
10155
|
+
if (originalDoStream) {
|
|
10156
|
+
resolvedModel.doStream = async function doStreamPatched(options) {
|
|
10157
|
+
const span = parentSpan.startSpan({
|
|
10158
|
+
name: "doStream",
|
|
10159
|
+
spanAttributes: {
|
|
10160
|
+
type: "llm" /* LLM */
|
|
10161
|
+
},
|
|
10162
|
+
event: {
|
|
10163
|
+
input: processAISDKInput(options).input,
|
|
10164
|
+
metadata: baseMetadata
|
|
10165
|
+
}
|
|
10166
|
+
});
|
|
10167
|
+
const result = await withCurrent(
|
|
10168
|
+
span,
|
|
10169
|
+
() => Reflect.apply(originalDoStream, resolvedModel, [options])
|
|
10170
|
+
);
|
|
10171
|
+
const streamStartTime = getCurrentUnixTimestamp();
|
|
10172
|
+
let firstChunkTime;
|
|
10173
|
+
const output = {};
|
|
10174
|
+
let text = "";
|
|
10175
|
+
let reasoning = "";
|
|
10176
|
+
const toolCalls = [];
|
|
9854
10177
|
let object = void 0;
|
|
9855
10178
|
const transformStream = new TransformStream({
|
|
9856
10179
|
transform(chunk, controller) {
|
|
10180
|
+
if (firstChunkTime === void 0) {
|
|
10181
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
10182
|
+
}
|
|
9857
10183
|
switch (chunk.type) {
|
|
9858
10184
|
case "text-delta":
|
|
9859
10185
|
text += extractTextDelta(chunk);
|
|
@@ -9894,12 +10220,19 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
9894
10220
|
if (object !== void 0) {
|
|
9895
10221
|
output.object = object;
|
|
9896
10222
|
}
|
|
10223
|
+
const metrics = extractTokenMetrics(output);
|
|
10224
|
+
if (firstChunkTime !== void 0) {
|
|
10225
|
+
metrics.time_to_first_token = Math.max(
|
|
10226
|
+
firstChunkTime - streamStartTime,
|
|
10227
|
+
1e-6
|
|
10228
|
+
);
|
|
10229
|
+
}
|
|
9897
10230
|
span.log({
|
|
9898
10231
|
output: processAISDKOutput(
|
|
9899
10232
|
output,
|
|
9900
10233
|
denyOutputPaths
|
|
9901
10234
|
),
|
|
9902
|
-
metrics
|
|
10235
|
+
metrics,
|
|
9903
10236
|
...buildResolvedMetadataPayload(output)
|
|
9904
10237
|
});
|
|
9905
10238
|
span.end();
|
|
@@ -9921,6 +10254,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
9921
10254
|
}
|
|
9922
10255
|
delete resolvedModel[AUTO_PATCHED_MODEL];
|
|
9923
10256
|
});
|
|
10257
|
+
return resolvedModel;
|
|
9924
10258
|
};
|
|
9925
10259
|
const patchTool = (tool, name) => {
|
|
9926
10260
|
if (tool == null || typeof tool !== "object" || !("execute" in tool) || typeof tool.execute !== "function" || patchedTools.has(tool) || tool[AUTO_PATCHED_TOOL]) {
|
|
@@ -9993,17 +10327,26 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
9993
10327
|
}
|
|
9994
10328
|
};
|
|
9995
10329
|
if (params && typeof params === "object") {
|
|
9996
|
-
patchModel(params.model);
|
|
10330
|
+
const patchedParamModel = patchModel(params.model);
|
|
10331
|
+
if (typeof params.model === "string" && patchedParamModel && typeof patchedParamModel === "object") {
|
|
10332
|
+
params.model = patchedParamModel;
|
|
10333
|
+
}
|
|
9997
10334
|
patchTools(params.tools);
|
|
9998
10335
|
}
|
|
9999
10336
|
if (self && typeof self === "object") {
|
|
10000
10337
|
const selfRecord = self;
|
|
10001
10338
|
if (selfRecord.model !== void 0) {
|
|
10002
|
-
patchModel(selfRecord.model);
|
|
10339
|
+
const patchedSelfModel = patchModel(selfRecord.model);
|
|
10340
|
+
if (typeof selfRecord.model === "string" && patchedSelfModel && typeof patchedSelfModel === "object") {
|
|
10341
|
+
selfRecord.model = patchedSelfModel;
|
|
10342
|
+
}
|
|
10003
10343
|
}
|
|
10004
10344
|
if (selfRecord.settings && typeof selfRecord.settings === "object") {
|
|
10005
10345
|
if (selfRecord.settings.model !== void 0) {
|
|
10006
|
-
patchModel(selfRecord.settings.model);
|
|
10346
|
+
const patchedSettingsModel = patchModel(selfRecord.settings.model);
|
|
10347
|
+
if (typeof selfRecord.settings.model === "string" && patchedSettingsModel && typeof patchedSettingsModel === "object") {
|
|
10348
|
+
selfRecord.settings.model = patchedSettingsModel;
|
|
10349
|
+
}
|
|
10007
10350
|
}
|
|
10008
10351
|
if (selfRecord.settings.tools !== void 0) {
|
|
10009
10352
|
patchTools(selfRecord.settings.tools);
|
|
@@ -10027,63 +10370,173 @@ function finalizeAISDKChildTracing(event) {
|
|
|
10027
10370
|
}
|
|
10028
10371
|
}
|
|
10029
10372
|
function patchAISDKStreamingResult(args) {
|
|
10030
|
-
const {
|
|
10373
|
+
const { defaultDenyOutputPaths, endEvent, result, span, startTime } = args;
|
|
10031
10374
|
if (!result || typeof result !== "object") {
|
|
10032
10375
|
return false;
|
|
10033
10376
|
}
|
|
10034
10377
|
const resultRecord = result;
|
|
10035
|
-
|
|
10378
|
+
attachKnownResultPromiseHandlers(resultRecord);
|
|
10379
|
+
if (isReadableStreamLike(resultRecord.baseStream)) {
|
|
10380
|
+
let firstChunkTime2;
|
|
10381
|
+
const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
|
|
10382
|
+
new TransformStream({
|
|
10383
|
+
transform(chunk, controller) {
|
|
10384
|
+
if (firstChunkTime2 === void 0) {
|
|
10385
|
+
firstChunkTime2 = getCurrentUnixTimestamp();
|
|
10386
|
+
}
|
|
10387
|
+
controller.enqueue(chunk);
|
|
10388
|
+
},
|
|
10389
|
+
async flush() {
|
|
10390
|
+
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
10391
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime2 !== void 0) {
|
|
10392
|
+
metrics.time_to_first_token = firstChunkTime2 - startTime;
|
|
10393
|
+
}
|
|
10394
|
+
const output = await processAISDKStreamingOutput(
|
|
10395
|
+
result,
|
|
10396
|
+
resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
|
|
10397
|
+
);
|
|
10398
|
+
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
10399
|
+
span.log({
|
|
10400
|
+
output,
|
|
10401
|
+
...metadata ? { metadata } : {},
|
|
10402
|
+
metrics
|
|
10403
|
+
});
|
|
10404
|
+
finalizeAISDKChildTracing(endEvent);
|
|
10405
|
+
span.end();
|
|
10406
|
+
}
|
|
10407
|
+
})
|
|
10408
|
+
);
|
|
10409
|
+
Object.defineProperty(resultRecord, "baseStream", {
|
|
10410
|
+
configurable: true,
|
|
10411
|
+
enumerable: true,
|
|
10412
|
+
value: wrappedBaseStream,
|
|
10413
|
+
writable: true
|
|
10414
|
+
});
|
|
10415
|
+
return true;
|
|
10416
|
+
}
|
|
10417
|
+
const streamField = findAsyncIterableField(resultRecord, [
|
|
10418
|
+
"partialObjectStream",
|
|
10419
|
+
"textStream",
|
|
10420
|
+
"fullStream",
|
|
10421
|
+
"stream"
|
|
10422
|
+
]);
|
|
10423
|
+
if (!streamField) {
|
|
10036
10424
|
return false;
|
|
10037
10425
|
}
|
|
10038
10426
|
let firstChunkTime;
|
|
10039
|
-
const
|
|
10040
|
-
|
|
10041
|
-
|
|
10042
|
-
|
|
10043
|
-
firstChunkTime = getCurrentUnixTimestamp();
|
|
10044
|
-
}
|
|
10045
|
-
controller.enqueue(chunk);
|
|
10046
|
-
},
|
|
10047
|
-
async flush() {
|
|
10048
|
-
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
10049
|
-
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
10050
|
-
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
10051
|
-
}
|
|
10052
|
-
const output = await processAISDKStreamingOutput(
|
|
10053
|
-
result,
|
|
10054
|
-
denyOutputPaths
|
|
10055
|
-
);
|
|
10056
|
-
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
10057
|
-
span.log({
|
|
10058
|
-
output,
|
|
10059
|
-
...metadata ? { metadata } : {},
|
|
10060
|
-
metrics
|
|
10061
|
-
});
|
|
10062
|
-
finalizeAISDKChildTracing(endEvent);
|
|
10063
|
-
span.end();
|
|
10427
|
+
const wrappedStream = createPatchedAsyncIterable(streamField.stream, {
|
|
10428
|
+
onChunk: () => {
|
|
10429
|
+
if (firstChunkTime === void 0) {
|
|
10430
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
10064
10431
|
}
|
|
10065
|
-
}
|
|
10066
|
-
|
|
10067
|
-
|
|
10432
|
+
},
|
|
10433
|
+
onComplete: async () => {
|
|
10434
|
+
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
10435
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
10436
|
+
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
10437
|
+
}
|
|
10438
|
+
const output = await processAISDKStreamingOutput(
|
|
10439
|
+
result,
|
|
10440
|
+
resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
|
|
10441
|
+
);
|
|
10442
|
+
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
10443
|
+
span.log({
|
|
10444
|
+
output,
|
|
10445
|
+
...metadata ? { metadata } : {},
|
|
10446
|
+
metrics
|
|
10447
|
+
});
|
|
10448
|
+
finalizeAISDKChildTracing(endEvent);
|
|
10449
|
+
span.end();
|
|
10450
|
+
},
|
|
10451
|
+
onError: (error) => {
|
|
10452
|
+
span.log({
|
|
10453
|
+
error: error.message
|
|
10454
|
+
});
|
|
10455
|
+
finalizeAISDKChildTracing(endEvent);
|
|
10456
|
+
span.end();
|
|
10457
|
+
}
|
|
10458
|
+
});
|
|
10459
|
+
Object.defineProperty(resultRecord, streamField.field, {
|
|
10068
10460
|
configurable: true,
|
|
10069
10461
|
enumerable: true,
|
|
10070
|
-
value:
|
|
10462
|
+
value: wrappedStream,
|
|
10071
10463
|
writable: true
|
|
10072
10464
|
});
|
|
10073
10465
|
return true;
|
|
10074
10466
|
}
|
|
10075
|
-
function
|
|
10076
|
-
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
|
|
10080
|
-
|
|
10467
|
+
function attachKnownResultPromiseHandlers(result) {
|
|
10468
|
+
const promiseLikeFields = [
|
|
10469
|
+
"content",
|
|
10470
|
+
"text",
|
|
10471
|
+
"object",
|
|
10472
|
+
"finishReason",
|
|
10473
|
+
"usage",
|
|
10474
|
+
"totalUsage",
|
|
10475
|
+
"steps"
|
|
10476
|
+
];
|
|
10477
|
+
for (const field of promiseLikeFields) {
|
|
10478
|
+
try {
|
|
10479
|
+
if (!(field in result)) {
|
|
10480
|
+
continue;
|
|
10481
|
+
}
|
|
10482
|
+
const value = result[field];
|
|
10483
|
+
if (isPromiseLike(value)) {
|
|
10484
|
+
void Promise.resolve(value).catch(() => {
|
|
10485
|
+
});
|
|
10486
|
+
}
|
|
10487
|
+
} catch {
|
|
10488
|
+
}
|
|
10489
|
+
}
|
|
10490
|
+
}
|
|
10491
|
+
function isReadableStreamLike(value) {
|
|
10492
|
+
return value != null && typeof value === "object" && typeof value.pipeThrough === "function";
|
|
10493
|
+
}
|
|
10494
|
+
function isAsyncIterableLike(value) {
|
|
10495
|
+
return value != null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
|
|
10496
|
+
}
|
|
10497
|
+
function findAsyncIterableField(result, candidateFields) {
|
|
10498
|
+
for (const field of candidateFields) {
|
|
10499
|
+
try {
|
|
10500
|
+
const stream = result[field];
|
|
10501
|
+
if (isAsyncIterableLike(stream)) {
|
|
10502
|
+
return { field, stream };
|
|
10503
|
+
}
|
|
10504
|
+
} catch {
|
|
10505
|
+
}
|
|
10506
|
+
}
|
|
10507
|
+
return null;
|
|
10508
|
+
}
|
|
10509
|
+
function createPatchedAsyncIterable(stream, hooks) {
|
|
10510
|
+
return {
|
|
10511
|
+
async *[Symbol.asyncIterator]() {
|
|
10512
|
+
try {
|
|
10513
|
+
for await (const chunk of stream) {
|
|
10514
|
+
hooks.onChunk(chunk);
|
|
10515
|
+
yield chunk;
|
|
10516
|
+
}
|
|
10517
|
+
await hooks.onComplete();
|
|
10518
|
+
} catch (error) {
|
|
10519
|
+
hooks.onError(
|
|
10520
|
+
error instanceof Error ? error : new Error(String(error))
|
|
10521
|
+
);
|
|
10522
|
+
throw error;
|
|
10523
|
+
}
|
|
10524
|
+
}
|
|
10525
|
+
};
|
|
10526
|
+
}
|
|
10527
|
+
async function processAISDKStreamingOutput(result, denyOutputPaths) {
|
|
10528
|
+
const output = processAISDKOutput(result, denyOutputPaths);
|
|
10529
|
+
if (!output || typeof output !== "object") {
|
|
10081
10530
|
return output;
|
|
10082
10531
|
}
|
|
10083
10532
|
const outputRecord = output;
|
|
10533
|
+
const isObjectStreamingResult = result != null && typeof result === "object" && "partialObjectStream" in result;
|
|
10084
10534
|
try {
|
|
10085
|
-
if ("text" in result
|
|
10086
|
-
|
|
10535
|
+
if (!isObjectStreamingResult && "text" in result) {
|
|
10536
|
+
const resolvedText = await Promise.resolve(result.text);
|
|
10537
|
+
if (typeof resolvedText === "string") {
|
|
10538
|
+
outputRecord.text = resolvedText;
|
|
10539
|
+
}
|
|
10087
10540
|
}
|
|
10088
10541
|
} catch {
|
|
10089
10542
|
}
|
|
@@ -10096,6 +10549,15 @@ async function processAISDKStreamingOutput(result, denyOutputPaths) {
|
|
|
10096
10549
|
}
|
|
10097
10550
|
} catch {
|
|
10098
10551
|
}
|
|
10552
|
+
try {
|
|
10553
|
+
if ("finishReason" in result) {
|
|
10554
|
+
const resolvedFinishReason = await Promise.resolve(result.finishReason);
|
|
10555
|
+
if (resolvedFinishReason !== void 0) {
|
|
10556
|
+
outputRecord.finishReason = resolvedFinishReason;
|
|
10557
|
+
}
|
|
10558
|
+
}
|
|
10559
|
+
} catch {
|
|
10560
|
+
}
|
|
10099
10561
|
return outputRecord;
|
|
10100
10562
|
}
|
|
10101
10563
|
function buildAISDKChildMetadata(model) {
|
|
@@ -10118,16 +10580,25 @@ function buildResolvedMetadataPayload(result) {
|
|
|
10118
10580
|
if (gatewayInfo?.model) {
|
|
10119
10581
|
metadata.model = gatewayInfo.model;
|
|
10120
10582
|
}
|
|
10121
|
-
|
|
10122
|
-
|
|
10583
|
+
let finishReason;
|
|
10584
|
+
try {
|
|
10585
|
+
finishReason = result.finishReason;
|
|
10586
|
+
} catch {
|
|
10587
|
+
finishReason = void 0;
|
|
10588
|
+
}
|
|
10589
|
+
if (isPromiseLike(finishReason)) {
|
|
10590
|
+
void Promise.resolve(finishReason).catch(() => {
|
|
10591
|
+
});
|
|
10592
|
+
} else if (finishReason !== void 0) {
|
|
10593
|
+
metadata.finish_reason = finishReason;
|
|
10123
10594
|
}
|
|
10124
10595
|
return Object.keys(metadata).length > 0 ? { metadata } : {};
|
|
10125
10596
|
}
|
|
10126
|
-
function resolveAISDKModel(model) {
|
|
10597
|
+
function resolveAISDKModel(model, aiSDK) {
|
|
10127
10598
|
if (typeof model !== "string") {
|
|
10128
10599
|
return model;
|
|
10129
10600
|
}
|
|
10130
|
-
const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? null;
|
|
10601
|
+
const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? aiSDK?.gateway ?? null;
|
|
10131
10602
|
if (provider && typeof provider.languageModel === "function") {
|
|
10132
10603
|
return provider.languageModel(model);
|
|
10133
10604
|
}
|
|
@@ -10150,15 +10621,15 @@ function processAISDKOutput(output, denyOutputPaths) {
|
|
|
10150
10621
|
}
|
|
10151
10622
|
function extractTokenMetrics(result) {
|
|
10152
10623
|
const metrics = {};
|
|
10153
|
-
let usage
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
|
|
10159
|
-
|
|
10160
|
-
|
|
10161
|
-
|
|
10624
|
+
let usage;
|
|
10625
|
+
const totalUsageValue = safeResultFieldRead(result, "totalUsage");
|
|
10626
|
+
if (totalUsageValue !== void 0 && !isPromiseLike(totalUsageValue)) {
|
|
10627
|
+
usage = totalUsageValue;
|
|
10628
|
+
}
|
|
10629
|
+
if (!usage) {
|
|
10630
|
+
const usageValue = safeResultFieldRead(result, "usage");
|
|
10631
|
+
if (usageValue !== void 0 && !isPromiseLike(usageValue)) {
|
|
10632
|
+
usage = usageValue;
|
|
10162
10633
|
}
|
|
10163
10634
|
}
|
|
10164
10635
|
if (!usage) {
|
|
@@ -10196,6 +10667,22 @@ function extractTokenMetrics(result) {
|
|
|
10196
10667
|
}
|
|
10197
10668
|
return metrics;
|
|
10198
10669
|
}
|
|
10670
|
+
function safeResultFieldRead(result, field) {
|
|
10671
|
+
return safeSerializableFieldRead(result, field);
|
|
10672
|
+
}
|
|
10673
|
+
function safeSerializableFieldRead(obj, field) {
|
|
10674
|
+
try {
|
|
10675
|
+
const value = obj?.[field];
|
|
10676
|
+
if (isPromiseLike(value)) {
|
|
10677
|
+
void Promise.resolve(value).catch(() => {
|
|
10678
|
+
});
|
|
10679
|
+
return void 0;
|
|
10680
|
+
}
|
|
10681
|
+
return value;
|
|
10682
|
+
} catch {
|
|
10683
|
+
return void 0;
|
|
10684
|
+
}
|
|
10685
|
+
}
|
|
10199
10686
|
function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
10200
10687
|
const lastChunk = chunks[chunks.length - 1];
|
|
10201
10688
|
const output = {};
|
|
@@ -10204,17 +10691,21 @@ function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
|
10204
10691
|
if (lastChunk) {
|
|
10205
10692
|
metrics = hasModelChildTracing(endEvent) ? {} : extractTokenMetrics(lastChunk);
|
|
10206
10693
|
metadata = buildResolvedMetadataPayload(lastChunk).metadata;
|
|
10207
|
-
|
|
10208
|
-
|
|
10694
|
+
const text = safeSerializableFieldRead(lastChunk, "text");
|
|
10695
|
+
if (text !== void 0) {
|
|
10696
|
+
output.text = text;
|
|
10209
10697
|
}
|
|
10210
|
-
|
|
10211
|
-
|
|
10698
|
+
const objectValue = safeSerializableFieldRead(lastChunk, "object");
|
|
10699
|
+
if (objectValue !== void 0) {
|
|
10700
|
+
output.object = objectValue;
|
|
10212
10701
|
}
|
|
10213
|
-
|
|
10214
|
-
|
|
10702
|
+
const finishReason = safeSerializableFieldRead(lastChunk, "finishReason");
|
|
10703
|
+
if (finishReason !== void 0) {
|
|
10704
|
+
output.finishReason = finishReason;
|
|
10215
10705
|
}
|
|
10216
|
-
|
|
10217
|
-
|
|
10706
|
+
const toolCalls = safeSerializableFieldRead(lastChunk, "toolCalls");
|
|
10707
|
+
if (toolCalls !== void 0) {
|
|
10708
|
+
output.toolCalls = toolCalls;
|
|
10218
10709
|
}
|
|
10219
10710
|
}
|
|
10220
10711
|
finalizeAISDKChildTracing(endEvent);
|
|
@@ -10223,6 +10714,7 @@ function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
|
10223
10714
|
function extractGetterValues(obj) {
|
|
10224
10715
|
const getterValues = {};
|
|
10225
10716
|
const getterNames = [
|
|
10717
|
+
"content",
|
|
10226
10718
|
"text",
|
|
10227
10719
|
"object",
|
|
10228
10720
|
"finishReason",
|
|
@@ -10238,8 +10730,17 @@ function extractGetterValues(obj) {
|
|
|
10238
10730
|
];
|
|
10239
10731
|
for (const name of getterNames) {
|
|
10240
10732
|
try {
|
|
10241
|
-
if (obj
|
|
10242
|
-
|
|
10733
|
+
if (!obj || !(name in obj)) {
|
|
10734
|
+
continue;
|
|
10735
|
+
}
|
|
10736
|
+
const value = obj[name];
|
|
10737
|
+
if (isPromiseLike(value)) {
|
|
10738
|
+
void Promise.resolve(value).catch(() => {
|
|
10739
|
+
});
|
|
10740
|
+
continue;
|
|
10741
|
+
}
|
|
10742
|
+
if (isSerializableOutputValue(value)) {
|
|
10743
|
+
getterValues[name] = value;
|
|
10243
10744
|
}
|
|
10244
10745
|
} catch {
|
|
10245
10746
|
}
|
|
@@ -10261,6 +10762,11 @@ function extractSerializableOutputFields(output) {
|
|
|
10261
10762
|
for (const name of directFieldNames) {
|
|
10262
10763
|
try {
|
|
10263
10764
|
const value = output?.[name];
|
|
10765
|
+
if (isPromiseLike(value)) {
|
|
10766
|
+
void Promise.resolve(value).catch(() => {
|
|
10767
|
+
});
|
|
10768
|
+
continue;
|
|
10769
|
+
}
|
|
10264
10770
|
if (isSerializableOutputValue(value)) {
|
|
10265
10771
|
serialized[name] = value;
|
|
10266
10772
|
}
|
|
@@ -10272,6 +10778,9 @@ function extractSerializableOutputFields(output) {
|
|
|
10272
10778
|
...extractGetterValues(output)
|
|
10273
10779
|
};
|
|
10274
10780
|
}
|
|
10781
|
+
function isPromiseLike(value) {
|
|
10782
|
+
return value != null && typeof value === "object" && typeof value.then === "function";
|
|
10783
|
+
}
|
|
10275
10784
|
function isSerializableOutputValue(value) {
|
|
10276
10785
|
if (typeof value === "function") {
|
|
10277
10786
|
return false;
|
|
@@ -10313,8 +10822,9 @@ function parseGatewayModelString(modelString) {
|
|
|
10313
10822
|
return { model: modelString };
|
|
10314
10823
|
}
|
|
10315
10824
|
function extractGatewayRoutingInfo(result) {
|
|
10316
|
-
|
|
10317
|
-
|
|
10825
|
+
const steps = safeSerializableFieldRead(result, "steps");
|
|
10826
|
+
if (Array.isArray(steps) && steps.length > 0) {
|
|
10827
|
+
const routing2 = steps[0]?.providerMetadata?.gateway?.routing;
|
|
10318
10828
|
if (routing2) {
|
|
10319
10829
|
return {
|
|
10320
10830
|
provider: routing2.resolvedProvider || routing2.finalProvider,
|
|
@@ -10322,7 +10832,11 @@ function extractGatewayRoutingInfo(result) {
|
|
|
10322
10832
|
};
|
|
10323
10833
|
}
|
|
10324
10834
|
}
|
|
10325
|
-
const
|
|
10835
|
+
const providerMetadata = safeSerializableFieldRead(
|
|
10836
|
+
result,
|
|
10837
|
+
"providerMetadata"
|
|
10838
|
+
);
|
|
10839
|
+
const routing = providerMetadata?.gateway?.routing;
|
|
10326
10840
|
if (routing) {
|
|
10327
10841
|
return {
|
|
10328
10842
|
provider: routing.resolvedProvider || routing.finalProvider,
|
|
@@ -10332,10 +10846,11 @@ function extractGatewayRoutingInfo(result) {
|
|
|
10332
10846
|
return null;
|
|
10333
10847
|
}
|
|
10334
10848
|
function extractCostFromResult(result) {
|
|
10335
|
-
|
|
10849
|
+
const steps = safeSerializableFieldRead(result, "steps");
|
|
10850
|
+
if (Array.isArray(steps) && steps.length > 0) {
|
|
10336
10851
|
let totalCost = 0;
|
|
10337
10852
|
let foundCost = false;
|
|
10338
|
-
for (const step of
|
|
10853
|
+
for (const step of steps) {
|
|
10339
10854
|
const gateway2 = step?.providerMetadata?.gateway;
|
|
10340
10855
|
const stepCost = parseGatewayCost(gateway2?.cost) || parseGatewayCost(gateway2?.marketCost);
|
|
10341
10856
|
if (stepCost !== void 0 && stepCost > 0) {
|
|
@@ -10347,7 +10862,11 @@ function extractCostFromResult(result) {
|
|
|
10347
10862
|
return totalCost;
|
|
10348
10863
|
}
|
|
10349
10864
|
}
|
|
10350
|
-
const
|
|
10865
|
+
const providerMetadata = safeSerializableFieldRead(
|
|
10866
|
+
result,
|
|
10867
|
+
"providerMetadata"
|
|
10868
|
+
);
|
|
10869
|
+
const gateway = providerMetadata?.gateway;
|
|
10351
10870
|
const directCost = parseGatewayCost(gateway?.cost) || parseGatewayCost(gateway?.marketCost);
|
|
10352
10871
|
if (directCost !== void 0 && directCost > 0) {
|
|
10353
10872
|
return directCost;
|
|
@@ -11048,20 +11567,16 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
11048
11567
|
);
|
|
11049
11568
|
});
|
|
11050
11569
|
},
|
|
11051
|
-
onComplete: () => {
|
|
11052
|
-
|
|
11053
|
-
|
|
11054
|
-
|
|
11055
|
-
|
|
11056
|
-
|
|
11057
|
-
void state.processing.then(() => {
|
|
11058
|
-
state.span.log({
|
|
11059
|
-
error: error.message
|
|
11060
|
-
});
|
|
11061
|
-
}).then(() => finalizeQuerySpan(state)).finally(() => {
|
|
11062
|
-
spans.delete(event);
|
|
11570
|
+
onComplete: () => state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
|
|
11571
|
+
spans.delete(event);
|
|
11572
|
+
}),
|
|
11573
|
+
onError: (error) => state.processing.then(() => {
|
|
11574
|
+
state.span.log({
|
|
11575
|
+
error: error.message
|
|
11063
11576
|
});
|
|
11064
|
-
}
|
|
11577
|
+
}).then(() => finalizeQuerySpan(state)).finally(() => {
|
|
11578
|
+
spans.delete(event);
|
|
11579
|
+
})
|
|
11065
11580
|
});
|
|
11066
11581
|
return;
|
|
11067
11582
|
}
|
|
@@ -11209,12 +11724,14 @@ var GoogleGenAIPlugin = class extends BasePlugin {
|
|
|
11209
11724
|
const params = event.arguments[0];
|
|
11210
11725
|
streamEvent.googleGenAIInput = serializeInput(params);
|
|
11211
11726
|
streamEvent.googleGenAIMetadata = extractMetadata(params);
|
|
11727
|
+
streamEvent.googleGenAIStartTime = getCurrentUnixTimestamp();
|
|
11212
11728
|
},
|
|
11213
11729
|
asyncEnd: (event) => {
|
|
11214
11730
|
const streamEvent = event;
|
|
11215
11731
|
patchGoogleGenAIStreamingResult({
|
|
11216
11732
|
input: streamEvent.googleGenAIInput,
|
|
11217
11733
|
metadata: streamEvent.googleGenAIMetadata,
|
|
11734
|
+
startTime: streamEvent.googleGenAIStartTime,
|
|
11218
11735
|
result: streamEvent.result
|
|
11219
11736
|
});
|
|
11220
11737
|
},
|
|
@@ -11267,7 +11784,7 @@ function logErrorAndEndSpan(states, event) {
|
|
|
11267
11784
|
states.delete(event);
|
|
11268
11785
|
}
|
|
11269
11786
|
function patchGoogleGenAIStreamingResult(args) {
|
|
11270
|
-
const { input, metadata, result } = args;
|
|
11787
|
+
const { input, metadata, result, startTime } = args;
|
|
11271
11788
|
if (!input || !metadata || !result || typeof result !== "object" || typeof result.next !== "function") {
|
|
11272
11789
|
return false;
|
|
11273
11790
|
}
|
|
@@ -11275,7 +11792,7 @@ function patchGoogleGenAIStreamingResult(args) {
|
|
|
11275
11792
|
let firstTokenTime = null;
|
|
11276
11793
|
let finalized = false;
|
|
11277
11794
|
let span = null;
|
|
11278
|
-
|
|
11795
|
+
const requestStartTime = startTime ?? getCurrentUnixTimestamp();
|
|
11279
11796
|
const ensureSpan = () => {
|
|
11280
11797
|
if (!span) {
|
|
11281
11798
|
span = startSpan({
|
|
@@ -11288,7 +11805,6 @@ function patchGoogleGenAIStreamingResult(args) {
|
|
|
11288
11805
|
metadata
|
|
11289
11806
|
}
|
|
11290
11807
|
});
|
|
11291
|
-
startTime = getCurrentUnixTimestamp();
|
|
11292
11808
|
}
|
|
11293
11809
|
return span;
|
|
11294
11810
|
};
|
|
@@ -11342,11 +11858,11 @@ function patchGoogleGenAIStreamingResult(args) {
|
|
|
11342
11858
|
}
|
|
11343
11859
|
chunks.push(nextResult.value);
|
|
11344
11860
|
}
|
|
11345
|
-
if (nextResult.done
|
|
11861
|
+
if (nextResult.done) {
|
|
11346
11862
|
finalize({
|
|
11347
11863
|
result: aggregateGenerateContentChunks(
|
|
11348
11864
|
chunks,
|
|
11349
|
-
|
|
11865
|
+
requestStartTime,
|
|
11350
11866
|
firstTokenTime
|
|
11351
11867
|
)
|
|
11352
11868
|
});
|
|
@@ -11366,13 +11882,13 @@ function patchGoogleGenAIStreamingResult(args) {
|
|
|
11366
11882
|
...returnArgs
|
|
11367
11883
|
);
|
|
11368
11884
|
} finally {
|
|
11369
|
-
if (
|
|
11885
|
+
if (chunks.length > 0) {
|
|
11370
11886
|
finalize({
|
|
11371
|
-
result:
|
|
11887
|
+
result: aggregateGenerateContentChunks(
|
|
11372
11888
|
chunks,
|
|
11373
|
-
|
|
11889
|
+
requestStartTime,
|
|
11374
11890
|
firstTokenTime
|
|
11375
|
-
)
|
|
11891
|
+
)
|
|
11376
11892
|
});
|
|
11377
11893
|
} else {
|
|
11378
11894
|
finalize({});
|
|
@@ -11664,500 +12180,488 @@ var openRouterChannels = defineChannels("@openrouter/sdk", {
|
|
|
11664
12180
|
channelName: "callModel",
|
|
11665
12181
|
kind: "sync-stream"
|
|
11666
12182
|
}),
|
|
12183
|
+
callModelTurn: channel({
|
|
12184
|
+
channelName: "callModel.turn",
|
|
12185
|
+
kind: "async"
|
|
12186
|
+
}),
|
|
11667
12187
|
toolExecute: channel({
|
|
11668
12188
|
channelName: "tool.execute",
|
|
11669
12189
|
kind: "async"
|
|
11670
12190
|
})
|
|
11671
12191
|
});
|
|
11672
12192
|
|
|
11673
|
-
// src/openrouter-
|
|
11674
|
-
var
|
|
11675
|
-
|
|
11676
|
-
|
|
11677
|
-
completionTokens: "completion_tokens",
|
|
11678
|
-
outputTokens: "completion_tokens",
|
|
11679
|
-
totalTokens: "tokens",
|
|
11680
|
-
prompt_tokens: "prompt_tokens",
|
|
11681
|
-
input_tokens: "prompt_tokens",
|
|
11682
|
-
completion_tokens: "completion_tokens",
|
|
11683
|
-
output_tokens: "completion_tokens",
|
|
11684
|
-
total_tokens: "tokens"
|
|
11685
|
-
};
|
|
11686
|
-
var TOKEN_DETAIL_PREFIX_MAP = {
|
|
11687
|
-
promptTokensDetails: "prompt",
|
|
11688
|
-
inputTokensDetails: "prompt",
|
|
11689
|
-
completionTokensDetails: "completion",
|
|
11690
|
-
outputTokensDetails: "completion",
|
|
11691
|
-
costDetails: "cost",
|
|
11692
|
-
prompt_tokens_details: "prompt",
|
|
11693
|
-
input_tokens_details: "prompt",
|
|
11694
|
-
completion_tokens_details: "completion",
|
|
11695
|
-
output_tokens_details: "completion",
|
|
11696
|
-
cost_details: "cost"
|
|
11697
|
-
};
|
|
11698
|
-
function camelToSnake(value) {
|
|
11699
|
-
return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
|
|
11700
|
-
}
|
|
11701
|
-
function parseOpenRouterMetricsFromUsage(usage) {
|
|
11702
|
-
if (!isObject(usage)) {
|
|
11703
|
-
return {};
|
|
11704
|
-
}
|
|
11705
|
-
const metrics = {};
|
|
11706
|
-
for (const [name, value] of Object.entries(usage)) {
|
|
11707
|
-
if (typeof value === "number") {
|
|
11708
|
-
metrics[TOKEN_NAME_MAP2[name] || camelToSnake(name)] = value;
|
|
11709
|
-
continue;
|
|
11710
|
-
}
|
|
11711
|
-
if (!isObject(value)) {
|
|
11712
|
-
continue;
|
|
11713
|
-
}
|
|
11714
|
-
const prefix = TOKEN_DETAIL_PREFIX_MAP[name];
|
|
11715
|
-
if (!prefix) {
|
|
11716
|
-
continue;
|
|
11717
|
-
}
|
|
11718
|
-
for (const [nestedName, nestedValue] of Object.entries(value)) {
|
|
11719
|
-
if (typeof nestedValue !== "number") {
|
|
11720
|
-
continue;
|
|
11721
|
-
}
|
|
11722
|
-
metrics[`${prefix}_${camelToSnake(nestedName)}`] = nestedValue;
|
|
11723
|
-
}
|
|
11724
|
-
}
|
|
11725
|
-
return metrics;
|
|
11726
|
-
}
|
|
11727
|
-
function extractOpenRouterUsageMetadata(usage) {
|
|
11728
|
-
if (!isObject(usage)) {
|
|
11729
|
-
return void 0;
|
|
11730
|
-
}
|
|
11731
|
-
const metadata = {};
|
|
11732
|
-
if (typeof usage.isByok === "boolean") {
|
|
11733
|
-
metadata.is_byok = usage.isByok;
|
|
11734
|
-
} else if (typeof usage.is_byok === "boolean") {
|
|
11735
|
-
metadata.is_byok = usage.is_byok;
|
|
11736
|
-
}
|
|
11737
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
11738
|
-
}
|
|
11739
|
-
|
|
11740
|
-
// src/openrouter-logging.ts
|
|
11741
|
-
var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
|
|
11742
|
-
"execute",
|
|
11743
|
-
"render",
|
|
11744
|
-
"nextTurnParams",
|
|
11745
|
-
"requireApproval"
|
|
11746
|
-
]);
|
|
11747
|
-
function parseOpenRouterModelString(model) {
|
|
11748
|
-
if (typeof model !== "string") {
|
|
11749
|
-
return { model };
|
|
11750
|
-
}
|
|
11751
|
-
const slashIndex = model.indexOf("/");
|
|
11752
|
-
if (slashIndex > 0 && slashIndex < model.length - 1) {
|
|
11753
|
-
return {
|
|
11754
|
-
provider: model.substring(0, slashIndex),
|
|
11755
|
-
model: model.substring(slashIndex + 1)
|
|
11756
|
-
};
|
|
11757
|
-
}
|
|
11758
|
-
return { model };
|
|
11759
|
-
}
|
|
11760
|
-
function isZodSchema2(value) {
|
|
11761
|
-
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
11762
|
-
}
|
|
11763
|
-
function serializeZodSchema2(schema) {
|
|
11764
|
-
try {
|
|
11765
|
-
return zodToJsonSchema(schema);
|
|
11766
|
-
} catch {
|
|
11767
|
-
return {
|
|
11768
|
-
type: "object",
|
|
11769
|
-
description: "Zod schema (conversion failed)"
|
|
11770
|
-
};
|
|
11771
|
-
}
|
|
11772
|
-
}
|
|
11773
|
-
function serializeOpenRouterTool(tool) {
|
|
11774
|
-
if (!isObject(tool)) {
|
|
11775
|
-
return tool;
|
|
11776
|
-
}
|
|
11777
|
-
const serialized = {};
|
|
11778
|
-
for (const [key, value] of Object.entries(tool)) {
|
|
11779
|
-
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
11780
|
-
continue;
|
|
11781
|
-
}
|
|
11782
|
-
if (key === "function" && isObject(value)) {
|
|
11783
|
-
serialized.function = sanitizeOpenRouterLoggedValue(value);
|
|
11784
|
-
continue;
|
|
11785
|
-
}
|
|
11786
|
-
serialized[key] = sanitizeOpenRouterLoggedValue(value);
|
|
11787
|
-
}
|
|
11788
|
-
return serialized;
|
|
11789
|
-
}
|
|
11790
|
-
function serializeOpenRouterToolsForLogging(tools) {
|
|
11791
|
-
if (!Array.isArray(tools)) {
|
|
11792
|
-
return void 0;
|
|
11793
|
-
}
|
|
11794
|
-
return tools.map((tool) => serializeOpenRouterTool(tool));
|
|
11795
|
-
}
|
|
11796
|
-
function sanitizeOpenRouterLoggedValue(value) {
|
|
11797
|
-
if (isZodSchema2(value)) {
|
|
11798
|
-
return serializeZodSchema2(value);
|
|
11799
|
-
}
|
|
11800
|
-
if (typeof value === "function") {
|
|
11801
|
-
return "[Function]";
|
|
11802
|
-
}
|
|
11803
|
-
if (Array.isArray(value)) {
|
|
11804
|
-
return value.map((entry) => sanitizeOpenRouterLoggedValue(entry));
|
|
11805
|
-
}
|
|
11806
|
-
if (!isObject(value)) {
|
|
11807
|
-
return value;
|
|
12193
|
+
// src/instrumentation/plugins/openrouter-plugin.ts
|
|
12194
|
+
var OpenRouterPlugin = class extends BasePlugin {
|
|
12195
|
+
onEnable() {
|
|
12196
|
+
this.subscribeToOpenRouterChannels();
|
|
11808
12197
|
}
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
11812
|
-
continue;
|
|
11813
|
-
}
|
|
11814
|
-
if (key === "tools" && Array.isArray(entry)) {
|
|
11815
|
-
sanitized.tools = serializeOpenRouterToolsForLogging(entry);
|
|
11816
|
-
continue;
|
|
11817
|
-
}
|
|
11818
|
-
sanitized[key] = sanitizeOpenRouterLoggedValue(entry);
|
|
12198
|
+
onDisable() {
|
|
12199
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
11819
12200
|
}
|
|
11820
|
-
|
|
11821
|
-
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
|
|
11825
|
-
|
|
11826
|
-
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
}
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
}
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
12201
|
+
subscribeToOpenRouterChannels() {
|
|
12202
|
+
this.unsubscribers.push(
|
|
12203
|
+
traceStreamingChannel(openRouterChannels.chatSend, {
|
|
12204
|
+
name: "openrouter.chat.send",
|
|
12205
|
+
type: "llm" /* LLM */,
|
|
12206
|
+
extractInput: (args) => {
|
|
12207
|
+
const request = getOpenRouterRequestArg(args);
|
|
12208
|
+
const chatGenerationParams = isObject(request?.chatGenerationParams) ? request.chatGenerationParams : {};
|
|
12209
|
+
const httpReferer = request?.httpReferer;
|
|
12210
|
+
const xTitle = request?.xTitle;
|
|
12211
|
+
const { messages, ...metadata } = chatGenerationParams;
|
|
12212
|
+
return {
|
|
12213
|
+
input: messages,
|
|
12214
|
+
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
12215
|
+
};
|
|
12216
|
+
},
|
|
12217
|
+
extractOutput: (result) => {
|
|
12218
|
+
return isObject(result) ? result.choices : void 0;
|
|
12219
|
+
},
|
|
12220
|
+
extractMetrics: (result, startTime) => {
|
|
12221
|
+
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
12222
|
+
if (startTime) {
|
|
12223
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
12224
|
+
}
|
|
12225
|
+
return metrics;
|
|
12226
|
+
},
|
|
12227
|
+
aggregateChunks: aggregateOpenRouterChatChunks
|
|
12228
|
+
})
|
|
12229
|
+
);
|
|
12230
|
+
this.unsubscribers.push(
|
|
12231
|
+
traceAsyncChannel(openRouterChannels.embeddingsGenerate, {
|
|
12232
|
+
name: "openrouter.embeddings.generate",
|
|
12233
|
+
type: "llm" /* LLM */,
|
|
12234
|
+
extractInput: (args) => {
|
|
12235
|
+
const request = getOpenRouterRequestArg(args);
|
|
12236
|
+
const requestBody = isObject(request?.requestBody) ? request.requestBody : {};
|
|
12237
|
+
const httpReferer = request?.httpReferer;
|
|
12238
|
+
const xTitle = request?.xTitle;
|
|
12239
|
+
const { input, ...metadata } = requestBody;
|
|
12240
|
+
return {
|
|
12241
|
+
input,
|
|
12242
|
+
metadata: buildOpenRouterEmbeddingMetadata(
|
|
12243
|
+
metadata,
|
|
12244
|
+
httpReferer,
|
|
12245
|
+
xTitle
|
|
12246
|
+
)
|
|
12247
|
+
};
|
|
12248
|
+
},
|
|
12249
|
+
extractOutput: (result) => {
|
|
12250
|
+
if (!isObject(result)) {
|
|
12251
|
+
return void 0;
|
|
12252
|
+
}
|
|
12253
|
+
const embedding = result.data?.[0]?.embedding;
|
|
12254
|
+
return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
|
|
12255
|
+
},
|
|
12256
|
+
extractMetadata: (result) => {
|
|
12257
|
+
if (!isObject(result)) {
|
|
12258
|
+
return void 0;
|
|
12259
|
+
}
|
|
12260
|
+
return extractOpenRouterResponseMetadata(result);
|
|
12261
|
+
},
|
|
12262
|
+
extractMetrics: (result) => {
|
|
12263
|
+
return isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {};
|
|
12264
|
+
}
|
|
12265
|
+
})
|
|
12266
|
+
);
|
|
12267
|
+
this.unsubscribers.push(
|
|
12268
|
+
traceStreamingChannel(openRouterChannels.betaResponsesSend, {
|
|
12269
|
+
name: "openrouter.beta.responses.send",
|
|
12270
|
+
type: "llm" /* LLM */,
|
|
12271
|
+
extractInput: (args) => {
|
|
12272
|
+
const request = getOpenRouterRequestArg(args);
|
|
12273
|
+
const openResponsesRequest = isObject(request?.openResponsesRequest) ? request.openResponsesRequest : {};
|
|
12274
|
+
const httpReferer = request?.httpReferer;
|
|
12275
|
+
const xTitle = request?.xTitle;
|
|
12276
|
+
const { input, ...metadata } = openResponsesRequest;
|
|
12277
|
+
return {
|
|
12278
|
+
input,
|
|
12279
|
+
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
12280
|
+
};
|
|
12281
|
+
},
|
|
12282
|
+
extractOutput: (result) => extractOpenRouterResponseOutput(result),
|
|
12283
|
+
extractMetadata: (result) => extractOpenRouterResponseMetadata(result),
|
|
12284
|
+
extractMetrics: (result, startTime) => {
|
|
12285
|
+
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
12286
|
+
if (startTime) {
|
|
12287
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
12288
|
+
}
|
|
12289
|
+
return metrics;
|
|
12290
|
+
},
|
|
12291
|
+
aggregateChunks: aggregateOpenRouterResponseStreamEvents
|
|
12292
|
+
})
|
|
12293
|
+
);
|
|
12294
|
+
this.unsubscribers.push(
|
|
12295
|
+
traceSyncStreamChannel(openRouterChannels.callModel, {
|
|
12296
|
+
name: "openrouter.callModel",
|
|
12297
|
+
type: "llm" /* LLM */,
|
|
12298
|
+
extractInput: (args) => {
|
|
12299
|
+
const request = getOpenRouterCallModelRequestArg(args);
|
|
12300
|
+
return {
|
|
12301
|
+
input: request ? extractOpenRouterCallModelInput(request) : void 0,
|
|
12302
|
+
metadata: request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" }
|
|
12303
|
+
};
|
|
12304
|
+
},
|
|
12305
|
+
patchResult: ({ endEvent, result, span }) => {
|
|
12306
|
+
return patchOpenRouterCallModelResult({
|
|
12307
|
+
request: getOpenRouterCallModelRequestArg(endEvent.arguments),
|
|
12308
|
+
result,
|
|
12309
|
+
span
|
|
12310
|
+
});
|
|
12311
|
+
}
|
|
12312
|
+
})
|
|
12313
|
+
);
|
|
12314
|
+
this.unsubscribers.push(
|
|
12315
|
+
traceAsyncChannel(openRouterChannels.callModelTurn, {
|
|
12316
|
+
name: "openrouter.beta.responses.send",
|
|
12317
|
+
type: "llm" /* LLM */,
|
|
12318
|
+
extractInput: (args, event) => {
|
|
12319
|
+
const request = getOpenRouterCallModelRequestArg(args);
|
|
12320
|
+
const metadata = request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" };
|
|
12321
|
+
if (isObject(metadata) && "tools" in metadata) {
|
|
12322
|
+
delete metadata.tools;
|
|
12323
|
+
}
|
|
12324
|
+
return {
|
|
12325
|
+
input: request ? extractOpenRouterCallModelInput(request) : void 0,
|
|
12326
|
+
metadata: {
|
|
12327
|
+
...metadata,
|
|
12328
|
+
step: event.step,
|
|
12329
|
+
step_type: event.stepType
|
|
12330
|
+
}
|
|
12331
|
+
};
|
|
12332
|
+
},
|
|
12333
|
+
extractOutput: (result) => extractOpenRouterResponseOutput(result),
|
|
12334
|
+
extractMetadata: (result, event) => {
|
|
12335
|
+
if (!isObject(result)) {
|
|
12336
|
+
return {
|
|
12337
|
+
step: event?.step,
|
|
12338
|
+
step_type: event?.stepType
|
|
12339
|
+
};
|
|
12340
|
+
}
|
|
12341
|
+
return {
|
|
12342
|
+
...extractOpenRouterResponseMetadata(result) || {},
|
|
12343
|
+
...event?.step !== void 0 ? { step: event.step } : {},
|
|
12344
|
+
...event?.stepType ? { step_type: event.stepType } : {}
|
|
12345
|
+
};
|
|
12346
|
+
},
|
|
12347
|
+
extractMetrics: (result) => isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {}
|
|
12348
|
+
})
|
|
12349
|
+
);
|
|
12350
|
+
this.unsubscribers.push(
|
|
12351
|
+
traceStreamingChannel(openRouterChannels.toolExecute, {
|
|
12352
|
+
name: "openrouter.tool",
|
|
12353
|
+
type: "tool" /* TOOL */,
|
|
12354
|
+
extractInput: (args, event) => ({
|
|
12355
|
+
input: args[0],
|
|
12356
|
+
metadata: {
|
|
12357
|
+
provider: "openrouter",
|
|
12358
|
+
tool_name: event.toolName,
|
|
12359
|
+
...event.toolCallId ? { tool_call_id: event.toolCallId } : {}
|
|
12360
|
+
}
|
|
12361
|
+
}),
|
|
12362
|
+
extractOutput: (result) => result,
|
|
12363
|
+
extractMetrics: () => ({}),
|
|
12364
|
+
aggregateChunks: (chunks) => ({
|
|
12365
|
+
output: chunks.length > 0 ? chunks[chunks.length - 1] : void 0,
|
|
12366
|
+
metrics: {}
|
|
12367
|
+
})
|
|
12368
|
+
})
|
|
12369
|
+
);
|
|
12370
|
+
const callModelChannel = openRouterChannels.callModel.tracingChannel();
|
|
12371
|
+
const callModelHandlers = {
|
|
12372
|
+
start: (event) => {
|
|
12373
|
+
const request = getOpenRouterCallModelRequestArg(event.arguments);
|
|
12374
|
+
if (!request) {
|
|
12375
|
+
return;
|
|
12376
|
+
}
|
|
12377
|
+
patchOpenRouterCallModelRequestTools(request);
|
|
12378
|
+
}
|
|
12379
|
+
};
|
|
12380
|
+
callModelChannel.subscribe(callModelHandlers);
|
|
12381
|
+
this.unsubscribers.push(() => {
|
|
12382
|
+
callModelChannel.unsubscribe(callModelHandlers);
|
|
12383
|
+
});
|
|
11856
12384
|
}
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
const normalizedModel = parseOpenRouterModelString(model);
|
|
11862
|
-
const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
|
|
11863
|
-
const usageMetadata = extractOpenRouterUsageMetadata(usage);
|
|
11864
|
-
const combined = {
|
|
11865
|
-
...rest,
|
|
11866
|
-
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
11867
|
-
...usageMetadata || {},
|
|
11868
|
-
...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
|
|
11869
|
-
};
|
|
11870
|
-
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
11871
|
-
}
|
|
11872
|
-
function extractOpenRouterResponseOutput(response, fallbackOutput) {
|
|
11873
|
-
if (isObject(response) && "output" in response && response.output !== void 0) {
|
|
11874
|
-
return sanitizeOpenRouterLoggedValue(response.output);
|
|
12385
|
+
};
|
|
12386
|
+
function normalizeArgs(args) {
|
|
12387
|
+
if (Array.isArray(args)) {
|
|
12388
|
+
return args;
|
|
11875
12389
|
}
|
|
11876
|
-
if (
|
|
11877
|
-
return
|
|
12390
|
+
if (isArrayLike(args)) {
|
|
12391
|
+
return Array.from(args);
|
|
11878
12392
|
}
|
|
11879
|
-
return
|
|
12393
|
+
return [args];
|
|
11880
12394
|
}
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
11884
|
-
|
|
11885
|
-
|
|
11886
|
-
|
|
11887
|
-
|
|
11888
|
-
"getFullResponsesStream",
|
|
11889
|
-
"getItemsStream",
|
|
11890
|
-
"getNewMessagesStream",
|
|
11891
|
-
"getReasoningStream",
|
|
11892
|
-
"getTextStream",
|
|
11893
|
-
"getToolCallsStream",
|
|
11894
|
-
"getToolStream"
|
|
11895
|
-
];
|
|
11896
|
-
var OPENROUTER_CALL_MODEL_CONTEXT_METHODS = [
|
|
11897
|
-
"cancel",
|
|
11898
|
-
"getPendingToolCalls",
|
|
11899
|
-
"getState",
|
|
11900
|
-
"getToolCalls",
|
|
11901
|
-
"requiresApproval"
|
|
11902
|
-
];
|
|
11903
|
-
function patchOpenRouterCallModelRequestTools(request) {
|
|
11904
|
-
if (!Array.isArray(request.tools) || request.tools.length === 0) {
|
|
11905
|
-
return void 0;
|
|
11906
|
-
}
|
|
11907
|
-
const originalTools = request.tools;
|
|
11908
|
-
const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
|
|
11909
|
-
const didPatch = wrappedTools.some(
|
|
11910
|
-
(tool, index) => tool !== originalTools[index]
|
|
12395
|
+
function isArrayLike(value) {
|
|
12396
|
+
return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
|
|
12397
|
+
}
|
|
12398
|
+
function getOpenRouterRequestArg(args) {
|
|
12399
|
+
const normalizedArgs = normalizeArgs(args);
|
|
12400
|
+
const keyedCandidate = normalizedArgs.find(
|
|
12401
|
+
(arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
|
|
11911
12402
|
);
|
|
11912
|
-
if (
|
|
11913
|
-
return
|
|
12403
|
+
if (isObject(keyedCandidate)) {
|
|
12404
|
+
return keyedCandidate;
|
|
11914
12405
|
}
|
|
11915
|
-
|
|
11916
|
-
return ()
|
|
11917
|
-
request.tools = originalTools;
|
|
11918
|
-
};
|
|
12406
|
+
const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
|
|
12407
|
+
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
11919
12408
|
}
|
|
11920
|
-
function
|
|
11921
|
-
|
|
11922
|
-
|
|
11923
|
-
|
|
11924
|
-
|
|
11925
|
-
|
|
11926
|
-
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
|
|
12409
|
+
function getOpenRouterCallModelRequestArg(args) {
|
|
12410
|
+
const firstObjectArg = normalizeArgs(args).find((arg) => isObject(arg));
|
|
12411
|
+
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
12412
|
+
}
|
|
12413
|
+
var TOKEN_NAME_MAP2 = {
|
|
12414
|
+
promptTokens: "prompt_tokens",
|
|
12415
|
+
inputTokens: "prompt_tokens",
|
|
12416
|
+
completionTokens: "completion_tokens",
|
|
12417
|
+
outputTokens: "completion_tokens",
|
|
12418
|
+
totalTokens: "tokens",
|
|
12419
|
+
prompt_tokens: "prompt_tokens",
|
|
12420
|
+
input_tokens: "prompt_tokens",
|
|
12421
|
+
completion_tokens: "completion_tokens",
|
|
12422
|
+
output_tokens: "completion_tokens",
|
|
12423
|
+
total_tokens: "tokens"
|
|
12424
|
+
};
|
|
12425
|
+
var TOKEN_DETAIL_PREFIX_MAP = {
|
|
12426
|
+
promptTokensDetails: "prompt",
|
|
12427
|
+
inputTokensDetails: "prompt",
|
|
12428
|
+
completionTokensDetails: "completion",
|
|
12429
|
+
outputTokensDetails: "completion",
|
|
12430
|
+
costDetails: "cost",
|
|
12431
|
+
prompt_tokens_details: "prompt",
|
|
12432
|
+
input_tokens_details: "prompt",
|
|
12433
|
+
completion_tokens_details: "completion",
|
|
12434
|
+
output_tokens_details: "completion",
|
|
12435
|
+
cost_details: "cost"
|
|
12436
|
+
};
|
|
12437
|
+
function camelToSnake(value) {
|
|
12438
|
+
return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
|
|
12439
|
+
}
|
|
12440
|
+
function parseOpenRouterMetricsFromUsage(usage) {
|
|
12441
|
+
if (!isObject(usage)) {
|
|
12442
|
+
return {};
|
|
11930
12443
|
}
|
|
11931
|
-
|
|
11932
|
-
|
|
11933
|
-
|
|
11934
|
-
|
|
11935
|
-
|
|
11936
|
-
const originalGetResponse = typeof resultLike.getResponse === "function" ? resultLike.getResponse.bind(resultLike) : void 0;
|
|
11937
|
-
const originalGetInitialResponse = typeof resultLike.getInitialResponse === "function" ? resultLike.getInitialResponse.bind(resultLike) : void 0;
|
|
11938
|
-
const originalMakeFollowupRequest = typeof resultLike.makeFollowupRequest === "function" ? resultLike.makeFollowupRequest.bind(resultLike) : void 0;
|
|
11939
|
-
let ended = false;
|
|
11940
|
-
let tracedTurnCount = 0;
|
|
11941
|
-
const endSpanWithResult = async (response, fallbackOutput) => {
|
|
11942
|
-
if (ended) {
|
|
11943
|
-
return;
|
|
11944
|
-
}
|
|
11945
|
-
ended = true;
|
|
11946
|
-
const finalResponse = getFinalOpenRouterCallModelResponse(
|
|
11947
|
-
resultLike,
|
|
11948
|
-
response
|
|
11949
|
-
);
|
|
11950
|
-
if (finalResponse) {
|
|
11951
|
-
const rounds = getOpenRouterCallModelRounds(resultLike);
|
|
11952
|
-
const metadata = extractOpenRouterCallModelResultMetadata(
|
|
11953
|
-
finalResponse,
|
|
11954
|
-
rounds.length + 1
|
|
11955
|
-
);
|
|
11956
|
-
span.log({
|
|
11957
|
-
output: extractOpenRouterResponseOutput(finalResponse, fallbackOutput),
|
|
11958
|
-
...metadata ? { metadata } : {},
|
|
11959
|
-
metrics: aggregateOpenRouterCallModelMetrics(rounds, finalResponse)
|
|
11960
|
-
});
|
|
11961
|
-
span.end();
|
|
11962
|
-
return;
|
|
11963
|
-
}
|
|
11964
|
-
if (fallbackOutput !== void 0) {
|
|
11965
|
-
span.log({
|
|
11966
|
-
output: fallbackOutput
|
|
11967
|
-
});
|
|
12444
|
+
const metrics = {};
|
|
12445
|
+
for (const [name, value] of Object.entries(usage)) {
|
|
12446
|
+
if (typeof value === "number") {
|
|
12447
|
+
metrics[TOKEN_NAME_MAP2[name] || camelToSnake(name)] = value;
|
|
12448
|
+
continue;
|
|
11968
12449
|
}
|
|
11969
|
-
|
|
11970
|
-
|
|
11971
|
-
const endSpanWithError = (error) => {
|
|
11972
|
-
if (ended) {
|
|
11973
|
-
return;
|
|
12450
|
+
if (!isObject(value)) {
|
|
12451
|
+
continue;
|
|
11974
12452
|
}
|
|
11975
|
-
|
|
11976
|
-
|
|
11977
|
-
|
|
11978
|
-
});
|
|
11979
|
-
span.end();
|
|
11980
|
-
};
|
|
11981
|
-
const finalizeFromResponse = async (fallbackOutput) => {
|
|
11982
|
-
if (!originalGetResponse) {
|
|
11983
|
-
await endSpanWithResult(void 0, fallbackOutput);
|
|
11984
|
-
return;
|
|
12453
|
+
const prefix = TOKEN_DETAIL_PREFIX_MAP[name];
|
|
12454
|
+
if (!prefix) {
|
|
12455
|
+
continue;
|
|
11985
12456
|
}
|
|
11986
|
-
|
|
11987
|
-
|
|
11988
|
-
|
|
11989
|
-
|
|
12457
|
+
for (const [nestedName, nestedValue] of Object.entries(value)) {
|
|
12458
|
+
if (typeof nestedValue !== "number") {
|
|
12459
|
+
continue;
|
|
12460
|
+
}
|
|
12461
|
+
metrics[`${prefix}_${camelToSnake(nestedName)}`] = nestedValue;
|
|
11990
12462
|
}
|
|
11991
|
-
};
|
|
11992
|
-
if (originalGetResponse) {
|
|
11993
|
-
resultLike.getResponse = async (...args) => {
|
|
11994
|
-
return await withCurrent(span, async () => {
|
|
11995
|
-
try {
|
|
11996
|
-
const response = await originalGetResponse(...args);
|
|
11997
|
-
await endSpanWithResult(response);
|
|
11998
|
-
return response;
|
|
11999
|
-
} catch (error) {
|
|
12000
|
-
endSpanWithError(error);
|
|
12001
|
-
throw error;
|
|
12002
|
-
}
|
|
12003
|
-
});
|
|
12004
|
-
};
|
|
12005
12463
|
}
|
|
12006
|
-
|
|
12007
|
-
|
|
12008
|
-
|
|
12009
|
-
|
|
12010
|
-
|
|
12011
|
-
const text = await originalGetText(...args);
|
|
12012
|
-
await finalizeFromResponse(text);
|
|
12013
|
-
return text;
|
|
12014
|
-
} catch (error) {
|
|
12015
|
-
endSpanWithError(error);
|
|
12016
|
-
throw error;
|
|
12017
|
-
}
|
|
12018
|
-
});
|
|
12019
|
-
};
|
|
12464
|
+
return metrics;
|
|
12465
|
+
}
|
|
12466
|
+
function extractOpenRouterUsageMetadata(usage) {
|
|
12467
|
+
if (!isObject(usage)) {
|
|
12468
|
+
return void 0;
|
|
12020
12469
|
}
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
|
|
12024
|
-
|
|
12025
|
-
|
|
12026
|
-
resultLike[methodName] = async (...args) => {
|
|
12027
|
-
return await withCurrent(span, async () => {
|
|
12028
|
-
return await originalMethod.apply(resultLike, args);
|
|
12029
|
-
});
|
|
12030
|
-
};
|
|
12470
|
+
const metadata = {};
|
|
12471
|
+
if (typeof usage.isByok === "boolean") {
|
|
12472
|
+
metadata.is_byok = usage.isByok;
|
|
12473
|
+
} else if (typeof usage.is_byok === "boolean") {
|
|
12474
|
+
metadata.is_byok = usage.is_byok;
|
|
12031
12475
|
}
|
|
12032
|
-
|
|
12033
|
-
|
|
12034
|
-
|
|
12035
|
-
|
|
12036
|
-
|
|
12037
|
-
|
|
12038
|
-
|
|
12039
|
-
|
|
12040
|
-
|
|
12041
|
-
|
|
12042
|
-
|
|
12043
|
-
return stream;
|
|
12044
|
-
}
|
|
12045
|
-
return wrapAsyncIterableWithSpan({
|
|
12046
|
-
finalize: finalizeFromResponse,
|
|
12047
|
-
iteratorFactory: () => stream[Symbol.asyncIterator](),
|
|
12048
|
-
onError: endSpanWithError,
|
|
12049
|
-
span
|
|
12050
|
-
});
|
|
12051
|
-
};
|
|
12476
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
12477
|
+
}
|
|
12478
|
+
var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
|
|
12479
|
+
"execute",
|
|
12480
|
+
"render",
|
|
12481
|
+
"nextTurnParams",
|
|
12482
|
+
"requireApproval"
|
|
12483
|
+
]);
|
|
12484
|
+
function parseOpenRouterModelString(model) {
|
|
12485
|
+
if (typeof model !== "string") {
|
|
12486
|
+
return { model };
|
|
12052
12487
|
}
|
|
12053
|
-
|
|
12054
|
-
|
|
12055
|
-
|
|
12056
|
-
|
|
12057
|
-
|
|
12058
|
-
return await originalGetInitialResponse(...args);
|
|
12059
|
-
});
|
|
12060
|
-
}
|
|
12061
|
-
initialTurnTraced = true;
|
|
12062
|
-
const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
|
|
12063
|
-
const childSpan = startOpenRouterCallModelTurnSpan({
|
|
12064
|
-
request: resolvedRequest,
|
|
12065
|
-
step: tracedTurnCount + 1,
|
|
12066
|
-
stepType: tracedTurnCount === 0 ? "initial" : "continue"
|
|
12067
|
-
});
|
|
12068
|
-
return await withCurrent(childSpan, async () => {
|
|
12069
|
-
try {
|
|
12070
|
-
const response = await originalGetInitialResponse(...args);
|
|
12071
|
-
tracedTurnCount++;
|
|
12072
|
-
finishOpenRouterCallModelTurnSpan({
|
|
12073
|
-
response,
|
|
12074
|
-
step: tracedTurnCount,
|
|
12075
|
-
stepType: tracedTurnCount === 1 ? "initial" : "continue",
|
|
12076
|
-
span: childSpan
|
|
12077
|
-
});
|
|
12078
|
-
return response;
|
|
12079
|
-
} catch (error) {
|
|
12080
|
-
childSpan.log({
|
|
12081
|
-
error: normalizeError(error).message
|
|
12082
|
-
});
|
|
12083
|
-
childSpan.end();
|
|
12084
|
-
throw error;
|
|
12085
|
-
}
|
|
12086
|
-
});
|
|
12488
|
+
const slashIndex = model.indexOf("/");
|
|
12489
|
+
if (slashIndex > 0 && slashIndex < model.length - 1) {
|
|
12490
|
+
return {
|
|
12491
|
+
provider: model.substring(0, slashIndex),
|
|
12492
|
+
model: model.substring(slashIndex + 1)
|
|
12087
12493
|
};
|
|
12088
12494
|
}
|
|
12089
|
-
|
|
12090
|
-
|
|
12091
|
-
|
|
12092
|
-
|
|
12093
|
-
|
|
12094
|
-
|
|
12095
|
-
|
|
12096
|
-
|
|
12097
|
-
|
|
12098
|
-
|
|
12099
|
-
|
|
12100
|
-
|
|
12101
|
-
step: tracedTurnCount + 1,
|
|
12102
|
-
stepType: "continue"
|
|
12103
|
-
});
|
|
12104
|
-
return await withCurrent(childSpan, async () => {
|
|
12105
|
-
try {
|
|
12106
|
-
const response = await originalMakeFollowupRequest(...args);
|
|
12107
|
-
tracedTurnCount++;
|
|
12108
|
-
finishOpenRouterCallModelTurnSpan({
|
|
12109
|
-
response,
|
|
12110
|
-
step: tracedTurnCount,
|
|
12111
|
-
stepType: "continue",
|
|
12112
|
-
span: childSpan
|
|
12113
|
-
});
|
|
12114
|
-
return response;
|
|
12115
|
-
} catch (error) {
|
|
12116
|
-
childSpan.log({
|
|
12117
|
-
error: normalizeError(error).message
|
|
12118
|
-
});
|
|
12119
|
-
childSpan.end();
|
|
12120
|
-
throw error;
|
|
12121
|
-
}
|
|
12122
|
-
});
|
|
12495
|
+
return { model };
|
|
12496
|
+
}
|
|
12497
|
+
function isZodSchema3(value) {
|
|
12498
|
+
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
12499
|
+
}
|
|
12500
|
+
function serializeZodSchema3(schema) {
|
|
12501
|
+
try {
|
|
12502
|
+
return zodToJsonSchema(schema);
|
|
12503
|
+
} catch {
|
|
12504
|
+
return {
|
|
12505
|
+
type: "object",
|
|
12506
|
+
description: "Zod schema (conversion failed)"
|
|
12123
12507
|
};
|
|
12124
12508
|
}
|
|
12125
|
-
return true;
|
|
12126
12509
|
}
|
|
12127
|
-
function
|
|
12128
|
-
if (
|
|
12510
|
+
function serializeOpenRouterTool(tool) {
|
|
12511
|
+
if (!isObject(tool)) {
|
|
12129
12512
|
return tool;
|
|
12130
12513
|
}
|
|
12131
|
-
const
|
|
12132
|
-
const
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
function: {
|
|
12136
|
-
...tool.function,
|
|
12137
|
-
execute(...args) {
|
|
12138
|
-
return traceToolExecution({
|
|
12139
|
-
args,
|
|
12140
|
-
execute: () => Reflect.apply(originalExecute, this, args),
|
|
12141
|
-
toolCallId: getToolCallId(args[1]),
|
|
12142
|
-
toolName
|
|
12143
|
-
});
|
|
12144
|
-
}
|
|
12514
|
+
const serialized = {};
|
|
12515
|
+
for (const [key, value] of Object.entries(tool)) {
|
|
12516
|
+
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
12517
|
+
continue;
|
|
12145
12518
|
}
|
|
12146
|
-
|
|
12147
|
-
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
}
|
|
12152
|
-
return
|
|
12153
|
-
}
|
|
12154
|
-
function isWrappedTool(tool) {
|
|
12155
|
-
return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
|
|
12519
|
+
if (key === "function" && isObject(value)) {
|
|
12520
|
+
serialized.function = sanitizeOpenRouterLoggedValue(value);
|
|
12521
|
+
continue;
|
|
12522
|
+
}
|
|
12523
|
+
serialized[key] = sanitizeOpenRouterLoggedValue(value);
|
|
12524
|
+
}
|
|
12525
|
+
return serialized;
|
|
12156
12526
|
}
|
|
12157
|
-
function
|
|
12158
|
-
|
|
12159
|
-
|
|
12527
|
+
function serializeOpenRouterToolsForLogging(tools) {
|
|
12528
|
+
if (!Array.isArray(tools)) {
|
|
12529
|
+
return void 0;
|
|
12530
|
+
}
|
|
12531
|
+
return tools.map((tool) => serializeOpenRouterTool(tool));
|
|
12532
|
+
}
|
|
12533
|
+
function sanitizeOpenRouterLoggedValue(value) {
|
|
12534
|
+
if (isZodSchema3(value)) {
|
|
12535
|
+
return serializeZodSchema3(value);
|
|
12536
|
+
}
|
|
12537
|
+
if (typeof value === "function") {
|
|
12538
|
+
return "[Function]";
|
|
12539
|
+
}
|
|
12540
|
+
if (Array.isArray(value)) {
|
|
12541
|
+
return value.map((entry) => sanitizeOpenRouterLoggedValue(entry));
|
|
12542
|
+
}
|
|
12543
|
+
if (!isObject(value)) {
|
|
12544
|
+
return value;
|
|
12545
|
+
}
|
|
12546
|
+
const sanitized = {};
|
|
12547
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
12548
|
+
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
12549
|
+
continue;
|
|
12550
|
+
}
|
|
12551
|
+
if (key === "tools" && Array.isArray(entry)) {
|
|
12552
|
+
sanitized.tools = serializeOpenRouterToolsForLogging(entry);
|
|
12553
|
+
continue;
|
|
12554
|
+
}
|
|
12555
|
+
sanitized[key] = sanitizeOpenRouterLoggedValue(entry);
|
|
12556
|
+
}
|
|
12557
|
+
return sanitized;
|
|
12558
|
+
}
|
|
12559
|
+
function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
|
|
12560
|
+
const sanitized = sanitizeOpenRouterLoggedValue(metadata);
|
|
12561
|
+
const metadataRecord = isObject(sanitized) ? sanitized : {};
|
|
12562
|
+
const { model, provider: providerRouting, ...rest } = metadataRecord;
|
|
12563
|
+
const normalizedModel = parseOpenRouterModelString(model);
|
|
12564
|
+
return {
|
|
12565
|
+
...rest,
|
|
12566
|
+
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
12567
|
+
...providerRouting !== void 0 ? { providerRouting } : {},
|
|
12568
|
+
...httpReferer !== void 0 ? { httpReferer } : {},
|
|
12569
|
+
...xTitle !== void 0 ? { xTitle } : {},
|
|
12570
|
+
provider: normalizedModel.provider || "openrouter"
|
|
12571
|
+
};
|
|
12572
|
+
}
|
|
12573
|
+
function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
|
|
12574
|
+
const normalized = buildOpenRouterMetadata(metadata, httpReferer, xTitle);
|
|
12575
|
+
return typeof normalized.model === "string" ? {
|
|
12576
|
+
...normalized,
|
|
12577
|
+
embedding_model: normalized.model
|
|
12578
|
+
} : normalized;
|
|
12579
|
+
}
|
|
12580
|
+
function extractOpenRouterCallModelInput(request) {
|
|
12581
|
+
return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue(request.input) : void 0;
|
|
12582
|
+
}
|
|
12583
|
+
function extractOpenRouterCallModelMetadata(request) {
|
|
12584
|
+
if (!isObject(request)) {
|
|
12585
|
+
return { provider: "openrouter" };
|
|
12586
|
+
}
|
|
12587
|
+
const { input: _input, ...metadata } = request;
|
|
12588
|
+
return buildOpenRouterMetadata(metadata, void 0, void 0);
|
|
12589
|
+
}
|
|
12590
|
+
function extractOpenRouterResponseMetadata(result) {
|
|
12591
|
+
if (!isObject(result)) {
|
|
12592
|
+
return void 0;
|
|
12593
|
+
}
|
|
12594
|
+
const { output: _output, data: _data, usage, ...metadata } = result;
|
|
12595
|
+
const sanitized = sanitizeOpenRouterLoggedValue(metadata);
|
|
12596
|
+
const metadataRecord = isObject(sanitized) ? sanitized : {};
|
|
12597
|
+
const { model, provider, ...rest } = metadataRecord;
|
|
12598
|
+
const normalizedModel = parseOpenRouterModelString(model);
|
|
12599
|
+
const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
|
|
12600
|
+
const usageMetadata = extractOpenRouterUsageMetadata(usage);
|
|
12601
|
+
const combined = {
|
|
12602
|
+
...rest,
|
|
12603
|
+
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
12604
|
+
...usageMetadata || {},
|
|
12605
|
+
...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
|
|
12606
|
+
};
|
|
12607
|
+
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
12608
|
+
}
|
|
12609
|
+
function extractOpenRouterResponseOutput(response, fallbackOutput) {
|
|
12610
|
+
if (isObject(response) && "output" in response && response.output !== void 0) {
|
|
12611
|
+
return sanitizeOpenRouterLoggedValue(response.output);
|
|
12612
|
+
}
|
|
12613
|
+
if (fallbackOutput !== void 0) {
|
|
12614
|
+
return sanitizeOpenRouterLoggedValue(fallbackOutput);
|
|
12615
|
+
}
|
|
12616
|
+
return void 0;
|
|
12617
|
+
}
|
|
12618
|
+
var OPENROUTER_WRAPPED_TOOL = Symbol("braintrust.openrouter.wrappedTool");
|
|
12619
|
+
function patchOpenRouterCallModelRequestTools(request) {
|
|
12620
|
+
if (!Array.isArray(request.tools) || request.tools.length === 0) {
|
|
12621
|
+
return void 0;
|
|
12622
|
+
}
|
|
12623
|
+
const originalTools = request.tools;
|
|
12624
|
+
const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
|
|
12625
|
+
const didPatch = wrappedTools.some(
|
|
12626
|
+
(tool, index) => tool !== originalTools[index]
|
|
12160
12627
|
);
|
|
12628
|
+
if (!didPatch) {
|
|
12629
|
+
return void 0;
|
|
12630
|
+
}
|
|
12631
|
+
request.tools = wrappedTools;
|
|
12632
|
+
return () => {
|
|
12633
|
+
request.tools = originalTools;
|
|
12634
|
+
};
|
|
12635
|
+
}
|
|
12636
|
+
function wrapOpenRouterTool(tool) {
|
|
12637
|
+
if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
|
|
12638
|
+
return tool;
|
|
12639
|
+
}
|
|
12640
|
+
const toolName = tool.function.name || "tool";
|
|
12641
|
+
const originalExecute = tool.function.execute;
|
|
12642
|
+
const wrappedTool = {
|
|
12643
|
+
...tool,
|
|
12644
|
+
function: {
|
|
12645
|
+
...tool.function,
|
|
12646
|
+
execute(...args) {
|
|
12647
|
+
return traceToolExecution({
|
|
12648
|
+
args,
|
|
12649
|
+
execute: () => Reflect.apply(originalExecute, this, args),
|
|
12650
|
+
toolCallId: getToolCallId(args[1]),
|
|
12651
|
+
toolName
|
|
12652
|
+
});
|
|
12653
|
+
}
|
|
12654
|
+
}
|
|
12655
|
+
};
|
|
12656
|
+
Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL, {
|
|
12657
|
+
value: true,
|
|
12658
|
+
enumerable: false,
|
|
12659
|
+
configurable: false
|
|
12660
|
+
});
|
|
12661
|
+
return wrappedTool;
|
|
12662
|
+
}
|
|
12663
|
+
function isWrappedTool(tool) {
|
|
12664
|
+
return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
|
|
12161
12665
|
}
|
|
12162
12666
|
function traceToolExecution(args) {
|
|
12163
12667
|
const tracingChannel = openRouterChannels.toolExecute.tracingChannel();
|
|
@@ -12181,7 +12685,7 @@ function traceToolExecution(args) {
|
|
|
12181
12685
|
}
|
|
12182
12686
|
}
|
|
12183
12687
|
function publishToolResult(tracingChannel, event, result) {
|
|
12184
|
-
if (
|
|
12688
|
+
if (isPromiseLike2(result)) {
|
|
12185
12689
|
return result.then(
|
|
12186
12690
|
(resolved) => {
|
|
12187
12691
|
event.result = resolved;
|
|
@@ -12203,465 +12707,460 @@ function getToolCallId(context) {
|
|
|
12203
12707
|
const toolContext = context;
|
|
12204
12708
|
return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
|
|
12205
12709
|
}
|
|
12206
|
-
function
|
|
12207
|
-
|
|
12208
|
-
...extractOpenRouterResponseMetadata(response) || {},
|
|
12209
|
-
...turnCount !== void 0 ? { turn_count: turnCount } : {}
|
|
12210
|
-
};
|
|
12211
|
-
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
12212
|
-
}
|
|
12213
|
-
function getFinalOpenRouterCallModelResponse(result, response) {
|
|
12214
|
-
if (isObject(response)) {
|
|
12215
|
-
return response;
|
|
12216
|
-
}
|
|
12217
|
-
return isObject(result.finalResponse) ? result.finalResponse : void 0;
|
|
12218
|
-
}
|
|
12219
|
-
function getOpenRouterCallModelRounds(result) {
|
|
12220
|
-
if (!Array.isArray(result.allToolExecutionRounds)) {
|
|
12221
|
-
return [];
|
|
12222
|
-
}
|
|
12223
|
-
return result.allToolExecutionRounds.filter((round) => isObject(round)).map((round) => ({
|
|
12224
|
-
response: isObject(round.response) ? round.response : void 0,
|
|
12225
|
-
round: typeof round.round === "number" ? round.round : void 0,
|
|
12226
|
-
toolResults: Array.isArray(round.toolResults) ? round.toolResults : []
|
|
12227
|
-
})).filter((round) => round.response !== void 0);
|
|
12228
|
-
}
|
|
12229
|
-
function aggregateOpenRouterCallModelMetrics(rounds, finalResponse) {
|
|
12230
|
-
const metrics = {};
|
|
12231
|
-
const responses = [
|
|
12232
|
-
...rounds.map((round) => round.response).filter(isObject),
|
|
12233
|
-
finalResponse
|
|
12234
|
-
];
|
|
12235
|
-
for (const response of responses) {
|
|
12236
|
-
const responseMetrics = parseOpenRouterMetricsFromUsage(response.usage);
|
|
12237
|
-
for (const [name, value] of Object.entries(responseMetrics)) {
|
|
12238
|
-
metrics[name] = (metrics[name] || 0) + value;
|
|
12239
|
-
}
|
|
12240
|
-
}
|
|
12241
|
-
return metrics;
|
|
12242
|
-
}
|
|
12243
|
-
function buildNextOpenRouterCallModelInput(currentInput, response, toolResults) {
|
|
12244
|
-
const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
|
|
12245
|
-
const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
|
|
12246
|
-
return [...normalizedInput, ...responseOutput, ...toolResults].map(
|
|
12247
|
-
(entry) => sanitizeOpenRouterLoggedValue(entry)
|
|
12248
|
-
);
|
|
12710
|
+
function isPromiseLike2(value) {
|
|
12711
|
+
return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
|
|
12249
12712
|
}
|
|
12250
|
-
function
|
|
12251
|
-
|
|
12252
|
-
|
|
12253
|
-
|
|
12254
|
-
|
|
12255
|
-
}
|
|
12256
|
-
|
|
12257
|
-
|
|
12258
|
-
|
|
12259
|
-
|
|
12260
|
-
}
|
|
12261
|
-
|
|
12262
|
-
|
|
12263
|
-
|
|
12264
|
-
|
|
12265
|
-
|
|
12266
|
-
step_type: args.stepType
|
|
12713
|
+
function aggregateOpenRouterChatChunks(chunks) {
|
|
12714
|
+
let role;
|
|
12715
|
+
let content = "";
|
|
12716
|
+
let toolCalls;
|
|
12717
|
+
let finishReason;
|
|
12718
|
+
let metrics = {};
|
|
12719
|
+
for (const chunk of chunks) {
|
|
12720
|
+
metrics = {
|
|
12721
|
+
...metrics,
|
|
12722
|
+
...parseOpenRouterMetricsFromUsage(chunk?.usage)
|
|
12723
|
+
};
|
|
12724
|
+
const choice = chunk?.choices?.[0];
|
|
12725
|
+
const delta = choice?.delta;
|
|
12726
|
+
if (!delta) {
|
|
12727
|
+
if (choice?.finish_reason !== void 0) {
|
|
12728
|
+
finishReason = choice.finish_reason;
|
|
12267
12729
|
}
|
|
12730
|
+
continue;
|
|
12268
12731
|
}
|
|
12269
|
-
|
|
12270
|
-
|
|
12271
|
-
|
|
12272
|
-
|
|
12273
|
-
|
|
12274
|
-
|
|
12275
|
-
|
|
12276
|
-
|
|
12277
|
-
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12732
|
+
if (!role && delta.role) {
|
|
12733
|
+
role = delta.role;
|
|
12734
|
+
}
|
|
12735
|
+
if (typeof delta.content === "string") {
|
|
12736
|
+
content += delta.content;
|
|
12737
|
+
}
|
|
12738
|
+
const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
|
|
12739
|
+
const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
|
|
12740
|
+
if (choiceFinishReason !== void 0) {
|
|
12741
|
+
finishReason = choiceFinishReason;
|
|
12742
|
+
} else if (deltaFinishReason !== void 0) {
|
|
12743
|
+
finishReason = deltaFinishReason;
|
|
12744
|
+
}
|
|
12745
|
+
const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
|
|
12746
|
+
if (!toolCallDeltas) {
|
|
12747
|
+
continue;
|
|
12748
|
+
}
|
|
12749
|
+
for (const toolDelta of toolCallDeltas) {
|
|
12750
|
+
if (!toolDelta?.function) {
|
|
12751
|
+
continue;
|
|
12283
12752
|
}
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
|
|
12290
|
-
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
|
|
12295
|
-
function buildOpenRouterFollowupRequest(request, currentResponse, toolResults) {
|
|
12296
|
-
if (!request) {
|
|
12297
|
-
return void 0;
|
|
12298
|
-
}
|
|
12299
|
-
return {
|
|
12300
|
-
...request,
|
|
12301
|
-
input: buildNextOpenRouterCallModelInput(
|
|
12302
|
-
extractOpenRouterCallModelInput(request),
|
|
12303
|
-
isObject(currentResponse) ? currentResponse : {},
|
|
12304
|
-
toolResults
|
|
12305
|
-
),
|
|
12306
|
-
stream: false
|
|
12307
|
-
};
|
|
12308
|
-
}
|
|
12309
|
-
function wrapAsyncIterableWithSpan(args) {
|
|
12310
|
-
return {
|
|
12311
|
-
[Symbol.asyncIterator]() {
|
|
12312
|
-
const iterator = args.iteratorFactory();
|
|
12313
|
-
return {
|
|
12314
|
-
next(value) {
|
|
12315
|
-
return withCurrent(
|
|
12316
|
-
args.span,
|
|
12317
|
-
() => value === void 0 ? iterator.next() : iterator.next(value)
|
|
12318
|
-
).then(
|
|
12319
|
-
async (result) => {
|
|
12320
|
-
if (result.done) {
|
|
12321
|
-
await args.finalize();
|
|
12322
|
-
}
|
|
12323
|
-
return result;
|
|
12324
|
-
},
|
|
12325
|
-
(error) => {
|
|
12326
|
-
args.onError(error);
|
|
12327
|
-
throw error;
|
|
12328
|
-
}
|
|
12329
|
-
);
|
|
12330
|
-
},
|
|
12331
|
-
return(value) {
|
|
12332
|
-
if (typeof iterator.return !== "function") {
|
|
12333
|
-
return args.finalize().then(() => ({
|
|
12334
|
-
done: true,
|
|
12335
|
-
value
|
|
12336
|
-
}));
|
|
12337
|
-
}
|
|
12338
|
-
return withCurrent(args.span, () => iterator.return(value)).then(
|
|
12339
|
-
async (result) => {
|
|
12340
|
-
await args.finalize();
|
|
12341
|
-
return result;
|
|
12342
|
-
},
|
|
12343
|
-
(error) => {
|
|
12344
|
-
args.onError(error);
|
|
12345
|
-
throw error;
|
|
12346
|
-
}
|
|
12347
|
-
);
|
|
12348
|
-
},
|
|
12349
|
-
throw(error) {
|
|
12350
|
-
args.onError(error);
|
|
12351
|
-
if (typeof iterator.throw !== "function") {
|
|
12352
|
-
return Promise.reject(error);
|
|
12753
|
+
const toolIndex = toolDelta.index ?? 0;
|
|
12754
|
+
const existingToolCall = toolCalls?.[toolIndex];
|
|
12755
|
+
if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
|
|
12756
|
+
const nextToolCalls = [...toolCalls || []];
|
|
12757
|
+
nextToolCalls[toolIndex] = {
|
|
12758
|
+
index: toolIndex,
|
|
12759
|
+
id: toolDelta.id,
|
|
12760
|
+
type: toolDelta.type,
|
|
12761
|
+
function: {
|
|
12762
|
+
name: toolDelta.function.name,
|
|
12763
|
+
arguments: toolDelta.function.arguments || ""
|
|
12353
12764
|
}
|
|
12354
|
-
|
|
12355
|
-
|
|
12356
|
-
|
|
12357
|
-
|
|
12358
|
-
|
|
12359
|
-
|
|
12765
|
+
};
|
|
12766
|
+
toolCalls = nextToolCalls;
|
|
12767
|
+
continue;
|
|
12768
|
+
}
|
|
12769
|
+
const current = existingToolCall;
|
|
12770
|
+
if (toolDelta.id && !current.id) {
|
|
12771
|
+
current.id = toolDelta.id;
|
|
12772
|
+
}
|
|
12773
|
+
if (toolDelta.type && !current.type) {
|
|
12774
|
+
current.type = toolDelta.type;
|
|
12775
|
+
}
|
|
12776
|
+
if (toolDelta.function.name && !current.function.name) {
|
|
12777
|
+
current.function.name = toolDelta.function.name;
|
|
12778
|
+
}
|
|
12779
|
+
current.function.arguments += toolDelta.function.arguments || "";
|
|
12360
12780
|
}
|
|
12781
|
+
}
|
|
12782
|
+
return {
|
|
12783
|
+
output: [
|
|
12784
|
+
{
|
|
12785
|
+
index: 0,
|
|
12786
|
+
message: {
|
|
12787
|
+
role,
|
|
12788
|
+
content: content || void 0,
|
|
12789
|
+
...toolCalls ? { tool_calls: toolCalls } : {}
|
|
12790
|
+
},
|
|
12791
|
+
logprobs: null,
|
|
12792
|
+
finish_reason: finishReason
|
|
12793
|
+
}
|
|
12794
|
+
],
|
|
12795
|
+
metrics
|
|
12361
12796
|
};
|
|
12362
12797
|
}
|
|
12363
|
-
function
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
|
|
12367
|
-
|
|
12368
|
-
|
|
12369
|
-
|
|
12370
|
-
|
|
12798
|
+
function aggregateOpenRouterResponseStreamEvents(chunks) {
|
|
12799
|
+
let finalResponse;
|
|
12800
|
+
for (const chunk of chunks) {
|
|
12801
|
+
const response = chunk?.response;
|
|
12802
|
+
if (!response) {
|
|
12803
|
+
continue;
|
|
12804
|
+
}
|
|
12805
|
+
if (chunk.type === "response.completed" || chunk.type === "response.incomplete" || chunk.type === "response.failed") {
|
|
12806
|
+
finalResponse = response;
|
|
12807
|
+
}
|
|
12808
|
+
}
|
|
12809
|
+
if (!finalResponse) {
|
|
12810
|
+
return {
|
|
12811
|
+
output: void 0,
|
|
12812
|
+
metrics: {}
|
|
12813
|
+
};
|
|
12814
|
+
}
|
|
12815
|
+
return {
|
|
12816
|
+
output: extractOpenRouterResponseOutput(finalResponse),
|
|
12817
|
+
metrics: parseOpenRouterMetricsFromUsage(finalResponse.usage),
|
|
12818
|
+
...extractOpenRouterResponseMetadata(finalResponse) ? { metadata: extractOpenRouterResponseMetadata(finalResponse) } : {}
|
|
12819
|
+
};
|
|
12371
12820
|
}
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12376
|
-
|
|
12821
|
+
var OPENROUTER_WRAPPED_CALL_MODEL_RESULT = Symbol(
|
|
12822
|
+
"braintrust.openrouter.wrappedCallModelResult"
|
|
12823
|
+
);
|
|
12824
|
+
var OPENROUTER_CALL_MODEL_STREAM_METHODS = [
|
|
12825
|
+
"getFullResponsesStream",
|
|
12826
|
+
"getItemsStream",
|
|
12827
|
+
"getNewMessagesStream",
|
|
12828
|
+
"getReasoningStream",
|
|
12829
|
+
"getTextStream",
|
|
12830
|
+
"getToolCallsStream",
|
|
12831
|
+
"getToolStream"
|
|
12832
|
+
];
|
|
12833
|
+
var OPENROUTER_CALL_MODEL_CONTEXT_METHODS = [
|
|
12834
|
+
"cancel",
|
|
12835
|
+
"getPendingToolCalls",
|
|
12836
|
+
"getState",
|
|
12837
|
+
"getToolCalls",
|
|
12838
|
+
"requiresApproval"
|
|
12839
|
+
];
|
|
12840
|
+
function patchOpenRouterCallModelResult(args) {
|
|
12841
|
+
const { request, result, span } = args;
|
|
12842
|
+
if (!isObject(result) || isWrappedCallModelResult(result)) {
|
|
12843
|
+
return false;
|
|
12377
12844
|
}
|
|
12378
|
-
|
|
12379
|
-
|
|
12845
|
+
const resultLike = result;
|
|
12846
|
+
const hasInstrumentableMethod = typeof resultLike.getResponse === "function" || typeof resultLike.getText === "function" || OPENROUTER_CALL_MODEL_STREAM_METHODS.some(
|
|
12847
|
+
(methodName) => typeof resultLike[methodName] === "function"
|
|
12848
|
+
);
|
|
12849
|
+
if (!hasInstrumentableMethod) {
|
|
12850
|
+
return false;
|
|
12380
12851
|
}
|
|
12381
|
-
|
|
12382
|
-
|
|
12383
|
-
|
|
12384
|
-
|
|
12385
|
-
|
|
12386
|
-
|
|
12387
|
-
|
|
12388
|
-
|
|
12389
|
-
|
|
12390
|
-
|
|
12391
|
-
|
|
12392
|
-
|
|
12393
|
-
|
|
12394
|
-
|
|
12395
|
-
|
|
12396
|
-
|
|
12397
|
-
|
|
12398
|
-
|
|
12399
|
-
},
|
|
12400
|
-
extractMetrics: (result, startTime) => {
|
|
12401
|
-
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
12402
|
-
if (startTime) {
|
|
12403
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
12404
|
-
}
|
|
12405
|
-
return metrics;
|
|
12406
|
-
},
|
|
12407
|
-
aggregateChunks: aggregateOpenRouterChatChunks
|
|
12408
|
-
})
|
|
12409
|
-
);
|
|
12410
|
-
this.unsubscribers.push(
|
|
12411
|
-
traceAsyncChannel(openRouterChannels.embeddingsGenerate, {
|
|
12412
|
-
name: "openrouter.embeddings.generate",
|
|
12413
|
-
type: "llm" /* LLM */,
|
|
12414
|
-
extractInput: (args) => {
|
|
12415
|
-
const request = getOpenRouterRequestArg(args);
|
|
12416
|
-
const requestBody = isObject(request?.requestBody) ? request.requestBody : {};
|
|
12417
|
-
const httpReferer = request?.httpReferer;
|
|
12418
|
-
const xTitle = request?.xTitle;
|
|
12419
|
-
const { input, ...metadata } = requestBody;
|
|
12420
|
-
return {
|
|
12421
|
-
input,
|
|
12422
|
-
metadata: buildOpenRouterEmbeddingMetadata(
|
|
12423
|
-
metadata,
|
|
12424
|
-
httpReferer,
|
|
12425
|
-
xTitle
|
|
12426
|
-
)
|
|
12427
|
-
};
|
|
12428
|
-
},
|
|
12429
|
-
extractOutput: (result) => {
|
|
12430
|
-
if (!isObject(result)) {
|
|
12431
|
-
return void 0;
|
|
12432
|
-
}
|
|
12433
|
-
const embedding = result.data?.[0]?.embedding;
|
|
12434
|
-
return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
|
|
12435
|
-
},
|
|
12436
|
-
extractMetadata: (result) => {
|
|
12437
|
-
if (!isObject(result)) {
|
|
12438
|
-
return void 0;
|
|
12439
|
-
}
|
|
12440
|
-
return extractOpenRouterResponseMetadata(result);
|
|
12441
|
-
},
|
|
12442
|
-
extractMetrics: (result) => {
|
|
12443
|
-
return isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {};
|
|
12444
|
-
}
|
|
12445
|
-
})
|
|
12446
|
-
);
|
|
12447
|
-
this.unsubscribers.push(
|
|
12448
|
-
traceStreamingChannel(openRouterChannels.betaResponsesSend, {
|
|
12449
|
-
name: "openrouter.beta.responses.send",
|
|
12450
|
-
type: "llm" /* LLM */,
|
|
12451
|
-
extractInput: (args) => {
|
|
12452
|
-
const request = getOpenRouterRequestArg(args);
|
|
12453
|
-
const openResponsesRequest = isObject(request?.openResponsesRequest) ? request.openResponsesRequest : {};
|
|
12454
|
-
const httpReferer = request?.httpReferer;
|
|
12455
|
-
const xTitle = request?.xTitle;
|
|
12456
|
-
const { input, ...metadata } = openResponsesRequest;
|
|
12457
|
-
return {
|
|
12458
|
-
input,
|
|
12459
|
-
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
12460
|
-
};
|
|
12461
|
-
},
|
|
12462
|
-
extractOutput: (result) => extractOpenRouterResponseOutput(result),
|
|
12463
|
-
extractMetadata: (result) => extractOpenRouterResponseMetadata(result),
|
|
12464
|
-
extractMetrics: (result, startTime) => {
|
|
12465
|
-
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
12466
|
-
if (startTime) {
|
|
12467
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
12468
|
-
}
|
|
12469
|
-
return metrics;
|
|
12470
|
-
},
|
|
12471
|
-
aggregateChunks: aggregateOpenRouterResponseStreamEvents
|
|
12472
|
-
})
|
|
12852
|
+
Object.defineProperty(resultLike, OPENROUTER_WRAPPED_CALL_MODEL_RESULT, {
|
|
12853
|
+
value: true,
|
|
12854
|
+
enumerable: false,
|
|
12855
|
+
configurable: false
|
|
12856
|
+
});
|
|
12857
|
+
const originalGetResponse = typeof resultLike.getResponse === "function" ? resultLike.getResponse.bind(resultLike) : void 0;
|
|
12858
|
+
const originalGetInitialResponse = typeof resultLike.getInitialResponse === "function" ? resultLike.getInitialResponse.bind(resultLike) : void 0;
|
|
12859
|
+
const originalMakeFollowupRequest = typeof resultLike.makeFollowupRequest === "function" ? resultLike.makeFollowupRequest.bind(resultLike) : void 0;
|
|
12860
|
+
let ended = false;
|
|
12861
|
+
let tracedTurnCount = 0;
|
|
12862
|
+
const endSpanWithResult = async (response, fallbackOutput) => {
|
|
12863
|
+
if (ended) {
|
|
12864
|
+
return;
|
|
12865
|
+
}
|
|
12866
|
+
ended = true;
|
|
12867
|
+
const finalResponse = getFinalOpenRouterCallModelResponse(
|
|
12868
|
+
resultLike,
|
|
12869
|
+
response
|
|
12473
12870
|
);
|
|
12474
|
-
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
|
|
12479
|
-
|
|
12480
|
-
|
|
12481
|
-
|
|
12482
|
-
|
|
12483
|
-
|
|
12484
|
-
|
|
12485
|
-
|
|
12486
|
-
|
|
12487
|
-
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
|
|
12871
|
+
if (finalResponse) {
|
|
12872
|
+
const rounds = getOpenRouterCallModelRounds(resultLike);
|
|
12873
|
+
const metadata = extractOpenRouterCallModelResultMetadata(
|
|
12874
|
+
finalResponse,
|
|
12875
|
+
rounds.length + 1
|
|
12876
|
+
);
|
|
12877
|
+
span.log({
|
|
12878
|
+
output: extractOpenRouterResponseOutput(finalResponse, fallbackOutput),
|
|
12879
|
+
...metadata ? { metadata } : {},
|
|
12880
|
+
metrics: aggregateOpenRouterCallModelMetrics(rounds, finalResponse)
|
|
12881
|
+
});
|
|
12882
|
+
span.end();
|
|
12883
|
+
return;
|
|
12884
|
+
}
|
|
12885
|
+
if (fallbackOutput !== void 0) {
|
|
12886
|
+
span.log({
|
|
12887
|
+
output: fallbackOutput
|
|
12888
|
+
});
|
|
12889
|
+
}
|
|
12890
|
+
span.end();
|
|
12891
|
+
};
|
|
12892
|
+
const endSpanWithError = (error) => {
|
|
12893
|
+
if (ended) {
|
|
12894
|
+
return;
|
|
12895
|
+
}
|
|
12896
|
+
ended = true;
|
|
12897
|
+
span.log({
|
|
12898
|
+
error: normalizeError(error).message
|
|
12899
|
+
});
|
|
12900
|
+
span.end();
|
|
12901
|
+
};
|
|
12902
|
+
const finalizeFromResponse = async (fallbackOutput) => {
|
|
12903
|
+
if (!originalGetResponse) {
|
|
12904
|
+
await endSpanWithResult(void 0, fallbackOutput);
|
|
12905
|
+
return;
|
|
12906
|
+
}
|
|
12907
|
+
try {
|
|
12908
|
+
await endSpanWithResult(await originalGetResponse(), fallbackOutput);
|
|
12909
|
+
} catch {
|
|
12910
|
+
await endSpanWithResult(void 0, fallbackOutput);
|
|
12911
|
+
}
|
|
12912
|
+
};
|
|
12913
|
+
if (originalGetResponse) {
|
|
12914
|
+
resultLike.getResponse = async (...args2) => {
|
|
12915
|
+
return await withCurrent(span, async () => {
|
|
12916
|
+
try {
|
|
12917
|
+
const response = await originalGetResponse(...args2);
|
|
12918
|
+
await endSpanWithResult(response);
|
|
12919
|
+
return response;
|
|
12920
|
+
} catch (error) {
|
|
12921
|
+
endSpanWithError(error);
|
|
12922
|
+
throw error;
|
|
12491
12923
|
}
|
|
12492
|
-
})
|
|
12493
|
-
|
|
12494
|
-
|
|
12495
|
-
|
|
12496
|
-
|
|
12497
|
-
|
|
12498
|
-
|
|
12499
|
-
|
|
12500
|
-
|
|
12501
|
-
|
|
12502
|
-
|
|
12503
|
-
|
|
12504
|
-
|
|
12505
|
-
|
|
12506
|
-
extractOutput: (result) => result,
|
|
12507
|
-
extractMetrics: () => ({}),
|
|
12508
|
-
aggregateChunks: (chunks) => ({
|
|
12509
|
-
output: chunks.length > 0 ? chunks[chunks.length - 1] : void 0,
|
|
12510
|
-
metrics: {}
|
|
12511
|
-
})
|
|
12512
|
-
})
|
|
12513
|
-
);
|
|
12514
|
-
const callModelChannel = openRouterChannels.callModel.tracingChannel();
|
|
12515
|
-
const callModelHandlers = {
|
|
12516
|
-
start: (event) => {
|
|
12517
|
-
const request = getOpenRouterCallModelRequestArg(event.arguments);
|
|
12518
|
-
if (!request) {
|
|
12519
|
-
return;
|
|
12924
|
+
});
|
|
12925
|
+
};
|
|
12926
|
+
}
|
|
12927
|
+
if (typeof resultLike.getText === "function") {
|
|
12928
|
+
const originalGetText = resultLike.getText.bind(resultLike);
|
|
12929
|
+
resultLike.getText = async (...args2) => {
|
|
12930
|
+
return await withCurrent(span, async () => {
|
|
12931
|
+
try {
|
|
12932
|
+
const text = await originalGetText(...args2);
|
|
12933
|
+
await finalizeFromResponse(text);
|
|
12934
|
+
return text;
|
|
12935
|
+
} catch (error) {
|
|
12936
|
+
endSpanWithError(error);
|
|
12937
|
+
throw error;
|
|
12520
12938
|
}
|
|
12521
|
-
|
|
12939
|
+
});
|
|
12940
|
+
};
|
|
12941
|
+
}
|
|
12942
|
+
for (const methodName of OPENROUTER_CALL_MODEL_CONTEXT_METHODS) {
|
|
12943
|
+
if (typeof resultLike[methodName] !== "function") {
|
|
12944
|
+
continue;
|
|
12945
|
+
}
|
|
12946
|
+
const originalMethod = resultLike[methodName];
|
|
12947
|
+
resultLike[methodName] = async (...args2) => {
|
|
12948
|
+
return await withCurrent(span, async () => {
|
|
12949
|
+
return await originalMethod.apply(resultLike, args2);
|
|
12950
|
+
});
|
|
12951
|
+
};
|
|
12952
|
+
}
|
|
12953
|
+
for (const methodName of OPENROUTER_CALL_MODEL_STREAM_METHODS) {
|
|
12954
|
+
if (typeof resultLike[methodName] !== "function") {
|
|
12955
|
+
continue;
|
|
12956
|
+
}
|
|
12957
|
+
const originalMethod = resultLike[methodName];
|
|
12958
|
+
resultLike[methodName] = (...args2) => {
|
|
12959
|
+
const stream = withCurrent(
|
|
12960
|
+
span,
|
|
12961
|
+
() => originalMethod.apply(resultLike, args2)
|
|
12962
|
+
);
|
|
12963
|
+
if (!isAsyncIterable2(stream)) {
|
|
12964
|
+
return stream;
|
|
12965
|
+
}
|
|
12966
|
+
return wrapAsyncIterableWithSpan({
|
|
12967
|
+
finalize: finalizeFromResponse,
|
|
12968
|
+
iteratorFactory: () => stream[Symbol.asyncIterator](),
|
|
12969
|
+
onError: endSpanWithError,
|
|
12970
|
+
span
|
|
12971
|
+
});
|
|
12972
|
+
};
|
|
12973
|
+
}
|
|
12974
|
+
if (originalGetInitialResponse) {
|
|
12975
|
+
let initialTurnTraced = false;
|
|
12976
|
+
resultLike.getInitialResponse = async (...args2) => {
|
|
12977
|
+
if (initialTurnTraced) {
|
|
12978
|
+
return await withCurrent(span, async () => {
|
|
12979
|
+
return await originalGetInitialResponse(...args2);
|
|
12980
|
+
});
|
|
12522
12981
|
}
|
|
12982
|
+
initialTurnTraced = true;
|
|
12983
|
+
const step = tracedTurnCount + 1;
|
|
12984
|
+
const stepType = tracedTurnCount === 0 ? "initial" : "continue";
|
|
12985
|
+
const response = await traceOpenRouterCallModelTurn({
|
|
12986
|
+
fn: async () => {
|
|
12987
|
+
const nextResponse = await originalGetInitialResponse(...args2);
|
|
12988
|
+
tracedTurnCount++;
|
|
12989
|
+
return nextResponse;
|
|
12990
|
+
},
|
|
12991
|
+
parentSpan: span,
|
|
12992
|
+
request: getOpenRouterResolvedRequest(resultLike, request),
|
|
12993
|
+
step,
|
|
12994
|
+
stepType
|
|
12995
|
+
});
|
|
12996
|
+
return response;
|
|
12523
12997
|
};
|
|
12524
|
-
callModelChannel.subscribe(callModelHandlers);
|
|
12525
|
-
this.unsubscribers.push(() => {
|
|
12526
|
-
callModelChannel.unsubscribe(callModelHandlers);
|
|
12527
|
-
});
|
|
12528
|
-
}
|
|
12529
|
-
};
|
|
12530
|
-
function normalizeArgs(args) {
|
|
12531
|
-
if (Array.isArray(args)) {
|
|
12532
|
-
return args;
|
|
12533
12998
|
}
|
|
12534
|
-
if (
|
|
12535
|
-
|
|
12999
|
+
if (originalMakeFollowupRequest) {
|
|
13000
|
+
resultLike.makeFollowupRequest = async (...args2) => {
|
|
13001
|
+
const currentResponse = args2[0];
|
|
13002
|
+
const toolResults = Array.isArray(args2[1]) ? args2[1] : [];
|
|
13003
|
+
const step = tracedTurnCount + 1;
|
|
13004
|
+
const response = await traceOpenRouterCallModelTurn({
|
|
13005
|
+
fn: async () => {
|
|
13006
|
+
const nextResponse = await originalMakeFollowupRequest(...args2);
|
|
13007
|
+
tracedTurnCount++;
|
|
13008
|
+
return nextResponse;
|
|
13009
|
+
},
|
|
13010
|
+
parentSpan: span,
|
|
13011
|
+
request: buildOpenRouterFollowupRequest(
|
|
13012
|
+
getOpenRouterResolvedRequest(resultLike, request),
|
|
13013
|
+
currentResponse,
|
|
13014
|
+
toolResults
|
|
13015
|
+
),
|
|
13016
|
+
step,
|
|
13017
|
+
stepType: "continue"
|
|
13018
|
+
});
|
|
13019
|
+
return response;
|
|
13020
|
+
};
|
|
12536
13021
|
}
|
|
12537
|
-
return
|
|
13022
|
+
return true;
|
|
12538
13023
|
}
|
|
12539
|
-
function
|
|
12540
|
-
|
|
13024
|
+
async function traceOpenRouterCallModelTurn(args) {
|
|
13025
|
+
const context = {
|
|
13026
|
+
arguments: [args.request],
|
|
13027
|
+
step: args.step,
|
|
13028
|
+
stepType: args.stepType
|
|
13029
|
+
};
|
|
13030
|
+
return await withCurrent(
|
|
13031
|
+
args.parentSpan,
|
|
13032
|
+
() => openRouterChannels.callModelTurn.tracePromise(args.fn, context)
|
|
13033
|
+
);
|
|
12541
13034
|
}
|
|
12542
|
-
function
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
(arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
|
|
13035
|
+
function isWrappedCallModelResult(value) {
|
|
13036
|
+
return Boolean(
|
|
13037
|
+
isObject(value) && value[OPENROUTER_WRAPPED_CALL_MODEL_RESULT]
|
|
12546
13038
|
);
|
|
12547
|
-
|
|
12548
|
-
|
|
13039
|
+
}
|
|
13040
|
+
function extractOpenRouterCallModelResultMetadata(response, turnCount) {
|
|
13041
|
+
const combined = {
|
|
13042
|
+
...extractOpenRouterResponseMetadata(response) || {},
|
|
13043
|
+
...turnCount !== void 0 ? { turn_count: turnCount } : {}
|
|
13044
|
+
};
|
|
13045
|
+
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
13046
|
+
}
|
|
13047
|
+
function getFinalOpenRouterCallModelResponse(result, response) {
|
|
13048
|
+
if (isObject(response)) {
|
|
13049
|
+
return response;
|
|
12549
13050
|
}
|
|
12550
|
-
|
|
12551
|
-
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
13051
|
+
return isObject(result.finalResponse) ? result.finalResponse : void 0;
|
|
12552
13052
|
}
|
|
12553
|
-
function
|
|
12554
|
-
|
|
12555
|
-
|
|
13053
|
+
function getOpenRouterCallModelRounds(result) {
|
|
13054
|
+
if (!Array.isArray(result.allToolExecutionRounds)) {
|
|
13055
|
+
return [];
|
|
13056
|
+
}
|
|
13057
|
+
return result.allToolExecutionRounds.filter((round) => isObject(round)).map((round) => ({
|
|
13058
|
+
response: isObject(round.response) ? round.response : void 0,
|
|
13059
|
+
round: typeof round.round === "number" ? round.round : void 0,
|
|
13060
|
+
toolResults: Array.isArray(round.toolResults) ? round.toolResults : []
|
|
13061
|
+
})).filter((round) => round.response !== void 0);
|
|
12556
13062
|
}
|
|
12557
|
-
function
|
|
12558
|
-
|
|
12559
|
-
|
|
12560
|
-
|
|
12561
|
-
|
|
12562
|
-
|
|
12563
|
-
for (const
|
|
12564
|
-
|
|
12565
|
-
|
|
12566
|
-
|
|
12567
|
-
};
|
|
12568
|
-
const choice = chunk?.choices?.[0];
|
|
12569
|
-
const delta = choice?.delta;
|
|
12570
|
-
if (!delta) {
|
|
12571
|
-
if (choice?.finish_reason !== void 0) {
|
|
12572
|
-
finishReason = choice.finish_reason;
|
|
12573
|
-
}
|
|
12574
|
-
continue;
|
|
12575
|
-
}
|
|
12576
|
-
if (!role && delta.role) {
|
|
12577
|
-
role = delta.role;
|
|
12578
|
-
}
|
|
12579
|
-
if (typeof delta.content === "string") {
|
|
12580
|
-
content += delta.content;
|
|
12581
|
-
}
|
|
12582
|
-
const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
|
|
12583
|
-
const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
|
|
12584
|
-
if (choiceFinishReason !== void 0) {
|
|
12585
|
-
finishReason = choiceFinishReason;
|
|
12586
|
-
} else if (deltaFinishReason !== void 0) {
|
|
12587
|
-
finishReason = deltaFinishReason;
|
|
12588
|
-
}
|
|
12589
|
-
const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
|
|
12590
|
-
if (!toolCallDeltas) {
|
|
12591
|
-
continue;
|
|
12592
|
-
}
|
|
12593
|
-
for (const toolDelta of toolCallDeltas) {
|
|
12594
|
-
if (!toolDelta?.function) {
|
|
12595
|
-
continue;
|
|
12596
|
-
}
|
|
12597
|
-
const toolIndex = toolDelta.index ?? 0;
|
|
12598
|
-
const existingToolCall = toolCalls?.[toolIndex];
|
|
12599
|
-
if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
|
|
12600
|
-
const nextToolCalls = [...toolCalls || []];
|
|
12601
|
-
nextToolCalls[toolIndex] = {
|
|
12602
|
-
index: toolIndex,
|
|
12603
|
-
id: toolDelta.id,
|
|
12604
|
-
type: toolDelta.type,
|
|
12605
|
-
function: {
|
|
12606
|
-
name: toolDelta.function.name,
|
|
12607
|
-
arguments: toolDelta.function.arguments || ""
|
|
12608
|
-
}
|
|
12609
|
-
};
|
|
12610
|
-
toolCalls = nextToolCalls;
|
|
12611
|
-
continue;
|
|
12612
|
-
}
|
|
12613
|
-
const current = existingToolCall;
|
|
12614
|
-
if (toolDelta.id && !current.id) {
|
|
12615
|
-
current.id = toolDelta.id;
|
|
12616
|
-
}
|
|
12617
|
-
if (toolDelta.type && !current.type) {
|
|
12618
|
-
current.type = toolDelta.type;
|
|
12619
|
-
}
|
|
12620
|
-
if (toolDelta.function.name && !current.function.name) {
|
|
12621
|
-
current.function.name = toolDelta.function.name;
|
|
12622
|
-
}
|
|
12623
|
-
current.function.arguments += toolDelta.function.arguments || "";
|
|
13063
|
+
function aggregateOpenRouterCallModelMetrics(rounds, finalResponse) {
|
|
13064
|
+
const metrics = {};
|
|
13065
|
+
const responses = [
|
|
13066
|
+
...rounds.map((round) => round.response).filter(isObject),
|
|
13067
|
+
finalResponse
|
|
13068
|
+
];
|
|
13069
|
+
for (const response of responses) {
|
|
13070
|
+
const responseMetrics = parseOpenRouterMetricsFromUsage(response.usage);
|
|
13071
|
+
for (const [name, value] of Object.entries(responseMetrics)) {
|
|
13072
|
+
metrics[name] = (metrics[name] || 0) + value;
|
|
12624
13073
|
}
|
|
12625
13074
|
}
|
|
12626
|
-
return
|
|
12627
|
-
output: [
|
|
12628
|
-
{
|
|
12629
|
-
index: 0,
|
|
12630
|
-
message: {
|
|
12631
|
-
role,
|
|
12632
|
-
content: content || void 0,
|
|
12633
|
-
...toolCalls ? { tool_calls: toolCalls } : {}
|
|
12634
|
-
},
|
|
12635
|
-
logprobs: null,
|
|
12636
|
-
finish_reason: finishReason
|
|
12637
|
-
}
|
|
12638
|
-
],
|
|
12639
|
-
metrics
|
|
12640
|
-
};
|
|
13075
|
+
return metrics;
|
|
12641
13076
|
}
|
|
12642
|
-
function
|
|
12643
|
-
|
|
12644
|
-
|
|
12645
|
-
|
|
12646
|
-
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
13077
|
+
function buildNextOpenRouterCallModelInput(currentInput, response, toolResults) {
|
|
13078
|
+
const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
|
|
13079
|
+
const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
|
|
13080
|
+
return [...normalizedInput, ...responseOutput, ...toolResults].map(
|
|
13081
|
+
(entry) => sanitizeOpenRouterLoggedValue(entry)
|
|
13082
|
+
);
|
|
13083
|
+
}
|
|
13084
|
+
function getOpenRouterResolvedRequest(result, request) {
|
|
13085
|
+
if (isObject(result.resolvedRequest)) {
|
|
13086
|
+
return result.resolvedRequest;
|
|
12652
13087
|
}
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
13088
|
+
return request;
|
|
13089
|
+
}
|
|
13090
|
+
function buildOpenRouterFollowupRequest(request, currentResponse, toolResults) {
|
|
13091
|
+
if (!request) {
|
|
13092
|
+
return void 0;
|
|
12658
13093
|
}
|
|
12659
13094
|
return {
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
13095
|
+
...request,
|
|
13096
|
+
input: buildNextOpenRouterCallModelInput(
|
|
13097
|
+
extractOpenRouterCallModelInput(request),
|
|
13098
|
+
isObject(currentResponse) ? currentResponse : {},
|
|
13099
|
+
toolResults
|
|
13100
|
+
),
|
|
13101
|
+
stream: false
|
|
13102
|
+
};
|
|
13103
|
+
}
|
|
13104
|
+
function wrapAsyncIterableWithSpan(args) {
|
|
13105
|
+
return {
|
|
13106
|
+
[Symbol.asyncIterator]() {
|
|
13107
|
+
const iterator = args.iteratorFactory();
|
|
13108
|
+
return {
|
|
13109
|
+
next(value) {
|
|
13110
|
+
return withCurrent(
|
|
13111
|
+
args.span,
|
|
13112
|
+
() => value === void 0 ? iterator.next() : iterator.next(value)
|
|
13113
|
+
).then(
|
|
13114
|
+
async (result) => {
|
|
13115
|
+
if (result.done) {
|
|
13116
|
+
await args.finalize();
|
|
13117
|
+
}
|
|
13118
|
+
return result;
|
|
13119
|
+
},
|
|
13120
|
+
(error) => {
|
|
13121
|
+
args.onError(error);
|
|
13122
|
+
throw error;
|
|
13123
|
+
}
|
|
13124
|
+
);
|
|
13125
|
+
},
|
|
13126
|
+
return(value) {
|
|
13127
|
+
if (typeof iterator.return !== "function") {
|
|
13128
|
+
return args.finalize().then(() => ({
|
|
13129
|
+
done: true,
|
|
13130
|
+
value
|
|
13131
|
+
}));
|
|
13132
|
+
}
|
|
13133
|
+
return withCurrent(args.span, () => iterator.return(value)).then(
|
|
13134
|
+
async (result) => {
|
|
13135
|
+
await args.finalize();
|
|
13136
|
+
return result;
|
|
13137
|
+
},
|
|
13138
|
+
(error) => {
|
|
13139
|
+
args.onError(error);
|
|
13140
|
+
throw error;
|
|
13141
|
+
}
|
|
13142
|
+
);
|
|
13143
|
+
},
|
|
13144
|
+
throw(error) {
|
|
13145
|
+
args.onError(error);
|
|
13146
|
+
if (typeof iterator.throw !== "function") {
|
|
13147
|
+
return Promise.reject(error);
|
|
13148
|
+
}
|
|
13149
|
+
return withCurrent(args.span, () => iterator.throw(error));
|
|
13150
|
+
},
|
|
13151
|
+
[Symbol.asyncIterator]() {
|
|
13152
|
+
return this;
|
|
13153
|
+
}
|
|
13154
|
+
};
|
|
13155
|
+
}
|
|
12663
13156
|
};
|
|
12664
13157
|
}
|
|
13158
|
+
function isAsyncIterable2(value) {
|
|
13159
|
+
return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
13160
|
+
}
|
|
13161
|
+
function normalizeError(error) {
|
|
13162
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
13163
|
+
}
|
|
12665
13164
|
|
|
12666
13165
|
// src/instrumentation/braintrust-plugin.ts
|
|
12667
13166
|
var BraintrustPlugin = class extends BasePlugin {
|