braintrust 3.6.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 +2692 -1472
- package/dev/dist/index.mjs +2616 -1396
- package/dist/auto-instrumentations/bundler/esbuild.cjs +46 -21
- package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
- package/dist/auto-instrumentations/bundler/rollup.cjs +46 -21
- package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
- package/dist/auto-instrumentations/bundler/vite.cjs +46 -21
- package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
- package/dist/auto-instrumentations/bundler/webpack-loader.cjs +952 -0
- package/dist/auto-instrumentations/bundler/webpack-loader.d.ts +53 -0
- package/dist/auto-instrumentations/bundler/webpack.cjs +46 -21
- package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
- package/dist/auto-instrumentations/{chunk-WOUC73KB.mjs → chunk-NY4CGTN6.mjs} +1 -1
- package/dist/auto-instrumentations/{chunk-F7WAXFNM.mjs → chunk-YCKND42U.mjs} +46 -21
- package/dist/auto-instrumentations/hook.mjs +77 -26
- package/dist/auto-instrumentations/index.cjs +46 -21
- 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 +5051 -6344
- package/dist/browser.mjs +5051 -6344
- package/dist/cli.js +2622 -1398
- package/dist/edge-light.js +9456 -10773
- package/dist/edge-light.mjs +9456 -10773
- package/dist/index.d.mts +8 -30
- package/dist/index.d.ts +8 -30
- package/dist/index.js +5078 -6371
- package/dist/index.mjs +4870 -6163
- package/dist/instrumentation/index.js +2491 -1319
- package/dist/instrumentation/index.mjs +2491 -1319
- package/dist/workerd.js +9456 -10773
- package/dist/workerd.mjs +9456 -10773
- package/package.json +6 -2
|
@@ -111,7 +111,7 @@ var DefaultTracingChannel = class {
|
|
|
111
111
|
}
|
|
112
112
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
113
113
|
tracePromise(fn, _message, thisArg, ...args) {
|
|
114
|
-
return
|
|
114
|
+
return fn.apply(thisArg, args);
|
|
115
115
|
}
|
|
116
116
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
117
117
|
traceCallback(fn, _position, _message, thisArg, ...args) {
|
|
@@ -131,6 +131,7 @@ var iso = {
|
|
|
131
131
|
processOn: (_0, _1) => {
|
|
132
132
|
},
|
|
133
133
|
basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
|
|
134
|
+
// eslint-disable-next-line no-restricted-properties -- preserving intentional console usage.
|
|
134
135
|
writeln: (text) => console.log(text)
|
|
135
136
|
};
|
|
136
137
|
var isomorph_default = iso;
|
|
@@ -166,7 +167,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
166
167
|
if (!completed) {
|
|
167
168
|
completed = true;
|
|
168
169
|
try {
|
|
169
|
-
options.onComplete(chunks);
|
|
170
|
+
await options.onComplete(chunks);
|
|
170
171
|
} catch (error) {
|
|
171
172
|
console.error("Error in stream onComplete handler:", error);
|
|
172
173
|
}
|
|
@@ -178,7 +179,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
178
179
|
chunks.push(chunk);
|
|
179
180
|
if (options.onChunk) {
|
|
180
181
|
try {
|
|
181
|
-
options.onChunk(chunk);
|
|
182
|
+
await options.onChunk(chunk);
|
|
182
183
|
} catch (error) {
|
|
183
184
|
console.error("Error in stream onChunk handler:", error);
|
|
184
185
|
}
|
|
@@ -191,7 +192,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
191
192
|
completed = true;
|
|
192
193
|
if (options.onError) {
|
|
193
194
|
try {
|
|
194
|
-
options.onError(
|
|
195
|
+
await options.onError(
|
|
195
196
|
error instanceof Error ? error : new Error(String(error)),
|
|
196
197
|
chunks
|
|
197
198
|
);
|
|
@@ -209,7 +210,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
209
210
|
if (!completed) {
|
|
210
211
|
completed = true;
|
|
211
212
|
try {
|
|
212
|
-
options.onComplete(chunks);
|
|
213
|
+
await options.onComplete(chunks);
|
|
213
214
|
} catch (error) {
|
|
214
215
|
console.error("Error in stream onComplete handler:", error);
|
|
215
216
|
}
|
|
@@ -226,7 +227,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
226
227
|
const error = rawError instanceof Error ? rawError : new Error(String(rawError));
|
|
227
228
|
if (options.onError) {
|
|
228
229
|
try {
|
|
229
|
-
options.onError(error, chunks);
|
|
230
|
+
await options.onError(error, chunks);
|
|
230
231
|
} catch (handlerError) {
|
|
231
232
|
console.error("Error in stream onError handler:", handlerError);
|
|
232
233
|
}
|
|
@@ -1578,6 +1579,15 @@ function addAzureBlobHeaders(headers, url) {
|
|
|
1578
1579
|
headers["x-ms-blob-type"] = "BlockBlob";
|
|
1579
1580
|
}
|
|
1580
1581
|
}
|
|
1582
|
+
function filterFrom(record, keys) {
|
|
1583
|
+
const out = {};
|
|
1584
|
+
for (const k of Object.keys(record)) {
|
|
1585
|
+
if (!keys.includes(k)) {
|
|
1586
|
+
out[k] = record[k];
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
return out;
|
|
1590
|
+
}
|
|
1581
1591
|
|
|
1582
1592
|
// src/generated_types.ts
|
|
1583
1593
|
var import_v36 = require("zod/v3");
|
|
@@ -8371,51 +8381,28 @@ function traceSyncStreamChannel(channel2, config) {
|
|
|
8371
8381
|
}
|
|
8372
8382
|
const { span, startTime } = spanData;
|
|
8373
8383
|
const endEvent = event;
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
return;
|
|
8388
|
-
}
|
|
8389
|
-
let first = true;
|
|
8390
|
-
stream.on("chunk", () => {
|
|
8391
|
-
if (first) {
|
|
8392
|
-
span.log({
|
|
8393
|
-
metrics: {
|
|
8394
|
-
time_to_first_token: getCurrentUnixTimestamp() - startTime
|
|
8395
|
-
}
|
|
8396
|
-
});
|
|
8397
|
-
first = false;
|
|
8398
|
-
}
|
|
8399
|
-
});
|
|
8400
|
-
stream.on("chatCompletion", (completion) => {
|
|
8401
|
-
try {
|
|
8402
|
-
if (hasChoices(completion)) {
|
|
8403
|
-
span.log({
|
|
8404
|
-
output: completion.choices
|
|
8405
|
-
});
|
|
8406
|
-
}
|
|
8407
|
-
} catch (error) {
|
|
8408
|
-
console.error(
|
|
8409
|
-
`Error extracting chatCompletion for ${channelName}:`,
|
|
8410
|
-
error
|
|
8411
|
-
);
|
|
8384
|
+
const handleResolvedResult = (result) => {
|
|
8385
|
+
const resolvedEndEvent = {
|
|
8386
|
+
...endEvent,
|
|
8387
|
+
result
|
|
8388
|
+
};
|
|
8389
|
+
if (config.patchResult?.({
|
|
8390
|
+
channelName,
|
|
8391
|
+
endEvent: resolvedEndEvent,
|
|
8392
|
+
result,
|
|
8393
|
+
span,
|
|
8394
|
+
startTime
|
|
8395
|
+
})) {
|
|
8396
|
+
return;
|
|
8412
8397
|
}
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8398
|
+
const stream = result;
|
|
8399
|
+
if (!isSyncStreamLike(stream)) {
|
|
8400
|
+
span.end();
|
|
8401
|
+
states.delete(event);
|
|
8416
8402
|
return;
|
|
8417
8403
|
}
|
|
8418
|
-
|
|
8404
|
+
let first = true;
|
|
8405
|
+
stream.on("chunk", () => {
|
|
8419
8406
|
if (first) {
|
|
8420
8407
|
span.log({
|
|
8421
8408
|
metrics: {
|
|
@@ -8424,25 +8411,55 @@ function traceSyncStreamChannel(channel2, config) {
|
|
|
8424
8411
|
});
|
|
8425
8412
|
first = false;
|
|
8426
8413
|
}
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8414
|
+
});
|
|
8415
|
+
stream.on("chatCompletion", (completion) => {
|
|
8416
|
+
try {
|
|
8417
|
+
if (hasChoices(completion)) {
|
|
8418
|
+
span.log({
|
|
8419
|
+
output: completion.choices
|
|
8420
|
+
});
|
|
8421
|
+
}
|
|
8422
|
+
} catch (error) {
|
|
8423
|
+
console.error(
|
|
8424
|
+
`Error extracting chatCompletion for ${channelName}:`,
|
|
8425
|
+
error
|
|
8426
|
+
);
|
|
8430
8427
|
}
|
|
8431
|
-
} catch (error) {
|
|
8432
|
-
console.error(`Error extracting event for ${channelName}:`, error);
|
|
8433
|
-
}
|
|
8434
|
-
});
|
|
8435
|
-
stream.on("end", () => {
|
|
8436
|
-
span.end();
|
|
8437
|
-
states.delete(event);
|
|
8438
|
-
});
|
|
8439
|
-
stream.on("error", (error) => {
|
|
8440
|
-
span.log({
|
|
8441
|
-
error: error.message
|
|
8442
8428
|
});
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8429
|
+
stream.on("event", (streamEvent) => {
|
|
8430
|
+
if (!config.extractFromEvent) {
|
|
8431
|
+
return;
|
|
8432
|
+
}
|
|
8433
|
+
try {
|
|
8434
|
+
if (first) {
|
|
8435
|
+
span.log({
|
|
8436
|
+
metrics: {
|
|
8437
|
+
time_to_first_token: getCurrentUnixTimestamp() - startTime
|
|
8438
|
+
}
|
|
8439
|
+
});
|
|
8440
|
+
first = false;
|
|
8441
|
+
}
|
|
8442
|
+
const extracted = config.extractFromEvent(streamEvent);
|
|
8443
|
+
if (extracted && Object.keys(extracted).length > 0) {
|
|
8444
|
+
span.log(extracted);
|
|
8445
|
+
}
|
|
8446
|
+
} catch (error) {
|
|
8447
|
+
console.error(`Error extracting event for ${channelName}:`, error);
|
|
8448
|
+
}
|
|
8449
|
+
});
|
|
8450
|
+
stream.on("end", () => {
|
|
8451
|
+
span.end();
|
|
8452
|
+
states.delete(event);
|
|
8453
|
+
});
|
|
8454
|
+
stream.on("error", (error) => {
|
|
8455
|
+
span.log({
|
|
8456
|
+
error: error.message
|
|
8457
|
+
});
|
|
8458
|
+
span.end();
|
|
8459
|
+
states.delete(event);
|
|
8460
|
+
});
|
|
8461
|
+
};
|
|
8462
|
+
handleResolvedResult(endEvent.result);
|
|
8446
8463
|
},
|
|
8447
8464
|
error: (event) => {
|
|
8448
8465
|
logErrorAndEnd(states, event);
|
|
@@ -9222,7 +9239,7 @@ var AnthropicPlugin = class extends BasePlugin {
|
|
|
9222
9239
|
this.unsubscribers.push(
|
|
9223
9240
|
traceStreamingChannel(anthropicChannels.betaMessagesCreate, {
|
|
9224
9241
|
...anthropicConfig,
|
|
9225
|
-
name: "anthropic.
|
|
9242
|
+
name: "anthropic.messages.create"
|
|
9226
9243
|
})
|
|
9227
9244
|
);
|
|
9228
9245
|
}
|
|
@@ -9245,9 +9262,12 @@ function parseMetricsFromUsage2(usage) {
|
|
|
9245
9262
|
return metrics;
|
|
9246
9263
|
}
|
|
9247
9264
|
function aggregateAnthropicStreamChunks(chunks) {
|
|
9248
|
-
const
|
|
9265
|
+
const fallbackTextDeltas = [];
|
|
9266
|
+
const contentBlocks = {};
|
|
9267
|
+
const contentBlockDeltas = {};
|
|
9249
9268
|
let metrics = {};
|
|
9250
9269
|
let metadata = {};
|
|
9270
|
+
let role;
|
|
9251
9271
|
for (const event of chunks) {
|
|
9252
9272
|
switch (event?.type) {
|
|
9253
9273
|
case "message_start":
|
|
@@ -9255,15 +9275,55 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
9255
9275
|
const initialMetrics = parseMetricsFromUsage2(event.message.usage);
|
|
9256
9276
|
metrics = { ...metrics, ...initialMetrics };
|
|
9257
9277
|
}
|
|
9278
|
+
if (typeof event.message?.role === "string") {
|
|
9279
|
+
role = event.message.role;
|
|
9280
|
+
}
|
|
9281
|
+
break;
|
|
9282
|
+
case "content_block_start":
|
|
9283
|
+
if (event.content_block) {
|
|
9284
|
+
contentBlocks[event.index] = event.content_block;
|
|
9285
|
+
contentBlockDeltas[event.index] = { textDeltas: [], citations: [] };
|
|
9286
|
+
}
|
|
9258
9287
|
break;
|
|
9259
|
-
case "content_block_delta":
|
|
9260
|
-
|
|
9261
|
-
|
|
9288
|
+
case "content_block_delta": {
|
|
9289
|
+
const acc = contentBlockDeltas[event.index];
|
|
9290
|
+
const delta = event.delta;
|
|
9291
|
+
if (!delta) break;
|
|
9292
|
+
if (delta.type === "text_delta" && "text" in delta) {
|
|
9293
|
+
const text = delta.text;
|
|
9262
9294
|
if (text) {
|
|
9263
|
-
|
|
9295
|
+
if (acc !== void 0) {
|
|
9296
|
+
acc.textDeltas.push(text);
|
|
9297
|
+
} else {
|
|
9298
|
+
fallbackTextDeltas.push(text);
|
|
9299
|
+
}
|
|
9300
|
+
}
|
|
9301
|
+
} else if (delta.type === "input_json_delta" && "partial_json" in delta) {
|
|
9302
|
+
const partialJson = delta.partial_json;
|
|
9303
|
+
if (partialJson && acc !== void 0) {
|
|
9304
|
+
acc.textDeltas.push(partialJson);
|
|
9305
|
+
}
|
|
9306
|
+
} else if (delta.type === "thinking_delta" && "thinking" in delta) {
|
|
9307
|
+
const thinking = delta.thinking;
|
|
9308
|
+
if (thinking && acc !== void 0) {
|
|
9309
|
+
acc.textDeltas.push(thinking);
|
|
9310
|
+
}
|
|
9311
|
+
} else if (delta.type === "citations_delta" && "citation" in delta) {
|
|
9312
|
+
const citation = delta.citation;
|
|
9313
|
+
if (citation && acc !== void 0) {
|
|
9314
|
+
acc.citations.push(citation);
|
|
9264
9315
|
}
|
|
9265
9316
|
}
|
|
9266
9317
|
break;
|
|
9318
|
+
}
|
|
9319
|
+
case "content_block_stop":
|
|
9320
|
+
finalizeContentBlock(
|
|
9321
|
+
event.index,
|
|
9322
|
+
contentBlocks,
|
|
9323
|
+
contentBlockDeltas,
|
|
9324
|
+
fallbackTextDeltas
|
|
9325
|
+
);
|
|
9326
|
+
break;
|
|
9267
9327
|
case "message_delta":
|
|
9268
9328
|
if (event.usage) {
|
|
9269
9329
|
const finalMetrics = parseMetricsFromUsage2(event.usage);
|
|
@@ -9275,7 +9335,21 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
9275
9335
|
break;
|
|
9276
9336
|
}
|
|
9277
9337
|
}
|
|
9278
|
-
const
|
|
9338
|
+
const orderedContent = Object.entries(contentBlocks).map(([index, block]) => ({
|
|
9339
|
+
block,
|
|
9340
|
+
index: Number(index)
|
|
9341
|
+
})).filter(({ block }) => block !== void 0).sort((left, right) => left.index - right.index).map(({ block }) => block);
|
|
9342
|
+
let output = fallbackTextDeltas.join("");
|
|
9343
|
+
if (orderedContent.length > 0) {
|
|
9344
|
+
if (orderedContent.every(isTextContentBlock) && orderedContent.every((block) => !block.citations?.length)) {
|
|
9345
|
+
output = orderedContent.map((block) => block.text).join("");
|
|
9346
|
+
} else {
|
|
9347
|
+
output = {
|
|
9348
|
+
...role ? { role } : {},
|
|
9349
|
+
content: orderedContent
|
|
9350
|
+
};
|
|
9351
|
+
}
|
|
9352
|
+
}
|
|
9279
9353
|
const finalized = finalizeAnthropicTokens(metrics);
|
|
9280
9354
|
const filteredMetrics = Object.fromEntries(
|
|
9281
9355
|
Object.entries(finalized).filter(
|
|
@@ -9288,6 +9362,61 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
9288
9362
|
metadata
|
|
9289
9363
|
};
|
|
9290
9364
|
}
|
|
9365
|
+
function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallbackTextDeltas) {
|
|
9366
|
+
const contentBlock = contentBlocks[index];
|
|
9367
|
+
if (!contentBlock) {
|
|
9368
|
+
return;
|
|
9369
|
+
}
|
|
9370
|
+
const acc = contentBlockDeltas[index];
|
|
9371
|
+
const text = acc?.textDeltas.join("") ?? "";
|
|
9372
|
+
if (isToolUseContentBlock(contentBlock)) {
|
|
9373
|
+
if (!text) {
|
|
9374
|
+
return;
|
|
9375
|
+
}
|
|
9376
|
+
try {
|
|
9377
|
+
contentBlocks[index] = {
|
|
9378
|
+
...contentBlock,
|
|
9379
|
+
input: JSON.parse(text)
|
|
9380
|
+
};
|
|
9381
|
+
} catch {
|
|
9382
|
+
fallbackTextDeltas.push(text);
|
|
9383
|
+
delete contentBlocks[index];
|
|
9384
|
+
}
|
|
9385
|
+
return;
|
|
9386
|
+
}
|
|
9387
|
+
if (isTextContentBlock(contentBlock)) {
|
|
9388
|
+
if (!text) {
|
|
9389
|
+
delete contentBlocks[index];
|
|
9390
|
+
return;
|
|
9391
|
+
}
|
|
9392
|
+
const updated = { ...contentBlock, text };
|
|
9393
|
+
if (acc?.citations.length) {
|
|
9394
|
+
updated.citations = acc.citations;
|
|
9395
|
+
}
|
|
9396
|
+
contentBlocks[index] = updated;
|
|
9397
|
+
return;
|
|
9398
|
+
}
|
|
9399
|
+
if (isThinkingContentBlock(contentBlock)) {
|
|
9400
|
+
if (!text) {
|
|
9401
|
+
delete contentBlocks[index];
|
|
9402
|
+
return;
|
|
9403
|
+
}
|
|
9404
|
+
contentBlocks[index] = {
|
|
9405
|
+
...contentBlock,
|
|
9406
|
+
thinking: text
|
|
9407
|
+
};
|
|
9408
|
+
return;
|
|
9409
|
+
}
|
|
9410
|
+
}
|
|
9411
|
+
function isTextContentBlock(contentBlock) {
|
|
9412
|
+
return contentBlock.type === "text";
|
|
9413
|
+
}
|
|
9414
|
+
function isToolUseContentBlock(contentBlock) {
|
|
9415
|
+
return contentBlock.type === "tool_use";
|
|
9416
|
+
}
|
|
9417
|
+
function isThinkingContentBlock(contentBlock) {
|
|
9418
|
+
return contentBlock.type === "thinking";
|
|
9419
|
+
}
|
|
9291
9420
|
function isAnthropicBase64ContentBlock(input) {
|
|
9292
9421
|
return (input.type === "image" || input.type === "document") && isObject(input.source) && input.source.type === "base64";
|
|
9293
9422
|
}
|
|
@@ -9342,15 +9471,6 @@ function coalesceInput(messages, system) {
|
|
|
9342
9471
|
}
|
|
9343
9472
|
return input;
|
|
9344
9473
|
}
|
|
9345
|
-
function filterFrom(obj, fieldsToRemove) {
|
|
9346
|
-
const result = {};
|
|
9347
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
9348
|
-
if (!fieldsToRemove.includes(key)) {
|
|
9349
|
-
result[key] = value;
|
|
9350
|
-
}
|
|
9351
|
-
}
|
|
9352
|
-
return result;
|
|
9353
|
-
}
|
|
9354
9474
|
|
|
9355
9475
|
// src/wrappers/ai-sdk/normalize-logged-output.ts
|
|
9356
9476
|
var REMOVE_NORMALIZED_VALUE = Symbol("braintrust.ai-sdk.remove-normalized");
|
|
@@ -9464,10 +9584,6 @@ var aiSDKChannels = defineChannels("ai", {
|
|
|
9464
9584
|
channelName: "streamText",
|
|
9465
9585
|
kind: "async"
|
|
9466
9586
|
}),
|
|
9467
|
-
streamTextSync: channel({
|
|
9468
|
-
channelName: "streamText.sync",
|
|
9469
|
-
kind: "sync-stream"
|
|
9470
|
-
}),
|
|
9471
9587
|
generateObject: channel({
|
|
9472
9588
|
channelName: "generateObject",
|
|
9473
9589
|
kind: "async"
|
|
@@ -9476,10 +9592,6 @@ var aiSDKChannels = defineChannels("ai", {
|
|
|
9476
9592
|
channelName: "streamObject",
|
|
9477
9593
|
kind: "async"
|
|
9478
9594
|
}),
|
|
9479
|
-
streamObjectSync: channel({
|
|
9480
|
-
channelName: "streamObject.sync",
|
|
9481
|
-
kind: "sync-stream"
|
|
9482
|
-
}),
|
|
9483
9595
|
agentGenerate: channel({
|
|
9484
9596
|
channelName: "Agent.generate",
|
|
9485
9597
|
kind: "async"
|
|
@@ -9515,6 +9627,9 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
|
|
|
9515
9627
|
];
|
|
9516
9628
|
var AUTO_PATCHED_MODEL = Symbol.for("braintrust.ai-sdk.auto-patched-model");
|
|
9517
9629
|
var AUTO_PATCHED_TOOL = Symbol.for("braintrust.ai-sdk.auto-patched-tool");
|
|
9630
|
+
var RUNTIME_DENY_OUTPUT_PATHS = Symbol.for(
|
|
9631
|
+
"braintrust.ai-sdk.deny-output-paths"
|
|
9632
|
+
);
|
|
9518
9633
|
var AISDKPlugin = class extends BasePlugin {
|
|
9519
9634
|
config;
|
|
9520
9635
|
constructor(config = {}) {
|
|
@@ -9536,7 +9651,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9536
9651
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9537
9652
|
extractOutput: (result, endEvent) => {
|
|
9538
9653
|
finalizeAISDKChildTracing(endEvent);
|
|
9539
|
-
return processAISDKOutput(
|
|
9654
|
+
return processAISDKOutput(
|
|
9655
|
+
result,
|
|
9656
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9657
|
+
);
|
|
9540
9658
|
},
|
|
9541
9659
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9542
9660
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -9547,25 +9665,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9547
9665
|
name: "streamText",
|
|
9548
9666
|
type: "llm" /* LLM */,
|
|
9549
9667
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9550
|
-
extractOutput: (result) => processAISDKOutput(
|
|
9668
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
9669
|
+
result,
|
|
9670
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9671
|
+
),
|
|
9551
9672
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9552
9673
|
aggregateChunks: aggregateAISDKChunks,
|
|
9553
9674
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9554
|
-
denyOutputPaths,
|
|
9555
|
-
endEvent,
|
|
9556
|
-
result,
|
|
9557
|
-
span,
|
|
9558
|
-
startTime
|
|
9559
|
-
})
|
|
9560
|
-
})
|
|
9561
|
-
);
|
|
9562
|
-
this.unsubscribers.push(
|
|
9563
|
-
traceSyncStreamChannel(aiSDKChannels.streamTextSync, {
|
|
9564
|
-
name: "streamText",
|
|
9565
|
-
type: "llm" /* LLM */,
|
|
9566
|
-
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9567
|
-
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9568
|
-
denyOutputPaths,
|
|
9675
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
9569
9676
|
endEvent,
|
|
9570
9677
|
result,
|
|
9571
9678
|
span,
|
|
@@ -9580,7 +9687,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9580
9687
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9581
9688
|
extractOutput: (result, endEvent) => {
|
|
9582
9689
|
finalizeAISDKChildTracing(endEvent);
|
|
9583
|
-
return processAISDKOutput(
|
|
9690
|
+
return processAISDKOutput(
|
|
9691
|
+
result,
|
|
9692
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9693
|
+
);
|
|
9584
9694
|
},
|
|
9585
9695
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9586
9696
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -9591,25 +9701,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9591
9701
|
name: "streamObject",
|
|
9592
9702
|
type: "llm" /* LLM */,
|
|
9593
9703
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9594
|
-
extractOutput: (result) => processAISDKOutput(
|
|
9704
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
9705
|
+
result,
|
|
9706
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9707
|
+
),
|
|
9595
9708
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9596
9709
|
aggregateChunks: aggregateAISDKChunks,
|
|
9597
9710
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9598
|
-
denyOutputPaths,
|
|
9599
|
-
endEvent,
|
|
9600
|
-
result,
|
|
9601
|
-
span,
|
|
9602
|
-
startTime
|
|
9603
|
-
})
|
|
9604
|
-
})
|
|
9605
|
-
);
|
|
9606
|
-
this.unsubscribers.push(
|
|
9607
|
-
traceSyncStreamChannel(aiSDKChannels.streamObjectSync, {
|
|
9608
|
-
name: "streamObject",
|
|
9609
|
-
type: "llm" /* LLM */,
|
|
9610
|
-
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9611
|
-
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9612
|
-
denyOutputPaths,
|
|
9711
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
9613
9712
|
endEvent,
|
|
9614
9713
|
result,
|
|
9615
9714
|
span,
|
|
@@ -9624,7 +9723,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9624
9723
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9625
9724
|
extractOutput: (result, endEvent) => {
|
|
9626
9725
|
finalizeAISDKChildTracing(endEvent);
|
|
9627
|
-
return processAISDKOutput(
|
|
9726
|
+
return processAISDKOutput(
|
|
9727
|
+
result,
|
|
9728
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9729
|
+
);
|
|
9628
9730
|
},
|
|
9629
9731
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9630
9732
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -9635,11 +9737,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9635
9737
|
name: "Agent.stream",
|
|
9636
9738
|
type: "llm" /* LLM */,
|
|
9637
9739
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9638
|
-
extractOutput: (result) => processAISDKOutput(
|
|
9740
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
9741
|
+
result,
|
|
9742
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9743
|
+
),
|
|
9639
9744
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9640
9745
|
aggregateChunks: aggregateAISDKChunks,
|
|
9641
9746
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9642
|
-
denyOutputPaths,
|
|
9747
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
9643
9748
|
endEvent,
|
|
9644
9749
|
result,
|
|
9645
9750
|
span,
|
|
@@ -9654,7 +9759,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9654
9759
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9655
9760
|
extractOutput: (result, endEvent) => {
|
|
9656
9761
|
finalizeAISDKChildTracing(endEvent);
|
|
9657
|
-
return processAISDKOutput(
|
|
9762
|
+
return processAISDKOutput(
|
|
9763
|
+
result,
|
|
9764
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9765
|
+
);
|
|
9658
9766
|
},
|
|
9659
9767
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
9660
9768
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -9665,11 +9773,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9665
9773
|
name: "ToolLoopAgent.stream",
|
|
9666
9774
|
type: "llm" /* LLM */,
|
|
9667
9775
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
9668
|
-
extractOutput: (result) => processAISDKOutput(
|
|
9776
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
9777
|
+
result,
|
|
9778
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
9779
|
+
),
|
|
9669
9780
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
9670
9781
|
aggregateChunks: aggregateAISDKChunks,
|
|
9671
9782
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
9672
|
-
denyOutputPaths,
|
|
9783
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
9673
9784
|
endEvent,
|
|
9674
9785
|
result,
|
|
9675
9786
|
span,
|
|
@@ -9679,80 +9790,378 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
9679
9790
|
);
|
|
9680
9791
|
}
|
|
9681
9792
|
};
|
|
9682
|
-
function
|
|
9683
|
-
if (
|
|
9684
|
-
|
|
9685
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
9686
|
-
return input;
|
|
9793
|
+
function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
|
|
9794
|
+
if (Array.isArray(event?.denyOutputPaths)) {
|
|
9795
|
+
return event.denyOutputPaths;
|
|
9687
9796
|
}
|
|
9688
|
-
const
|
|
9689
|
-
|
|
9690
|
-
|
|
9691
|
-
function prepareAISDKInput(params, event, span, denyOutputPaths) {
|
|
9692
|
-
const input = processAISDKInput(params);
|
|
9693
|
-
const metadata = extractMetadataFromParams(params, event.self);
|
|
9694
|
-
const childTracing = prepareAISDKChildTracing(
|
|
9695
|
-
params,
|
|
9696
|
-
event.self,
|
|
9697
|
-
span,
|
|
9698
|
-
denyOutputPaths
|
|
9699
|
-
);
|
|
9700
|
-
event.__braintrust_ai_sdk_model_wrapped = childTracing.modelWrapped;
|
|
9701
|
-
if (childTracing.cleanup) {
|
|
9702
|
-
event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
|
|
9797
|
+
const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
|
|
9798
|
+
if (!firstArgument || typeof firstArgument !== "object") {
|
|
9799
|
+
return defaultDenyOutputPaths;
|
|
9703
9800
|
}
|
|
9704
|
-
|
|
9705
|
-
|
|
9706
|
-
|
|
9707
|
-
};
|
|
9708
|
-
}
|
|
9709
|
-
function extractTopLevelAISDKMetrics(result, event, startTime) {
|
|
9710
|
-
const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
|
|
9711
|
-
if (startTime) {
|
|
9712
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
9801
|
+
const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
|
|
9802
|
+
if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path) => typeof path === "string")) {
|
|
9803
|
+
return runtimeDenyOutputPaths;
|
|
9713
9804
|
}
|
|
9714
|
-
return
|
|
9715
|
-
}
|
|
9716
|
-
function hasModelChildTracing(event) {
|
|
9717
|
-
return event?.__braintrust_ai_sdk_model_wrapped === true;
|
|
9805
|
+
return defaultDenyOutputPaths;
|
|
9718
9806
|
}
|
|
9719
|
-
|
|
9720
|
-
|
|
9721
|
-
|
|
9722
|
-
|
|
9723
|
-
|
|
9807
|
+
var isZodSchema2 = (value) => {
|
|
9808
|
+
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
9809
|
+
};
|
|
9810
|
+
var serializeZodSchema2 = (schema) => {
|
|
9811
|
+
try {
|
|
9812
|
+
return zodToJsonSchema(schema);
|
|
9813
|
+
} catch {
|
|
9814
|
+
return {
|
|
9815
|
+
type: "object",
|
|
9816
|
+
description: "Zod schema (conversion failed)"
|
|
9817
|
+
};
|
|
9818
|
+
}
|
|
9819
|
+
};
|
|
9820
|
+
var isOutputObject = (value) => {
|
|
9821
|
+
if (value == null || typeof value !== "object") {
|
|
9822
|
+
return false;
|
|
9823
|
+
}
|
|
9824
|
+
const output = value;
|
|
9825
|
+
if (!("responseFormat" in output)) {
|
|
9826
|
+
return false;
|
|
9827
|
+
}
|
|
9828
|
+
if (output.type === "object" || output.type === "text") {
|
|
9829
|
+
return true;
|
|
9830
|
+
}
|
|
9831
|
+
if (typeof output.responseFormat === "function" || typeof output.responseFormat === "object") {
|
|
9832
|
+
return true;
|
|
9833
|
+
}
|
|
9834
|
+
return false;
|
|
9835
|
+
};
|
|
9836
|
+
var serializeOutputObject = (output, model) => {
|
|
9837
|
+
try {
|
|
9838
|
+
const result = {
|
|
9839
|
+
response_format: null
|
|
9840
|
+
};
|
|
9841
|
+
if (output.type) {
|
|
9842
|
+
result.type = output.type;
|
|
9843
|
+
}
|
|
9844
|
+
let responseFormat;
|
|
9845
|
+
if (typeof output.responseFormat === "function") {
|
|
9846
|
+
const mockModelForSchema = {
|
|
9847
|
+
supportsStructuredOutputs: true,
|
|
9848
|
+
...model && typeof model === "object" ? model : {}
|
|
9849
|
+
};
|
|
9850
|
+
responseFormat = output.responseFormat({ model: mockModelForSchema });
|
|
9851
|
+
} else if (output.responseFormat != null && typeof output.responseFormat === "object") {
|
|
9852
|
+
responseFormat = output.responseFormat;
|
|
9853
|
+
}
|
|
9854
|
+
if (responseFormat) {
|
|
9855
|
+
if (typeof responseFormat.then === "function") {
|
|
9856
|
+
result.response_format = Promise.resolve(responseFormat).then(
|
|
9857
|
+
(resolved) => {
|
|
9858
|
+
if (resolved.schema && isZodSchema2(resolved.schema)) {
|
|
9859
|
+
return {
|
|
9860
|
+
...resolved,
|
|
9861
|
+
schema: serializeZodSchema2(resolved.schema)
|
|
9862
|
+
};
|
|
9863
|
+
}
|
|
9864
|
+
return resolved;
|
|
9865
|
+
}
|
|
9866
|
+
);
|
|
9867
|
+
} else {
|
|
9868
|
+
const syncResponseFormat = responseFormat;
|
|
9869
|
+
if (syncResponseFormat.schema && isZodSchema2(syncResponseFormat.schema)) {
|
|
9870
|
+
responseFormat = {
|
|
9871
|
+
...syncResponseFormat,
|
|
9872
|
+
schema: serializeZodSchema2(syncResponseFormat.schema)
|
|
9873
|
+
};
|
|
9874
|
+
}
|
|
9875
|
+
result.response_format = responseFormat;
|
|
9876
|
+
}
|
|
9724
9877
|
}
|
|
9725
|
-
|
|
9726
|
-
|
|
9727
|
-
|
|
9728
|
-
|
|
9729
|
-
|
|
9730
|
-
if (model) {
|
|
9731
|
-
metadata.model = model;
|
|
9878
|
+
return result;
|
|
9879
|
+
} catch {
|
|
9880
|
+
return {
|
|
9881
|
+
response_format: null
|
|
9882
|
+
};
|
|
9732
9883
|
}
|
|
9733
|
-
|
|
9734
|
-
|
|
9884
|
+
};
|
|
9885
|
+
var processInputAttachmentsSync = (input) => {
|
|
9886
|
+
if (!input) return { input };
|
|
9887
|
+
const processed = { ...input };
|
|
9888
|
+
if (input.messages && Array.isArray(input.messages)) {
|
|
9889
|
+
processed.messages = input.messages.map(processMessage);
|
|
9890
|
+
}
|
|
9891
|
+
if (input.prompt && typeof input.prompt === "object") {
|
|
9892
|
+
if (Array.isArray(input.prompt)) {
|
|
9893
|
+
processed.prompt = input.prompt.map(processMessage);
|
|
9894
|
+
} else {
|
|
9895
|
+
processed.prompt = processPromptContent(input.prompt);
|
|
9896
|
+
}
|
|
9735
9897
|
}
|
|
9736
|
-
|
|
9737
|
-
|
|
9738
|
-
metadata.tools = tools;
|
|
9898
|
+
if (input.schema && isZodSchema2(input.schema)) {
|
|
9899
|
+
processed.schema = serializeZodSchema2(input.schema);
|
|
9739
9900
|
}
|
|
9740
|
-
|
|
9741
|
-
|
|
9742
|
-
|
|
9743
|
-
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
let
|
|
9747
|
-
|
|
9748
|
-
const
|
|
9749
|
-
if (
|
|
9750
|
-
|
|
9901
|
+
if (input.callOptionsSchema && isZodSchema2(input.callOptionsSchema)) {
|
|
9902
|
+
processed.callOptionsSchema = serializeZodSchema2(input.callOptionsSchema);
|
|
9903
|
+
}
|
|
9904
|
+
if (input.tools) {
|
|
9905
|
+
processed.tools = serializeAISDKToolsForLogging(input.tools);
|
|
9906
|
+
}
|
|
9907
|
+
let outputPromise;
|
|
9908
|
+
if (input.output && isOutputObject(input.output)) {
|
|
9909
|
+
const serialized = serializeOutputObject(input.output, input.model);
|
|
9910
|
+
if (serialized.response_format && typeof serialized.response_format.then === "function") {
|
|
9911
|
+
processed.output = { ...serialized, response_format: {} };
|
|
9912
|
+
outputPromise = serialized.response_format.then(
|
|
9913
|
+
(resolvedFormat) => ({
|
|
9914
|
+
output: { ...serialized, response_format: resolvedFormat }
|
|
9915
|
+
})
|
|
9916
|
+
);
|
|
9917
|
+
} else {
|
|
9918
|
+
processed.output = serialized;
|
|
9751
9919
|
}
|
|
9752
|
-
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9920
|
+
}
|
|
9921
|
+
if ("prepareCall" in processed && typeof processed.prepareCall === "function") {
|
|
9922
|
+
processed.prepareCall = "[Function]";
|
|
9923
|
+
}
|
|
9924
|
+
return { input: processed, outputPromise };
|
|
9925
|
+
};
|
|
9926
|
+
var processMessage = (message) => {
|
|
9927
|
+
if (!message || typeof message !== "object") return message;
|
|
9928
|
+
if (Array.isArray(message.content)) {
|
|
9929
|
+
return {
|
|
9930
|
+
...message,
|
|
9931
|
+
content: message.content.map(processContentPart)
|
|
9932
|
+
};
|
|
9933
|
+
}
|
|
9934
|
+
if (typeof message.content === "object" && message.content !== null) {
|
|
9935
|
+
return {
|
|
9936
|
+
...message,
|
|
9937
|
+
content: processContentPart(message.content)
|
|
9938
|
+
};
|
|
9939
|
+
}
|
|
9940
|
+
return message;
|
|
9941
|
+
};
|
|
9942
|
+
var processPromptContent = (prompt) => {
|
|
9943
|
+
if (Array.isArray(prompt)) {
|
|
9944
|
+
return prompt.map(processContentPart);
|
|
9945
|
+
}
|
|
9946
|
+
if (prompt.content) {
|
|
9947
|
+
if (Array.isArray(prompt.content)) {
|
|
9948
|
+
return {
|
|
9949
|
+
...prompt,
|
|
9950
|
+
content: prompt.content.map(processContentPart)
|
|
9951
|
+
};
|
|
9952
|
+
} else if (typeof prompt.content === "object") {
|
|
9953
|
+
return {
|
|
9954
|
+
...prompt,
|
|
9955
|
+
content: processContentPart(prompt.content)
|
|
9956
|
+
};
|
|
9957
|
+
}
|
|
9958
|
+
}
|
|
9959
|
+
return prompt;
|
|
9960
|
+
};
|
|
9961
|
+
var processContentPart = (part) => {
|
|
9962
|
+
if (!part || typeof part !== "object") return part;
|
|
9963
|
+
try {
|
|
9964
|
+
if (part.type === "image" && part.image) {
|
|
9965
|
+
const imageAttachment = convertImageToAttachment(
|
|
9966
|
+
part.image,
|
|
9967
|
+
part.mimeType || part.mediaType
|
|
9968
|
+
);
|
|
9969
|
+
if (imageAttachment) {
|
|
9970
|
+
return {
|
|
9971
|
+
...part,
|
|
9972
|
+
image: imageAttachment
|
|
9973
|
+
};
|
|
9974
|
+
}
|
|
9975
|
+
}
|
|
9976
|
+
if (part.type === "file" && part.data && (part.mimeType || part.mediaType)) {
|
|
9977
|
+
const fileAttachment = convertDataToAttachment(
|
|
9978
|
+
part.data,
|
|
9979
|
+
part.mimeType || part.mediaType,
|
|
9980
|
+
part.name || part.filename
|
|
9981
|
+
);
|
|
9982
|
+
if (fileAttachment) {
|
|
9983
|
+
return {
|
|
9984
|
+
...part,
|
|
9985
|
+
data: fileAttachment
|
|
9986
|
+
};
|
|
9987
|
+
}
|
|
9988
|
+
}
|
|
9989
|
+
if (part.type === "image_url" && part.image_url) {
|
|
9990
|
+
if (typeof part.image_url === "object" && part.image_url.url) {
|
|
9991
|
+
const imageAttachment = convertImageToAttachment(part.image_url.url);
|
|
9992
|
+
if (imageAttachment) {
|
|
9993
|
+
return {
|
|
9994
|
+
...part,
|
|
9995
|
+
image_url: {
|
|
9996
|
+
...part.image_url,
|
|
9997
|
+
url: imageAttachment
|
|
9998
|
+
}
|
|
9999
|
+
};
|
|
10000
|
+
}
|
|
10001
|
+
}
|
|
10002
|
+
}
|
|
10003
|
+
} catch (error) {
|
|
10004
|
+
console.warn("Error processing content part:", error);
|
|
10005
|
+
}
|
|
10006
|
+
return part;
|
|
10007
|
+
};
|
|
10008
|
+
var convertImageToAttachment = (image, explicitMimeType) => {
|
|
10009
|
+
try {
|
|
10010
|
+
if (typeof image === "string" && image.startsWith("data:")) {
|
|
10011
|
+
const [mimeTypeSection, base64Data] = image.split(",");
|
|
10012
|
+
const mimeType = mimeTypeSection.match(/data:(.*?);/)?.[1];
|
|
10013
|
+
if (mimeType && base64Data) {
|
|
10014
|
+
const blob = convertDataToBlob(base64Data, mimeType);
|
|
10015
|
+
if (blob) {
|
|
10016
|
+
return new Attachment({
|
|
10017
|
+
data: blob,
|
|
10018
|
+
filename: `image.${getExtensionFromMediaType(mimeType)}`,
|
|
10019
|
+
contentType: mimeType
|
|
10020
|
+
});
|
|
10021
|
+
}
|
|
10022
|
+
}
|
|
10023
|
+
}
|
|
10024
|
+
if (explicitMimeType) {
|
|
10025
|
+
if (image instanceof Uint8Array) {
|
|
10026
|
+
return new Attachment({
|
|
10027
|
+
data: new Blob([image], { type: explicitMimeType }),
|
|
10028
|
+
filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
|
|
10029
|
+
contentType: explicitMimeType
|
|
10030
|
+
});
|
|
10031
|
+
}
|
|
10032
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
|
|
10033
|
+
return new Attachment({
|
|
10034
|
+
data: new Blob([image], { type: explicitMimeType }),
|
|
10035
|
+
filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
|
|
10036
|
+
contentType: explicitMimeType
|
|
10037
|
+
});
|
|
10038
|
+
}
|
|
10039
|
+
}
|
|
10040
|
+
if (image instanceof Blob && image.type) {
|
|
10041
|
+
return new Attachment({
|
|
10042
|
+
data: image,
|
|
10043
|
+
filename: `image.${getExtensionFromMediaType(image.type)}`,
|
|
10044
|
+
contentType: image.type
|
|
10045
|
+
});
|
|
10046
|
+
}
|
|
10047
|
+
if (image instanceof Attachment) {
|
|
10048
|
+
return image;
|
|
10049
|
+
}
|
|
10050
|
+
} catch (error) {
|
|
10051
|
+
console.warn("Error converting image to attachment:", error);
|
|
10052
|
+
}
|
|
10053
|
+
return null;
|
|
10054
|
+
};
|
|
10055
|
+
var convertDataToAttachment = (data, mimeType, filename) => {
|
|
10056
|
+
if (!mimeType) return null;
|
|
10057
|
+
try {
|
|
10058
|
+
let blob = null;
|
|
10059
|
+
if (typeof data === "string" && data.startsWith("data:")) {
|
|
10060
|
+
const [, base64Data] = data.split(",");
|
|
10061
|
+
if (base64Data) {
|
|
10062
|
+
blob = convertDataToBlob(base64Data, mimeType);
|
|
10063
|
+
}
|
|
10064
|
+
} else if (typeof data === "string" && data.length > 0) {
|
|
10065
|
+
blob = convertDataToBlob(data, mimeType);
|
|
10066
|
+
} else if (data instanceof Uint8Array) {
|
|
10067
|
+
blob = new Blob([data], { type: mimeType });
|
|
10068
|
+
} else if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
|
|
10069
|
+
blob = new Blob([data], { type: mimeType });
|
|
10070
|
+
} else if (data instanceof Blob) {
|
|
10071
|
+
blob = data;
|
|
10072
|
+
}
|
|
10073
|
+
if (blob) {
|
|
10074
|
+
return new Attachment({
|
|
10075
|
+
data: blob,
|
|
10076
|
+
filename: filename || `file.${getExtensionFromMediaType(mimeType)}`,
|
|
10077
|
+
contentType: mimeType
|
|
10078
|
+
});
|
|
10079
|
+
}
|
|
10080
|
+
} catch (error) {
|
|
10081
|
+
console.warn("Error converting data to attachment:", error);
|
|
10082
|
+
}
|
|
10083
|
+
return null;
|
|
10084
|
+
};
|
|
10085
|
+
function processAISDKInput(params) {
|
|
10086
|
+
return processInputAttachmentsSync(params);
|
|
10087
|
+
}
|
|
10088
|
+
function prepareAISDKInput(params, event, span, defaultDenyOutputPaths) {
|
|
10089
|
+
const { input, outputPromise } = processAISDKInput(params);
|
|
10090
|
+
if (outputPromise && input && typeof input === "object") {
|
|
10091
|
+
outputPromise.then((resolvedData) => {
|
|
10092
|
+
span.log({
|
|
10093
|
+
input: {
|
|
10094
|
+
...input,
|
|
10095
|
+
...resolvedData
|
|
10096
|
+
}
|
|
10097
|
+
});
|
|
10098
|
+
}).catch(() => {
|
|
10099
|
+
});
|
|
10100
|
+
}
|
|
10101
|
+
const metadata = extractMetadataFromParams(params, event.self);
|
|
10102
|
+
const childTracing = prepareAISDKChildTracing(
|
|
10103
|
+
params,
|
|
10104
|
+
event.self,
|
|
10105
|
+
span,
|
|
10106
|
+
defaultDenyOutputPaths,
|
|
10107
|
+
event.aiSDK
|
|
10108
|
+
);
|
|
10109
|
+
event.modelWrapped = childTracing.modelWrapped;
|
|
10110
|
+
if (childTracing.cleanup) {
|
|
10111
|
+
event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
|
|
10112
|
+
}
|
|
10113
|
+
return {
|
|
10114
|
+
input,
|
|
10115
|
+
metadata
|
|
10116
|
+
};
|
|
10117
|
+
}
|
|
10118
|
+
function extractTopLevelAISDKMetrics(result, event, startTime) {
|
|
10119
|
+
const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
|
|
10120
|
+
if (startTime) {
|
|
10121
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
10122
|
+
}
|
|
10123
|
+
return metrics;
|
|
10124
|
+
}
|
|
10125
|
+
function hasModelChildTracing(event) {
|
|
10126
|
+
return event?.modelWrapped === true || event?.__braintrust_ai_sdk_model_wrapped === true;
|
|
10127
|
+
}
|
|
10128
|
+
function extractMetadataFromParams(params, self) {
|
|
10129
|
+
const metadata = {
|
|
10130
|
+
braintrust: {
|
|
10131
|
+
integration_name: "ai-sdk",
|
|
10132
|
+
sdk_language: "typescript"
|
|
10133
|
+
}
|
|
10134
|
+
};
|
|
10135
|
+
const agentModel = self && typeof self === "object" && "model" in self && self.model ? self.model : self && typeof self === "object" && "settings" in self && self.settings?.model ? self.settings?.model : void 0;
|
|
10136
|
+
const { model, provider } = serializeModelWithProvider(
|
|
10137
|
+
params.model ?? agentModel
|
|
10138
|
+
);
|
|
10139
|
+
if (model) {
|
|
10140
|
+
metadata.model = model;
|
|
10141
|
+
}
|
|
10142
|
+
if (provider) {
|
|
10143
|
+
metadata.provider = provider;
|
|
10144
|
+
}
|
|
10145
|
+
const tools = serializeAISDKToolsForLogging(params.tools);
|
|
10146
|
+
if (tools) {
|
|
10147
|
+
metadata.tools = tools;
|
|
10148
|
+
}
|
|
10149
|
+
return metadata;
|
|
10150
|
+
}
|
|
10151
|
+
function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiSDK) {
|
|
10152
|
+
const cleanup = [];
|
|
10153
|
+
const patchedModels = /* @__PURE__ */ new WeakSet();
|
|
10154
|
+
const patchedTools = /* @__PURE__ */ new WeakSet();
|
|
10155
|
+
let modelWrapped = false;
|
|
10156
|
+
const patchModel = (model) => {
|
|
10157
|
+
const resolvedModel = resolveAISDKModel(model, aiSDK);
|
|
10158
|
+
if (!resolvedModel || typeof resolvedModel !== "object" || typeof resolvedModel.doGenerate !== "function" || patchedModels.has(resolvedModel) || resolvedModel[AUTO_PATCHED_MODEL]) {
|
|
10159
|
+
return resolvedModel;
|
|
10160
|
+
}
|
|
10161
|
+
patchedModels.add(resolvedModel);
|
|
10162
|
+
resolvedModel[AUTO_PATCHED_MODEL] = true;
|
|
10163
|
+
modelWrapped = true;
|
|
10164
|
+
const originalDoGenerate = resolvedModel.doGenerate;
|
|
9756
10165
|
const originalDoStream = resolvedModel.doStream;
|
|
9757
10166
|
const baseMetadata = buildAISDKChildMetadata(resolvedModel);
|
|
9758
10167
|
resolvedModel.doGenerate = async function doGeneratePatched(options) {
|
|
@@ -9776,7 +10185,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
9776
10185
|
type: "llm" /* LLM */
|
|
9777
10186
|
},
|
|
9778
10187
|
event: {
|
|
9779
|
-
input: processAISDKInput(options),
|
|
10188
|
+
input: processAISDKInput(options).input,
|
|
9780
10189
|
metadata: baseMetadata
|
|
9781
10190
|
}
|
|
9782
10191
|
}
|
|
@@ -9790,7 +10199,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
9790
10199
|
type: "llm" /* LLM */
|
|
9791
10200
|
},
|
|
9792
10201
|
event: {
|
|
9793
|
-
input: processAISDKInput(options),
|
|
10202
|
+
input: processAISDKInput(options).input,
|
|
9794
10203
|
metadata: baseMetadata
|
|
9795
10204
|
}
|
|
9796
10205
|
});
|
|
@@ -9798,6 +10207,8 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
9798
10207
|
span,
|
|
9799
10208
|
() => Reflect.apply(originalDoStream, resolvedModel, [options])
|
|
9800
10209
|
);
|
|
10210
|
+
const streamStartTime = getCurrentUnixTimestamp();
|
|
10211
|
+
let firstChunkTime;
|
|
9801
10212
|
const output = {};
|
|
9802
10213
|
let text = "";
|
|
9803
10214
|
let reasoning = "";
|
|
@@ -9805,6 +10216,9 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
9805
10216
|
let object = void 0;
|
|
9806
10217
|
const transformStream = new TransformStream({
|
|
9807
10218
|
transform(chunk, controller) {
|
|
10219
|
+
if (firstChunkTime === void 0) {
|
|
10220
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
10221
|
+
}
|
|
9808
10222
|
switch (chunk.type) {
|
|
9809
10223
|
case "text-delta":
|
|
9810
10224
|
text += extractTextDelta(chunk);
|
|
@@ -9845,12 +10259,19 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
9845
10259
|
if (object !== void 0) {
|
|
9846
10260
|
output.object = object;
|
|
9847
10261
|
}
|
|
10262
|
+
const metrics = extractTokenMetrics(output);
|
|
10263
|
+
if (firstChunkTime !== void 0) {
|
|
10264
|
+
metrics.time_to_first_token = Math.max(
|
|
10265
|
+
firstChunkTime - streamStartTime,
|
|
10266
|
+
1e-6
|
|
10267
|
+
);
|
|
10268
|
+
}
|
|
9848
10269
|
span.log({
|
|
9849
10270
|
output: processAISDKOutput(
|
|
9850
10271
|
output,
|
|
9851
10272
|
denyOutputPaths
|
|
9852
10273
|
),
|
|
9853
|
-
metrics
|
|
10274
|
+
metrics,
|
|
9854
10275
|
...buildResolvedMetadataPayload(output)
|
|
9855
10276
|
});
|
|
9856
10277
|
span.end();
|
|
@@ -9872,6 +10293,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
9872
10293
|
}
|
|
9873
10294
|
delete resolvedModel[AUTO_PATCHED_MODEL];
|
|
9874
10295
|
});
|
|
10296
|
+
return resolvedModel;
|
|
9875
10297
|
};
|
|
9876
10298
|
const patchTool = (tool, name) => {
|
|
9877
10299
|
if (tool == null || typeof tool !== "object" || !("execute" in tool) || typeof tool.execute !== "function" || patchedTools.has(tool) || tool[AUTO_PATCHED_TOOL]) {
|
|
@@ -9944,17 +10366,26 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
9944
10366
|
}
|
|
9945
10367
|
};
|
|
9946
10368
|
if (params && typeof params === "object") {
|
|
9947
|
-
patchModel(params.model);
|
|
10369
|
+
const patchedParamModel = patchModel(params.model);
|
|
10370
|
+
if (typeof params.model === "string" && patchedParamModel && typeof patchedParamModel === "object") {
|
|
10371
|
+
params.model = patchedParamModel;
|
|
10372
|
+
}
|
|
9948
10373
|
patchTools(params.tools);
|
|
9949
10374
|
}
|
|
9950
10375
|
if (self && typeof self === "object") {
|
|
9951
10376
|
const selfRecord = self;
|
|
9952
10377
|
if (selfRecord.model !== void 0) {
|
|
9953
|
-
patchModel(selfRecord.model);
|
|
10378
|
+
const patchedSelfModel = patchModel(selfRecord.model);
|
|
10379
|
+
if (typeof selfRecord.model === "string" && patchedSelfModel && typeof patchedSelfModel === "object") {
|
|
10380
|
+
selfRecord.model = patchedSelfModel;
|
|
10381
|
+
}
|
|
9954
10382
|
}
|
|
9955
10383
|
if (selfRecord.settings && typeof selfRecord.settings === "object") {
|
|
9956
10384
|
if (selfRecord.settings.model !== void 0) {
|
|
9957
|
-
patchModel(selfRecord.settings.model);
|
|
10385
|
+
const patchedSettingsModel = patchModel(selfRecord.settings.model);
|
|
10386
|
+
if (typeof selfRecord.settings.model === "string" && patchedSettingsModel && typeof patchedSettingsModel === "object") {
|
|
10387
|
+
selfRecord.settings.model = patchedSettingsModel;
|
|
10388
|
+
}
|
|
9958
10389
|
}
|
|
9959
10390
|
if (selfRecord.settings.tools !== void 0) {
|
|
9960
10391
|
patchTools(selfRecord.settings.tools);
|
|
@@ -9978,63 +10409,173 @@ function finalizeAISDKChildTracing(event) {
|
|
|
9978
10409
|
}
|
|
9979
10410
|
}
|
|
9980
10411
|
function patchAISDKStreamingResult(args) {
|
|
9981
|
-
const {
|
|
10412
|
+
const { defaultDenyOutputPaths, endEvent, result, span, startTime } = args;
|
|
9982
10413
|
if (!result || typeof result !== "object") {
|
|
9983
10414
|
return false;
|
|
9984
10415
|
}
|
|
9985
10416
|
const resultRecord = result;
|
|
9986
|
-
|
|
10417
|
+
attachKnownResultPromiseHandlers(resultRecord);
|
|
10418
|
+
if (isReadableStreamLike(resultRecord.baseStream)) {
|
|
10419
|
+
let firstChunkTime2;
|
|
10420
|
+
const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
|
|
10421
|
+
new TransformStream({
|
|
10422
|
+
transform(chunk, controller) {
|
|
10423
|
+
if (firstChunkTime2 === void 0) {
|
|
10424
|
+
firstChunkTime2 = getCurrentUnixTimestamp();
|
|
10425
|
+
}
|
|
10426
|
+
controller.enqueue(chunk);
|
|
10427
|
+
},
|
|
10428
|
+
async flush() {
|
|
10429
|
+
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
10430
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime2 !== void 0) {
|
|
10431
|
+
metrics.time_to_first_token = firstChunkTime2 - startTime;
|
|
10432
|
+
}
|
|
10433
|
+
const output = await processAISDKStreamingOutput(
|
|
10434
|
+
result,
|
|
10435
|
+
resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
|
|
10436
|
+
);
|
|
10437
|
+
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
10438
|
+
span.log({
|
|
10439
|
+
output,
|
|
10440
|
+
...metadata ? { metadata } : {},
|
|
10441
|
+
metrics
|
|
10442
|
+
});
|
|
10443
|
+
finalizeAISDKChildTracing(endEvent);
|
|
10444
|
+
span.end();
|
|
10445
|
+
}
|
|
10446
|
+
})
|
|
10447
|
+
);
|
|
10448
|
+
Object.defineProperty(resultRecord, "baseStream", {
|
|
10449
|
+
configurable: true,
|
|
10450
|
+
enumerable: true,
|
|
10451
|
+
value: wrappedBaseStream,
|
|
10452
|
+
writable: true
|
|
10453
|
+
});
|
|
10454
|
+
return true;
|
|
10455
|
+
}
|
|
10456
|
+
const streamField = findAsyncIterableField(resultRecord, [
|
|
10457
|
+
"partialObjectStream",
|
|
10458
|
+
"textStream",
|
|
10459
|
+
"fullStream",
|
|
10460
|
+
"stream"
|
|
10461
|
+
]);
|
|
10462
|
+
if (!streamField) {
|
|
9987
10463
|
return false;
|
|
9988
10464
|
}
|
|
9989
10465
|
let firstChunkTime;
|
|
9990
|
-
const
|
|
9991
|
-
|
|
9992
|
-
|
|
9993
|
-
|
|
9994
|
-
firstChunkTime = getCurrentUnixTimestamp();
|
|
9995
|
-
}
|
|
9996
|
-
controller.enqueue(chunk);
|
|
9997
|
-
},
|
|
9998
|
-
async flush() {
|
|
9999
|
-
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
10000
|
-
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
10001
|
-
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
10002
|
-
}
|
|
10003
|
-
const output = await processAISDKStreamingOutput(
|
|
10004
|
-
result,
|
|
10005
|
-
denyOutputPaths
|
|
10006
|
-
);
|
|
10007
|
-
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
10008
|
-
span.log({
|
|
10009
|
-
output,
|
|
10010
|
-
...metadata ? { metadata } : {},
|
|
10011
|
-
metrics
|
|
10012
|
-
});
|
|
10013
|
-
finalizeAISDKChildTracing(endEvent);
|
|
10014
|
-
span.end();
|
|
10466
|
+
const wrappedStream = createPatchedAsyncIterable(streamField.stream, {
|
|
10467
|
+
onChunk: () => {
|
|
10468
|
+
if (firstChunkTime === void 0) {
|
|
10469
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
10015
10470
|
}
|
|
10016
|
-
}
|
|
10017
|
-
|
|
10018
|
-
|
|
10471
|
+
},
|
|
10472
|
+
onComplete: async () => {
|
|
10473
|
+
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
10474
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
10475
|
+
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
10476
|
+
}
|
|
10477
|
+
const output = await processAISDKStreamingOutput(
|
|
10478
|
+
result,
|
|
10479
|
+
resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
|
|
10480
|
+
);
|
|
10481
|
+
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
10482
|
+
span.log({
|
|
10483
|
+
output,
|
|
10484
|
+
...metadata ? { metadata } : {},
|
|
10485
|
+
metrics
|
|
10486
|
+
});
|
|
10487
|
+
finalizeAISDKChildTracing(endEvent);
|
|
10488
|
+
span.end();
|
|
10489
|
+
},
|
|
10490
|
+
onError: (error) => {
|
|
10491
|
+
span.log({
|
|
10492
|
+
error: error.message
|
|
10493
|
+
});
|
|
10494
|
+
finalizeAISDKChildTracing(endEvent);
|
|
10495
|
+
span.end();
|
|
10496
|
+
}
|
|
10497
|
+
});
|
|
10498
|
+
Object.defineProperty(resultRecord, streamField.field, {
|
|
10019
10499
|
configurable: true,
|
|
10020
10500
|
enumerable: true,
|
|
10021
|
-
value:
|
|
10501
|
+
value: wrappedStream,
|
|
10022
10502
|
writable: true
|
|
10023
10503
|
});
|
|
10024
10504
|
return true;
|
|
10025
10505
|
}
|
|
10506
|
+
function attachKnownResultPromiseHandlers(result) {
|
|
10507
|
+
const promiseLikeFields = [
|
|
10508
|
+
"content",
|
|
10509
|
+
"text",
|
|
10510
|
+
"object",
|
|
10511
|
+
"finishReason",
|
|
10512
|
+
"usage",
|
|
10513
|
+
"totalUsage",
|
|
10514
|
+
"steps"
|
|
10515
|
+
];
|
|
10516
|
+
for (const field of promiseLikeFields) {
|
|
10517
|
+
try {
|
|
10518
|
+
if (!(field in result)) {
|
|
10519
|
+
continue;
|
|
10520
|
+
}
|
|
10521
|
+
const value = result[field];
|
|
10522
|
+
if (isPromiseLike(value)) {
|
|
10523
|
+
void Promise.resolve(value).catch(() => {
|
|
10524
|
+
});
|
|
10525
|
+
}
|
|
10526
|
+
} catch {
|
|
10527
|
+
}
|
|
10528
|
+
}
|
|
10529
|
+
}
|
|
10026
10530
|
function isReadableStreamLike(value) {
|
|
10027
10531
|
return value != null && typeof value === "object" && typeof value.pipeThrough === "function";
|
|
10028
10532
|
}
|
|
10533
|
+
function isAsyncIterableLike(value) {
|
|
10534
|
+
return value != null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
|
|
10535
|
+
}
|
|
10536
|
+
function findAsyncIterableField(result, candidateFields) {
|
|
10537
|
+
for (const field of candidateFields) {
|
|
10538
|
+
try {
|
|
10539
|
+
const stream = result[field];
|
|
10540
|
+
if (isAsyncIterableLike(stream)) {
|
|
10541
|
+
return { field, stream };
|
|
10542
|
+
}
|
|
10543
|
+
} catch {
|
|
10544
|
+
}
|
|
10545
|
+
}
|
|
10546
|
+
return null;
|
|
10547
|
+
}
|
|
10548
|
+
function createPatchedAsyncIterable(stream, hooks) {
|
|
10549
|
+
return {
|
|
10550
|
+
async *[Symbol.asyncIterator]() {
|
|
10551
|
+
try {
|
|
10552
|
+
for await (const chunk of stream) {
|
|
10553
|
+
hooks.onChunk(chunk);
|
|
10554
|
+
yield chunk;
|
|
10555
|
+
}
|
|
10556
|
+
await hooks.onComplete();
|
|
10557
|
+
} catch (error) {
|
|
10558
|
+
hooks.onError(
|
|
10559
|
+
error instanceof Error ? error : new Error(String(error))
|
|
10560
|
+
);
|
|
10561
|
+
throw error;
|
|
10562
|
+
}
|
|
10563
|
+
}
|
|
10564
|
+
};
|
|
10565
|
+
}
|
|
10029
10566
|
async function processAISDKStreamingOutput(result, denyOutputPaths) {
|
|
10030
10567
|
const output = processAISDKOutput(result, denyOutputPaths);
|
|
10031
10568
|
if (!output || typeof output !== "object") {
|
|
10032
10569
|
return output;
|
|
10033
10570
|
}
|
|
10034
10571
|
const outputRecord = output;
|
|
10572
|
+
const isObjectStreamingResult = result != null && typeof result === "object" && "partialObjectStream" in result;
|
|
10035
10573
|
try {
|
|
10036
|
-
if ("text" in result
|
|
10037
|
-
|
|
10574
|
+
if (!isObjectStreamingResult && "text" in result) {
|
|
10575
|
+
const resolvedText = await Promise.resolve(result.text);
|
|
10576
|
+
if (typeof resolvedText === "string") {
|
|
10577
|
+
outputRecord.text = resolvedText;
|
|
10578
|
+
}
|
|
10038
10579
|
}
|
|
10039
10580
|
} catch {
|
|
10040
10581
|
}
|
|
@@ -10047,6 +10588,15 @@ async function processAISDKStreamingOutput(result, denyOutputPaths) {
|
|
|
10047
10588
|
}
|
|
10048
10589
|
} catch {
|
|
10049
10590
|
}
|
|
10591
|
+
try {
|
|
10592
|
+
if ("finishReason" in result) {
|
|
10593
|
+
const resolvedFinishReason = await Promise.resolve(result.finishReason);
|
|
10594
|
+
if (resolvedFinishReason !== void 0) {
|
|
10595
|
+
outputRecord.finishReason = resolvedFinishReason;
|
|
10596
|
+
}
|
|
10597
|
+
}
|
|
10598
|
+
} catch {
|
|
10599
|
+
}
|
|
10050
10600
|
return outputRecord;
|
|
10051
10601
|
}
|
|
10052
10602
|
function buildAISDKChildMetadata(model) {
|
|
@@ -10069,16 +10619,25 @@ function buildResolvedMetadataPayload(result) {
|
|
|
10069
10619
|
if (gatewayInfo?.model) {
|
|
10070
10620
|
metadata.model = gatewayInfo.model;
|
|
10071
10621
|
}
|
|
10072
|
-
|
|
10073
|
-
|
|
10622
|
+
let finishReason;
|
|
10623
|
+
try {
|
|
10624
|
+
finishReason = result.finishReason;
|
|
10625
|
+
} catch {
|
|
10626
|
+
finishReason = void 0;
|
|
10627
|
+
}
|
|
10628
|
+
if (isPromiseLike(finishReason)) {
|
|
10629
|
+
void Promise.resolve(finishReason).catch(() => {
|
|
10630
|
+
});
|
|
10631
|
+
} else if (finishReason !== void 0) {
|
|
10632
|
+
metadata.finish_reason = finishReason;
|
|
10074
10633
|
}
|
|
10075
10634
|
return Object.keys(metadata).length > 0 ? { metadata } : {};
|
|
10076
10635
|
}
|
|
10077
|
-
function resolveAISDKModel(model) {
|
|
10636
|
+
function resolveAISDKModel(model, aiSDK) {
|
|
10078
10637
|
if (typeof model !== "string") {
|
|
10079
10638
|
return model;
|
|
10080
10639
|
}
|
|
10081
|
-
const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? null;
|
|
10640
|
+
const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? aiSDK?.gateway ?? null;
|
|
10082
10641
|
if (provider && typeof provider.languageModel === "function") {
|
|
10083
10642
|
return provider.languageModel(model);
|
|
10084
10643
|
}
|
|
@@ -10101,15 +10660,15 @@ function processAISDKOutput(output, denyOutputPaths) {
|
|
|
10101
10660
|
}
|
|
10102
10661
|
function extractTokenMetrics(result) {
|
|
10103
10662
|
const metrics = {};
|
|
10104
|
-
let usage
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
|
|
10110
|
-
|
|
10111
|
-
|
|
10112
|
-
|
|
10663
|
+
let usage;
|
|
10664
|
+
const totalUsageValue = safeResultFieldRead(result, "totalUsage");
|
|
10665
|
+
if (totalUsageValue !== void 0 && !isPromiseLike(totalUsageValue)) {
|
|
10666
|
+
usage = totalUsageValue;
|
|
10667
|
+
}
|
|
10668
|
+
if (!usage) {
|
|
10669
|
+
const usageValue = safeResultFieldRead(result, "usage");
|
|
10670
|
+
if (usageValue !== void 0 && !isPromiseLike(usageValue)) {
|
|
10671
|
+
usage = usageValue;
|
|
10113
10672
|
}
|
|
10114
10673
|
}
|
|
10115
10674
|
if (!usage) {
|
|
@@ -10147,6 +10706,22 @@ function extractTokenMetrics(result) {
|
|
|
10147
10706
|
}
|
|
10148
10707
|
return metrics;
|
|
10149
10708
|
}
|
|
10709
|
+
function safeResultFieldRead(result, field) {
|
|
10710
|
+
return safeSerializableFieldRead(result, field);
|
|
10711
|
+
}
|
|
10712
|
+
function safeSerializableFieldRead(obj, field) {
|
|
10713
|
+
try {
|
|
10714
|
+
const value = obj?.[field];
|
|
10715
|
+
if (isPromiseLike(value)) {
|
|
10716
|
+
void Promise.resolve(value).catch(() => {
|
|
10717
|
+
});
|
|
10718
|
+
return void 0;
|
|
10719
|
+
}
|
|
10720
|
+
return value;
|
|
10721
|
+
} catch {
|
|
10722
|
+
return void 0;
|
|
10723
|
+
}
|
|
10724
|
+
}
|
|
10150
10725
|
function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
10151
10726
|
const lastChunk = chunks[chunks.length - 1];
|
|
10152
10727
|
const output = {};
|
|
@@ -10155,17 +10730,21 @@ function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
|
10155
10730
|
if (lastChunk) {
|
|
10156
10731
|
metrics = hasModelChildTracing(endEvent) ? {} : extractTokenMetrics(lastChunk);
|
|
10157
10732
|
metadata = buildResolvedMetadataPayload(lastChunk).metadata;
|
|
10158
|
-
|
|
10159
|
-
|
|
10733
|
+
const text = safeSerializableFieldRead(lastChunk, "text");
|
|
10734
|
+
if (text !== void 0) {
|
|
10735
|
+
output.text = text;
|
|
10160
10736
|
}
|
|
10161
|
-
|
|
10162
|
-
|
|
10737
|
+
const objectValue = safeSerializableFieldRead(lastChunk, "object");
|
|
10738
|
+
if (objectValue !== void 0) {
|
|
10739
|
+
output.object = objectValue;
|
|
10163
10740
|
}
|
|
10164
|
-
|
|
10165
|
-
|
|
10741
|
+
const finishReason = safeSerializableFieldRead(lastChunk, "finishReason");
|
|
10742
|
+
if (finishReason !== void 0) {
|
|
10743
|
+
output.finishReason = finishReason;
|
|
10166
10744
|
}
|
|
10167
|
-
|
|
10168
|
-
|
|
10745
|
+
const toolCalls = safeSerializableFieldRead(lastChunk, "toolCalls");
|
|
10746
|
+
if (toolCalls !== void 0) {
|
|
10747
|
+
output.toolCalls = toolCalls;
|
|
10169
10748
|
}
|
|
10170
10749
|
}
|
|
10171
10750
|
finalizeAISDKChildTracing(endEvent);
|
|
@@ -10174,6 +10753,7 @@ function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
|
10174
10753
|
function extractGetterValues(obj) {
|
|
10175
10754
|
const getterValues = {};
|
|
10176
10755
|
const getterNames = [
|
|
10756
|
+
"content",
|
|
10177
10757
|
"text",
|
|
10178
10758
|
"object",
|
|
10179
10759
|
"finishReason",
|
|
@@ -10189,8 +10769,17 @@ function extractGetterValues(obj) {
|
|
|
10189
10769
|
];
|
|
10190
10770
|
for (const name of getterNames) {
|
|
10191
10771
|
try {
|
|
10192
|
-
if (obj
|
|
10193
|
-
|
|
10772
|
+
if (!obj || !(name in obj)) {
|
|
10773
|
+
continue;
|
|
10774
|
+
}
|
|
10775
|
+
const value = obj[name];
|
|
10776
|
+
if (isPromiseLike(value)) {
|
|
10777
|
+
void Promise.resolve(value).catch(() => {
|
|
10778
|
+
});
|
|
10779
|
+
continue;
|
|
10780
|
+
}
|
|
10781
|
+
if (isSerializableOutputValue(value)) {
|
|
10782
|
+
getterValues[name] = value;
|
|
10194
10783
|
}
|
|
10195
10784
|
} catch {
|
|
10196
10785
|
}
|
|
@@ -10212,6 +10801,11 @@ function extractSerializableOutputFields(output) {
|
|
|
10212
10801
|
for (const name of directFieldNames) {
|
|
10213
10802
|
try {
|
|
10214
10803
|
const value = output?.[name];
|
|
10804
|
+
if (isPromiseLike(value)) {
|
|
10805
|
+
void Promise.resolve(value).catch(() => {
|
|
10806
|
+
});
|
|
10807
|
+
continue;
|
|
10808
|
+
}
|
|
10215
10809
|
if (isSerializableOutputValue(value)) {
|
|
10216
10810
|
serialized[name] = value;
|
|
10217
10811
|
}
|
|
@@ -10223,6 +10817,9 @@ function extractSerializableOutputFields(output) {
|
|
|
10223
10817
|
...extractGetterValues(output)
|
|
10224
10818
|
};
|
|
10225
10819
|
}
|
|
10820
|
+
function isPromiseLike(value) {
|
|
10821
|
+
return value != null && typeof value === "object" && typeof value.then === "function";
|
|
10822
|
+
}
|
|
10226
10823
|
function isSerializableOutputValue(value) {
|
|
10227
10824
|
if (typeof value === "function") {
|
|
10228
10825
|
return false;
|
|
@@ -10264,8 +10861,9 @@ function parseGatewayModelString(modelString) {
|
|
|
10264
10861
|
return { model: modelString };
|
|
10265
10862
|
}
|
|
10266
10863
|
function extractGatewayRoutingInfo(result) {
|
|
10267
|
-
|
|
10268
|
-
|
|
10864
|
+
const steps = safeSerializableFieldRead(result, "steps");
|
|
10865
|
+
if (Array.isArray(steps) && steps.length > 0) {
|
|
10866
|
+
const routing2 = steps[0]?.providerMetadata?.gateway?.routing;
|
|
10269
10867
|
if (routing2) {
|
|
10270
10868
|
return {
|
|
10271
10869
|
provider: routing2.resolvedProvider || routing2.finalProvider,
|
|
@@ -10273,7 +10871,11 @@ function extractGatewayRoutingInfo(result) {
|
|
|
10273
10871
|
};
|
|
10274
10872
|
}
|
|
10275
10873
|
}
|
|
10276
|
-
const
|
|
10874
|
+
const providerMetadata = safeSerializableFieldRead(
|
|
10875
|
+
result,
|
|
10876
|
+
"providerMetadata"
|
|
10877
|
+
);
|
|
10878
|
+
const routing = providerMetadata?.gateway?.routing;
|
|
10277
10879
|
if (routing) {
|
|
10278
10880
|
return {
|
|
10279
10881
|
provider: routing.resolvedProvider || routing.finalProvider,
|
|
@@ -10283,10 +10885,11 @@ function extractGatewayRoutingInfo(result) {
|
|
|
10283
10885
|
return null;
|
|
10284
10886
|
}
|
|
10285
10887
|
function extractCostFromResult(result) {
|
|
10286
|
-
|
|
10888
|
+
const steps = safeSerializableFieldRead(result, "steps");
|
|
10889
|
+
if (Array.isArray(steps) && steps.length > 0) {
|
|
10287
10890
|
let totalCost = 0;
|
|
10288
10891
|
let foundCost = false;
|
|
10289
|
-
for (const step of
|
|
10892
|
+
for (const step of steps) {
|
|
10290
10893
|
const gateway2 = step?.providerMetadata?.gateway;
|
|
10291
10894
|
const stepCost = parseGatewayCost(gateway2?.cost) || parseGatewayCost(gateway2?.marketCost);
|
|
10292
10895
|
if (stepCost !== void 0 && stepCost > 0) {
|
|
@@ -10298,7 +10901,11 @@ function extractCostFromResult(result) {
|
|
|
10298
10901
|
return totalCost;
|
|
10299
10902
|
}
|
|
10300
10903
|
}
|
|
10301
|
-
const
|
|
10904
|
+
const providerMetadata = safeSerializableFieldRead(
|
|
10905
|
+
result,
|
|
10906
|
+
"providerMetadata"
|
|
10907
|
+
);
|
|
10908
|
+
const gateway = providerMetadata?.gateway;
|
|
10302
10909
|
const directCost = parseGatewayCost(gateway?.cost) || parseGatewayCost(gateway?.marketCost);
|
|
10303
10910
|
if (directCost !== void 0 && directCost > 0) {
|
|
10304
10911
|
return directCost;
|
|
@@ -10410,12 +11017,15 @@ var claudeAgentSDKChannels = defineChannels(
|
|
|
10410
11017
|
{
|
|
10411
11018
|
query: channel({
|
|
10412
11019
|
channelName: "query",
|
|
10413
|
-
kind: "
|
|
11020
|
+
kind: "sync-stream"
|
|
10414
11021
|
})
|
|
10415
11022
|
}
|
|
10416
11023
|
);
|
|
10417
11024
|
|
|
10418
11025
|
// src/instrumentation/plugins/claude-agent-sdk-plugin.ts
|
|
11026
|
+
function isSubAgentToolName(toolName) {
|
|
11027
|
+
return toolName === "Agent" || toolName === "Task";
|
|
11028
|
+
}
|
|
10419
11029
|
function filterSerializableOptions(options) {
|
|
10420
11030
|
const allowedKeys = [
|
|
10421
11031
|
"model",
|
|
@@ -10469,34 +11079,50 @@ function extractUsageFromMessage(message) {
|
|
|
10469
11079
|
const cacheReadTokens = getNumberProperty(usage, "cache_read_input_tokens") || 0;
|
|
10470
11080
|
const cacheCreationTokens = getNumberProperty(usage, "cache_creation_input_tokens") || 0;
|
|
10471
11081
|
if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
|
|
10472
|
-
|
|
10473
|
-
|
|
10474
|
-
cacheCreationTokens
|
|
11082
|
+
Object.assign(
|
|
11083
|
+
metrics,
|
|
11084
|
+
extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
|
|
10475
11085
|
);
|
|
10476
|
-
Object.assign(metrics, cacheTokens);
|
|
10477
11086
|
}
|
|
10478
11087
|
if (Object.keys(metrics).length > 0) {
|
|
10479
11088
|
Object.assign(metrics, finalizeAnthropicTokens(metrics));
|
|
10480
11089
|
}
|
|
10481
11090
|
return metrics;
|
|
10482
11091
|
}
|
|
10483
|
-
function buildLLMInput(prompt, conversationHistory) {
|
|
10484
|
-
const
|
|
10485
|
-
|
|
10486
|
-
|
|
10487
|
-
|
|
10488
|
-
|
|
11092
|
+
function buildLLMInput(prompt, conversationHistory, capturedPromptMessages) {
|
|
11093
|
+
const promptMessages = [];
|
|
11094
|
+
if (typeof prompt === "string") {
|
|
11095
|
+
promptMessages.push({ content: prompt, role: "user" });
|
|
11096
|
+
} else if (capturedPromptMessages && capturedPromptMessages.length > 0) {
|
|
11097
|
+
for (const msg of capturedPromptMessages) {
|
|
11098
|
+
const role = msg.message?.role;
|
|
11099
|
+
const content = msg.message?.content;
|
|
11100
|
+
if (role && content !== void 0) {
|
|
11101
|
+
promptMessages.push({ content, role });
|
|
11102
|
+
}
|
|
11103
|
+
}
|
|
11104
|
+
}
|
|
11105
|
+
const inputParts = [...promptMessages, ...conversationHistory];
|
|
10489
11106
|
return inputParts.length > 0 ? inputParts : void 0;
|
|
10490
11107
|
}
|
|
10491
|
-
|
|
10492
|
-
|
|
11108
|
+
function formatCapturedMessages(messages) {
|
|
11109
|
+
return messages.length > 0 ? messages : [];
|
|
11110
|
+
}
|
|
11111
|
+
async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan) {
|
|
11112
|
+
if (messages.length === 0) {
|
|
11113
|
+
return void 0;
|
|
11114
|
+
}
|
|
10493
11115
|
const lastMessage = messages[messages.length - 1];
|
|
10494
11116
|
if (lastMessage.type !== "assistant" || !lastMessage.message?.usage) {
|
|
10495
11117
|
return void 0;
|
|
10496
11118
|
}
|
|
10497
11119
|
const model = lastMessage.message.model || options.model;
|
|
10498
11120
|
const usage = extractUsageFromMessage(lastMessage);
|
|
10499
|
-
const input = buildLLMInput(
|
|
11121
|
+
const input = buildLLMInput(
|
|
11122
|
+
prompt,
|
|
11123
|
+
conversationHistory,
|
|
11124
|
+
capturedPromptMessages
|
|
11125
|
+
);
|
|
10500
11126
|
const outputs = messages.map(
|
|
10501
11127
|
(m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
|
|
10502
11128
|
).filter(
|
|
@@ -10504,21 +11130,359 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
|
|
|
10504
11130
|
);
|
|
10505
11131
|
const span = startSpan({
|
|
10506
11132
|
name: "anthropic.messages.create",
|
|
11133
|
+
parent: parentSpan,
|
|
10507
11134
|
spanAttributes: {
|
|
10508
11135
|
type: "llm" /* LLM */
|
|
10509
11136
|
},
|
|
10510
|
-
startTime
|
|
10511
|
-
parent: parentSpan
|
|
11137
|
+
startTime
|
|
10512
11138
|
});
|
|
10513
11139
|
span.log({
|
|
10514
11140
|
input,
|
|
10515
|
-
output: outputs,
|
|
10516
11141
|
metadata: model ? { model } : void 0,
|
|
10517
|
-
metrics: usage
|
|
11142
|
+
metrics: usage,
|
|
11143
|
+
output: outputs
|
|
10518
11144
|
});
|
|
10519
11145
|
await span.end();
|
|
10520
11146
|
return lastMessage.message?.content && lastMessage.message?.role ? { content: lastMessage.message.content, role: lastMessage.message.role } : void 0;
|
|
10521
11147
|
}
|
|
11148
|
+
function getMcpServerMetadata(serverName, mcpServers) {
|
|
11149
|
+
if (!serverName || !mcpServers) {
|
|
11150
|
+
return {};
|
|
11151
|
+
}
|
|
11152
|
+
const serverConfig = mcpServers[serverName];
|
|
11153
|
+
if (!serverConfig) {
|
|
11154
|
+
return {};
|
|
11155
|
+
}
|
|
11156
|
+
const metadata = {};
|
|
11157
|
+
if (serverConfig.type) {
|
|
11158
|
+
metadata["mcp.type"] = serverConfig.type;
|
|
11159
|
+
} else if (typeof serverConfig === "object" && "transport" in serverConfig) {
|
|
11160
|
+
metadata["mcp.type"] = "sdk";
|
|
11161
|
+
}
|
|
11162
|
+
if (serverConfig.url) {
|
|
11163
|
+
metadata["mcp.url"] = serverConfig.url;
|
|
11164
|
+
}
|
|
11165
|
+
if (serverConfig.command) {
|
|
11166
|
+
metadata["mcp.command"] = serverConfig.command;
|
|
11167
|
+
if (serverConfig.args) {
|
|
11168
|
+
metadata["mcp.args"] = serverConfig.args.join(" ");
|
|
11169
|
+
}
|
|
11170
|
+
}
|
|
11171
|
+
return metadata;
|
|
11172
|
+
}
|
|
11173
|
+
function parseToolName(rawToolName) {
|
|
11174
|
+
const mcpMatch = rawToolName.match(/^mcp__([^_]+)__(.+)$/);
|
|
11175
|
+
if (mcpMatch) {
|
|
11176
|
+
const [, mcpServer, toolName] = mcpMatch;
|
|
11177
|
+
return {
|
|
11178
|
+
displayName: `tool: ${mcpServer}/${toolName}`,
|
|
11179
|
+
mcpServer,
|
|
11180
|
+
rawToolName,
|
|
11181
|
+
toolName
|
|
11182
|
+
};
|
|
11183
|
+
}
|
|
11184
|
+
return {
|
|
11185
|
+
displayName: `tool: ${rawToolName}`,
|
|
11186
|
+
rawToolName,
|
|
11187
|
+
toolName: rawToolName
|
|
11188
|
+
};
|
|
11189
|
+
}
|
|
11190
|
+
function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, subAgentSpans, endedSubAgentSpans) {
|
|
11191
|
+
const preToolUse = async (input, toolUseID) => {
|
|
11192
|
+
if (input.hook_event_name !== "PreToolUse" || !toolUseID) {
|
|
11193
|
+
return {};
|
|
11194
|
+
}
|
|
11195
|
+
if (isSubAgentToolName(input.tool_name)) {
|
|
11196
|
+
return {};
|
|
11197
|
+
}
|
|
11198
|
+
const parsed = parseToolName(input.tool_name);
|
|
11199
|
+
const toolSpan = startSpan({
|
|
11200
|
+
event: {
|
|
11201
|
+
input: input.tool_input,
|
|
11202
|
+
metadata: {
|
|
11203
|
+
"claude_agent_sdk.cwd": input.cwd,
|
|
11204
|
+
"claude_agent_sdk.raw_tool_name": parsed.rawToolName,
|
|
11205
|
+
"claude_agent_sdk.session_id": input.session_id,
|
|
11206
|
+
"gen_ai.tool.call.id": toolUseID,
|
|
11207
|
+
"gen_ai.tool.name": parsed.toolName,
|
|
11208
|
+
...parsed.mcpServer && { "mcp.server": parsed.mcpServer },
|
|
11209
|
+
...getMcpServerMetadata(parsed.mcpServer, mcpServers)
|
|
11210
|
+
}
|
|
11211
|
+
},
|
|
11212
|
+
name: parsed.displayName,
|
|
11213
|
+
parent: await resolveParentSpan(toolUseID),
|
|
11214
|
+
spanAttributes: { type: "tool" /* TOOL */ }
|
|
11215
|
+
});
|
|
11216
|
+
activeToolSpans.set(toolUseID, toolSpan);
|
|
11217
|
+
return {};
|
|
11218
|
+
};
|
|
11219
|
+
const postToolUse = async (input, toolUseID) => {
|
|
11220
|
+
if (input.hook_event_name !== "PostToolUse" || !toolUseID) {
|
|
11221
|
+
return {};
|
|
11222
|
+
}
|
|
11223
|
+
const subAgentSpan = subAgentSpans.get(toolUseID);
|
|
11224
|
+
if (subAgentSpan) {
|
|
11225
|
+
try {
|
|
11226
|
+
const response = input.tool_response;
|
|
11227
|
+
const metadata = {};
|
|
11228
|
+
if (response?.status) {
|
|
11229
|
+
metadata["claude_agent_sdk.status"] = response.status;
|
|
11230
|
+
}
|
|
11231
|
+
if (response?.totalDurationMs) {
|
|
11232
|
+
metadata["claude_agent_sdk.duration_ms"] = response.totalDurationMs;
|
|
11233
|
+
}
|
|
11234
|
+
if (response?.totalToolUseCount !== void 0) {
|
|
11235
|
+
metadata["claude_agent_sdk.tool_use_count"] = response.totalToolUseCount;
|
|
11236
|
+
}
|
|
11237
|
+
subAgentSpan.log({
|
|
11238
|
+
metadata,
|
|
11239
|
+
output: response?.content
|
|
11240
|
+
});
|
|
11241
|
+
} finally {
|
|
11242
|
+
subAgentSpan.end();
|
|
11243
|
+
endedSubAgentSpans.add(toolUseID);
|
|
11244
|
+
}
|
|
11245
|
+
return {};
|
|
11246
|
+
}
|
|
11247
|
+
const toolSpan = activeToolSpans.get(toolUseID);
|
|
11248
|
+
if (!toolSpan) {
|
|
11249
|
+
return {};
|
|
11250
|
+
}
|
|
11251
|
+
try {
|
|
11252
|
+
toolSpan.log({ output: input.tool_response });
|
|
11253
|
+
} finally {
|
|
11254
|
+
toolSpan.end();
|
|
11255
|
+
activeToolSpans.delete(toolUseID);
|
|
11256
|
+
}
|
|
11257
|
+
return {};
|
|
11258
|
+
};
|
|
11259
|
+
const postToolUseFailure = async (input, toolUseID) => {
|
|
11260
|
+
if (input.hook_event_name !== "PostToolUseFailure" || !toolUseID) {
|
|
11261
|
+
return {};
|
|
11262
|
+
}
|
|
11263
|
+
const subAgentSpan = subAgentSpans.get(toolUseID);
|
|
11264
|
+
if (subAgentSpan) {
|
|
11265
|
+
try {
|
|
11266
|
+
subAgentSpan.log({ error: input.error });
|
|
11267
|
+
} finally {
|
|
11268
|
+
subAgentSpan.end();
|
|
11269
|
+
endedSubAgentSpans.add(toolUseID);
|
|
11270
|
+
}
|
|
11271
|
+
return {};
|
|
11272
|
+
}
|
|
11273
|
+
const toolSpan = activeToolSpans.get(toolUseID);
|
|
11274
|
+
if (!toolSpan) {
|
|
11275
|
+
return {};
|
|
11276
|
+
}
|
|
11277
|
+
const parsed = parseToolName(input.tool_name);
|
|
11278
|
+
try {
|
|
11279
|
+
toolSpan.log({
|
|
11280
|
+
error: input.error,
|
|
11281
|
+
metadata: {
|
|
11282
|
+
"claude_agent_sdk.is_interrupt": input.is_interrupt,
|
|
11283
|
+
"claude_agent_sdk.session_id": input.session_id,
|
|
11284
|
+
"gen_ai.tool.call.id": toolUseID,
|
|
11285
|
+
"gen_ai.tool.name": parsed.toolName,
|
|
11286
|
+
...parsed.mcpServer && { "mcp.server": parsed.mcpServer }
|
|
11287
|
+
}
|
|
11288
|
+
});
|
|
11289
|
+
} finally {
|
|
11290
|
+
toolSpan.end();
|
|
11291
|
+
activeToolSpans.delete(toolUseID);
|
|
11292
|
+
}
|
|
11293
|
+
return {};
|
|
11294
|
+
};
|
|
11295
|
+
return { postToolUse, postToolUseFailure, preToolUse };
|
|
11296
|
+
}
|
|
11297
|
+
function injectTracingHooks(options, resolveParentSpan, activeToolSpans, subAgentSpans, endedSubAgentSpans) {
|
|
11298
|
+
const { preToolUse, postToolUse, postToolUseFailure } = createToolTracingHooks(
|
|
11299
|
+
resolveParentSpan,
|
|
11300
|
+
activeToolSpans,
|
|
11301
|
+
options.mcpServers,
|
|
11302
|
+
subAgentSpans,
|
|
11303
|
+
endedSubAgentSpans
|
|
11304
|
+
);
|
|
11305
|
+
const existingHooks = options.hooks ?? {};
|
|
11306
|
+
return {
|
|
11307
|
+
...options,
|
|
11308
|
+
hooks: {
|
|
11309
|
+
...existingHooks,
|
|
11310
|
+
PostToolUse: [
|
|
11311
|
+
...existingHooks.PostToolUse ?? [],
|
|
11312
|
+
{ hooks: [postToolUse] }
|
|
11313
|
+
],
|
|
11314
|
+
PostToolUseFailure: [
|
|
11315
|
+
...existingHooks.PostToolUseFailure ?? [],
|
|
11316
|
+
{
|
|
11317
|
+
hooks: [postToolUseFailure]
|
|
11318
|
+
}
|
|
11319
|
+
],
|
|
11320
|
+
PreToolUse: [
|
|
11321
|
+
...existingHooks.PreToolUse ?? [],
|
|
11322
|
+
{ hooks: [preToolUse] }
|
|
11323
|
+
]
|
|
11324
|
+
}
|
|
11325
|
+
};
|
|
11326
|
+
}
|
|
11327
|
+
async function finalizeCurrentMessageGroup(state) {
|
|
11328
|
+
if (state.currentMessages.length === 0) {
|
|
11329
|
+
return;
|
|
11330
|
+
}
|
|
11331
|
+
const parentToolUseId = state.currentMessages[0]?.parent_tool_use_id ?? null;
|
|
11332
|
+
let parentSpan = await state.span.export();
|
|
11333
|
+
if (parentToolUseId) {
|
|
11334
|
+
const subAgentSpan = state.subAgentSpans.get(parentToolUseId);
|
|
11335
|
+
if (subAgentSpan) {
|
|
11336
|
+
parentSpan = await subAgentSpan.export();
|
|
11337
|
+
}
|
|
11338
|
+
}
|
|
11339
|
+
const finalMessage = await createLLMSpanForMessages(
|
|
11340
|
+
state.currentMessages,
|
|
11341
|
+
state.originalPrompt,
|
|
11342
|
+
state.finalResults,
|
|
11343
|
+
state.options,
|
|
11344
|
+
state.currentMessageStartTime,
|
|
11345
|
+
state.capturedPromptMessages,
|
|
11346
|
+
parentSpan
|
|
11347
|
+
);
|
|
11348
|
+
if (finalMessage) {
|
|
11349
|
+
state.finalResults.push(finalMessage);
|
|
11350
|
+
}
|
|
11351
|
+
const lastMessage = state.currentMessages[state.currentMessages.length - 1];
|
|
11352
|
+
if (lastMessage?.message?.usage) {
|
|
11353
|
+
state.accumulatedOutputTokens += getNumberProperty(lastMessage.message.usage, "output_tokens") || 0;
|
|
11354
|
+
}
|
|
11355
|
+
state.currentMessages.length = 0;
|
|
11356
|
+
}
|
|
11357
|
+
function maybeTrackToolUseContext(state, message) {
|
|
11358
|
+
if (message.type !== "assistant" || !Array.isArray(message.message?.content)) {
|
|
11359
|
+
return;
|
|
11360
|
+
}
|
|
11361
|
+
const parentToolUseId = message.parent_tool_use_id ?? null;
|
|
11362
|
+
for (const block of message.message.content) {
|
|
11363
|
+
if (typeof block !== "object" || block === null || !("type" in block) || block.type !== "tool_use" || !("id" in block) || typeof block.id !== "string") {
|
|
11364
|
+
continue;
|
|
11365
|
+
}
|
|
11366
|
+
state.toolUseToParent.set(block.id, parentToolUseId);
|
|
11367
|
+
if (block.name === "Task" && typeof block.input === "object" && block.input !== null && "subagent_type" in block.input && typeof block.input.subagent_type === "string") {
|
|
11368
|
+
state.pendingSubAgentNames.set(block.id, block.input.subagent_type);
|
|
11369
|
+
}
|
|
11370
|
+
}
|
|
11371
|
+
}
|
|
11372
|
+
async function maybeStartSubAgentSpan(state, message) {
|
|
11373
|
+
if (!("parent_tool_use_id" in message)) {
|
|
11374
|
+
return;
|
|
11375
|
+
}
|
|
11376
|
+
const parentToolUseId = message.parent_tool_use_id;
|
|
11377
|
+
if (!parentToolUseId) {
|
|
11378
|
+
return;
|
|
11379
|
+
}
|
|
11380
|
+
await ensureSubAgentSpan(
|
|
11381
|
+
state.pendingSubAgentNames,
|
|
11382
|
+
state.span,
|
|
11383
|
+
state.subAgentSpans,
|
|
11384
|
+
parentToolUseId
|
|
11385
|
+
);
|
|
11386
|
+
}
|
|
11387
|
+
async function ensureSubAgentSpan(pendingSubAgentNames, rootSpan, subAgentSpans, parentToolUseId) {
|
|
11388
|
+
const existingSpan = subAgentSpans.get(parentToolUseId);
|
|
11389
|
+
if (existingSpan) {
|
|
11390
|
+
return existingSpan;
|
|
11391
|
+
}
|
|
11392
|
+
const agentName = pendingSubAgentNames.get(parentToolUseId);
|
|
11393
|
+
const spanName = agentName ? `Agent: ${agentName}` : "Agent: sub-agent";
|
|
11394
|
+
const subAgentSpan = startSpan({
|
|
11395
|
+
event: {
|
|
11396
|
+
metadata: {
|
|
11397
|
+
...agentName && { "claude_agent_sdk.agent_type": agentName }
|
|
11398
|
+
}
|
|
11399
|
+
},
|
|
11400
|
+
name: spanName,
|
|
11401
|
+
parent: await rootSpan.export(),
|
|
11402
|
+
spanAttributes: { type: "task" /* TASK */ }
|
|
11403
|
+
});
|
|
11404
|
+
subAgentSpans.set(parentToolUseId, subAgentSpan);
|
|
11405
|
+
return subAgentSpan;
|
|
11406
|
+
}
|
|
11407
|
+
async function handleStreamMessage(state, message) {
|
|
11408
|
+
maybeTrackToolUseContext(state, message);
|
|
11409
|
+
await maybeStartSubAgentSpan(state, message);
|
|
11410
|
+
const messageId = message.message?.id;
|
|
11411
|
+
if (messageId && messageId !== state.currentMessageId) {
|
|
11412
|
+
await finalizeCurrentMessageGroup(state);
|
|
11413
|
+
state.currentMessageId = messageId;
|
|
11414
|
+
state.currentMessageStartTime = getCurrentUnixTimestamp();
|
|
11415
|
+
}
|
|
11416
|
+
if (message.type === "assistant" && message.message?.usage) {
|
|
11417
|
+
state.currentMessages.push(message);
|
|
11418
|
+
}
|
|
11419
|
+
if (message.type !== "result" || !message.usage) {
|
|
11420
|
+
return;
|
|
11421
|
+
}
|
|
11422
|
+
const finalUsageMetrics = extractUsageFromMessage(message);
|
|
11423
|
+
if (state.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
|
|
11424
|
+
const lastMessage = state.currentMessages[state.currentMessages.length - 1];
|
|
11425
|
+
if (lastMessage?.message?.usage) {
|
|
11426
|
+
const adjustedTokens = finalUsageMetrics.completion_tokens - state.accumulatedOutputTokens;
|
|
11427
|
+
if (adjustedTokens >= 0) {
|
|
11428
|
+
lastMessage.message.usage.output_tokens = adjustedTokens;
|
|
11429
|
+
}
|
|
11430
|
+
const resultUsage = message.usage;
|
|
11431
|
+
if (resultUsage && typeof resultUsage === "object") {
|
|
11432
|
+
const cacheReadTokens = getNumberProperty(
|
|
11433
|
+
resultUsage,
|
|
11434
|
+
"cache_read_input_tokens"
|
|
11435
|
+
);
|
|
11436
|
+
if (cacheReadTokens !== void 0) {
|
|
11437
|
+
lastMessage.message.usage.cache_read_input_tokens = cacheReadTokens;
|
|
11438
|
+
}
|
|
11439
|
+
const cacheCreationTokens = getNumberProperty(
|
|
11440
|
+
resultUsage,
|
|
11441
|
+
"cache_creation_input_tokens"
|
|
11442
|
+
);
|
|
11443
|
+
if (cacheCreationTokens !== void 0) {
|
|
11444
|
+
lastMessage.message.usage.cache_creation_input_tokens = cacheCreationTokens;
|
|
11445
|
+
}
|
|
11446
|
+
}
|
|
11447
|
+
}
|
|
11448
|
+
}
|
|
11449
|
+
const metadata = {};
|
|
11450
|
+
if (message.num_turns !== void 0) {
|
|
11451
|
+
metadata.num_turns = message.num_turns;
|
|
11452
|
+
}
|
|
11453
|
+
if (message.session_id !== void 0) {
|
|
11454
|
+
metadata.session_id = message.session_id;
|
|
11455
|
+
}
|
|
11456
|
+
if (Object.keys(metadata).length > 0) {
|
|
11457
|
+
state.span.log({ metadata });
|
|
11458
|
+
}
|
|
11459
|
+
}
|
|
11460
|
+
async function finalizeQuerySpan(state) {
|
|
11461
|
+
try {
|
|
11462
|
+
await finalizeCurrentMessageGroup(state);
|
|
11463
|
+
state.span.log({
|
|
11464
|
+
output: state.finalResults.length > 0 ? state.finalResults[state.finalResults.length - 1] : void 0
|
|
11465
|
+
});
|
|
11466
|
+
if (state.capturedPromptMessages) {
|
|
11467
|
+
if (state.promptStarted()) {
|
|
11468
|
+
await state.promptDone;
|
|
11469
|
+
}
|
|
11470
|
+
if (state.capturedPromptMessages.length > 0) {
|
|
11471
|
+
state.span.log({
|
|
11472
|
+
input: formatCapturedMessages(state.capturedPromptMessages)
|
|
11473
|
+
});
|
|
11474
|
+
}
|
|
11475
|
+
}
|
|
11476
|
+
} finally {
|
|
11477
|
+
for (const [id, subAgentSpan] of state.subAgentSpans) {
|
|
11478
|
+
if (!state.endedSubAgentSpans.has(id)) {
|
|
11479
|
+
subAgentSpan.end();
|
|
11480
|
+
}
|
|
11481
|
+
}
|
|
11482
|
+
state.subAgentSpans.clear();
|
|
11483
|
+
state.span.end();
|
|
11484
|
+
}
|
|
11485
|
+
}
|
|
10522
11486
|
var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
10523
11487
|
onEnable() {
|
|
10524
11488
|
this.subscribeToQuery();
|
|
@@ -10529,19 +11493,36 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
10529
11493
|
}
|
|
10530
11494
|
this.unsubscribers = [];
|
|
10531
11495
|
}
|
|
10532
|
-
/**
|
|
10533
|
-
* Subscribe to the query channel for agent interactions.
|
|
10534
|
-
* Handles streaming responses and traces both the top-level agent task
|
|
10535
|
-
* and individual LLM calls.
|
|
10536
|
-
*/
|
|
10537
11496
|
subscribeToQuery() {
|
|
10538
11497
|
const channel2 = claudeAgentSDKChannels.query.tracingChannel();
|
|
10539
11498
|
const spans = /* @__PURE__ */ new WeakMap();
|
|
10540
11499
|
const handlers = {
|
|
10541
11500
|
start: (event) => {
|
|
10542
|
-
const params = event.arguments[0];
|
|
10543
|
-
const
|
|
10544
|
-
const options = params
|
|
11501
|
+
const params = event.arguments[0] ?? {};
|
|
11502
|
+
const originalPrompt = params.prompt;
|
|
11503
|
+
const options = params.options ?? {};
|
|
11504
|
+
const promptIsAsyncIterable = isAsyncIterable(originalPrompt);
|
|
11505
|
+
let promptStarted = false;
|
|
11506
|
+
let capturedPromptMessages;
|
|
11507
|
+
let resolvePromptDone;
|
|
11508
|
+
const promptDone = new Promise((resolve) => {
|
|
11509
|
+
resolvePromptDone = resolve;
|
|
11510
|
+
});
|
|
11511
|
+
if (promptIsAsyncIterable) {
|
|
11512
|
+
capturedPromptMessages = [];
|
|
11513
|
+
const promptStream = originalPrompt;
|
|
11514
|
+
params.prompt = (async function* () {
|
|
11515
|
+
promptStarted = true;
|
|
11516
|
+
try {
|
|
11517
|
+
for await (const message of promptStream) {
|
|
11518
|
+
capturedPromptMessages.push(message);
|
|
11519
|
+
yield message;
|
|
11520
|
+
}
|
|
11521
|
+
} finally {
|
|
11522
|
+
resolvePromptDone?.();
|
|
11523
|
+
}
|
|
11524
|
+
})();
|
|
11525
|
+
}
|
|
10545
11526
|
const span = startSpan({
|
|
10546
11527
|
name: "Claude Agent",
|
|
10547
11528
|
spanAttributes: {
|
|
@@ -10551,163 +11532,111 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
10551
11532
|
const startTime = getCurrentUnixTimestamp();
|
|
10552
11533
|
try {
|
|
10553
11534
|
span.log({
|
|
10554
|
-
input: typeof
|
|
10555
|
-
type: "streaming",
|
|
10556
|
-
description: "AsyncIterable<ClaudeAgentSDKMessage>"
|
|
10557
|
-
},
|
|
11535
|
+
input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
|
|
10558
11536
|
metadata: filterSerializableOptions(options)
|
|
10559
11537
|
});
|
|
10560
11538
|
} catch (error) {
|
|
10561
11539
|
console.error("Error extracting input for Claude Agent SDK:", error);
|
|
10562
11540
|
}
|
|
11541
|
+
const activeToolSpans = /* @__PURE__ */ new Map();
|
|
11542
|
+
const subAgentSpans = /* @__PURE__ */ new Map();
|
|
11543
|
+
const endedSubAgentSpans = /* @__PURE__ */ new Set();
|
|
11544
|
+
const toolUseToParent = /* @__PURE__ */ new Map();
|
|
11545
|
+
const pendingSubAgentNames = /* @__PURE__ */ new Map();
|
|
11546
|
+
const optionsWithHooks = injectTracingHooks(
|
|
11547
|
+
options,
|
|
11548
|
+
async (toolUseID) => {
|
|
11549
|
+
const parentToolUseId = toolUseToParent.get(toolUseID);
|
|
11550
|
+
if (parentToolUseId) {
|
|
11551
|
+
const subAgentSpan = await ensureSubAgentSpan(
|
|
11552
|
+
pendingSubAgentNames,
|
|
11553
|
+
span,
|
|
11554
|
+
subAgentSpans,
|
|
11555
|
+
parentToolUseId
|
|
11556
|
+
);
|
|
11557
|
+
return subAgentSpan.export();
|
|
11558
|
+
}
|
|
11559
|
+
return span.export();
|
|
11560
|
+
},
|
|
11561
|
+
activeToolSpans,
|
|
11562
|
+
subAgentSpans,
|
|
11563
|
+
endedSubAgentSpans
|
|
11564
|
+
);
|
|
11565
|
+
params.options = optionsWithHooks;
|
|
11566
|
+
event.arguments[0] = params;
|
|
10563
11567
|
spans.set(event, {
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10567
|
-
currentMessages: [],
|
|
11568
|
+
accumulatedOutputTokens: 0,
|
|
11569
|
+
activeToolSpans,
|
|
11570
|
+
capturedPromptMessages,
|
|
10568
11571
|
currentMessageId: void 0,
|
|
10569
11572
|
currentMessageStartTime: startTime,
|
|
10570
|
-
|
|
11573
|
+
currentMessages: [],
|
|
11574
|
+
endedSubAgentSpans,
|
|
11575
|
+
finalResults: [],
|
|
11576
|
+
options: optionsWithHooks,
|
|
11577
|
+
originalPrompt,
|
|
11578
|
+
pendingSubAgentNames,
|
|
11579
|
+
processing: Promise.resolve(),
|
|
11580
|
+
promptDone,
|
|
11581
|
+
promptStarted: () => promptStarted,
|
|
11582
|
+
span,
|
|
11583
|
+
subAgentSpans,
|
|
11584
|
+
toolUseToParent
|
|
10571
11585
|
});
|
|
10572
11586
|
},
|
|
10573
|
-
|
|
10574
|
-
const
|
|
10575
|
-
if (!
|
|
11587
|
+
end: (event) => {
|
|
11588
|
+
const state = spans.get(event);
|
|
11589
|
+
if (!state) {
|
|
10576
11590
|
return;
|
|
10577
11591
|
}
|
|
10578
11592
|
const eventResult = event.result;
|
|
10579
11593
|
if (eventResult === void 0) {
|
|
10580
|
-
|
|
11594
|
+
state.span.end();
|
|
10581
11595
|
spans.delete(event);
|
|
10582
11596
|
return;
|
|
10583
11597
|
}
|
|
10584
11598
|
if (isAsyncIterable(eventResult)) {
|
|
10585
11599
|
patchStreamIfNeeded(eventResult, {
|
|
10586
|
-
onChunk:
|
|
10587
|
-
|
|
10588
|
-
|
|
10589
|
-
const prompt = params?.prompt;
|
|
10590
|
-
const options = params?.options ?? {};
|
|
10591
|
-
const messageId = message.message?.id;
|
|
10592
|
-
if (messageId && messageId !== spanData.currentMessageId) {
|
|
10593
|
-
if (spanData.currentMessages.length > 0) {
|
|
10594
|
-
const finalMessage = await createLLMSpanForMessages(
|
|
10595
|
-
spanData.currentMessages,
|
|
10596
|
-
prompt,
|
|
10597
|
-
spanData.conversationHistory,
|
|
10598
|
-
options,
|
|
10599
|
-
spanData.currentMessageStartTime,
|
|
10600
|
-
await spanData.span.export()
|
|
10601
|
-
);
|
|
10602
|
-
if (finalMessage) {
|
|
10603
|
-
spanData.conversationHistory.push(finalMessage);
|
|
10604
|
-
}
|
|
10605
|
-
const lastMessage = spanData.currentMessages[spanData.currentMessages.length - 1];
|
|
10606
|
-
if (lastMessage?.message?.usage) {
|
|
10607
|
-
const outputTokens = getNumberProperty(
|
|
10608
|
-
lastMessage.message.usage,
|
|
10609
|
-
"output_tokens"
|
|
10610
|
-
) || 0;
|
|
10611
|
-
spanData.accumulatedOutputTokens += outputTokens;
|
|
10612
|
-
}
|
|
10613
|
-
spanData.currentMessages = [];
|
|
10614
|
-
}
|
|
10615
|
-
spanData.currentMessageId = messageId;
|
|
10616
|
-
spanData.currentMessageStartTime = currentTime;
|
|
10617
|
-
}
|
|
10618
|
-
if (message.type === "assistant" && message.message?.usage) {
|
|
10619
|
-
spanData.currentMessages.push(message);
|
|
10620
|
-
}
|
|
10621
|
-
if (message.type === "result" && message.usage) {
|
|
10622
|
-
const finalUsageMetrics = extractUsageFromMessage(message);
|
|
10623
|
-
if (spanData.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
|
|
10624
|
-
const lastMessage = spanData.currentMessages[spanData.currentMessages.length - 1];
|
|
10625
|
-
if (lastMessage?.message?.usage) {
|
|
10626
|
-
const adjustedTokens = finalUsageMetrics.completion_tokens - spanData.accumulatedOutputTokens;
|
|
10627
|
-
if (adjustedTokens >= 0) {
|
|
10628
|
-
lastMessage.message.usage.output_tokens = adjustedTokens;
|
|
10629
|
-
}
|
|
10630
|
-
}
|
|
10631
|
-
}
|
|
10632
|
-
const result_metadata = {};
|
|
10633
|
-
if (message.num_turns !== void 0) {
|
|
10634
|
-
result_metadata.num_turns = message.num_turns;
|
|
10635
|
-
}
|
|
10636
|
-
if (message.session_id !== void 0) {
|
|
10637
|
-
result_metadata.session_id = message.session_id;
|
|
10638
|
-
}
|
|
10639
|
-
if (Object.keys(result_metadata).length > 0) {
|
|
10640
|
-
spanData.span.log({
|
|
10641
|
-
metadata: result_metadata
|
|
10642
|
-
});
|
|
10643
|
-
}
|
|
10644
|
-
}
|
|
10645
|
-
},
|
|
10646
|
-
onComplete: async () => {
|
|
10647
|
-
try {
|
|
10648
|
-
const params = event.arguments[0];
|
|
10649
|
-
const prompt = params?.prompt;
|
|
10650
|
-
const options = params?.options ?? {};
|
|
10651
|
-
if (spanData.currentMessages.length > 0) {
|
|
10652
|
-
const finalMessage = await createLLMSpanForMessages(
|
|
10653
|
-
spanData.currentMessages,
|
|
10654
|
-
prompt,
|
|
10655
|
-
spanData.conversationHistory,
|
|
10656
|
-
options,
|
|
10657
|
-
spanData.currentMessageStartTime,
|
|
10658
|
-
await spanData.span.export()
|
|
10659
|
-
);
|
|
10660
|
-
if (finalMessage) {
|
|
10661
|
-
spanData.conversationHistory.push(finalMessage);
|
|
10662
|
-
}
|
|
10663
|
-
}
|
|
10664
|
-
spanData.span.log({
|
|
10665
|
-
output: spanData.conversationHistory.length > 0 ? spanData.conversationHistory[spanData.conversationHistory.length - 1] : void 0
|
|
10666
|
-
});
|
|
10667
|
-
} catch (error) {
|
|
11600
|
+
onChunk: (message) => {
|
|
11601
|
+
maybeTrackToolUseContext(state, message);
|
|
11602
|
+
state.processing = state.processing.then(() => handleStreamMessage(state, message)).catch((error) => {
|
|
10668
11603
|
console.error(
|
|
10669
|
-
"Error
|
|
11604
|
+
"Error processing Claude Agent SDK stream chunk:",
|
|
10670
11605
|
error
|
|
10671
11606
|
);
|
|
10672
|
-
}
|
|
10673
|
-
spanData.span.end();
|
|
10674
|
-
spans.delete(event);
|
|
10675
|
-
}
|
|
11607
|
+
});
|
|
10676
11608
|
},
|
|
10677
|
-
|
|
10678
|
-
|
|
11609
|
+
onComplete: () => state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
|
|
11610
|
+
spans.delete(event);
|
|
11611
|
+
}),
|
|
11612
|
+
onError: (error) => state.processing.then(() => {
|
|
11613
|
+
state.span.log({
|
|
10679
11614
|
error: error.message
|
|
10680
11615
|
});
|
|
10681
|
-
|
|
11616
|
+
}).then(() => finalizeQuerySpan(state)).finally(() => {
|
|
10682
11617
|
spans.delete(event);
|
|
10683
|
-
}
|
|
11618
|
+
})
|
|
10684
11619
|
});
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
|
-
);
|
|
10695
|
-
} finally {
|
|
10696
|
-
spanData.span.end();
|
|
10697
|
-
spans.delete(event);
|
|
10698
|
-
}
|
|
11620
|
+
return;
|
|
11621
|
+
}
|
|
11622
|
+
try {
|
|
11623
|
+
state.span.log({ output: eventResult });
|
|
11624
|
+
} catch (error) {
|
|
11625
|
+
console.error("Error extracting output for Claude Agent SDK:", error);
|
|
11626
|
+
} finally {
|
|
11627
|
+
state.span.end();
|
|
11628
|
+
spans.delete(event);
|
|
10699
11629
|
}
|
|
10700
11630
|
},
|
|
10701
11631
|
error: (event) => {
|
|
10702
|
-
const
|
|
10703
|
-
if (!
|
|
11632
|
+
const state = spans.get(event);
|
|
11633
|
+
if (!state || !event.error) {
|
|
10704
11634
|
return;
|
|
10705
11635
|
}
|
|
10706
|
-
|
|
10707
|
-
span.log({
|
|
11636
|
+
state.span.log({
|
|
10708
11637
|
error: event.error.message
|
|
10709
11638
|
});
|
|
10710
|
-
span.end();
|
|
11639
|
+
state.span.end();
|
|
10711
11640
|
spans.delete(event);
|
|
10712
11641
|
}
|
|
10713
11642
|
};
|
|
@@ -10731,6 +11660,18 @@ var googleGenAIChannels = defineChannels("@google/genai", {
|
|
|
10731
11660
|
});
|
|
10732
11661
|
|
|
10733
11662
|
// src/instrumentation/plugins/google-genai-plugin.ts
|
|
11663
|
+
var GOOGLE_GENAI_INTERNAL_CONTEXT = {
|
|
11664
|
+
caller_filename: "<node-internal>",
|
|
11665
|
+
caller_functionname: "<node-internal>",
|
|
11666
|
+
caller_lineno: 0
|
|
11667
|
+
};
|
|
11668
|
+
function createWrapperParityEvent(args) {
|
|
11669
|
+
return {
|
|
11670
|
+
context: GOOGLE_GENAI_INTERNAL_CONTEXT,
|
|
11671
|
+
input: args.input,
|
|
11672
|
+
metadata: args.metadata
|
|
11673
|
+
};
|
|
11674
|
+
}
|
|
10734
11675
|
var GoogleGenAIPlugin = class extends BasePlugin {
|
|
10735
11676
|
onEnable() {
|
|
10736
11677
|
this.subscribeToGoogleGenAIChannels();
|
|
@@ -10739,70 +11680,304 @@ var GoogleGenAIPlugin = class extends BasePlugin {
|
|
|
10739
11680
|
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
10740
11681
|
}
|
|
10741
11682
|
subscribeToGoogleGenAIChannels() {
|
|
10742
|
-
this.
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
|
|
10756
|
-
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
11683
|
+
this.subscribeToGenerateContentChannel();
|
|
11684
|
+
this.subscribeToGenerateContentStreamChannel();
|
|
11685
|
+
}
|
|
11686
|
+
subscribeToGenerateContentChannel() {
|
|
11687
|
+
const tracingChannel = googleGenAIChannels.generateContent.tracingChannel();
|
|
11688
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
11689
|
+
const unbindCurrentSpanStore = bindCurrentSpanStoreToStart2(
|
|
11690
|
+
tracingChannel,
|
|
11691
|
+
states,
|
|
11692
|
+
(event) => {
|
|
11693
|
+
const params = event.arguments[0];
|
|
11694
|
+
const input = serializeInput(params);
|
|
11695
|
+
const metadata = extractMetadata(params);
|
|
11696
|
+
const span = startSpan({
|
|
11697
|
+
name: "generate_content",
|
|
11698
|
+
spanAttributes: {
|
|
11699
|
+
type: "llm" /* LLM */
|
|
11700
|
+
},
|
|
11701
|
+
event: createWrapperParityEvent({ input, metadata })
|
|
11702
|
+
});
|
|
11703
|
+
return {
|
|
11704
|
+
span,
|
|
11705
|
+
startTime: getCurrentUnixTimestamp()
|
|
11706
|
+
};
|
|
11707
|
+
}
|
|
10761
11708
|
);
|
|
10762
|
-
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
extractInput: ([params]) => {
|
|
11709
|
+
const handlers = {
|
|
11710
|
+
start: (event) => {
|
|
11711
|
+
ensureSpanState(states, event, () => {
|
|
11712
|
+
const params = event.arguments[0];
|
|
10767
11713
|
const input = serializeInput(params);
|
|
10768
11714
|
const metadata = extractMetadata(params);
|
|
11715
|
+
const span = startSpan({
|
|
11716
|
+
name: "generate_content",
|
|
11717
|
+
spanAttributes: {
|
|
11718
|
+
type: "llm" /* LLM */
|
|
11719
|
+
},
|
|
11720
|
+
event: createWrapperParityEvent({ input, metadata })
|
|
11721
|
+
});
|
|
10769
11722
|
return {
|
|
10770
|
-
|
|
10771
|
-
|
|
11723
|
+
span,
|
|
11724
|
+
startTime: getCurrentUnixTimestamp()
|
|
10772
11725
|
};
|
|
10773
|
-
}
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
return
|
|
10779
|
-
},
|
|
10780
|
-
aggregateChunks: (chunks, _result, _endEvent, startTime) => {
|
|
10781
|
-
return aggregateGenerateContentChunks(chunks, startTime);
|
|
11726
|
+
});
|
|
11727
|
+
},
|
|
11728
|
+
asyncEnd: (event) => {
|
|
11729
|
+
const spanState = states.get(event);
|
|
11730
|
+
if (!spanState) {
|
|
11731
|
+
return;
|
|
10782
11732
|
}
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
|
|
10788
|
-
|
|
10789
|
-
|
|
10790
|
-
|
|
10791
|
-
|
|
10792
|
-
|
|
10793
|
-
|
|
10794
|
-
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
|
|
11733
|
+
try {
|
|
11734
|
+
spanState.span.log({
|
|
11735
|
+
metrics: cleanMetrics(
|
|
11736
|
+
extractGenerateContentMetrics(
|
|
11737
|
+
event.result,
|
|
11738
|
+
spanState.startTime
|
|
11739
|
+
)
|
|
11740
|
+
),
|
|
11741
|
+
output: event.result
|
|
11742
|
+
});
|
|
11743
|
+
} finally {
|
|
11744
|
+
spanState.span.end();
|
|
11745
|
+
states.delete(event);
|
|
11746
|
+
}
|
|
11747
|
+
},
|
|
11748
|
+
error: (event) => {
|
|
11749
|
+
logErrorAndEndSpan(states, event);
|
|
10798
11750
|
}
|
|
10799
|
-
|
|
10800
|
-
|
|
11751
|
+
};
|
|
11752
|
+
tracingChannel.subscribe(handlers);
|
|
11753
|
+
this.unsubscribers.push(() => {
|
|
11754
|
+
unbindCurrentSpanStore?.();
|
|
11755
|
+
tracingChannel.unsubscribe(handlers);
|
|
11756
|
+
});
|
|
10801
11757
|
}
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
11758
|
+
subscribeToGenerateContentStreamChannel() {
|
|
11759
|
+
const tracingChannel = googleGenAIChannels.generateContentStream.tracingChannel();
|
|
11760
|
+
const handlers = {
|
|
11761
|
+
start: (event) => {
|
|
11762
|
+
const streamEvent = event;
|
|
11763
|
+
const params = event.arguments[0];
|
|
11764
|
+
streamEvent.googleGenAIInput = serializeInput(params);
|
|
11765
|
+
streamEvent.googleGenAIMetadata = extractMetadata(params);
|
|
11766
|
+
streamEvent.googleGenAIStartTime = getCurrentUnixTimestamp();
|
|
11767
|
+
},
|
|
11768
|
+
asyncEnd: (event) => {
|
|
11769
|
+
const streamEvent = event;
|
|
11770
|
+
patchGoogleGenAIStreamingResult({
|
|
11771
|
+
input: streamEvent.googleGenAIInput,
|
|
11772
|
+
metadata: streamEvent.googleGenAIMetadata,
|
|
11773
|
+
startTime: streamEvent.googleGenAIStartTime,
|
|
11774
|
+
result: streamEvent.result
|
|
11775
|
+
});
|
|
11776
|
+
},
|
|
11777
|
+
error: () => {
|
|
11778
|
+
}
|
|
11779
|
+
};
|
|
11780
|
+
tracingChannel.subscribe(handlers);
|
|
11781
|
+
this.unsubscribers.push(() => {
|
|
11782
|
+
tracingChannel.unsubscribe(handlers);
|
|
11783
|
+
});
|
|
11784
|
+
}
|
|
11785
|
+
};
|
|
11786
|
+
function ensureSpanState(states, event, create) {
|
|
11787
|
+
const existing = states.get(event);
|
|
11788
|
+
if (existing) {
|
|
11789
|
+
return existing;
|
|
11790
|
+
}
|
|
11791
|
+
const created = create();
|
|
11792
|
+
states.set(event, created);
|
|
11793
|
+
return created;
|
|
11794
|
+
}
|
|
11795
|
+
function bindCurrentSpanStoreToStart2(tracingChannel, states, create) {
|
|
11796
|
+
const state = _internalGetGlobalState();
|
|
11797
|
+
const startChannel = tracingChannel.start;
|
|
11798
|
+
const currentSpanStore = state?.contextManager ? state.contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
|
|
11799
|
+
if (!startChannel?.bindStore || !currentSpanStore) {
|
|
11800
|
+
return void 0;
|
|
11801
|
+
}
|
|
11802
|
+
startChannel.bindStore(
|
|
11803
|
+
currentSpanStore,
|
|
11804
|
+
(event) => ensureSpanState(
|
|
11805
|
+
states,
|
|
11806
|
+
event,
|
|
11807
|
+
() => create(event)
|
|
11808
|
+
).span
|
|
11809
|
+
);
|
|
11810
|
+
return () => {
|
|
11811
|
+
startChannel.unbindStore?.(currentSpanStore);
|
|
11812
|
+
};
|
|
11813
|
+
}
|
|
11814
|
+
function logErrorAndEndSpan(states, event) {
|
|
11815
|
+
const spanState = states.get(event);
|
|
11816
|
+
if (!spanState) {
|
|
11817
|
+
return;
|
|
11818
|
+
}
|
|
11819
|
+
spanState.span.log({
|
|
11820
|
+
error: event.error.message
|
|
11821
|
+
});
|
|
11822
|
+
spanState.span.end();
|
|
11823
|
+
states.delete(event);
|
|
11824
|
+
}
|
|
11825
|
+
function patchGoogleGenAIStreamingResult(args) {
|
|
11826
|
+
const { input, metadata, result, startTime } = args;
|
|
11827
|
+
if (!input || !metadata || !result || typeof result !== "object" || typeof result.next !== "function") {
|
|
11828
|
+
return false;
|
|
11829
|
+
}
|
|
11830
|
+
const chunks = [];
|
|
11831
|
+
let firstTokenTime = null;
|
|
11832
|
+
let finalized = false;
|
|
11833
|
+
let span = null;
|
|
11834
|
+
const requestStartTime = startTime ?? getCurrentUnixTimestamp();
|
|
11835
|
+
const ensureSpan = () => {
|
|
11836
|
+
if (!span) {
|
|
11837
|
+
span = startSpan({
|
|
11838
|
+
name: "generate_content_stream",
|
|
11839
|
+
spanAttributes: {
|
|
11840
|
+
type: "llm" /* LLM */
|
|
11841
|
+
},
|
|
11842
|
+
event: {
|
|
11843
|
+
input,
|
|
11844
|
+
metadata
|
|
11845
|
+
}
|
|
11846
|
+
});
|
|
11847
|
+
}
|
|
11848
|
+
return span;
|
|
11849
|
+
};
|
|
11850
|
+
const finalize = (options) => {
|
|
11851
|
+
if (finalized || !span) {
|
|
11852
|
+
return;
|
|
11853
|
+
}
|
|
11854
|
+
finalized = true;
|
|
11855
|
+
if (options.result) {
|
|
11856
|
+
const { end, ...metricsWithoutEnd } = options.result.metrics;
|
|
11857
|
+
span.log({
|
|
11858
|
+
metrics: cleanMetrics(metricsWithoutEnd),
|
|
11859
|
+
output: options.result.aggregated
|
|
11860
|
+
});
|
|
11861
|
+
span.end(typeof end === "number" ? { endTime: end } : void 0);
|
|
11862
|
+
return;
|
|
11863
|
+
}
|
|
11864
|
+
if (options.error !== void 0) {
|
|
11865
|
+
span.log({
|
|
11866
|
+
error: options.error instanceof Error ? options.error.message : String(options.error)
|
|
11867
|
+
});
|
|
11868
|
+
}
|
|
11869
|
+
span.end();
|
|
11870
|
+
};
|
|
11871
|
+
const patchIterator = (iterator) => {
|
|
11872
|
+
if (typeof iterator !== "object" || iterator === null || "__braintrustGoogleGenAIPatched" in iterator) {
|
|
11873
|
+
return iterator;
|
|
11874
|
+
}
|
|
11875
|
+
const iteratorRecord = iterator;
|
|
11876
|
+
const originalNext = typeof iteratorRecord.next === "function" ? iteratorRecord.next.bind(iterator) : void 0;
|
|
11877
|
+
const originalReturn = typeof iteratorRecord.return === "function" ? iteratorRecord.return.bind(iterator) : void 0;
|
|
11878
|
+
const originalThrow = typeof iteratorRecord.throw === "function" ? iteratorRecord.throw.bind(iterator) : void 0;
|
|
11879
|
+
const asyncIteratorMethod = iteratorRecord[Symbol.asyncIterator];
|
|
11880
|
+
const originalAsyncIterator = typeof asyncIteratorMethod === "function" ? asyncIteratorMethod.bind(iterator) : void 0;
|
|
11881
|
+
Object.defineProperty(iteratorRecord, "__braintrustGoogleGenAIPatched", {
|
|
11882
|
+
configurable: true,
|
|
11883
|
+
enumerable: false,
|
|
11884
|
+
value: true,
|
|
11885
|
+
writable: false
|
|
11886
|
+
});
|
|
11887
|
+
if (originalNext) {
|
|
11888
|
+
iteratorRecord.next = async (...nextArgs) => {
|
|
11889
|
+
ensureSpan();
|
|
11890
|
+
try {
|
|
11891
|
+
const nextResult = await originalNext(
|
|
11892
|
+
...nextArgs
|
|
11893
|
+
);
|
|
11894
|
+
if (!nextResult.done && nextResult.value) {
|
|
11895
|
+
if (firstTokenTime === null) {
|
|
11896
|
+
firstTokenTime = getCurrentUnixTimestamp();
|
|
11897
|
+
}
|
|
11898
|
+
chunks.push(nextResult.value);
|
|
11899
|
+
}
|
|
11900
|
+
if (nextResult.done) {
|
|
11901
|
+
finalize({
|
|
11902
|
+
result: aggregateGenerateContentChunks(
|
|
11903
|
+
chunks,
|
|
11904
|
+
requestStartTime,
|
|
11905
|
+
firstTokenTime
|
|
11906
|
+
)
|
|
11907
|
+
});
|
|
11908
|
+
}
|
|
11909
|
+
return nextResult;
|
|
11910
|
+
} catch (error) {
|
|
11911
|
+
finalize({ error });
|
|
11912
|
+
throw error;
|
|
11913
|
+
}
|
|
11914
|
+
};
|
|
11915
|
+
}
|
|
11916
|
+
if (originalReturn) {
|
|
11917
|
+
iteratorRecord.return = async (...returnArgs) => {
|
|
11918
|
+
ensureSpan();
|
|
11919
|
+
try {
|
|
11920
|
+
return await originalReturn(
|
|
11921
|
+
...returnArgs
|
|
11922
|
+
);
|
|
11923
|
+
} finally {
|
|
11924
|
+
if (chunks.length > 0) {
|
|
11925
|
+
finalize({
|
|
11926
|
+
result: aggregateGenerateContentChunks(
|
|
11927
|
+
chunks,
|
|
11928
|
+
requestStartTime,
|
|
11929
|
+
firstTokenTime
|
|
11930
|
+
)
|
|
11931
|
+
});
|
|
11932
|
+
} else {
|
|
11933
|
+
finalize({});
|
|
11934
|
+
}
|
|
11935
|
+
}
|
|
11936
|
+
};
|
|
11937
|
+
}
|
|
11938
|
+
if (originalThrow) {
|
|
11939
|
+
iteratorRecord.throw = async (...throwArgs) => {
|
|
11940
|
+
ensureSpan();
|
|
11941
|
+
try {
|
|
11942
|
+
return await originalThrow(
|
|
11943
|
+
...throwArgs
|
|
11944
|
+
);
|
|
11945
|
+
} catch (error) {
|
|
11946
|
+
finalize({ error });
|
|
11947
|
+
throw error;
|
|
11948
|
+
}
|
|
11949
|
+
};
|
|
11950
|
+
}
|
|
11951
|
+
iteratorRecord[Symbol.asyncIterator] = () => {
|
|
11952
|
+
const asyncIterator = originalAsyncIterator ? originalAsyncIterator() : iterator;
|
|
11953
|
+
return patchIterator(asyncIterator);
|
|
11954
|
+
};
|
|
11955
|
+
return iterator;
|
|
11956
|
+
};
|
|
11957
|
+
patchIterator(result);
|
|
11958
|
+
return true;
|
|
11959
|
+
}
|
|
11960
|
+
function serializeInput(params) {
|
|
11961
|
+
const input = {
|
|
11962
|
+
model: params.model,
|
|
11963
|
+
contents: serializeContents(params.contents)
|
|
11964
|
+
};
|
|
11965
|
+
if (params.config) {
|
|
11966
|
+
const config = tryToDict(params.config);
|
|
11967
|
+
if (config) {
|
|
11968
|
+
const filteredConfig = {};
|
|
11969
|
+
Object.keys(config).forEach((key) => {
|
|
11970
|
+
if (key !== "tools") {
|
|
11971
|
+
filteredConfig[key] = config[key];
|
|
11972
|
+
}
|
|
11973
|
+
});
|
|
11974
|
+
input.config = filteredConfig;
|
|
11975
|
+
}
|
|
11976
|
+
}
|
|
11977
|
+
return input;
|
|
11978
|
+
}
|
|
11979
|
+
function serializeContents(contents) {
|
|
11980
|
+
if (contents === null || contents === void 0) {
|
|
10806
11981
|
return null;
|
|
10807
11982
|
}
|
|
10808
11983
|
if (Array.isArray(contents)) {
|
|
@@ -10883,12 +12058,18 @@ function extractMetadata(params) {
|
|
|
10883
12058
|
});
|
|
10884
12059
|
}
|
|
10885
12060
|
}
|
|
12061
|
+
const tools = serializeTools(params);
|
|
12062
|
+
if (tools) {
|
|
12063
|
+
metadata.tools = tools;
|
|
12064
|
+
}
|
|
10886
12065
|
return metadata;
|
|
10887
12066
|
}
|
|
10888
12067
|
function extractGenerateContentMetrics(response, startTime) {
|
|
10889
12068
|
const metrics = {};
|
|
10890
|
-
if (startTime) {
|
|
12069
|
+
if (startTime !== void 0) {
|
|
10891
12070
|
const end = getCurrentUnixTimestamp();
|
|
12071
|
+
metrics.start = startTime;
|
|
12072
|
+
metrics.end = end;
|
|
10892
12073
|
metrics.duration = end - startTime;
|
|
10893
12074
|
}
|
|
10894
12075
|
if (response?.usageMetadata) {
|
|
@@ -10913,19 +12094,18 @@ function populateUsageMetrics(metrics, usage) {
|
|
|
10913
12094
|
metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
|
|
10914
12095
|
}
|
|
10915
12096
|
}
|
|
10916
|
-
function aggregateGenerateContentChunks(chunks, startTime) {
|
|
10917
|
-
const
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
if (
|
|
10924
|
-
firstTokenTime = getCurrentUnixTimestamp();
|
|
12097
|
+
function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
|
|
12098
|
+
const end = getCurrentUnixTimestamp();
|
|
12099
|
+
const metrics = {
|
|
12100
|
+
start: startTime,
|
|
12101
|
+
end,
|
|
12102
|
+
duration: end - startTime
|
|
12103
|
+
};
|
|
12104
|
+
if (firstTokenTime !== null) {
|
|
10925
12105
|
metrics.time_to_first_token = firstTokenTime - startTime;
|
|
10926
12106
|
}
|
|
10927
12107
|
if (chunks.length === 0) {
|
|
10928
|
-
return {
|
|
12108
|
+
return { aggregated: {}, metrics };
|
|
10929
12109
|
}
|
|
10930
12110
|
let text = "";
|
|
10931
12111
|
let thoughtText = "";
|
|
@@ -10961,7 +12141,7 @@ function aggregateGenerateContentChunks(chunks, startTime) {
|
|
|
10961
12141
|
}
|
|
10962
12142
|
}
|
|
10963
12143
|
}
|
|
10964
|
-
const
|
|
12144
|
+
const aggregated = {};
|
|
10965
12145
|
const parts = [];
|
|
10966
12146
|
if (thoughtText) {
|
|
10967
12147
|
parts.push({ text: thoughtText, thought: true });
|
|
@@ -10987,16 +12167,25 @@ function aggregateGenerateContentChunks(chunks, startTime) {
|
|
|
10987
12167
|
}
|
|
10988
12168
|
candidates.push(candidateDict);
|
|
10989
12169
|
}
|
|
10990
|
-
|
|
12170
|
+
aggregated.candidates = candidates;
|
|
10991
12171
|
}
|
|
10992
12172
|
if (usageMetadata) {
|
|
10993
|
-
|
|
12173
|
+
aggregated.usageMetadata = usageMetadata;
|
|
10994
12174
|
populateUsageMetrics(metrics, usageMetadata);
|
|
10995
12175
|
}
|
|
10996
12176
|
if (text) {
|
|
10997
|
-
|
|
12177
|
+
aggregated.text = text;
|
|
12178
|
+
}
|
|
12179
|
+
return { aggregated, metrics };
|
|
12180
|
+
}
|
|
12181
|
+
function cleanMetrics(metrics) {
|
|
12182
|
+
const cleaned = {};
|
|
12183
|
+
for (const [key, value] of Object.entries(metrics)) {
|
|
12184
|
+
if (value !== null && value !== void 0) {
|
|
12185
|
+
cleaned[key] = value;
|
|
12186
|
+
}
|
|
10998
12187
|
}
|
|
10999
|
-
return
|
|
12188
|
+
return cleaned;
|
|
11000
12189
|
}
|
|
11001
12190
|
function tryToDict(obj) {
|
|
11002
12191
|
if (obj === null || obj === void 0) {
|
|
@@ -11030,242 +12219,442 @@ var openRouterChannels = defineChannels("@openrouter/sdk", {
|
|
|
11030
12219
|
channelName: "callModel",
|
|
11031
12220
|
kind: "sync-stream"
|
|
11032
12221
|
}),
|
|
12222
|
+
callModelTurn: channel({
|
|
12223
|
+
channelName: "callModel.turn",
|
|
12224
|
+
kind: "async"
|
|
12225
|
+
}),
|
|
11033
12226
|
toolExecute: channel({
|
|
11034
12227
|
channelName: "tool.execute",
|
|
11035
12228
|
kind: "async"
|
|
11036
12229
|
})
|
|
11037
12230
|
});
|
|
11038
12231
|
|
|
11039
|
-
// src/openrouter-
|
|
11040
|
-
var
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
completionTokens: "completion_tokens",
|
|
11044
|
-
outputTokens: "completion_tokens",
|
|
11045
|
-
totalTokens: "tokens",
|
|
11046
|
-
prompt_tokens: "prompt_tokens",
|
|
11047
|
-
input_tokens: "prompt_tokens",
|
|
11048
|
-
completion_tokens: "completion_tokens",
|
|
11049
|
-
output_tokens: "completion_tokens",
|
|
11050
|
-
total_tokens: "tokens"
|
|
11051
|
-
};
|
|
11052
|
-
var TOKEN_DETAIL_PREFIX_MAP = {
|
|
11053
|
-
promptTokensDetails: "prompt",
|
|
11054
|
-
inputTokensDetails: "prompt",
|
|
11055
|
-
completionTokensDetails: "completion",
|
|
11056
|
-
outputTokensDetails: "completion",
|
|
11057
|
-
costDetails: "cost",
|
|
11058
|
-
prompt_tokens_details: "prompt",
|
|
11059
|
-
input_tokens_details: "prompt",
|
|
11060
|
-
completion_tokens_details: "completion",
|
|
11061
|
-
output_tokens_details: "completion",
|
|
11062
|
-
cost_details: "cost"
|
|
11063
|
-
};
|
|
11064
|
-
function camelToSnake(value) {
|
|
11065
|
-
return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
|
|
11066
|
-
}
|
|
11067
|
-
function parseOpenRouterMetricsFromUsage(usage) {
|
|
11068
|
-
if (!isObject(usage)) {
|
|
11069
|
-
return {};
|
|
11070
|
-
}
|
|
11071
|
-
const metrics = {};
|
|
11072
|
-
for (const [name, value] of Object.entries(usage)) {
|
|
11073
|
-
if (typeof value === "number") {
|
|
11074
|
-
metrics[TOKEN_NAME_MAP2[name] || camelToSnake(name)] = value;
|
|
11075
|
-
continue;
|
|
11076
|
-
}
|
|
11077
|
-
if (!isObject(value)) {
|
|
11078
|
-
continue;
|
|
11079
|
-
}
|
|
11080
|
-
const prefix = TOKEN_DETAIL_PREFIX_MAP[name];
|
|
11081
|
-
if (!prefix) {
|
|
11082
|
-
continue;
|
|
11083
|
-
}
|
|
11084
|
-
for (const [nestedName, nestedValue] of Object.entries(value)) {
|
|
11085
|
-
if (typeof nestedValue !== "number") {
|
|
11086
|
-
continue;
|
|
11087
|
-
}
|
|
11088
|
-
metrics[`${prefix}_${camelToSnake(nestedName)}`] = nestedValue;
|
|
11089
|
-
}
|
|
11090
|
-
}
|
|
11091
|
-
return metrics;
|
|
11092
|
-
}
|
|
11093
|
-
function extractOpenRouterUsageMetadata(usage) {
|
|
11094
|
-
if (!isObject(usage)) {
|
|
11095
|
-
return void 0;
|
|
11096
|
-
}
|
|
11097
|
-
const metadata = {};
|
|
11098
|
-
if (typeof usage.isByok === "boolean") {
|
|
11099
|
-
metadata.is_byok = usage.isByok;
|
|
11100
|
-
} else if (typeof usage.is_byok === "boolean") {
|
|
11101
|
-
metadata.is_byok = usage.is_byok;
|
|
11102
|
-
}
|
|
11103
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
11104
|
-
}
|
|
11105
|
-
|
|
11106
|
-
// src/openrouter-logging.ts
|
|
11107
|
-
var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
|
|
11108
|
-
"execute",
|
|
11109
|
-
"render",
|
|
11110
|
-
"nextTurnParams",
|
|
11111
|
-
"requireApproval"
|
|
11112
|
-
]);
|
|
11113
|
-
function parseOpenRouterModelString(model) {
|
|
11114
|
-
if (typeof model !== "string") {
|
|
11115
|
-
return { model };
|
|
11116
|
-
}
|
|
11117
|
-
const slashIndex = model.indexOf("/");
|
|
11118
|
-
if (slashIndex > 0 && slashIndex < model.length - 1) {
|
|
11119
|
-
return {
|
|
11120
|
-
provider: model.substring(0, slashIndex),
|
|
11121
|
-
model: model.substring(slashIndex + 1)
|
|
11122
|
-
};
|
|
11123
|
-
}
|
|
11124
|
-
return { model };
|
|
11125
|
-
}
|
|
11126
|
-
function isZodSchema2(value) {
|
|
11127
|
-
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
11128
|
-
}
|
|
11129
|
-
function serializeZodSchema2(schema) {
|
|
11130
|
-
try {
|
|
11131
|
-
return zodToJsonSchema(schema);
|
|
11132
|
-
} catch {
|
|
11133
|
-
return {
|
|
11134
|
-
type: "object",
|
|
11135
|
-
description: "Zod schema (conversion failed)"
|
|
11136
|
-
};
|
|
11137
|
-
}
|
|
11138
|
-
}
|
|
11139
|
-
function serializeOpenRouterTool(tool) {
|
|
11140
|
-
if (!isObject(tool)) {
|
|
11141
|
-
return tool;
|
|
11142
|
-
}
|
|
11143
|
-
const serialized = {};
|
|
11144
|
-
for (const [key, value] of Object.entries(tool)) {
|
|
11145
|
-
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
11146
|
-
continue;
|
|
11147
|
-
}
|
|
11148
|
-
if (key === "function" && isObject(value)) {
|
|
11149
|
-
serialized.function = sanitizeOpenRouterLoggedValue(value);
|
|
11150
|
-
continue;
|
|
11151
|
-
}
|
|
11152
|
-
serialized[key] = sanitizeOpenRouterLoggedValue(value);
|
|
11153
|
-
}
|
|
11154
|
-
return serialized;
|
|
11155
|
-
}
|
|
11156
|
-
function serializeOpenRouterToolsForLogging(tools) {
|
|
11157
|
-
if (!Array.isArray(tools)) {
|
|
11158
|
-
return void 0;
|
|
11159
|
-
}
|
|
11160
|
-
return tools.map((tool) => serializeOpenRouterTool(tool));
|
|
11161
|
-
}
|
|
11162
|
-
function sanitizeOpenRouterLoggedValue(value) {
|
|
11163
|
-
if (isZodSchema2(value)) {
|
|
11164
|
-
return serializeZodSchema2(value);
|
|
12232
|
+
// src/instrumentation/plugins/openrouter-plugin.ts
|
|
12233
|
+
var OpenRouterPlugin = class extends BasePlugin {
|
|
12234
|
+
onEnable() {
|
|
12235
|
+
this.subscribeToOpenRouterChannels();
|
|
11165
12236
|
}
|
|
11166
|
-
|
|
11167
|
-
|
|
12237
|
+
onDisable() {
|
|
12238
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
11168
12239
|
}
|
|
11169
|
-
|
|
11170
|
-
|
|
12240
|
+
subscribeToOpenRouterChannels() {
|
|
12241
|
+
this.unsubscribers.push(
|
|
12242
|
+
traceStreamingChannel(openRouterChannels.chatSend, {
|
|
12243
|
+
name: "openrouter.chat.send",
|
|
12244
|
+
type: "llm" /* LLM */,
|
|
12245
|
+
extractInput: (args) => {
|
|
12246
|
+
const request = getOpenRouterRequestArg(args);
|
|
12247
|
+
const chatGenerationParams = isObject(request?.chatGenerationParams) ? request.chatGenerationParams : {};
|
|
12248
|
+
const httpReferer = request?.httpReferer;
|
|
12249
|
+
const xTitle = request?.xTitle;
|
|
12250
|
+
const { messages, ...metadata } = chatGenerationParams;
|
|
12251
|
+
return {
|
|
12252
|
+
input: messages,
|
|
12253
|
+
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
12254
|
+
};
|
|
12255
|
+
},
|
|
12256
|
+
extractOutput: (result) => {
|
|
12257
|
+
return isObject(result) ? result.choices : void 0;
|
|
12258
|
+
},
|
|
12259
|
+
extractMetrics: (result, startTime) => {
|
|
12260
|
+
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
12261
|
+
if (startTime) {
|
|
12262
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
12263
|
+
}
|
|
12264
|
+
return metrics;
|
|
12265
|
+
},
|
|
12266
|
+
aggregateChunks: aggregateOpenRouterChatChunks
|
|
12267
|
+
})
|
|
12268
|
+
);
|
|
12269
|
+
this.unsubscribers.push(
|
|
12270
|
+
traceAsyncChannel(openRouterChannels.embeddingsGenerate, {
|
|
12271
|
+
name: "openrouter.embeddings.generate",
|
|
12272
|
+
type: "llm" /* LLM */,
|
|
12273
|
+
extractInput: (args) => {
|
|
12274
|
+
const request = getOpenRouterRequestArg(args);
|
|
12275
|
+
const requestBody = isObject(request?.requestBody) ? request.requestBody : {};
|
|
12276
|
+
const httpReferer = request?.httpReferer;
|
|
12277
|
+
const xTitle = request?.xTitle;
|
|
12278
|
+
const { input, ...metadata } = requestBody;
|
|
12279
|
+
return {
|
|
12280
|
+
input,
|
|
12281
|
+
metadata: buildOpenRouterEmbeddingMetadata(
|
|
12282
|
+
metadata,
|
|
12283
|
+
httpReferer,
|
|
12284
|
+
xTitle
|
|
12285
|
+
)
|
|
12286
|
+
};
|
|
12287
|
+
},
|
|
12288
|
+
extractOutput: (result) => {
|
|
12289
|
+
if (!isObject(result)) {
|
|
12290
|
+
return void 0;
|
|
12291
|
+
}
|
|
12292
|
+
const embedding = result.data?.[0]?.embedding;
|
|
12293
|
+
return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
|
|
12294
|
+
},
|
|
12295
|
+
extractMetadata: (result) => {
|
|
12296
|
+
if (!isObject(result)) {
|
|
12297
|
+
return void 0;
|
|
12298
|
+
}
|
|
12299
|
+
return extractOpenRouterResponseMetadata(result);
|
|
12300
|
+
},
|
|
12301
|
+
extractMetrics: (result) => {
|
|
12302
|
+
return isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {};
|
|
12303
|
+
}
|
|
12304
|
+
})
|
|
12305
|
+
);
|
|
12306
|
+
this.unsubscribers.push(
|
|
12307
|
+
traceStreamingChannel(openRouterChannels.betaResponsesSend, {
|
|
12308
|
+
name: "openrouter.beta.responses.send",
|
|
12309
|
+
type: "llm" /* LLM */,
|
|
12310
|
+
extractInput: (args) => {
|
|
12311
|
+
const request = getOpenRouterRequestArg(args);
|
|
12312
|
+
const openResponsesRequest = isObject(request?.openResponsesRequest) ? request.openResponsesRequest : {};
|
|
12313
|
+
const httpReferer = request?.httpReferer;
|
|
12314
|
+
const xTitle = request?.xTitle;
|
|
12315
|
+
const { input, ...metadata } = openResponsesRequest;
|
|
12316
|
+
return {
|
|
12317
|
+
input,
|
|
12318
|
+
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
12319
|
+
};
|
|
12320
|
+
},
|
|
12321
|
+
extractOutput: (result) => extractOpenRouterResponseOutput(result),
|
|
12322
|
+
extractMetadata: (result) => extractOpenRouterResponseMetadata(result),
|
|
12323
|
+
extractMetrics: (result, startTime) => {
|
|
12324
|
+
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
12325
|
+
if (startTime) {
|
|
12326
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
12327
|
+
}
|
|
12328
|
+
return metrics;
|
|
12329
|
+
},
|
|
12330
|
+
aggregateChunks: aggregateOpenRouterResponseStreamEvents
|
|
12331
|
+
})
|
|
12332
|
+
);
|
|
12333
|
+
this.unsubscribers.push(
|
|
12334
|
+
traceSyncStreamChannel(openRouterChannels.callModel, {
|
|
12335
|
+
name: "openrouter.callModel",
|
|
12336
|
+
type: "llm" /* LLM */,
|
|
12337
|
+
extractInput: (args) => {
|
|
12338
|
+
const request = getOpenRouterCallModelRequestArg(args);
|
|
12339
|
+
return {
|
|
12340
|
+
input: request ? extractOpenRouterCallModelInput(request) : void 0,
|
|
12341
|
+
metadata: request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" }
|
|
12342
|
+
};
|
|
12343
|
+
},
|
|
12344
|
+
patchResult: ({ endEvent, result, span }) => {
|
|
12345
|
+
return patchOpenRouterCallModelResult({
|
|
12346
|
+
request: getOpenRouterCallModelRequestArg(endEvent.arguments),
|
|
12347
|
+
result,
|
|
12348
|
+
span
|
|
12349
|
+
});
|
|
12350
|
+
}
|
|
12351
|
+
})
|
|
12352
|
+
);
|
|
12353
|
+
this.unsubscribers.push(
|
|
12354
|
+
traceAsyncChannel(openRouterChannels.callModelTurn, {
|
|
12355
|
+
name: "openrouter.beta.responses.send",
|
|
12356
|
+
type: "llm" /* LLM */,
|
|
12357
|
+
extractInput: (args, event) => {
|
|
12358
|
+
const request = getOpenRouterCallModelRequestArg(args);
|
|
12359
|
+
const metadata = request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" };
|
|
12360
|
+
if (isObject(metadata) && "tools" in metadata) {
|
|
12361
|
+
delete metadata.tools;
|
|
12362
|
+
}
|
|
12363
|
+
return {
|
|
12364
|
+
input: request ? extractOpenRouterCallModelInput(request) : void 0,
|
|
12365
|
+
metadata: {
|
|
12366
|
+
...metadata,
|
|
12367
|
+
step: event.step,
|
|
12368
|
+
step_type: event.stepType
|
|
12369
|
+
}
|
|
12370
|
+
};
|
|
12371
|
+
},
|
|
12372
|
+
extractOutput: (result) => extractOpenRouterResponseOutput(result),
|
|
12373
|
+
extractMetadata: (result, event) => {
|
|
12374
|
+
if (!isObject(result)) {
|
|
12375
|
+
return {
|
|
12376
|
+
step: event?.step,
|
|
12377
|
+
step_type: event?.stepType
|
|
12378
|
+
};
|
|
12379
|
+
}
|
|
12380
|
+
return {
|
|
12381
|
+
...extractOpenRouterResponseMetadata(result) || {},
|
|
12382
|
+
...event?.step !== void 0 ? { step: event.step } : {},
|
|
12383
|
+
...event?.stepType ? { step_type: event.stepType } : {}
|
|
12384
|
+
};
|
|
12385
|
+
},
|
|
12386
|
+
extractMetrics: (result) => isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {}
|
|
12387
|
+
})
|
|
12388
|
+
);
|
|
12389
|
+
this.unsubscribers.push(
|
|
12390
|
+
traceStreamingChannel(openRouterChannels.toolExecute, {
|
|
12391
|
+
name: "openrouter.tool",
|
|
12392
|
+
type: "tool" /* TOOL */,
|
|
12393
|
+
extractInput: (args, event) => ({
|
|
12394
|
+
input: args[0],
|
|
12395
|
+
metadata: {
|
|
12396
|
+
provider: "openrouter",
|
|
12397
|
+
tool_name: event.toolName,
|
|
12398
|
+
...event.toolCallId ? { tool_call_id: event.toolCallId } : {}
|
|
12399
|
+
}
|
|
12400
|
+
}),
|
|
12401
|
+
extractOutput: (result) => result,
|
|
12402
|
+
extractMetrics: () => ({}),
|
|
12403
|
+
aggregateChunks: (chunks) => ({
|
|
12404
|
+
output: chunks.length > 0 ? chunks[chunks.length - 1] : void 0,
|
|
12405
|
+
metrics: {}
|
|
12406
|
+
})
|
|
12407
|
+
})
|
|
12408
|
+
);
|
|
12409
|
+
const callModelChannel = openRouterChannels.callModel.tracingChannel();
|
|
12410
|
+
const callModelHandlers = {
|
|
12411
|
+
start: (event) => {
|
|
12412
|
+
const request = getOpenRouterCallModelRequestArg(event.arguments);
|
|
12413
|
+
if (!request) {
|
|
12414
|
+
return;
|
|
12415
|
+
}
|
|
12416
|
+
patchOpenRouterCallModelRequestTools(request);
|
|
12417
|
+
}
|
|
12418
|
+
};
|
|
12419
|
+
callModelChannel.subscribe(callModelHandlers);
|
|
12420
|
+
this.unsubscribers.push(() => {
|
|
12421
|
+
callModelChannel.unsubscribe(callModelHandlers);
|
|
12422
|
+
});
|
|
11171
12423
|
}
|
|
11172
|
-
|
|
11173
|
-
|
|
12424
|
+
};
|
|
12425
|
+
function normalizeArgs(args) {
|
|
12426
|
+
if (Array.isArray(args)) {
|
|
12427
|
+
return args;
|
|
11174
12428
|
}
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
11178
|
-
continue;
|
|
11179
|
-
}
|
|
11180
|
-
if (key === "tools" && Array.isArray(entry)) {
|
|
11181
|
-
sanitized.tools = serializeOpenRouterToolsForLogging(entry);
|
|
11182
|
-
continue;
|
|
11183
|
-
}
|
|
11184
|
-
sanitized[key] = sanitizeOpenRouterLoggedValue(entry);
|
|
12429
|
+
if (isArrayLike(args)) {
|
|
12430
|
+
return Array.from(args);
|
|
11185
12431
|
}
|
|
11186
|
-
return
|
|
11187
|
-
}
|
|
11188
|
-
function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
|
|
11189
|
-
const sanitized = sanitizeOpenRouterLoggedValue(metadata);
|
|
11190
|
-
const metadataRecord = isObject(sanitized) ? sanitized : {};
|
|
11191
|
-
const { model, provider: providerRouting, ...rest } = metadataRecord;
|
|
11192
|
-
const normalizedModel = parseOpenRouterModelString(model);
|
|
11193
|
-
return {
|
|
11194
|
-
...rest,
|
|
11195
|
-
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
11196
|
-
...providerRouting !== void 0 ? { providerRouting } : {},
|
|
11197
|
-
...httpReferer !== void 0 ? { httpReferer } : {},
|
|
11198
|
-
...xTitle !== void 0 ? { xTitle } : {},
|
|
11199
|
-
provider: normalizedModel.provider || "openrouter"
|
|
11200
|
-
};
|
|
11201
|
-
}
|
|
11202
|
-
function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
|
|
11203
|
-
const normalized = buildOpenRouterMetadata(metadata, httpReferer, xTitle);
|
|
11204
|
-
return typeof normalized.model === "string" ? {
|
|
11205
|
-
...normalized,
|
|
11206
|
-
embedding_model: normalized.model
|
|
11207
|
-
} : normalized;
|
|
11208
|
-
}
|
|
11209
|
-
function extractOpenRouterCallModelInput(request) {
|
|
11210
|
-
return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue(request.input) : void 0;
|
|
12432
|
+
return [args];
|
|
11211
12433
|
}
|
|
11212
|
-
function
|
|
11213
|
-
|
|
11214
|
-
return { provider: "openrouter" };
|
|
11215
|
-
}
|
|
11216
|
-
const { input: _input, ...metadata } = request;
|
|
11217
|
-
return buildOpenRouterMetadata(metadata, void 0, void 0);
|
|
12434
|
+
function isArrayLike(value) {
|
|
12435
|
+
return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
|
|
11218
12436
|
}
|
|
11219
|
-
function
|
|
11220
|
-
|
|
11221
|
-
|
|
12437
|
+
function getOpenRouterRequestArg(args) {
|
|
12438
|
+
const normalizedArgs = normalizeArgs(args);
|
|
12439
|
+
const keyedCandidate = normalizedArgs.find(
|
|
12440
|
+
(arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
|
|
12441
|
+
);
|
|
12442
|
+
if (isObject(keyedCandidate)) {
|
|
12443
|
+
return keyedCandidate;
|
|
11222
12444
|
}
|
|
11223
|
-
const
|
|
11224
|
-
|
|
11225
|
-
const metadataRecord = isObject(sanitized) ? sanitized : {};
|
|
11226
|
-
const { model, provider, ...rest } = metadataRecord;
|
|
11227
|
-
const normalizedModel = parseOpenRouterModelString(model);
|
|
11228
|
-
const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
|
|
11229
|
-
const usageMetadata = extractOpenRouterUsageMetadata(usage);
|
|
11230
|
-
const combined = {
|
|
11231
|
-
...rest,
|
|
11232
|
-
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
11233
|
-
...usageMetadata || {},
|
|
11234
|
-
...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
|
|
11235
|
-
};
|
|
11236
|
-
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
12445
|
+
const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
|
|
12446
|
+
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
11237
12447
|
}
|
|
11238
|
-
function
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
}
|
|
11242
|
-
if (fallbackOutput !== void 0) {
|
|
11243
|
-
return sanitizeOpenRouterLoggedValue(fallbackOutput);
|
|
11244
|
-
}
|
|
11245
|
-
return void 0;
|
|
12448
|
+
function getOpenRouterCallModelRequestArg(args) {
|
|
12449
|
+
const firstObjectArg = normalizeArgs(args).find((arg) => isObject(arg));
|
|
12450
|
+
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
11246
12451
|
}
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
"
|
|
11252
|
-
|
|
11253
|
-
|
|
11254
|
-
"
|
|
11255
|
-
"
|
|
11256
|
-
"
|
|
11257
|
-
"
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
"
|
|
11261
|
-
|
|
11262
|
-
|
|
11263
|
-
"
|
|
11264
|
-
"
|
|
11265
|
-
"
|
|
11266
|
-
"
|
|
11267
|
-
"
|
|
11268
|
-
|
|
12452
|
+
var TOKEN_NAME_MAP2 = {
|
|
12453
|
+
promptTokens: "prompt_tokens",
|
|
12454
|
+
inputTokens: "prompt_tokens",
|
|
12455
|
+
completionTokens: "completion_tokens",
|
|
12456
|
+
outputTokens: "completion_tokens",
|
|
12457
|
+
totalTokens: "tokens",
|
|
12458
|
+
prompt_tokens: "prompt_tokens",
|
|
12459
|
+
input_tokens: "prompt_tokens",
|
|
12460
|
+
completion_tokens: "completion_tokens",
|
|
12461
|
+
output_tokens: "completion_tokens",
|
|
12462
|
+
total_tokens: "tokens"
|
|
12463
|
+
};
|
|
12464
|
+
var TOKEN_DETAIL_PREFIX_MAP = {
|
|
12465
|
+
promptTokensDetails: "prompt",
|
|
12466
|
+
inputTokensDetails: "prompt",
|
|
12467
|
+
completionTokensDetails: "completion",
|
|
12468
|
+
outputTokensDetails: "completion",
|
|
12469
|
+
costDetails: "cost",
|
|
12470
|
+
prompt_tokens_details: "prompt",
|
|
12471
|
+
input_tokens_details: "prompt",
|
|
12472
|
+
completion_tokens_details: "completion",
|
|
12473
|
+
output_tokens_details: "completion",
|
|
12474
|
+
cost_details: "cost"
|
|
12475
|
+
};
|
|
12476
|
+
function camelToSnake(value) {
|
|
12477
|
+
return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
|
|
12478
|
+
}
|
|
12479
|
+
function parseOpenRouterMetricsFromUsage(usage) {
|
|
12480
|
+
if (!isObject(usage)) {
|
|
12481
|
+
return {};
|
|
12482
|
+
}
|
|
12483
|
+
const metrics = {};
|
|
12484
|
+
for (const [name, value] of Object.entries(usage)) {
|
|
12485
|
+
if (typeof value === "number") {
|
|
12486
|
+
metrics[TOKEN_NAME_MAP2[name] || camelToSnake(name)] = value;
|
|
12487
|
+
continue;
|
|
12488
|
+
}
|
|
12489
|
+
if (!isObject(value)) {
|
|
12490
|
+
continue;
|
|
12491
|
+
}
|
|
12492
|
+
const prefix = TOKEN_DETAIL_PREFIX_MAP[name];
|
|
12493
|
+
if (!prefix) {
|
|
12494
|
+
continue;
|
|
12495
|
+
}
|
|
12496
|
+
for (const [nestedName, nestedValue] of Object.entries(value)) {
|
|
12497
|
+
if (typeof nestedValue !== "number") {
|
|
12498
|
+
continue;
|
|
12499
|
+
}
|
|
12500
|
+
metrics[`${prefix}_${camelToSnake(nestedName)}`] = nestedValue;
|
|
12501
|
+
}
|
|
12502
|
+
}
|
|
12503
|
+
return metrics;
|
|
12504
|
+
}
|
|
12505
|
+
function extractOpenRouterUsageMetadata(usage) {
|
|
12506
|
+
if (!isObject(usage)) {
|
|
12507
|
+
return void 0;
|
|
12508
|
+
}
|
|
12509
|
+
const metadata = {};
|
|
12510
|
+
if (typeof usage.isByok === "boolean") {
|
|
12511
|
+
metadata.is_byok = usage.isByok;
|
|
12512
|
+
} else if (typeof usage.is_byok === "boolean") {
|
|
12513
|
+
metadata.is_byok = usage.is_byok;
|
|
12514
|
+
}
|
|
12515
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
12516
|
+
}
|
|
12517
|
+
var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
|
|
12518
|
+
"execute",
|
|
12519
|
+
"render",
|
|
12520
|
+
"nextTurnParams",
|
|
12521
|
+
"requireApproval"
|
|
12522
|
+
]);
|
|
12523
|
+
function parseOpenRouterModelString(model) {
|
|
12524
|
+
if (typeof model !== "string") {
|
|
12525
|
+
return { model };
|
|
12526
|
+
}
|
|
12527
|
+
const slashIndex = model.indexOf("/");
|
|
12528
|
+
if (slashIndex > 0 && slashIndex < model.length - 1) {
|
|
12529
|
+
return {
|
|
12530
|
+
provider: model.substring(0, slashIndex),
|
|
12531
|
+
model: model.substring(slashIndex + 1)
|
|
12532
|
+
};
|
|
12533
|
+
}
|
|
12534
|
+
return { model };
|
|
12535
|
+
}
|
|
12536
|
+
function isZodSchema3(value) {
|
|
12537
|
+
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
12538
|
+
}
|
|
12539
|
+
function serializeZodSchema3(schema) {
|
|
12540
|
+
try {
|
|
12541
|
+
return zodToJsonSchema(schema);
|
|
12542
|
+
} catch {
|
|
12543
|
+
return {
|
|
12544
|
+
type: "object",
|
|
12545
|
+
description: "Zod schema (conversion failed)"
|
|
12546
|
+
};
|
|
12547
|
+
}
|
|
12548
|
+
}
|
|
12549
|
+
function serializeOpenRouterTool(tool) {
|
|
12550
|
+
if (!isObject(tool)) {
|
|
12551
|
+
return tool;
|
|
12552
|
+
}
|
|
12553
|
+
const serialized = {};
|
|
12554
|
+
for (const [key, value] of Object.entries(tool)) {
|
|
12555
|
+
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
12556
|
+
continue;
|
|
12557
|
+
}
|
|
12558
|
+
if (key === "function" && isObject(value)) {
|
|
12559
|
+
serialized.function = sanitizeOpenRouterLoggedValue(value);
|
|
12560
|
+
continue;
|
|
12561
|
+
}
|
|
12562
|
+
serialized[key] = sanitizeOpenRouterLoggedValue(value);
|
|
12563
|
+
}
|
|
12564
|
+
return serialized;
|
|
12565
|
+
}
|
|
12566
|
+
function serializeOpenRouterToolsForLogging(tools) {
|
|
12567
|
+
if (!Array.isArray(tools)) {
|
|
12568
|
+
return void 0;
|
|
12569
|
+
}
|
|
12570
|
+
return tools.map((tool) => serializeOpenRouterTool(tool));
|
|
12571
|
+
}
|
|
12572
|
+
function sanitizeOpenRouterLoggedValue(value) {
|
|
12573
|
+
if (isZodSchema3(value)) {
|
|
12574
|
+
return serializeZodSchema3(value);
|
|
12575
|
+
}
|
|
12576
|
+
if (typeof value === "function") {
|
|
12577
|
+
return "[Function]";
|
|
12578
|
+
}
|
|
12579
|
+
if (Array.isArray(value)) {
|
|
12580
|
+
return value.map((entry) => sanitizeOpenRouterLoggedValue(entry));
|
|
12581
|
+
}
|
|
12582
|
+
if (!isObject(value)) {
|
|
12583
|
+
return value;
|
|
12584
|
+
}
|
|
12585
|
+
const sanitized = {};
|
|
12586
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
12587
|
+
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
12588
|
+
continue;
|
|
12589
|
+
}
|
|
12590
|
+
if (key === "tools" && Array.isArray(entry)) {
|
|
12591
|
+
sanitized.tools = serializeOpenRouterToolsForLogging(entry);
|
|
12592
|
+
continue;
|
|
12593
|
+
}
|
|
12594
|
+
sanitized[key] = sanitizeOpenRouterLoggedValue(entry);
|
|
12595
|
+
}
|
|
12596
|
+
return sanitized;
|
|
12597
|
+
}
|
|
12598
|
+
function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
|
|
12599
|
+
const sanitized = sanitizeOpenRouterLoggedValue(metadata);
|
|
12600
|
+
const metadataRecord = isObject(sanitized) ? sanitized : {};
|
|
12601
|
+
const { model, provider: providerRouting, ...rest } = metadataRecord;
|
|
12602
|
+
const normalizedModel = parseOpenRouterModelString(model);
|
|
12603
|
+
return {
|
|
12604
|
+
...rest,
|
|
12605
|
+
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
12606
|
+
...providerRouting !== void 0 ? { providerRouting } : {},
|
|
12607
|
+
...httpReferer !== void 0 ? { httpReferer } : {},
|
|
12608
|
+
...xTitle !== void 0 ? { xTitle } : {},
|
|
12609
|
+
provider: normalizedModel.provider || "openrouter"
|
|
12610
|
+
};
|
|
12611
|
+
}
|
|
12612
|
+
function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
|
|
12613
|
+
const normalized = buildOpenRouterMetadata(metadata, httpReferer, xTitle);
|
|
12614
|
+
return typeof normalized.model === "string" ? {
|
|
12615
|
+
...normalized,
|
|
12616
|
+
embedding_model: normalized.model
|
|
12617
|
+
} : normalized;
|
|
12618
|
+
}
|
|
12619
|
+
function extractOpenRouterCallModelInput(request) {
|
|
12620
|
+
return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue(request.input) : void 0;
|
|
12621
|
+
}
|
|
12622
|
+
function extractOpenRouterCallModelMetadata(request) {
|
|
12623
|
+
if (!isObject(request)) {
|
|
12624
|
+
return { provider: "openrouter" };
|
|
12625
|
+
}
|
|
12626
|
+
const { input: _input, ...metadata } = request;
|
|
12627
|
+
return buildOpenRouterMetadata(metadata, void 0, void 0);
|
|
12628
|
+
}
|
|
12629
|
+
function extractOpenRouterResponseMetadata(result) {
|
|
12630
|
+
if (!isObject(result)) {
|
|
12631
|
+
return void 0;
|
|
12632
|
+
}
|
|
12633
|
+
const { output: _output, data: _data, usage, ...metadata } = result;
|
|
12634
|
+
const sanitized = sanitizeOpenRouterLoggedValue(metadata);
|
|
12635
|
+
const metadataRecord = isObject(sanitized) ? sanitized : {};
|
|
12636
|
+
const { model, provider, ...rest } = metadataRecord;
|
|
12637
|
+
const normalizedModel = parseOpenRouterModelString(model);
|
|
12638
|
+
const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
|
|
12639
|
+
const usageMetadata = extractOpenRouterUsageMetadata(usage);
|
|
12640
|
+
const combined = {
|
|
12641
|
+
...rest,
|
|
12642
|
+
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
12643
|
+
...usageMetadata || {},
|
|
12644
|
+
...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
|
|
12645
|
+
};
|
|
12646
|
+
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
12647
|
+
}
|
|
12648
|
+
function extractOpenRouterResponseOutput(response, fallbackOutput) {
|
|
12649
|
+
if (isObject(response) && "output" in response && response.output !== void 0) {
|
|
12650
|
+
return sanitizeOpenRouterLoggedValue(response.output);
|
|
12651
|
+
}
|
|
12652
|
+
if (fallbackOutput !== void 0) {
|
|
12653
|
+
return sanitizeOpenRouterLoggedValue(fallbackOutput);
|
|
12654
|
+
}
|
|
12655
|
+
return void 0;
|
|
12656
|
+
}
|
|
12657
|
+
var OPENROUTER_WRAPPED_TOOL = Symbol("braintrust.openrouter.wrappedTool");
|
|
11269
12658
|
function patchOpenRouterCallModelRequestTools(request) {
|
|
11270
12659
|
if (!Array.isArray(request.tools) || request.tools.length === 0) {
|
|
11271
12660
|
return void 0;
|
|
@@ -11283,29 +12672,234 @@ function patchOpenRouterCallModelRequestTools(request) {
|
|
|
11283
12672
|
request.tools = originalTools;
|
|
11284
12673
|
};
|
|
11285
12674
|
}
|
|
11286
|
-
function
|
|
11287
|
-
if (
|
|
11288
|
-
return
|
|
11289
|
-
}
|
|
11290
|
-
const resultLike = result;
|
|
11291
|
-
const hasInstrumentableMethod = typeof resultLike.getResponse === "function" || typeof resultLike.getText === "function" || OPENROUTER_CALL_MODEL_STREAM_METHODS.some(
|
|
11292
|
-
(methodName) => typeof resultLike[methodName] === "function"
|
|
11293
|
-
);
|
|
11294
|
-
if (!hasInstrumentableMethod) {
|
|
11295
|
-
return false;
|
|
12675
|
+
function wrapOpenRouterTool(tool) {
|
|
12676
|
+
if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
|
|
12677
|
+
return tool;
|
|
11296
12678
|
}
|
|
11297
|
-
|
|
12679
|
+
const toolName = tool.function.name || "tool";
|
|
12680
|
+
const originalExecute = tool.function.execute;
|
|
12681
|
+
const wrappedTool = {
|
|
12682
|
+
...tool,
|
|
12683
|
+
function: {
|
|
12684
|
+
...tool.function,
|
|
12685
|
+
execute(...args) {
|
|
12686
|
+
return traceToolExecution({
|
|
12687
|
+
args,
|
|
12688
|
+
execute: () => Reflect.apply(originalExecute, this, args),
|
|
12689
|
+
toolCallId: getToolCallId(args[1]),
|
|
12690
|
+
toolName
|
|
12691
|
+
});
|
|
12692
|
+
}
|
|
12693
|
+
}
|
|
12694
|
+
};
|
|
12695
|
+
Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL, {
|
|
11298
12696
|
value: true,
|
|
11299
12697
|
enumerable: false,
|
|
11300
12698
|
configurable: false
|
|
11301
12699
|
});
|
|
11302
|
-
|
|
11303
|
-
|
|
11304
|
-
|
|
11305
|
-
|
|
11306
|
-
|
|
11307
|
-
|
|
11308
|
-
|
|
12700
|
+
return wrappedTool;
|
|
12701
|
+
}
|
|
12702
|
+
function isWrappedTool(tool) {
|
|
12703
|
+
return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
|
|
12704
|
+
}
|
|
12705
|
+
function traceToolExecution(args) {
|
|
12706
|
+
const tracingChannel = openRouterChannels.toolExecute.tracingChannel();
|
|
12707
|
+
const input = args.args.length > 0 ? args.args[0] : void 0;
|
|
12708
|
+
const event = {
|
|
12709
|
+
arguments: [input],
|
|
12710
|
+
span_info: {
|
|
12711
|
+
name: args.toolName
|
|
12712
|
+
},
|
|
12713
|
+
toolCallId: args.toolCallId,
|
|
12714
|
+
toolName: args.toolName
|
|
12715
|
+
};
|
|
12716
|
+
tracingChannel.start.publish(event);
|
|
12717
|
+
try {
|
|
12718
|
+
const result = args.execute();
|
|
12719
|
+
return publishToolResult(tracingChannel, event, result);
|
|
12720
|
+
} catch (error) {
|
|
12721
|
+
event.error = normalizeError(error);
|
|
12722
|
+
tracingChannel.error.publish(event);
|
|
12723
|
+
throw error;
|
|
12724
|
+
}
|
|
12725
|
+
}
|
|
12726
|
+
function publishToolResult(tracingChannel, event, result) {
|
|
12727
|
+
if (isPromiseLike2(result)) {
|
|
12728
|
+
return result.then(
|
|
12729
|
+
(resolved) => {
|
|
12730
|
+
event.result = resolved;
|
|
12731
|
+
tracingChannel.asyncEnd.publish(event);
|
|
12732
|
+
return resolved;
|
|
12733
|
+
},
|
|
12734
|
+
(error) => {
|
|
12735
|
+
event.error = normalizeError(error);
|
|
12736
|
+
tracingChannel.error.publish(event);
|
|
12737
|
+
throw error;
|
|
12738
|
+
}
|
|
12739
|
+
);
|
|
12740
|
+
}
|
|
12741
|
+
event.result = result;
|
|
12742
|
+
tracingChannel.asyncEnd.publish(event);
|
|
12743
|
+
return result;
|
|
12744
|
+
}
|
|
12745
|
+
function getToolCallId(context) {
|
|
12746
|
+
const toolContext = context;
|
|
12747
|
+
return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
|
|
12748
|
+
}
|
|
12749
|
+
function isPromiseLike2(value) {
|
|
12750
|
+
return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
|
|
12751
|
+
}
|
|
12752
|
+
function aggregateOpenRouterChatChunks(chunks) {
|
|
12753
|
+
let role;
|
|
12754
|
+
let content = "";
|
|
12755
|
+
let toolCalls;
|
|
12756
|
+
let finishReason;
|
|
12757
|
+
let metrics = {};
|
|
12758
|
+
for (const chunk of chunks) {
|
|
12759
|
+
metrics = {
|
|
12760
|
+
...metrics,
|
|
12761
|
+
...parseOpenRouterMetricsFromUsage(chunk?.usage)
|
|
12762
|
+
};
|
|
12763
|
+
const choice = chunk?.choices?.[0];
|
|
12764
|
+
const delta = choice?.delta;
|
|
12765
|
+
if (!delta) {
|
|
12766
|
+
if (choice?.finish_reason !== void 0) {
|
|
12767
|
+
finishReason = choice.finish_reason;
|
|
12768
|
+
}
|
|
12769
|
+
continue;
|
|
12770
|
+
}
|
|
12771
|
+
if (!role && delta.role) {
|
|
12772
|
+
role = delta.role;
|
|
12773
|
+
}
|
|
12774
|
+
if (typeof delta.content === "string") {
|
|
12775
|
+
content += delta.content;
|
|
12776
|
+
}
|
|
12777
|
+
const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
|
|
12778
|
+
const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
|
|
12779
|
+
if (choiceFinishReason !== void 0) {
|
|
12780
|
+
finishReason = choiceFinishReason;
|
|
12781
|
+
} else if (deltaFinishReason !== void 0) {
|
|
12782
|
+
finishReason = deltaFinishReason;
|
|
12783
|
+
}
|
|
12784
|
+
const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
|
|
12785
|
+
if (!toolCallDeltas) {
|
|
12786
|
+
continue;
|
|
12787
|
+
}
|
|
12788
|
+
for (const toolDelta of toolCallDeltas) {
|
|
12789
|
+
if (!toolDelta?.function) {
|
|
12790
|
+
continue;
|
|
12791
|
+
}
|
|
12792
|
+
const toolIndex = toolDelta.index ?? 0;
|
|
12793
|
+
const existingToolCall = toolCalls?.[toolIndex];
|
|
12794
|
+
if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
|
|
12795
|
+
const nextToolCalls = [...toolCalls || []];
|
|
12796
|
+
nextToolCalls[toolIndex] = {
|
|
12797
|
+
index: toolIndex,
|
|
12798
|
+
id: toolDelta.id,
|
|
12799
|
+
type: toolDelta.type,
|
|
12800
|
+
function: {
|
|
12801
|
+
name: toolDelta.function.name,
|
|
12802
|
+
arguments: toolDelta.function.arguments || ""
|
|
12803
|
+
}
|
|
12804
|
+
};
|
|
12805
|
+
toolCalls = nextToolCalls;
|
|
12806
|
+
continue;
|
|
12807
|
+
}
|
|
12808
|
+
const current = existingToolCall;
|
|
12809
|
+
if (toolDelta.id && !current.id) {
|
|
12810
|
+
current.id = toolDelta.id;
|
|
12811
|
+
}
|
|
12812
|
+
if (toolDelta.type && !current.type) {
|
|
12813
|
+
current.type = toolDelta.type;
|
|
12814
|
+
}
|
|
12815
|
+
if (toolDelta.function.name && !current.function.name) {
|
|
12816
|
+
current.function.name = toolDelta.function.name;
|
|
12817
|
+
}
|
|
12818
|
+
current.function.arguments += toolDelta.function.arguments || "";
|
|
12819
|
+
}
|
|
12820
|
+
}
|
|
12821
|
+
return {
|
|
12822
|
+
output: [
|
|
12823
|
+
{
|
|
12824
|
+
index: 0,
|
|
12825
|
+
message: {
|
|
12826
|
+
role,
|
|
12827
|
+
content: content || void 0,
|
|
12828
|
+
...toolCalls ? { tool_calls: toolCalls } : {}
|
|
12829
|
+
},
|
|
12830
|
+
logprobs: null,
|
|
12831
|
+
finish_reason: finishReason
|
|
12832
|
+
}
|
|
12833
|
+
],
|
|
12834
|
+
metrics
|
|
12835
|
+
};
|
|
12836
|
+
}
|
|
12837
|
+
function aggregateOpenRouterResponseStreamEvents(chunks) {
|
|
12838
|
+
let finalResponse;
|
|
12839
|
+
for (const chunk of chunks) {
|
|
12840
|
+
const response = chunk?.response;
|
|
12841
|
+
if (!response) {
|
|
12842
|
+
continue;
|
|
12843
|
+
}
|
|
12844
|
+
if (chunk.type === "response.completed" || chunk.type === "response.incomplete" || chunk.type === "response.failed") {
|
|
12845
|
+
finalResponse = response;
|
|
12846
|
+
}
|
|
12847
|
+
}
|
|
12848
|
+
if (!finalResponse) {
|
|
12849
|
+
return {
|
|
12850
|
+
output: void 0,
|
|
12851
|
+
metrics: {}
|
|
12852
|
+
};
|
|
12853
|
+
}
|
|
12854
|
+
return {
|
|
12855
|
+
output: extractOpenRouterResponseOutput(finalResponse),
|
|
12856
|
+
metrics: parseOpenRouterMetricsFromUsage(finalResponse.usage),
|
|
12857
|
+
...extractOpenRouterResponseMetadata(finalResponse) ? { metadata: extractOpenRouterResponseMetadata(finalResponse) } : {}
|
|
12858
|
+
};
|
|
12859
|
+
}
|
|
12860
|
+
var OPENROUTER_WRAPPED_CALL_MODEL_RESULT = Symbol(
|
|
12861
|
+
"braintrust.openrouter.wrappedCallModelResult"
|
|
12862
|
+
);
|
|
12863
|
+
var OPENROUTER_CALL_MODEL_STREAM_METHODS = [
|
|
12864
|
+
"getFullResponsesStream",
|
|
12865
|
+
"getItemsStream",
|
|
12866
|
+
"getNewMessagesStream",
|
|
12867
|
+
"getReasoningStream",
|
|
12868
|
+
"getTextStream",
|
|
12869
|
+
"getToolCallsStream",
|
|
12870
|
+
"getToolStream"
|
|
12871
|
+
];
|
|
12872
|
+
var OPENROUTER_CALL_MODEL_CONTEXT_METHODS = [
|
|
12873
|
+
"cancel",
|
|
12874
|
+
"getPendingToolCalls",
|
|
12875
|
+
"getState",
|
|
12876
|
+
"getToolCalls",
|
|
12877
|
+
"requiresApproval"
|
|
12878
|
+
];
|
|
12879
|
+
function patchOpenRouterCallModelResult(args) {
|
|
12880
|
+
const { request, result, span } = args;
|
|
12881
|
+
if (!isObject(result) || isWrappedCallModelResult(result)) {
|
|
12882
|
+
return false;
|
|
12883
|
+
}
|
|
12884
|
+
const resultLike = result;
|
|
12885
|
+
const hasInstrumentableMethod = typeof resultLike.getResponse === "function" || typeof resultLike.getText === "function" || OPENROUTER_CALL_MODEL_STREAM_METHODS.some(
|
|
12886
|
+
(methodName) => typeof resultLike[methodName] === "function"
|
|
12887
|
+
);
|
|
12888
|
+
if (!hasInstrumentableMethod) {
|
|
12889
|
+
return false;
|
|
12890
|
+
}
|
|
12891
|
+
Object.defineProperty(resultLike, OPENROUTER_WRAPPED_CALL_MODEL_RESULT, {
|
|
12892
|
+
value: true,
|
|
12893
|
+
enumerable: false,
|
|
12894
|
+
configurable: false
|
|
12895
|
+
});
|
|
12896
|
+
const originalGetResponse = typeof resultLike.getResponse === "function" ? resultLike.getResponse.bind(resultLike) : void 0;
|
|
12897
|
+
const originalGetInitialResponse = typeof resultLike.getInitialResponse === "function" ? resultLike.getInitialResponse.bind(resultLike) : void 0;
|
|
12898
|
+
const originalMakeFollowupRequest = typeof resultLike.makeFollowupRequest === "function" ? resultLike.makeFollowupRequest.bind(resultLike) : void 0;
|
|
12899
|
+
let ended = false;
|
|
12900
|
+
let tracedTurnCount = 0;
|
|
12901
|
+
const endSpanWithResult = async (response, fallbackOutput) => {
|
|
12902
|
+
if (ended) {
|
|
11309
12903
|
return;
|
|
11310
12904
|
}
|
|
11311
12905
|
ended = true;
|
|
@@ -11356,10 +12950,10 @@ function patchOpenRouterCallModelResult(span, result, request) {
|
|
|
11356
12950
|
}
|
|
11357
12951
|
};
|
|
11358
12952
|
if (originalGetResponse) {
|
|
11359
|
-
resultLike.getResponse = async (...
|
|
12953
|
+
resultLike.getResponse = async (...args2) => {
|
|
11360
12954
|
return await withCurrent(span, async () => {
|
|
11361
12955
|
try {
|
|
11362
|
-
const response = await originalGetResponse(...
|
|
12956
|
+
const response = await originalGetResponse(...args2);
|
|
11363
12957
|
await endSpanWithResult(response);
|
|
11364
12958
|
return response;
|
|
11365
12959
|
} catch (error) {
|
|
@@ -11371,10 +12965,10 @@ function patchOpenRouterCallModelResult(span, result, request) {
|
|
|
11371
12965
|
}
|
|
11372
12966
|
if (typeof resultLike.getText === "function") {
|
|
11373
12967
|
const originalGetText = resultLike.getText.bind(resultLike);
|
|
11374
|
-
resultLike.getText = async (...
|
|
12968
|
+
resultLike.getText = async (...args2) => {
|
|
11375
12969
|
return await withCurrent(span, async () => {
|
|
11376
12970
|
try {
|
|
11377
|
-
const text = await originalGetText(...
|
|
12971
|
+
const text = await originalGetText(...args2);
|
|
11378
12972
|
await finalizeFromResponse(text);
|
|
11379
12973
|
return text;
|
|
11380
12974
|
} catch (error) {
|
|
@@ -11389,9 +12983,9 @@ function patchOpenRouterCallModelResult(span, result, request) {
|
|
|
11389
12983
|
continue;
|
|
11390
12984
|
}
|
|
11391
12985
|
const originalMethod = resultLike[methodName];
|
|
11392
|
-
resultLike[methodName] = async (...
|
|
12986
|
+
resultLike[methodName] = async (...args2) => {
|
|
11393
12987
|
return await withCurrent(span, async () => {
|
|
11394
|
-
return await originalMethod.apply(resultLike,
|
|
12988
|
+
return await originalMethod.apply(resultLike, args2);
|
|
11395
12989
|
});
|
|
11396
12990
|
};
|
|
11397
12991
|
}
|
|
@@ -11400,10 +12994,10 @@ function patchOpenRouterCallModelResult(span, result, request) {
|
|
|
11400
12994
|
continue;
|
|
11401
12995
|
}
|
|
11402
12996
|
const originalMethod = resultLike[methodName];
|
|
11403
|
-
resultLike[methodName] = (...
|
|
12997
|
+
resultLike[methodName] = (...args2) => {
|
|
11404
12998
|
const stream = withCurrent(
|
|
11405
12999
|
span,
|
|
11406
|
-
() => originalMethod.apply(resultLike,
|
|
13000
|
+
() => originalMethod.apply(resultLike, args2)
|
|
11407
13001
|
);
|
|
11408
13002
|
if (!isAsyncIterable2(stream)) {
|
|
11409
13003
|
return stream;
|
|
@@ -11418,616 +13012,194 @@ function patchOpenRouterCallModelResult(span, result, request) {
|
|
|
11418
13012
|
}
|
|
11419
13013
|
if (originalGetInitialResponse) {
|
|
11420
13014
|
let initialTurnTraced = false;
|
|
11421
|
-
resultLike.getInitialResponse = async (...
|
|
13015
|
+
resultLike.getInitialResponse = async (...args2) => {
|
|
11422
13016
|
if (initialTurnTraced) {
|
|
11423
13017
|
return await withCurrent(span, async () => {
|
|
11424
|
-
return await originalGetInitialResponse(...
|
|
11425
|
-
});
|
|
11426
|
-
}
|
|
11427
|
-
initialTurnTraced = true;
|
|
11428
|
-
const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
|
|
11429
|
-
const childSpan = startOpenRouterCallModelTurnSpan({
|
|
11430
|
-
request: resolvedRequest,
|
|
11431
|
-
step: tracedTurnCount + 1,
|
|
11432
|
-
stepType: tracedTurnCount === 0 ? "initial" : "continue"
|
|
11433
|
-
});
|
|
11434
|
-
return await withCurrent(childSpan, async () => {
|
|
11435
|
-
try {
|
|
11436
|
-
const response = await originalGetInitialResponse(...args);
|
|
11437
|
-
tracedTurnCount++;
|
|
11438
|
-
finishOpenRouterCallModelTurnSpan({
|
|
11439
|
-
response,
|
|
11440
|
-
step: tracedTurnCount,
|
|
11441
|
-
stepType: tracedTurnCount === 1 ? "initial" : "continue",
|
|
11442
|
-
span: childSpan
|
|
11443
|
-
});
|
|
11444
|
-
return response;
|
|
11445
|
-
} catch (error) {
|
|
11446
|
-
childSpan.log({
|
|
11447
|
-
error: normalizeError(error).message
|
|
11448
|
-
});
|
|
11449
|
-
childSpan.end();
|
|
11450
|
-
throw error;
|
|
11451
|
-
}
|
|
11452
|
-
});
|
|
11453
|
-
};
|
|
11454
|
-
}
|
|
11455
|
-
if (originalMakeFollowupRequest) {
|
|
11456
|
-
resultLike.makeFollowupRequest = async (...args) => {
|
|
11457
|
-
const currentResponse = args[0];
|
|
11458
|
-
const toolResults = Array.isArray(args[1]) ? args[1] : [];
|
|
11459
|
-
const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
|
|
11460
|
-
const followupRequest = buildOpenRouterFollowupRequest(
|
|
11461
|
-
resolvedRequest,
|
|
11462
|
-
currentResponse,
|
|
11463
|
-
toolResults
|
|
11464
|
-
);
|
|
11465
|
-
const childSpan = startOpenRouterCallModelTurnSpan({
|
|
11466
|
-
request: followupRequest,
|
|
11467
|
-
step: tracedTurnCount + 1,
|
|
11468
|
-
stepType: "continue"
|
|
11469
|
-
});
|
|
11470
|
-
return await withCurrent(childSpan, async () => {
|
|
11471
|
-
try {
|
|
11472
|
-
const response = await originalMakeFollowupRequest(...args);
|
|
11473
|
-
tracedTurnCount++;
|
|
11474
|
-
finishOpenRouterCallModelTurnSpan({
|
|
11475
|
-
response,
|
|
11476
|
-
step: tracedTurnCount,
|
|
11477
|
-
stepType: "continue",
|
|
11478
|
-
span: childSpan
|
|
11479
|
-
});
|
|
11480
|
-
return response;
|
|
11481
|
-
} catch (error) {
|
|
11482
|
-
childSpan.log({
|
|
11483
|
-
error: normalizeError(error).message
|
|
11484
|
-
});
|
|
11485
|
-
childSpan.end();
|
|
11486
|
-
throw error;
|
|
11487
|
-
}
|
|
11488
|
-
});
|
|
11489
|
-
};
|
|
11490
|
-
}
|
|
11491
|
-
return true;
|
|
11492
|
-
}
|
|
11493
|
-
function wrapOpenRouterTool(tool) {
|
|
11494
|
-
if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
|
|
11495
|
-
return tool;
|
|
11496
|
-
}
|
|
11497
|
-
const toolName = tool.function.name || "tool";
|
|
11498
|
-
const originalExecute = tool.function.execute;
|
|
11499
|
-
const wrappedTool = {
|
|
11500
|
-
...tool,
|
|
11501
|
-
function: {
|
|
11502
|
-
...tool.function,
|
|
11503
|
-
execute(...args) {
|
|
11504
|
-
return traceToolExecution({
|
|
11505
|
-
args,
|
|
11506
|
-
execute: () => Reflect.apply(originalExecute, this, args),
|
|
11507
|
-
toolCallId: getToolCallId(args[1]),
|
|
11508
|
-
toolName
|
|
11509
|
-
});
|
|
11510
|
-
}
|
|
11511
|
-
}
|
|
11512
|
-
};
|
|
11513
|
-
Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL, {
|
|
11514
|
-
value: true,
|
|
11515
|
-
enumerable: false,
|
|
11516
|
-
configurable: false
|
|
11517
|
-
});
|
|
11518
|
-
return wrappedTool;
|
|
11519
|
-
}
|
|
11520
|
-
function isWrappedTool(tool) {
|
|
11521
|
-
return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
|
|
11522
|
-
}
|
|
11523
|
-
function isWrappedCallModelResult(value) {
|
|
11524
|
-
return Boolean(
|
|
11525
|
-
isObject(value) && value[OPENROUTER_WRAPPED_CALL_MODEL_RESULT]
|
|
11526
|
-
);
|
|
11527
|
-
}
|
|
11528
|
-
function traceToolExecution(args) {
|
|
11529
|
-
const tracingChannel = openRouterChannels.toolExecute.tracingChannel();
|
|
11530
|
-
const input = args.args.length > 0 ? args.args[0] : void 0;
|
|
11531
|
-
const event = {
|
|
11532
|
-
arguments: [input],
|
|
11533
|
-
span_info: {
|
|
11534
|
-
name: args.toolName
|
|
11535
|
-
},
|
|
11536
|
-
toolCallId: args.toolCallId,
|
|
11537
|
-
toolName: args.toolName
|
|
11538
|
-
};
|
|
11539
|
-
tracingChannel.start.publish(event);
|
|
11540
|
-
try {
|
|
11541
|
-
const result = args.execute();
|
|
11542
|
-
return publishToolResult(tracingChannel, event, result);
|
|
11543
|
-
} catch (error) {
|
|
11544
|
-
event.error = normalizeError(error);
|
|
11545
|
-
tracingChannel.error.publish(event);
|
|
11546
|
-
throw error;
|
|
11547
|
-
}
|
|
11548
|
-
}
|
|
11549
|
-
function publishToolResult(tracingChannel, event, result) {
|
|
11550
|
-
if (isPromiseLike(result)) {
|
|
11551
|
-
return result.then(
|
|
11552
|
-
(resolved) => {
|
|
11553
|
-
event.result = resolved;
|
|
11554
|
-
tracingChannel.asyncEnd.publish(event);
|
|
11555
|
-
return resolved;
|
|
11556
|
-
},
|
|
11557
|
-
(error) => {
|
|
11558
|
-
event.error = normalizeError(error);
|
|
11559
|
-
tracingChannel.error.publish(event);
|
|
11560
|
-
throw error;
|
|
11561
|
-
}
|
|
11562
|
-
);
|
|
11563
|
-
}
|
|
11564
|
-
event.result = result;
|
|
11565
|
-
tracingChannel.asyncEnd.publish(event);
|
|
11566
|
-
return result;
|
|
11567
|
-
}
|
|
11568
|
-
function getToolCallId(context) {
|
|
11569
|
-
const toolContext = context;
|
|
11570
|
-
return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
|
|
11571
|
-
}
|
|
11572
|
-
function extractOpenRouterCallModelResultMetadata(response, turnCount) {
|
|
11573
|
-
const combined = {
|
|
11574
|
-
...extractOpenRouterResponseMetadata(response) || {},
|
|
11575
|
-
...turnCount !== void 0 ? { turn_count: turnCount } : {}
|
|
11576
|
-
};
|
|
11577
|
-
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
11578
|
-
}
|
|
11579
|
-
function getFinalOpenRouterCallModelResponse(result, response) {
|
|
11580
|
-
if (isObject(response)) {
|
|
11581
|
-
return response;
|
|
11582
|
-
}
|
|
11583
|
-
return isObject(result.finalResponse) ? result.finalResponse : void 0;
|
|
11584
|
-
}
|
|
11585
|
-
function getOpenRouterCallModelRounds(result) {
|
|
11586
|
-
if (!Array.isArray(result.allToolExecutionRounds)) {
|
|
11587
|
-
return [];
|
|
11588
|
-
}
|
|
11589
|
-
return result.allToolExecutionRounds.filter((round) => isObject(round)).map((round) => ({
|
|
11590
|
-
response: isObject(round.response) ? round.response : void 0,
|
|
11591
|
-
round: typeof round.round === "number" ? round.round : void 0,
|
|
11592
|
-
toolResults: Array.isArray(round.toolResults) ? round.toolResults : []
|
|
11593
|
-
})).filter((round) => round.response !== void 0);
|
|
11594
|
-
}
|
|
11595
|
-
function aggregateOpenRouterCallModelMetrics(rounds, finalResponse) {
|
|
11596
|
-
const metrics = {};
|
|
11597
|
-
const responses = [
|
|
11598
|
-
...rounds.map((round) => round.response).filter(isObject),
|
|
11599
|
-
finalResponse
|
|
11600
|
-
];
|
|
11601
|
-
for (const response of responses) {
|
|
11602
|
-
const responseMetrics = parseOpenRouterMetricsFromUsage(response.usage);
|
|
11603
|
-
for (const [name, value] of Object.entries(responseMetrics)) {
|
|
11604
|
-
metrics[name] = (metrics[name] || 0) + value;
|
|
11605
|
-
}
|
|
11606
|
-
}
|
|
11607
|
-
return metrics;
|
|
11608
|
-
}
|
|
11609
|
-
function buildNextOpenRouterCallModelInput(currentInput, response, toolResults) {
|
|
11610
|
-
const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
|
|
11611
|
-
const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
|
|
11612
|
-
return [...normalizedInput, ...responseOutput, ...toolResults].map(
|
|
11613
|
-
(entry) => sanitizeOpenRouterLoggedValue(entry)
|
|
11614
|
-
);
|
|
11615
|
-
}
|
|
11616
|
-
function startOpenRouterCallModelTurnSpan(args) {
|
|
11617
|
-
const requestRecord = isObject(args.request) ? args.request : void 0;
|
|
11618
|
-
const metadata = requestRecord ? extractOpenRouterCallModelMetadata(requestRecord) : { provider: "openrouter" };
|
|
11619
|
-
if (isObject(metadata) && "tools" in metadata) {
|
|
11620
|
-
delete metadata.tools;
|
|
11621
|
-
}
|
|
11622
|
-
return startSpan({
|
|
11623
|
-
name: "openrouter.beta.responses.send",
|
|
11624
|
-
spanAttributes: {
|
|
11625
|
-
type: "llm" /* LLM */
|
|
11626
|
-
},
|
|
11627
|
-
event: {
|
|
11628
|
-
input: requestRecord ? extractOpenRouterCallModelInput(requestRecord) : void 0,
|
|
11629
|
-
metadata: {
|
|
11630
|
-
...metadata,
|
|
11631
|
-
step: args.step,
|
|
11632
|
-
step_type: args.stepType
|
|
11633
|
-
}
|
|
11634
|
-
}
|
|
11635
|
-
});
|
|
11636
|
-
}
|
|
11637
|
-
function finishOpenRouterCallModelTurnSpan(args) {
|
|
11638
|
-
if (!isObject(args.response)) {
|
|
11639
|
-
args.span.end();
|
|
11640
|
-
return;
|
|
11641
|
-
}
|
|
11642
|
-
args.span.log({
|
|
11643
|
-
output: extractOpenRouterResponseOutput(args.response),
|
|
11644
|
-
...extractOpenRouterResponseMetadata(args.response) ? {
|
|
11645
|
-
metadata: {
|
|
11646
|
-
...extractOpenRouterResponseMetadata(args.response),
|
|
11647
|
-
...args.step !== void 0 ? { step: args.step } : {},
|
|
11648
|
-
...args.stepType ? { step_type: args.stepType } : {}
|
|
11649
|
-
}
|
|
11650
|
-
} : {},
|
|
11651
|
-
metrics: parseOpenRouterMetricsFromUsage(args.response.usage)
|
|
11652
|
-
});
|
|
11653
|
-
args.span.end();
|
|
11654
|
-
}
|
|
11655
|
-
function getOpenRouterResolvedRequest(result, request) {
|
|
11656
|
-
if (isObject(result.resolvedRequest)) {
|
|
11657
|
-
return result.resolvedRequest;
|
|
11658
|
-
}
|
|
11659
|
-
return request;
|
|
11660
|
-
}
|
|
11661
|
-
function buildOpenRouterFollowupRequest(request, currentResponse, toolResults) {
|
|
11662
|
-
if (!request) {
|
|
11663
|
-
return void 0;
|
|
11664
|
-
}
|
|
11665
|
-
return {
|
|
11666
|
-
...request,
|
|
11667
|
-
input: buildNextOpenRouterCallModelInput(
|
|
11668
|
-
extractOpenRouterCallModelInput(request),
|
|
11669
|
-
isObject(currentResponse) ? currentResponse : {},
|
|
11670
|
-
toolResults
|
|
11671
|
-
),
|
|
11672
|
-
stream: false
|
|
11673
|
-
};
|
|
11674
|
-
}
|
|
11675
|
-
function wrapAsyncIterableWithSpan(args) {
|
|
11676
|
-
return {
|
|
11677
|
-
[Symbol.asyncIterator]() {
|
|
11678
|
-
const iterator = args.iteratorFactory();
|
|
11679
|
-
return {
|
|
11680
|
-
next(value) {
|
|
11681
|
-
return withCurrent(
|
|
11682
|
-
args.span,
|
|
11683
|
-
() => value === void 0 ? iterator.next() : iterator.next(value)
|
|
11684
|
-
).then(
|
|
11685
|
-
async (result) => {
|
|
11686
|
-
if (result.done) {
|
|
11687
|
-
await args.finalize();
|
|
11688
|
-
}
|
|
11689
|
-
return result;
|
|
11690
|
-
},
|
|
11691
|
-
(error) => {
|
|
11692
|
-
args.onError(error);
|
|
11693
|
-
throw error;
|
|
11694
|
-
}
|
|
11695
|
-
);
|
|
11696
|
-
},
|
|
11697
|
-
return(value) {
|
|
11698
|
-
if (typeof iterator.return !== "function") {
|
|
11699
|
-
return args.finalize().then(() => ({
|
|
11700
|
-
done: true,
|
|
11701
|
-
value
|
|
11702
|
-
}));
|
|
11703
|
-
}
|
|
11704
|
-
return withCurrent(args.span, () => iterator.return(value)).then(
|
|
11705
|
-
async (result) => {
|
|
11706
|
-
await args.finalize();
|
|
11707
|
-
return result;
|
|
11708
|
-
},
|
|
11709
|
-
(error) => {
|
|
11710
|
-
args.onError(error);
|
|
11711
|
-
throw error;
|
|
11712
|
-
}
|
|
11713
|
-
);
|
|
11714
|
-
},
|
|
11715
|
-
throw(error) {
|
|
11716
|
-
args.onError(error);
|
|
11717
|
-
if (typeof iterator.throw !== "function") {
|
|
11718
|
-
return Promise.reject(error);
|
|
11719
|
-
}
|
|
11720
|
-
return withCurrent(args.span, () => iterator.throw(error));
|
|
11721
|
-
},
|
|
11722
|
-
[Symbol.asyncIterator]() {
|
|
11723
|
-
return this;
|
|
11724
|
-
}
|
|
11725
|
-
};
|
|
11726
|
-
}
|
|
11727
|
-
};
|
|
11728
|
-
}
|
|
11729
|
-
function isAsyncIterable2(value) {
|
|
11730
|
-
return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
11731
|
-
}
|
|
11732
|
-
function isPromiseLike(value) {
|
|
11733
|
-
return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
|
|
11734
|
-
}
|
|
11735
|
-
function normalizeError(error) {
|
|
11736
|
-
return error instanceof Error ? error : new Error(String(error));
|
|
11737
|
-
}
|
|
11738
|
-
|
|
11739
|
-
// src/instrumentation/plugins/openrouter-plugin.ts
|
|
11740
|
-
var OpenRouterPlugin = class extends BasePlugin {
|
|
11741
|
-
onEnable() {
|
|
11742
|
-
this.subscribeToOpenRouterChannels();
|
|
11743
|
-
}
|
|
11744
|
-
onDisable() {
|
|
11745
|
-
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
11746
|
-
}
|
|
11747
|
-
subscribeToOpenRouterChannels() {
|
|
11748
|
-
this.unsubscribers.push(
|
|
11749
|
-
traceStreamingChannel(openRouterChannels.chatSend, {
|
|
11750
|
-
name: "openrouter.chat.send",
|
|
11751
|
-
type: "llm" /* LLM */,
|
|
11752
|
-
extractInput: (args) => {
|
|
11753
|
-
const request = getOpenRouterRequestArg(args);
|
|
11754
|
-
const chatGenerationParams = isObject(request?.chatGenerationParams) ? request.chatGenerationParams : {};
|
|
11755
|
-
const httpReferer = request?.httpReferer;
|
|
11756
|
-
const xTitle = request?.xTitle;
|
|
11757
|
-
const { messages, ...metadata } = chatGenerationParams;
|
|
11758
|
-
return {
|
|
11759
|
-
input: messages,
|
|
11760
|
-
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
11761
|
-
};
|
|
11762
|
-
},
|
|
11763
|
-
extractOutput: (result) => {
|
|
11764
|
-
return isObject(result) ? result.choices : void 0;
|
|
11765
|
-
},
|
|
11766
|
-
extractMetrics: (result, startTime) => {
|
|
11767
|
-
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
11768
|
-
if (startTime) {
|
|
11769
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
11770
|
-
}
|
|
11771
|
-
return metrics;
|
|
11772
|
-
},
|
|
11773
|
-
aggregateChunks: aggregateOpenRouterChatChunks
|
|
11774
|
-
})
|
|
11775
|
-
);
|
|
11776
|
-
this.unsubscribers.push(
|
|
11777
|
-
traceAsyncChannel(openRouterChannels.embeddingsGenerate, {
|
|
11778
|
-
name: "openrouter.embeddings.generate",
|
|
11779
|
-
type: "llm" /* LLM */,
|
|
11780
|
-
extractInput: (args) => {
|
|
11781
|
-
const request = getOpenRouterRequestArg(args);
|
|
11782
|
-
const requestBody = isObject(request?.requestBody) ? request.requestBody : {};
|
|
11783
|
-
const httpReferer = request?.httpReferer;
|
|
11784
|
-
const xTitle = request?.xTitle;
|
|
11785
|
-
const { input, ...metadata } = requestBody;
|
|
11786
|
-
return {
|
|
11787
|
-
input,
|
|
11788
|
-
metadata: buildOpenRouterEmbeddingMetadata(
|
|
11789
|
-
metadata,
|
|
11790
|
-
httpReferer,
|
|
11791
|
-
xTitle
|
|
11792
|
-
)
|
|
11793
|
-
};
|
|
11794
|
-
},
|
|
11795
|
-
extractOutput: (result) => {
|
|
11796
|
-
if (!isObject(result)) {
|
|
11797
|
-
return void 0;
|
|
11798
|
-
}
|
|
11799
|
-
const embedding = result.data?.[0]?.embedding;
|
|
11800
|
-
return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
|
|
11801
|
-
},
|
|
11802
|
-
extractMetadata: (result) => {
|
|
11803
|
-
if (!isObject(result)) {
|
|
11804
|
-
return void 0;
|
|
11805
|
-
}
|
|
11806
|
-
return extractOpenRouterResponseMetadata(result);
|
|
11807
|
-
},
|
|
11808
|
-
extractMetrics: (result) => {
|
|
11809
|
-
return isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {};
|
|
11810
|
-
}
|
|
11811
|
-
})
|
|
11812
|
-
);
|
|
11813
|
-
this.unsubscribers.push(
|
|
11814
|
-
traceStreamingChannel(openRouterChannels.betaResponsesSend, {
|
|
11815
|
-
name: "openrouter.beta.responses.send",
|
|
11816
|
-
type: "llm" /* LLM */,
|
|
11817
|
-
extractInput: (args) => {
|
|
11818
|
-
const request = getOpenRouterRequestArg(args);
|
|
11819
|
-
const openResponsesRequest = isObject(request?.openResponsesRequest) ? request.openResponsesRequest : {};
|
|
11820
|
-
const httpReferer = request?.httpReferer;
|
|
11821
|
-
const xTitle = request?.xTitle;
|
|
11822
|
-
const { input, ...metadata } = openResponsesRequest;
|
|
11823
|
-
return {
|
|
11824
|
-
input,
|
|
11825
|
-
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
11826
|
-
};
|
|
11827
|
-
},
|
|
11828
|
-
extractOutput: (result) => extractOpenRouterResponseOutput(result),
|
|
11829
|
-
extractMetadata: (result) => extractOpenRouterResponseMetadata(result),
|
|
11830
|
-
extractMetrics: (result, startTime) => {
|
|
11831
|
-
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
11832
|
-
if (startTime) {
|
|
11833
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
11834
|
-
}
|
|
11835
|
-
return metrics;
|
|
11836
|
-
},
|
|
11837
|
-
aggregateChunks: aggregateOpenRouterResponseStreamEvents
|
|
11838
|
-
})
|
|
11839
|
-
);
|
|
11840
|
-
this.unsubscribers.push(
|
|
11841
|
-
traceSyncStreamChannel(openRouterChannels.callModel, {
|
|
11842
|
-
name: "openrouter.callModel",
|
|
11843
|
-
type: "llm" /* LLM */,
|
|
11844
|
-
extractInput: (args) => {
|
|
11845
|
-
const request = getOpenRouterCallModelRequestArg(args);
|
|
11846
|
-
return {
|
|
11847
|
-
input: request ? extractOpenRouterCallModelInput(request) : void 0,
|
|
11848
|
-
metadata: request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" }
|
|
11849
|
-
};
|
|
11850
|
-
},
|
|
11851
|
-
patchResult: ({ endEvent, result, span }) => {
|
|
11852
|
-
return patchOpenRouterCallModelResult(
|
|
11853
|
-
span,
|
|
11854
|
-
result,
|
|
11855
|
-
getOpenRouterCallModelRequestArg(endEvent.arguments)
|
|
11856
|
-
);
|
|
11857
|
-
}
|
|
11858
|
-
})
|
|
11859
|
-
);
|
|
11860
|
-
this.unsubscribers.push(
|
|
11861
|
-
traceStreamingChannel(openRouterChannels.toolExecute, {
|
|
11862
|
-
name: "openrouter.tool",
|
|
11863
|
-
type: "tool" /* TOOL */,
|
|
11864
|
-
extractInput: (args, event) => ({
|
|
11865
|
-
input: args[0],
|
|
11866
|
-
metadata: {
|
|
11867
|
-
provider: "openrouter",
|
|
11868
|
-
tool_name: event.toolName,
|
|
11869
|
-
...event.toolCallId ? { tool_call_id: event.toolCallId } : {}
|
|
11870
|
-
}
|
|
11871
|
-
}),
|
|
11872
|
-
extractOutput: (result) => result,
|
|
11873
|
-
extractMetrics: () => ({}),
|
|
11874
|
-
aggregateChunks: (chunks) => ({
|
|
11875
|
-
output: chunks.length > 0 ? chunks[chunks.length - 1] : void 0,
|
|
11876
|
-
metrics: {}
|
|
11877
|
-
})
|
|
11878
|
-
})
|
|
11879
|
-
);
|
|
11880
|
-
const callModelChannel = openRouterChannels.callModel.tracingChannel();
|
|
11881
|
-
const callModelHandlers = {
|
|
11882
|
-
start: (event) => {
|
|
11883
|
-
const request = getOpenRouterCallModelRequestArg(event.arguments);
|
|
11884
|
-
if (!request) {
|
|
11885
|
-
return;
|
|
11886
|
-
}
|
|
11887
|
-
patchOpenRouterCallModelRequestTools(request);
|
|
13018
|
+
return await originalGetInitialResponse(...args2);
|
|
13019
|
+
});
|
|
11888
13020
|
}
|
|
13021
|
+
initialTurnTraced = true;
|
|
13022
|
+
const step = tracedTurnCount + 1;
|
|
13023
|
+
const stepType = tracedTurnCount === 0 ? "initial" : "continue";
|
|
13024
|
+
const response = await traceOpenRouterCallModelTurn({
|
|
13025
|
+
fn: async () => {
|
|
13026
|
+
const nextResponse = await originalGetInitialResponse(...args2);
|
|
13027
|
+
tracedTurnCount++;
|
|
13028
|
+
return nextResponse;
|
|
13029
|
+
},
|
|
13030
|
+
parentSpan: span,
|
|
13031
|
+
request: getOpenRouterResolvedRequest(resultLike, request),
|
|
13032
|
+
step,
|
|
13033
|
+
stepType
|
|
13034
|
+
});
|
|
13035
|
+
return response;
|
|
11889
13036
|
};
|
|
11890
|
-
callModelChannel.subscribe(callModelHandlers);
|
|
11891
|
-
this.unsubscribers.push(() => {
|
|
11892
|
-
callModelChannel.unsubscribe(callModelHandlers);
|
|
11893
|
-
});
|
|
11894
|
-
}
|
|
11895
|
-
};
|
|
11896
|
-
function normalizeArgs(args) {
|
|
11897
|
-
if (Array.isArray(args)) {
|
|
11898
|
-
return args;
|
|
11899
13037
|
}
|
|
11900
|
-
if (
|
|
11901
|
-
|
|
13038
|
+
if (originalMakeFollowupRequest) {
|
|
13039
|
+
resultLike.makeFollowupRequest = async (...args2) => {
|
|
13040
|
+
const currentResponse = args2[0];
|
|
13041
|
+
const toolResults = Array.isArray(args2[1]) ? args2[1] : [];
|
|
13042
|
+
const step = tracedTurnCount + 1;
|
|
13043
|
+
const response = await traceOpenRouterCallModelTurn({
|
|
13044
|
+
fn: async () => {
|
|
13045
|
+
const nextResponse = await originalMakeFollowupRequest(...args2);
|
|
13046
|
+
tracedTurnCount++;
|
|
13047
|
+
return nextResponse;
|
|
13048
|
+
},
|
|
13049
|
+
parentSpan: span,
|
|
13050
|
+
request: buildOpenRouterFollowupRequest(
|
|
13051
|
+
getOpenRouterResolvedRequest(resultLike, request),
|
|
13052
|
+
currentResponse,
|
|
13053
|
+
toolResults
|
|
13054
|
+
),
|
|
13055
|
+
step,
|
|
13056
|
+
stepType: "continue"
|
|
13057
|
+
});
|
|
13058
|
+
return response;
|
|
13059
|
+
};
|
|
11902
13060
|
}
|
|
11903
|
-
return
|
|
13061
|
+
return true;
|
|
11904
13062
|
}
|
|
11905
|
-
function
|
|
11906
|
-
|
|
13063
|
+
async function traceOpenRouterCallModelTurn(args) {
|
|
13064
|
+
const context = {
|
|
13065
|
+
arguments: [args.request],
|
|
13066
|
+
step: args.step,
|
|
13067
|
+
stepType: args.stepType
|
|
13068
|
+
};
|
|
13069
|
+
return await withCurrent(
|
|
13070
|
+
args.parentSpan,
|
|
13071
|
+
() => openRouterChannels.callModelTurn.tracePromise(args.fn, context)
|
|
13072
|
+
);
|
|
11907
13073
|
}
|
|
11908
|
-
function
|
|
11909
|
-
|
|
11910
|
-
|
|
11911
|
-
(arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
|
|
13074
|
+
function isWrappedCallModelResult(value) {
|
|
13075
|
+
return Boolean(
|
|
13076
|
+
isObject(value) && value[OPENROUTER_WRAPPED_CALL_MODEL_RESULT]
|
|
11912
13077
|
);
|
|
11913
|
-
|
|
11914
|
-
|
|
13078
|
+
}
|
|
13079
|
+
function extractOpenRouterCallModelResultMetadata(response, turnCount) {
|
|
13080
|
+
const combined = {
|
|
13081
|
+
...extractOpenRouterResponseMetadata(response) || {},
|
|
13082
|
+
...turnCount !== void 0 ? { turn_count: turnCount } : {}
|
|
13083
|
+
};
|
|
13084
|
+
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
13085
|
+
}
|
|
13086
|
+
function getFinalOpenRouterCallModelResponse(result, response) {
|
|
13087
|
+
if (isObject(response)) {
|
|
13088
|
+
return response;
|
|
11915
13089
|
}
|
|
11916
|
-
|
|
11917
|
-
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
13090
|
+
return isObject(result.finalResponse) ? result.finalResponse : void 0;
|
|
11918
13091
|
}
|
|
11919
|
-
function
|
|
11920
|
-
|
|
11921
|
-
|
|
13092
|
+
function getOpenRouterCallModelRounds(result) {
|
|
13093
|
+
if (!Array.isArray(result.allToolExecutionRounds)) {
|
|
13094
|
+
return [];
|
|
13095
|
+
}
|
|
13096
|
+
return result.allToolExecutionRounds.filter((round) => isObject(round)).map((round) => ({
|
|
13097
|
+
response: isObject(round.response) ? round.response : void 0,
|
|
13098
|
+
round: typeof round.round === "number" ? round.round : void 0,
|
|
13099
|
+
toolResults: Array.isArray(round.toolResults) ? round.toolResults : []
|
|
13100
|
+
})).filter((round) => round.response !== void 0);
|
|
11922
13101
|
}
|
|
11923
|
-
function
|
|
11924
|
-
|
|
11925
|
-
|
|
11926
|
-
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
for (const
|
|
11930
|
-
|
|
11931
|
-
|
|
11932
|
-
|
|
11933
|
-
};
|
|
11934
|
-
const choice = chunk?.choices?.[0];
|
|
11935
|
-
const delta = choice?.delta;
|
|
11936
|
-
if (!delta) {
|
|
11937
|
-
if (choice?.finish_reason !== void 0) {
|
|
11938
|
-
finishReason = choice.finish_reason;
|
|
11939
|
-
}
|
|
11940
|
-
continue;
|
|
11941
|
-
}
|
|
11942
|
-
if (!role && delta.role) {
|
|
11943
|
-
role = delta.role;
|
|
11944
|
-
}
|
|
11945
|
-
if (typeof delta.content === "string") {
|
|
11946
|
-
content += delta.content;
|
|
11947
|
-
}
|
|
11948
|
-
const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
|
|
11949
|
-
const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
|
|
11950
|
-
if (choiceFinishReason !== void 0) {
|
|
11951
|
-
finishReason = choiceFinishReason;
|
|
11952
|
-
} else if (deltaFinishReason !== void 0) {
|
|
11953
|
-
finishReason = deltaFinishReason;
|
|
11954
|
-
}
|
|
11955
|
-
const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
|
|
11956
|
-
if (!toolCallDeltas) {
|
|
11957
|
-
continue;
|
|
11958
|
-
}
|
|
11959
|
-
for (const toolDelta of toolCallDeltas) {
|
|
11960
|
-
if (!toolDelta?.function) {
|
|
11961
|
-
continue;
|
|
11962
|
-
}
|
|
11963
|
-
const toolIndex = toolDelta.index ?? 0;
|
|
11964
|
-
const existingToolCall = toolCalls?.[toolIndex];
|
|
11965
|
-
if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
|
|
11966
|
-
const nextToolCalls = [...toolCalls || []];
|
|
11967
|
-
nextToolCalls[toolIndex] = {
|
|
11968
|
-
index: toolIndex,
|
|
11969
|
-
id: toolDelta.id,
|
|
11970
|
-
type: toolDelta.type,
|
|
11971
|
-
function: {
|
|
11972
|
-
name: toolDelta.function.name,
|
|
11973
|
-
arguments: toolDelta.function.arguments || ""
|
|
11974
|
-
}
|
|
11975
|
-
};
|
|
11976
|
-
toolCalls = nextToolCalls;
|
|
11977
|
-
continue;
|
|
11978
|
-
}
|
|
11979
|
-
const current = existingToolCall;
|
|
11980
|
-
if (toolDelta.id && !current.id) {
|
|
11981
|
-
current.id = toolDelta.id;
|
|
11982
|
-
}
|
|
11983
|
-
if (toolDelta.type && !current.type) {
|
|
11984
|
-
current.type = toolDelta.type;
|
|
11985
|
-
}
|
|
11986
|
-
if (toolDelta.function.name && !current.function.name) {
|
|
11987
|
-
current.function.name = toolDelta.function.name;
|
|
11988
|
-
}
|
|
11989
|
-
current.function.arguments += toolDelta.function.arguments || "";
|
|
13102
|
+
function aggregateOpenRouterCallModelMetrics(rounds, finalResponse) {
|
|
13103
|
+
const metrics = {};
|
|
13104
|
+
const responses = [
|
|
13105
|
+
...rounds.map((round) => round.response).filter(isObject),
|
|
13106
|
+
finalResponse
|
|
13107
|
+
];
|
|
13108
|
+
for (const response of responses) {
|
|
13109
|
+
const responseMetrics = parseOpenRouterMetricsFromUsage(response.usage);
|
|
13110
|
+
for (const [name, value] of Object.entries(responseMetrics)) {
|
|
13111
|
+
metrics[name] = (metrics[name] || 0) + value;
|
|
11990
13112
|
}
|
|
11991
13113
|
}
|
|
11992
|
-
return
|
|
11993
|
-
output: [
|
|
11994
|
-
{
|
|
11995
|
-
index: 0,
|
|
11996
|
-
message: {
|
|
11997
|
-
role,
|
|
11998
|
-
content: content || void 0,
|
|
11999
|
-
...toolCalls ? { tool_calls: toolCalls } : {}
|
|
12000
|
-
},
|
|
12001
|
-
logprobs: null,
|
|
12002
|
-
finish_reason: finishReason
|
|
12003
|
-
}
|
|
12004
|
-
],
|
|
12005
|
-
metrics
|
|
12006
|
-
};
|
|
13114
|
+
return metrics;
|
|
12007
13115
|
}
|
|
12008
|
-
function
|
|
12009
|
-
|
|
12010
|
-
|
|
12011
|
-
|
|
12012
|
-
|
|
12013
|
-
|
|
12014
|
-
|
|
12015
|
-
|
|
12016
|
-
|
|
12017
|
-
|
|
13116
|
+
function buildNextOpenRouterCallModelInput(currentInput, response, toolResults) {
|
|
13117
|
+
const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
|
|
13118
|
+
const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
|
|
13119
|
+
return [...normalizedInput, ...responseOutput, ...toolResults].map(
|
|
13120
|
+
(entry) => sanitizeOpenRouterLoggedValue(entry)
|
|
13121
|
+
);
|
|
13122
|
+
}
|
|
13123
|
+
function getOpenRouterResolvedRequest(result, request) {
|
|
13124
|
+
if (isObject(result.resolvedRequest)) {
|
|
13125
|
+
return result.resolvedRequest;
|
|
12018
13126
|
}
|
|
12019
|
-
|
|
12020
|
-
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
|
|
13127
|
+
return request;
|
|
13128
|
+
}
|
|
13129
|
+
function buildOpenRouterFollowupRequest(request, currentResponse, toolResults) {
|
|
13130
|
+
if (!request) {
|
|
13131
|
+
return void 0;
|
|
12024
13132
|
}
|
|
12025
13133
|
return {
|
|
12026
|
-
|
|
12027
|
-
|
|
12028
|
-
|
|
13134
|
+
...request,
|
|
13135
|
+
input: buildNextOpenRouterCallModelInput(
|
|
13136
|
+
extractOpenRouterCallModelInput(request),
|
|
13137
|
+
isObject(currentResponse) ? currentResponse : {},
|
|
13138
|
+
toolResults
|
|
13139
|
+
),
|
|
13140
|
+
stream: false
|
|
13141
|
+
};
|
|
13142
|
+
}
|
|
13143
|
+
function wrapAsyncIterableWithSpan(args) {
|
|
13144
|
+
return {
|
|
13145
|
+
[Symbol.asyncIterator]() {
|
|
13146
|
+
const iterator = args.iteratorFactory();
|
|
13147
|
+
return {
|
|
13148
|
+
next(value) {
|
|
13149
|
+
return withCurrent(
|
|
13150
|
+
args.span,
|
|
13151
|
+
() => value === void 0 ? iterator.next() : iterator.next(value)
|
|
13152
|
+
).then(
|
|
13153
|
+
async (result) => {
|
|
13154
|
+
if (result.done) {
|
|
13155
|
+
await args.finalize();
|
|
13156
|
+
}
|
|
13157
|
+
return result;
|
|
13158
|
+
},
|
|
13159
|
+
(error) => {
|
|
13160
|
+
args.onError(error);
|
|
13161
|
+
throw error;
|
|
13162
|
+
}
|
|
13163
|
+
);
|
|
13164
|
+
},
|
|
13165
|
+
return(value) {
|
|
13166
|
+
if (typeof iterator.return !== "function") {
|
|
13167
|
+
return args.finalize().then(() => ({
|
|
13168
|
+
done: true,
|
|
13169
|
+
value
|
|
13170
|
+
}));
|
|
13171
|
+
}
|
|
13172
|
+
return withCurrent(args.span, () => iterator.return(value)).then(
|
|
13173
|
+
async (result) => {
|
|
13174
|
+
await args.finalize();
|
|
13175
|
+
return result;
|
|
13176
|
+
},
|
|
13177
|
+
(error) => {
|
|
13178
|
+
args.onError(error);
|
|
13179
|
+
throw error;
|
|
13180
|
+
}
|
|
13181
|
+
);
|
|
13182
|
+
},
|
|
13183
|
+
throw(error) {
|
|
13184
|
+
args.onError(error);
|
|
13185
|
+
if (typeof iterator.throw !== "function") {
|
|
13186
|
+
return Promise.reject(error);
|
|
13187
|
+
}
|
|
13188
|
+
return withCurrent(args.span, () => iterator.throw(error));
|
|
13189
|
+
},
|
|
13190
|
+
[Symbol.asyncIterator]() {
|
|
13191
|
+
return this;
|
|
13192
|
+
}
|
|
13193
|
+
};
|
|
13194
|
+
}
|
|
12029
13195
|
};
|
|
12030
13196
|
}
|
|
13197
|
+
function isAsyncIterable2(value) {
|
|
13198
|
+
return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
13199
|
+
}
|
|
13200
|
+
function normalizeError(error) {
|
|
13201
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
13202
|
+
}
|
|
12031
13203
|
|
|
12032
13204
|
// src/instrumentation/braintrust-plugin.ts
|
|
12033
13205
|
var BraintrustPlugin = class extends BasePlugin {
|