braintrust 3.5.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dev/dist/index.d.mts +4 -2
- package/dev/dist/index.d.ts +4 -2
- package/dev/dist/index.js +2453 -612
- package/dev/dist/index.mjs +2150 -309
- package/dist/auto-instrumentations/bundler/esbuild.cjs +115 -6
- package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
- package/dist/auto-instrumentations/bundler/rollup.cjs +115 -6
- package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
- package/dist/auto-instrumentations/bundler/vite.cjs +115 -6
- package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
- package/dist/auto-instrumentations/bundler/webpack-loader.cjs +955 -0
- package/dist/auto-instrumentations/bundler/webpack-loader.d.ts +53 -0
- package/dist/auto-instrumentations/bundler/webpack.cjs +115 -6
- package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
- package/dist/auto-instrumentations/{chunk-DQTPSXJB.mjs → chunk-AKEXR4AL.mjs} +116 -7
- package/dist/auto-instrumentations/{chunk-F3TJZ3Z2.mjs → chunk-ZK2IYER2.mjs} +3 -1
- package/dist/auto-instrumentations/hook.mjs +199 -55
- package/dist/auto-instrumentations/index.cjs +116 -6
- package/dist/auto-instrumentations/index.d.mts +3 -1
- package/dist/auto-instrumentations/index.d.ts +3 -1
- package/dist/auto-instrumentations/index.mjs +3 -1
- package/dist/browser.d.mts +17 -4
- package/dist/browser.d.ts +17 -4
- package/dist/browser.js +2386 -440
- package/dist/browser.mjs +2386 -440
- package/dist/cli.js +2118 -273
- package/dist/edge-light.d.mts +1 -1
- package/dist/edge-light.d.ts +1 -1
- package/dist/edge-light.js +2348 -485
- package/dist/edge-light.mjs +2348 -485
- package/dist/index.d.mts +30 -17
- package/dist/index.d.ts +30 -17
- package/dist/index.js +2709 -761
- package/dist/index.mjs +2392 -444
- package/dist/instrumentation/index.d.mts +3 -0
- package/dist/instrumentation/index.d.ts +3 -0
- package/dist/instrumentation/index.js +2030 -274
- package/dist/instrumentation/index.mjs +2030 -274
- package/dist/workerd.d.mts +1 -1
- package/dist/workerd.d.ts +1 -1
- package/dist/workerd.js +2348 -485
- package/dist/workerd.mjs +2348 -485
- package/package.json +5 -1
package/dev/dist/index.mjs
CHANGED
|
@@ -2,6 +2,90 @@
|
|
|
2
2
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
3
|
import * as diagnostics_channel from "node:diagnostics_channel";
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
+
|
|
6
|
+
// src/auto-instrumentations/patch-tracing-channel.ts
|
|
7
|
+
function patchTracingChannel(tracingChannelFn) {
|
|
8
|
+
const dummyChannel = tracingChannelFn("__braintrust_probe__");
|
|
9
|
+
const TracingChannel = dummyChannel?.constructor;
|
|
10
|
+
if (!TracingChannel?.prototype) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (!Object.getOwnPropertyDescriptor(TracingChannel.prototype, "hasSubscribers")) {
|
|
14
|
+
Object.defineProperty(TracingChannel.prototype, "hasSubscribers", {
|
|
15
|
+
configurable: true,
|
|
16
|
+
enumerable: false,
|
|
17
|
+
get() {
|
|
18
|
+
return Boolean(
|
|
19
|
+
this.start?.hasSubscribers || this.end?.hasSubscribers || this.asyncStart?.hasSubscribers || this.asyncEnd?.hasSubscribers || this.error?.hasSubscribers
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (TracingChannel.prototype.tracePromise) {
|
|
25
|
+
TracingChannel.prototype.tracePromise = function(fn, context = {}, thisArg, ...args) {
|
|
26
|
+
const { start, end, asyncStart, asyncEnd, error } = this;
|
|
27
|
+
function publishRejected(err) {
|
|
28
|
+
context.error = err;
|
|
29
|
+
error?.publish(context);
|
|
30
|
+
asyncStart?.publish(context);
|
|
31
|
+
asyncEnd?.publish(context);
|
|
32
|
+
}
|
|
33
|
+
function publishResolved(result) {
|
|
34
|
+
context.result = result;
|
|
35
|
+
asyncStart?.publish(context);
|
|
36
|
+
asyncEnd?.publish(context);
|
|
37
|
+
}
|
|
38
|
+
return start.runStores(context, () => {
|
|
39
|
+
try {
|
|
40
|
+
const result = Reflect.apply(fn, thisArg, args);
|
|
41
|
+
end?.publish(context);
|
|
42
|
+
if (result && (typeof result === "object" || typeof result === "function") && typeof result.then === "function") {
|
|
43
|
+
if (result.constructor === Promise) {
|
|
44
|
+
return result.then(
|
|
45
|
+
(res) => {
|
|
46
|
+
publishResolved(res);
|
|
47
|
+
return res;
|
|
48
|
+
},
|
|
49
|
+
(err) => {
|
|
50
|
+
publishRejected(err);
|
|
51
|
+
return Promise.reject(err);
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
void result.then(
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
|
+
(resolved) => {
|
|
58
|
+
try {
|
|
59
|
+
publishResolved(resolved);
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
+
(err) => {
|
|
65
|
+
try {
|
|
66
|
+
publishRejected(err);
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
context.result = result;
|
|
74
|
+
asyncStart?.publish(context);
|
|
75
|
+
asyncEnd?.publish(context);
|
|
76
|
+
return result;
|
|
77
|
+
} catch (err) {
|
|
78
|
+
context.error = err;
|
|
79
|
+
error?.publish(context);
|
|
80
|
+
end?.publish(context);
|
|
81
|
+
throw err;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/node/config.ts
|
|
5
89
|
import * as fs from "node:fs/promises";
|
|
6
90
|
import * as os from "node:os";
|
|
7
91
|
import * as fsSync from "node:fs";
|
|
@@ -4506,6 +4590,9 @@ var BRAINTRUST_ATTACHMENT = BraintrustAttachmentReference.shape.type.value;
|
|
|
4506
4590
|
var EXTERNAL_ATTACHMENT = ExternalAttachmentReference.shape.type.value;
|
|
4507
4591
|
var LOGS3_OVERFLOW_REFERENCE_TYPE = "logs3_overflow";
|
|
4508
4592
|
var BRAINTRUST_PARAMS = Object.keys(BraintrustModelParams.shape);
|
|
4593
|
+
var RESET_CONTEXT_MANAGER_STATE = Symbol.for(
|
|
4594
|
+
"braintrust.resetContextManagerState"
|
|
4595
|
+
);
|
|
4509
4596
|
var DEFAULT_MAX_REQUEST_SIZE = 6 * 1024 * 1024;
|
|
4510
4597
|
var parametersRowSchema = z8.object({
|
|
4511
4598
|
id: z8.string().uuid(),
|
|
@@ -4568,13 +4655,18 @@ function applyMaskingToField(maskingFunction, data, fieldName) {
|
|
|
4568
4655
|
return `ERROR: Failed to mask field '${fieldName}' - ${errorType}`;
|
|
4569
4656
|
}
|
|
4570
4657
|
}
|
|
4658
|
+
var BRAINTRUST_CURRENT_SPAN_STORE = Symbol.for(
|
|
4659
|
+
"braintrust.currentSpanStore"
|
|
4660
|
+
);
|
|
4571
4661
|
var ContextManager = class {
|
|
4572
4662
|
};
|
|
4573
4663
|
var BraintrustContextManager = class extends ContextManager {
|
|
4574
4664
|
_currentSpan;
|
|
4665
|
+
[BRAINTRUST_CURRENT_SPAN_STORE];
|
|
4575
4666
|
constructor() {
|
|
4576
4667
|
super();
|
|
4577
4668
|
this._currentSpan = isomorph_default.newAsyncLocalStorage();
|
|
4669
|
+
this[BRAINTRUST_CURRENT_SPAN_STORE] = this._currentSpan;
|
|
4578
4670
|
}
|
|
4579
4671
|
getParentSpanIds() {
|
|
4580
4672
|
const currentSpan2 = this._currentSpan.getStore();
|
|
@@ -4781,6 +4873,9 @@ var BraintrustState = class _BraintrustState {
|
|
|
4781
4873
|
resetIdGenState() {
|
|
4782
4874
|
this._idGenerator = null;
|
|
4783
4875
|
}
|
|
4876
|
+
[RESET_CONTEXT_MANAGER_STATE]() {
|
|
4877
|
+
this._contextManager = null;
|
|
4878
|
+
}
|
|
4784
4879
|
get idGenerator() {
|
|
4785
4880
|
if (this._idGenerator === null) {
|
|
4786
4881
|
this._idGenerator = getIdGenerator();
|
|
@@ -9283,6 +9378,36 @@ function startSpanForEvent(config, event, channelName) {
|
|
|
9283
9378
|
}
|
|
9284
9379
|
return { span, startTime };
|
|
9285
9380
|
}
|
|
9381
|
+
function ensureSpanStateForEvent(states, config, event, channelName) {
|
|
9382
|
+
const key = event;
|
|
9383
|
+
const existing = states.get(key);
|
|
9384
|
+
if (existing) {
|
|
9385
|
+
return existing;
|
|
9386
|
+
}
|
|
9387
|
+
const created = startSpanForEvent(config, event, channelName);
|
|
9388
|
+
states.set(key, created);
|
|
9389
|
+
return created;
|
|
9390
|
+
}
|
|
9391
|
+
function bindCurrentSpanStoreToStart(tracingChannel2, states, config, channelName) {
|
|
9392
|
+
const state = _internalGetGlobalState();
|
|
9393
|
+
const startChannel = tracingChannel2.start;
|
|
9394
|
+
const currentSpanStore = state?.contextManager ? state.contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
|
|
9395
|
+
if (!currentSpanStore || !startChannel) {
|
|
9396
|
+
return void 0;
|
|
9397
|
+
}
|
|
9398
|
+
startChannel.bindStore(
|
|
9399
|
+
currentSpanStore,
|
|
9400
|
+
(event) => ensureSpanStateForEvent(
|
|
9401
|
+
states,
|
|
9402
|
+
config,
|
|
9403
|
+
event,
|
|
9404
|
+
channelName
|
|
9405
|
+
).span
|
|
9406
|
+
);
|
|
9407
|
+
return () => {
|
|
9408
|
+
startChannel.unbindStore(currentSpanStore);
|
|
9409
|
+
};
|
|
9410
|
+
}
|
|
9286
9411
|
function logErrorAndEnd(states, event) {
|
|
9287
9412
|
const spanData = states.get(event);
|
|
9288
9413
|
if (!spanData) {
|
|
@@ -9298,15 +9423,19 @@ function traceAsyncChannel(channel2, config) {
|
|
|
9298
9423
|
const tracingChannel2 = channel2.tracingChannel();
|
|
9299
9424
|
const states = /* @__PURE__ */ new WeakMap();
|
|
9300
9425
|
const channelName = channel2.channelName;
|
|
9426
|
+
const unbindCurrentSpanStore = bindCurrentSpanStoreToStart(
|
|
9427
|
+
tracingChannel2,
|
|
9428
|
+
states,
|
|
9429
|
+
config,
|
|
9430
|
+
channelName
|
|
9431
|
+
);
|
|
9301
9432
|
const handlers = {
|
|
9302
9433
|
start: (event) => {
|
|
9303
|
-
|
|
9434
|
+
ensureSpanStateForEvent(
|
|
9435
|
+
states,
|
|
9436
|
+
config,
|
|
9304
9437
|
event,
|
|
9305
|
-
|
|
9306
|
-
config,
|
|
9307
|
-
event,
|
|
9308
|
-
channelName
|
|
9309
|
-
)
|
|
9438
|
+
channelName
|
|
9310
9439
|
);
|
|
9311
9440
|
},
|
|
9312
9441
|
asyncEnd: (event) => {
|
|
@@ -9348,6 +9477,7 @@ function traceAsyncChannel(channel2, config) {
|
|
|
9348
9477
|
};
|
|
9349
9478
|
tracingChannel2.subscribe(handlers);
|
|
9350
9479
|
return () => {
|
|
9480
|
+
unbindCurrentSpanStore?.();
|
|
9351
9481
|
tracingChannel2.unsubscribe(handlers);
|
|
9352
9482
|
};
|
|
9353
9483
|
}
|
|
@@ -9355,15 +9485,19 @@ function traceStreamingChannel(channel2, config) {
|
|
|
9355
9485
|
const tracingChannel2 = channel2.tracingChannel();
|
|
9356
9486
|
const states = /* @__PURE__ */ new WeakMap();
|
|
9357
9487
|
const channelName = channel2.channelName;
|
|
9488
|
+
const unbindCurrentSpanStore = bindCurrentSpanStoreToStart(
|
|
9489
|
+
tracingChannel2,
|
|
9490
|
+
states,
|
|
9491
|
+
config,
|
|
9492
|
+
channelName
|
|
9493
|
+
);
|
|
9358
9494
|
const handlers = {
|
|
9359
9495
|
start: (event) => {
|
|
9360
|
-
|
|
9496
|
+
ensureSpanStateForEvent(
|
|
9497
|
+
states,
|
|
9498
|
+
config,
|
|
9361
9499
|
event,
|
|
9362
|
-
|
|
9363
|
-
config,
|
|
9364
|
-
event,
|
|
9365
|
-
channelName
|
|
9366
|
-
)
|
|
9500
|
+
channelName
|
|
9367
9501
|
);
|
|
9368
9502
|
},
|
|
9369
9503
|
asyncEnd: (event) => {
|
|
@@ -9479,6 +9613,7 @@ function traceStreamingChannel(channel2, config) {
|
|
|
9479
9613
|
};
|
|
9480
9614
|
tracingChannel2.subscribe(handlers);
|
|
9481
9615
|
return () => {
|
|
9616
|
+
unbindCurrentSpanStore?.();
|
|
9482
9617
|
tracingChannel2.unsubscribe(handlers);
|
|
9483
9618
|
};
|
|
9484
9619
|
}
|
|
@@ -9486,15 +9621,19 @@ function traceSyncStreamChannel(channel2, config) {
|
|
|
9486
9621
|
const tracingChannel2 = channel2.tracingChannel();
|
|
9487
9622
|
const states = /* @__PURE__ */ new WeakMap();
|
|
9488
9623
|
const channelName = channel2.channelName;
|
|
9624
|
+
const unbindCurrentSpanStore = bindCurrentSpanStoreToStart(
|
|
9625
|
+
tracingChannel2,
|
|
9626
|
+
states,
|
|
9627
|
+
config,
|
|
9628
|
+
channelName
|
|
9629
|
+
);
|
|
9489
9630
|
const handlers = {
|
|
9490
9631
|
start: (event) => {
|
|
9491
|
-
|
|
9632
|
+
ensureSpanStateForEvent(
|
|
9633
|
+
states,
|
|
9634
|
+
config,
|
|
9492
9635
|
event,
|
|
9493
|
-
|
|
9494
|
-
config,
|
|
9495
|
-
event,
|
|
9496
|
-
channelName
|
|
9497
|
-
)
|
|
9636
|
+
channelName
|
|
9498
9637
|
);
|
|
9499
9638
|
},
|
|
9500
9639
|
end: (event) => {
|
|
@@ -9583,6 +9722,7 @@ function traceSyncStreamChannel(channel2, config) {
|
|
|
9583
9722
|
};
|
|
9584
9723
|
tracingChannel2.subscribe(handlers);
|
|
9585
9724
|
return () => {
|
|
9725
|
+
unbindCurrentSpanStore?.();
|
|
9586
9726
|
tracingChannel2.unsubscribe(handlers);
|
|
9587
9727
|
};
|
|
9588
9728
|
}
|
|
@@ -10354,7 +10494,7 @@ var AnthropicPlugin = class extends BasePlugin {
|
|
|
10354
10494
|
this.unsubscribers.push(
|
|
10355
10495
|
traceStreamingChannel(anthropicChannels.betaMessagesCreate, {
|
|
10356
10496
|
...anthropicConfig,
|
|
10357
|
-
name: "anthropic.
|
|
10497
|
+
name: "anthropic.messages.create"
|
|
10358
10498
|
})
|
|
10359
10499
|
);
|
|
10360
10500
|
}
|
|
@@ -10377,9 +10517,12 @@ function parseMetricsFromUsage2(usage) {
|
|
|
10377
10517
|
return metrics;
|
|
10378
10518
|
}
|
|
10379
10519
|
function aggregateAnthropicStreamChunks(chunks) {
|
|
10380
|
-
const
|
|
10520
|
+
const fallbackTextDeltas = [];
|
|
10521
|
+
const contentBlocks = {};
|
|
10522
|
+
const contentBlockDeltas = {};
|
|
10381
10523
|
let metrics = {};
|
|
10382
10524
|
let metadata = {};
|
|
10525
|
+
let role;
|
|
10383
10526
|
for (const event of chunks) {
|
|
10384
10527
|
switch (event?.type) {
|
|
10385
10528
|
case "message_start":
|
|
@@ -10387,15 +10530,43 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
10387
10530
|
const initialMetrics = parseMetricsFromUsage2(event.message.usage);
|
|
10388
10531
|
metrics = { ...metrics, ...initialMetrics };
|
|
10389
10532
|
}
|
|
10533
|
+
if (typeof event.message?.role === "string") {
|
|
10534
|
+
role = event.message.role;
|
|
10535
|
+
}
|
|
10536
|
+
break;
|
|
10537
|
+
case "content_block_start":
|
|
10538
|
+
if (event.content_block) {
|
|
10539
|
+
contentBlocks[event.index] = event.content_block;
|
|
10540
|
+
contentBlockDeltas[event.index] = [];
|
|
10541
|
+
}
|
|
10390
10542
|
break;
|
|
10391
10543
|
case "content_block_delta":
|
|
10392
10544
|
if (event.delta?.type === "text_delta") {
|
|
10393
10545
|
const text = event.delta.text;
|
|
10394
10546
|
if (text) {
|
|
10395
|
-
|
|
10547
|
+
if (contentBlocks[event.index] !== void 0 || contentBlockDeltas[event.index] !== void 0) {
|
|
10548
|
+
contentBlockDeltas[event.index] ??= [];
|
|
10549
|
+
contentBlockDeltas[event.index].push(text);
|
|
10550
|
+
} else {
|
|
10551
|
+
fallbackTextDeltas.push(text);
|
|
10552
|
+
}
|
|
10553
|
+
}
|
|
10554
|
+
} else if (event.delta?.type === "input_json_delta") {
|
|
10555
|
+
const partialJson = event.delta.partial_json;
|
|
10556
|
+
if (partialJson) {
|
|
10557
|
+
contentBlockDeltas[event.index] ??= [];
|
|
10558
|
+
contentBlockDeltas[event.index].push(partialJson);
|
|
10396
10559
|
}
|
|
10397
10560
|
}
|
|
10398
10561
|
break;
|
|
10562
|
+
case "content_block_stop":
|
|
10563
|
+
finalizeContentBlock(
|
|
10564
|
+
event.index,
|
|
10565
|
+
contentBlocks,
|
|
10566
|
+
contentBlockDeltas,
|
|
10567
|
+
fallbackTextDeltas
|
|
10568
|
+
);
|
|
10569
|
+
break;
|
|
10399
10570
|
case "message_delta":
|
|
10400
10571
|
if (event.usage) {
|
|
10401
10572
|
const finalMetrics = parseMetricsFromUsage2(event.usage);
|
|
@@ -10407,7 +10578,21 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
10407
10578
|
break;
|
|
10408
10579
|
}
|
|
10409
10580
|
}
|
|
10410
|
-
const
|
|
10581
|
+
const orderedContent = Object.entries(contentBlocks).map(([index, block]) => ({
|
|
10582
|
+
block,
|
|
10583
|
+
index: Number(index)
|
|
10584
|
+
})).filter(({ block }) => block !== void 0).sort((left, right) => left.index - right.index).map(({ block }) => block);
|
|
10585
|
+
let output = fallbackTextDeltas.join("");
|
|
10586
|
+
if (orderedContent.length > 0) {
|
|
10587
|
+
if (orderedContent.every(isTextContentBlock)) {
|
|
10588
|
+
output = orderedContent.map((block) => block.text).join("");
|
|
10589
|
+
} else {
|
|
10590
|
+
output = {
|
|
10591
|
+
...role ? { role } : {},
|
|
10592
|
+
content: orderedContent
|
|
10593
|
+
};
|
|
10594
|
+
}
|
|
10595
|
+
}
|
|
10411
10596
|
const finalized = finalizeAnthropicTokens(metrics);
|
|
10412
10597
|
const filteredMetrics = Object.fromEntries(
|
|
10413
10598
|
Object.entries(finalized).filter(
|
|
@@ -10420,6 +10605,49 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
10420
10605
|
metadata
|
|
10421
10606
|
};
|
|
10422
10607
|
}
|
|
10608
|
+
function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallbackTextDeltas) {
|
|
10609
|
+
const contentBlock = contentBlocks[index];
|
|
10610
|
+
if (!contentBlock) {
|
|
10611
|
+
return;
|
|
10612
|
+
}
|
|
10613
|
+
const text = contentBlockDeltas[index]?.join("") ?? "";
|
|
10614
|
+
if (isToolUseContentBlock(contentBlock)) {
|
|
10615
|
+
if (!text) {
|
|
10616
|
+
return;
|
|
10617
|
+
}
|
|
10618
|
+
try {
|
|
10619
|
+
contentBlocks[index] = {
|
|
10620
|
+
...contentBlock,
|
|
10621
|
+
input: JSON.parse(text)
|
|
10622
|
+
};
|
|
10623
|
+
} catch {
|
|
10624
|
+
fallbackTextDeltas.push(text);
|
|
10625
|
+
delete contentBlocks[index];
|
|
10626
|
+
}
|
|
10627
|
+
return;
|
|
10628
|
+
}
|
|
10629
|
+
if (isTextContentBlock(contentBlock)) {
|
|
10630
|
+
if (!text) {
|
|
10631
|
+
delete contentBlocks[index];
|
|
10632
|
+
return;
|
|
10633
|
+
}
|
|
10634
|
+
contentBlocks[index] = {
|
|
10635
|
+
...contentBlock,
|
|
10636
|
+
text
|
|
10637
|
+
};
|
|
10638
|
+
return;
|
|
10639
|
+
}
|
|
10640
|
+
if (text) {
|
|
10641
|
+
fallbackTextDeltas.push(text);
|
|
10642
|
+
}
|
|
10643
|
+
delete contentBlocks[index];
|
|
10644
|
+
}
|
|
10645
|
+
function isTextContentBlock(contentBlock) {
|
|
10646
|
+
return contentBlock.type === "text";
|
|
10647
|
+
}
|
|
10648
|
+
function isToolUseContentBlock(contentBlock) {
|
|
10649
|
+
return contentBlock.type === "tool_use";
|
|
10650
|
+
}
|
|
10423
10651
|
function isAnthropicBase64ContentBlock(input) {
|
|
10424
10652
|
return (input.type === "image" || input.type === "document") && isObject(input.source) && input.source.type === "base64";
|
|
10425
10653
|
}
|
|
@@ -11542,12 +11770,15 @@ var claudeAgentSDKChannels = defineChannels(
|
|
|
11542
11770
|
{
|
|
11543
11771
|
query: channel({
|
|
11544
11772
|
channelName: "query",
|
|
11545
|
-
kind: "
|
|
11773
|
+
kind: "sync-stream"
|
|
11546
11774
|
})
|
|
11547
11775
|
}
|
|
11548
11776
|
);
|
|
11549
11777
|
|
|
11550
11778
|
// src/instrumentation/plugins/claude-agent-sdk-plugin.ts
|
|
11779
|
+
function isSubAgentToolName(toolName) {
|
|
11780
|
+
return toolName === "Agent" || toolName === "Task";
|
|
11781
|
+
}
|
|
11551
11782
|
function filterSerializableOptions(options) {
|
|
11552
11783
|
const allowedKeys = [
|
|
11553
11784
|
"model",
|
|
@@ -11601,34 +11832,50 @@ function extractUsageFromMessage(message) {
|
|
|
11601
11832
|
const cacheReadTokens = getNumberProperty(usage, "cache_read_input_tokens") || 0;
|
|
11602
11833
|
const cacheCreationTokens = getNumberProperty(usage, "cache_creation_input_tokens") || 0;
|
|
11603
11834
|
if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
|
|
11604
|
-
|
|
11605
|
-
|
|
11606
|
-
cacheCreationTokens
|
|
11835
|
+
Object.assign(
|
|
11836
|
+
metrics,
|
|
11837
|
+
extractAnthropicCacheTokens(cacheReadTokens, cacheCreationTokens)
|
|
11607
11838
|
);
|
|
11608
|
-
Object.assign(metrics, cacheTokens);
|
|
11609
11839
|
}
|
|
11610
11840
|
if (Object.keys(metrics).length > 0) {
|
|
11611
11841
|
Object.assign(metrics, finalizeAnthropicTokens(metrics));
|
|
11612
11842
|
}
|
|
11613
11843
|
return metrics;
|
|
11614
11844
|
}
|
|
11615
|
-
function buildLLMInput(prompt, conversationHistory) {
|
|
11616
|
-
const
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11845
|
+
function buildLLMInput(prompt, conversationHistory, capturedPromptMessages) {
|
|
11846
|
+
const promptMessages = [];
|
|
11847
|
+
if (typeof prompt === "string") {
|
|
11848
|
+
promptMessages.push({ content: prompt, role: "user" });
|
|
11849
|
+
} else if (capturedPromptMessages && capturedPromptMessages.length > 0) {
|
|
11850
|
+
for (const msg of capturedPromptMessages) {
|
|
11851
|
+
const role = msg.message?.role;
|
|
11852
|
+
const content = msg.message?.content;
|
|
11853
|
+
if (role && content !== void 0) {
|
|
11854
|
+
promptMessages.push({ content, role });
|
|
11855
|
+
}
|
|
11856
|
+
}
|
|
11857
|
+
}
|
|
11858
|
+
const inputParts = [...promptMessages, ...conversationHistory];
|
|
11621
11859
|
return inputParts.length > 0 ? inputParts : void 0;
|
|
11622
11860
|
}
|
|
11623
|
-
|
|
11624
|
-
|
|
11861
|
+
function formatCapturedMessages(messages) {
|
|
11862
|
+
return messages.length > 0 ? messages : [];
|
|
11863
|
+
}
|
|
11864
|
+
async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan) {
|
|
11865
|
+
if (messages.length === 0) {
|
|
11866
|
+
return void 0;
|
|
11867
|
+
}
|
|
11625
11868
|
const lastMessage = messages[messages.length - 1];
|
|
11626
11869
|
if (lastMessage.type !== "assistant" || !lastMessage.message?.usage) {
|
|
11627
11870
|
return void 0;
|
|
11628
11871
|
}
|
|
11629
11872
|
const model = lastMessage.message.model || options.model;
|
|
11630
11873
|
const usage = extractUsageFromMessage(lastMessage);
|
|
11631
|
-
const input = buildLLMInput(
|
|
11874
|
+
const input = buildLLMInput(
|
|
11875
|
+
prompt,
|
|
11876
|
+
conversationHistory,
|
|
11877
|
+
capturedPromptMessages
|
|
11878
|
+
);
|
|
11632
11879
|
const outputs = messages.map(
|
|
11633
11880
|
(m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
|
|
11634
11881
|
).filter(
|
|
@@ -11636,21 +11883,359 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
|
|
|
11636
11883
|
);
|
|
11637
11884
|
const span = startSpan({
|
|
11638
11885
|
name: "anthropic.messages.create",
|
|
11886
|
+
parent: parentSpan,
|
|
11639
11887
|
spanAttributes: {
|
|
11640
11888
|
type: "llm" /* LLM */
|
|
11641
11889
|
},
|
|
11642
|
-
startTime
|
|
11643
|
-
parent: parentSpan
|
|
11890
|
+
startTime
|
|
11644
11891
|
});
|
|
11645
11892
|
span.log({
|
|
11646
11893
|
input,
|
|
11647
|
-
output: outputs,
|
|
11648
11894
|
metadata: model ? { model } : void 0,
|
|
11649
|
-
metrics: usage
|
|
11895
|
+
metrics: usage,
|
|
11896
|
+
output: outputs
|
|
11650
11897
|
});
|
|
11651
11898
|
await span.end();
|
|
11652
11899
|
return lastMessage.message?.content && lastMessage.message?.role ? { content: lastMessage.message.content, role: lastMessage.message.role } : void 0;
|
|
11653
11900
|
}
|
|
11901
|
+
function getMcpServerMetadata(serverName, mcpServers) {
|
|
11902
|
+
if (!serverName || !mcpServers) {
|
|
11903
|
+
return {};
|
|
11904
|
+
}
|
|
11905
|
+
const serverConfig = mcpServers[serverName];
|
|
11906
|
+
if (!serverConfig) {
|
|
11907
|
+
return {};
|
|
11908
|
+
}
|
|
11909
|
+
const metadata = {};
|
|
11910
|
+
if (serverConfig.type) {
|
|
11911
|
+
metadata["mcp.type"] = serverConfig.type;
|
|
11912
|
+
} else if (typeof serverConfig === "object" && "transport" in serverConfig) {
|
|
11913
|
+
metadata["mcp.type"] = "sdk";
|
|
11914
|
+
}
|
|
11915
|
+
if (serverConfig.url) {
|
|
11916
|
+
metadata["mcp.url"] = serverConfig.url;
|
|
11917
|
+
}
|
|
11918
|
+
if (serverConfig.command) {
|
|
11919
|
+
metadata["mcp.command"] = serverConfig.command;
|
|
11920
|
+
if (serverConfig.args) {
|
|
11921
|
+
metadata["mcp.args"] = serverConfig.args.join(" ");
|
|
11922
|
+
}
|
|
11923
|
+
}
|
|
11924
|
+
return metadata;
|
|
11925
|
+
}
|
|
11926
|
+
function parseToolName(rawToolName) {
|
|
11927
|
+
const mcpMatch = rawToolName.match(/^mcp__([^_]+)__(.+)$/);
|
|
11928
|
+
if (mcpMatch) {
|
|
11929
|
+
const [, mcpServer, toolName] = mcpMatch;
|
|
11930
|
+
return {
|
|
11931
|
+
displayName: `tool: ${mcpServer}/${toolName}`,
|
|
11932
|
+
mcpServer,
|
|
11933
|
+
rawToolName,
|
|
11934
|
+
toolName
|
|
11935
|
+
};
|
|
11936
|
+
}
|
|
11937
|
+
return {
|
|
11938
|
+
displayName: `tool: ${rawToolName}`,
|
|
11939
|
+
rawToolName,
|
|
11940
|
+
toolName: rawToolName
|
|
11941
|
+
};
|
|
11942
|
+
}
|
|
11943
|
+
function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, subAgentSpans, endedSubAgentSpans) {
|
|
11944
|
+
const preToolUse = async (input, toolUseID) => {
|
|
11945
|
+
if (input.hook_event_name !== "PreToolUse" || !toolUseID) {
|
|
11946
|
+
return {};
|
|
11947
|
+
}
|
|
11948
|
+
if (isSubAgentToolName(input.tool_name)) {
|
|
11949
|
+
return {};
|
|
11950
|
+
}
|
|
11951
|
+
const parsed = parseToolName(input.tool_name);
|
|
11952
|
+
const toolSpan = startSpan({
|
|
11953
|
+
event: {
|
|
11954
|
+
input: input.tool_input,
|
|
11955
|
+
metadata: {
|
|
11956
|
+
"claude_agent_sdk.cwd": input.cwd,
|
|
11957
|
+
"claude_agent_sdk.raw_tool_name": parsed.rawToolName,
|
|
11958
|
+
"claude_agent_sdk.session_id": input.session_id,
|
|
11959
|
+
"gen_ai.tool.call.id": toolUseID,
|
|
11960
|
+
"gen_ai.tool.name": parsed.toolName,
|
|
11961
|
+
...parsed.mcpServer && { "mcp.server": parsed.mcpServer },
|
|
11962
|
+
...getMcpServerMetadata(parsed.mcpServer, mcpServers)
|
|
11963
|
+
}
|
|
11964
|
+
},
|
|
11965
|
+
name: parsed.displayName,
|
|
11966
|
+
parent: await resolveParentSpan(toolUseID),
|
|
11967
|
+
spanAttributes: { type: "tool" /* TOOL */ }
|
|
11968
|
+
});
|
|
11969
|
+
activeToolSpans.set(toolUseID, toolSpan);
|
|
11970
|
+
return {};
|
|
11971
|
+
};
|
|
11972
|
+
const postToolUse = async (input, toolUseID) => {
|
|
11973
|
+
if (input.hook_event_name !== "PostToolUse" || !toolUseID) {
|
|
11974
|
+
return {};
|
|
11975
|
+
}
|
|
11976
|
+
const subAgentSpan = subAgentSpans.get(toolUseID);
|
|
11977
|
+
if (subAgentSpan) {
|
|
11978
|
+
try {
|
|
11979
|
+
const response = input.tool_response;
|
|
11980
|
+
const metadata = {};
|
|
11981
|
+
if (response?.status) {
|
|
11982
|
+
metadata["claude_agent_sdk.status"] = response.status;
|
|
11983
|
+
}
|
|
11984
|
+
if (response?.totalDurationMs) {
|
|
11985
|
+
metadata["claude_agent_sdk.duration_ms"] = response.totalDurationMs;
|
|
11986
|
+
}
|
|
11987
|
+
if (response?.totalToolUseCount !== void 0) {
|
|
11988
|
+
metadata["claude_agent_sdk.tool_use_count"] = response.totalToolUseCount;
|
|
11989
|
+
}
|
|
11990
|
+
subAgentSpan.log({
|
|
11991
|
+
metadata,
|
|
11992
|
+
output: response?.content
|
|
11993
|
+
});
|
|
11994
|
+
} finally {
|
|
11995
|
+
subAgentSpan.end();
|
|
11996
|
+
endedSubAgentSpans.add(toolUseID);
|
|
11997
|
+
}
|
|
11998
|
+
return {};
|
|
11999
|
+
}
|
|
12000
|
+
const toolSpan = activeToolSpans.get(toolUseID);
|
|
12001
|
+
if (!toolSpan) {
|
|
12002
|
+
return {};
|
|
12003
|
+
}
|
|
12004
|
+
try {
|
|
12005
|
+
toolSpan.log({ output: input.tool_response });
|
|
12006
|
+
} finally {
|
|
12007
|
+
toolSpan.end();
|
|
12008
|
+
activeToolSpans.delete(toolUseID);
|
|
12009
|
+
}
|
|
12010
|
+
return {};
|
|
12011
|
+
};
|
|
12012
|
+
const postToolUseFailure = async (input, toolUseID) => {
|
|
12013
|
+
if (input.hook_event_name !== "PostToolUseFailure" || !toolUseID) {
|
|
12014
|
+
return {};
|
|
12015
|
+
}
|
|
12016
|
+
const subAgentSpan = subAgentSpans.get(toolUseID);
|
|
12017
|
+
if (subAgentSpan) {
|
|
12018
|
+
try {
|
|
12019
|
+
subAgentSpan.log({ error: input.error });
|
|
12020
|
+
} finally {
|
|
12021
|
+
subAgentSpan.end();
|
|
12022
|
+
endedSubAgentSpans.add(toolUseID);
|
|
12023
|
+
}
|
|
12024
|
+
return {};
|
|
12025
|
+
}
|
|
12026
|
+
const toolSpan = activeToolSpans.get(toolUseID);
|
|
12027
|
+
if (!toolSpan) {
|
|
12028
|
+
return {};
|
|
12029
|
+
}
|
|
12030
|
+
const parsed = parseToolName(input.tool_name);
|
|
12031
|
+
try {
|
|
12032
|
+
toolSpan.log({
|
|
12033
|
+
error: input.error,
|
|
12034
|
+
metadata: {
|
|
12035
|
+
"claude_agent_sdk.is_interrupt": input.is_interrupt,
|
|
12036
|
+
"claude_agent_sdk.session_id": input.session_id,
|
|
12037
|
+
"gen_ai.tool.call.id": toolUseID,
|
|
12038
|
+
"gen_ai.tool.name": parsed.toolName,
|
|
12039
|
+
...parsed.mcpServer && { "mcp.server": parsed.mcpServer }
|
|
12040
|
+
}
|
|
12041
|
+
});
|
|
12042
|
+
} finally {
|
|
12043
|
+
toolSpan.end();
|
|
12044
|
+
activeToolSpans.delete(toolUseID);
|
|
12045
|
+
}
|
|
12046
|
+
return {};
|
|
12047
|
+
};
|
|
12048
|
+
return { postToolUse, postToolUseFailure, preToolUse };
|
|
12049
|
+
}
|
|
12050
|
+
function injectTracingHooks(options, resolveParentSpan, activeToolSpans, subAgentSpans, endedSubAgentSpans) {
|
|
12051
|
+
const { preToolUse, postToolUse, postToolUseFailure } = createToolTracingHooks(
|
|
12052
|
+
resolveParentSpan,
|
|
12053
|
+
activeToolSpans,
|
|
12054
|
+
options.mcpServers,
|
|
12055
|
+
subAgentSpans,
|
|
12056
|
+
endedSubAgentSpans
|
|
12057
|
+
);
|
|
12058
|
+
const existingHooks = options.hooks ?? {};
|
|
12059
|
+
return {
|
|
12060
|
+
...options,
|
|
12061
|
+
hooks: {
|
|
12062
|
+
...existingHooks,
|
|
12063
|
+
PostToolUse: [
|
|
12064
|
+
...existingHooks.PostToolUse ?? [],
|
|
12065
|
+
{ hooks: [postToolUse] }
|
|
12066
|
+
],
|
|
12067
|
+
PostToolUseFailure: [
|
|
12068
|
+
...existingHooks.PostToolUseFailure ?? [],
|
|
12069
|
+
{
|
|
12070
|
+
hooks: [postToolUseFailure]
|
|
12071
|
+
}
|
|
12072
|
+
],
|
|
12073
|
+
PreToolUse: [
|
|
12074
|
+
...existingHooks.PreToolUse ?? [],
|
|
12075
|
+
{ hooks: [preToolUse] }
|
|
12076
|
+
]
|
|
12077
|
+
}
|
|
12078
|
+
};
|
|
12079
|
+
}
|
|
12080
|
+
async function finalizeCurrentMessageGroup(state) {
|
|
12081
|
+
if (state.currentMessages.length === 0) {
|
|
12082
|
+
return;
|
|
12083
|
+
}
|
|
12084
|
+
const parentToolUseId = state.currentMessages[0]?.parent_tool_use_id ?? null;
|
|
12085
|
+
let parentSpan = await state.span.export();
|
|
12086
|
+
if (parentToolUseId) {
|
|
12087
|
+
const subAgentSpan = state.subAgentSpans.get(parentToolUseId);
|
|
12088
|
+
if (subAgentSpan) {
|
|
12089
|
+
parentSpan = await subAgentSpan.export();
|
|
12090
|
+
}
|
|
12091
|
+
}
|
|
12092
|
+
const finalMessage = await createLLMSpanForMessages(
|
|
12093
|
+
state.currentMessages,
|
|
12094
|
+
state.originalPrompt,
|
|
12095
|
+
state.finalResults,
|
|
12096
|
+
state.options,
|
|
12097
|
+
state.currentMessageStartTime,
|
|
12098
|
+
state.capturedPromptMessages,
|
|
12099
|
+
parentSpan
|
|
12100
|
+
);
|
|
12101
|
+
if (finalMessage) {
|
|
12102
|
+
state.finalResults.push(finalMessage);
|
|
12103
|
+
}
|
|
12104
|
+
const lastMessage = state.currentMessages[state.currentMessages.length - 1];
|
|
12105
|
+
if (lastMessage?.message?.usage) {
|
|
12106
|
+
state.accumulatedOutputTokens += getNumberProperty(lastMessage.message.usage, "output_tokens") || 0;
|
|
12107
|
+
}
|
|
12108
|
+
state.currentMessages.length = 0;
|
|
12109
|
+
}
|
|
12110
|
+
function maybeTrackToolUseContext(state, message) {
|
|
12111
|
+
if (message.type !== "assistant" || !Array.isArray(message.message?.content)) {
|
|
12112
|
+
return;
|
|
12113
|
+
}
|
|
12114
|
+
const parentToolUseId = message.parent_tool_use_id ?? null;
|
|
12115
|
+
for (const block of message.message.content) {
|
|
12116
|
+
if (typeof block !== "object" || block === null || !("type" in block) || block.type !== "tool_use" || !("id" in block) || typeof block.id !== "string") {
|
|
12117
|
+
continue;
|
|
12118
|
+
}
|
|
12119
|
+
state.toolUseToParent.set(block.id, parentToolUseId);
|
|
12120
|
+
if (block.name === "Task" && typeof block.input === "object" && block.input !== null && "subagent_type" in block.input && typeof block.input.subagent_type === "string") {
|
|
12121
|
+
state.pendingSubAgentNames.set(block.id, block.input.subagent_type);
|
|
12122
|
+
}
|
|
12123
|
+
}
|
|
12124
|
+
}
|
|
12125
|
+
async function maybeStartSubAgentSpan(state, message) {
|
|
12126
|
+
if (!("parent_tool_use_id" in message)) {
|
|
12127
|
+
return;
|
|
12128
|
+
}
|
|
12129
|
+
const parentToolUseId = message.parent_tool_use_id;
|
|
12130
|
+
if (!parentToolUseId) {
|
|
12131
|
+
return;
|
|
12132
|
+
}
|
|
12133
|
+
await ensureSubAgentSpan(
|
|
12134
|
+
state.pendingSubAgentNames,
|
|
12135
|
+
state.span,
|
|
12136
|
+
state.subAgentSpans,
|
|
12137
|
+
parentToolUseId
|
|
12138
|
+
);
|
|
12139
|
+
}
|
|
12140
|
+
async function ensureSubAgentSpan(pendingSubAgentNames, rootSpan, subAgentSpans, parentToolUseId) {
|
|
12141
|
+
const existingSpan = subAgentSpans.get(parentToolUseId);
|
|
12142
|
+
if (existingSpan) {
|
|
12143
|
+
return existingSpan;
|
|
12144
|
+
}
|
|
12145
|
+
const agentName = pendingSubAgentNames.get(parentToolUseId);
|
|
12146
|
+
const spanName = agentName ? `Agent: ${agentName}` : "Agent: sub-agent";
|
|
12147
|
+
const subAgentSpan = startSpan({
|
|
12148
|
+
event: {
|
|
12149
|
+
metadata: {
|
|
12150
|
+
...agentName && { "claude_agent_sdk.agent_type": agentName }
|
|
12151
|
+
}
|
|
12152
|
+
},
|
|
12153
|
+
name: spanName,
|
|
12154
|
+
parent: await rootSpan.export(),
|
|
12155
|
+
spanAttributes: { type: "task" /* TASK */ }
|
|
12156
|
+
});
|
|
12157
|
+
subAgentSpans.set(parentToolUseId, subAgentSpan);
|
|
12158
|
+
return subAgentSpan;
|
|
12159
|
+
}
|
|
12160
|
+
async function handleStreamMessage(state, message) {
|
|
12161
|
+
maybeTrackToolUseContext(state, message);
|
|
12162
|
+
await maybeStartSubAgentSpan(state, message);
|
|
12163
|
+
const messageId = message.message?.id;
|
|
12164
|
+
if (messageId && messageId !== state.currentMessageId) {
|
|
12165
|
+
await finalizeCurrentMessageGroup(state);
|
|
12166
|
+
state.currentMessageId = messageId;
|
|
12167
|
+
state.currentMessageStartTime = getCurrentUnixTimestamp();
|
|
12168
|
+
}
|
|
12169
|
+
if (message.type === "assistant" && message.message?.usage) {
|
|
12170
|
+
state.currentMessages.push(message);
|
|
12171
|
+
}
|
|
12172
|
+
if (message.type !== "result" || !message.usage) {
|
|
12173
|
+
return;
|
|
12174
|
+
}
|
|
12175
|
+
const finalUsageMetrics = extractUsageFromMessage(message);
|
|
12176
|
+
if (state.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
|
|
12177
|
+
const lastMessage = state.currentMessages[state.currentMessages.length - 1];
|
|
12178
|
+
if (lastMessage?.message?.usage) {
|
|
12179
|
+
const adjustedTokens = finalUsageMetrics.completion_tokens - state.accumulatedOutputTokens;
|
|
12180
|
+
if (adjustedTokens >= 0) {
|
|
12181
|
+
lastMessage.message.usage.output_tokens = adjustedTokens;
|
|
12182
|
+
}
|
|
12183
|
+
const resultUsage = message.usage;
|
|
12184
|
+
if (resultUsage && typeof resultUsage === "object") {
|
|
12185
|
+
const cacheReadTokens = getNumberProperty(
|
|
12186
|
+
resultUsage,
|
|
12187
|
+
"cache_read_input_tokens"
|
|
12188
|
+
);
|
|
12189
|
+
if (cacheReadTokens !== void 0) {
|
|
12190
|
+
lastMessage.message.usage.cache_read_input_tokens = cacheReadTokens;
|
|
12191
|
+
}
|
|
12192
|
+
const cacheCreationTokens = getNumberProperty(
|
|
12193
|
+
resultUsage,
|
|
12194
|
+
"cache_creation_input_tokens"
|
|
12195
|
+
);
|
|
12196
|
+
if (cacheCreationTokens !== void 0) {
|
|
12197
|
+
lastMessage.message.usage.cache_creation_input_tokens = cacheCreationTokens;
|
|
12198
|
+
}
|
|
12199
|
+
}
|
|
12200
|
+
}
|
|
12201
|
+
}
|
|
12202
|
+
const metadata = {};
|
|
12203
|
+
if (message.num_turns !== void 0) {
|
|
12204
|
+
metadata.num_turns = message.num_turns;
|
|
12205
|
+
}
|
|
12206
|
+
if (message.session_id !== void 0) {
|
|
12207
|
+
metadata.session_id = message.session_id;
|
|
12208
|
+
}
|
|
12209
|
+
if (Object.keys(metadata).length > 0) {
|
|
12210
|
+
state.span.log({ metadata });
|
|
12211
|
+
}
|
|
12212
|
+
}
|
|
12213
|
+
async function finalizeQuerySpan(state) {
|
|
12214
|
+
try {
|
|
12215
|
+
await finalizeCurrentMessageGroup(state);
|
|
12216
|
+
state.span.log({
|
|
12217
|
+
output: state.finalResults.length > 0 ? state.finalResults[state.finalResults.length - 1] : void 0
|
|
12218
|
+
});
|
|
12219
|
+
if (state.capturedPromptMessages) {
|
|
12220
|
+
if (state.promptStarted()) {
|
|
12221
|
+
await state.promptDone;
|
|
12222
|
+
}
|
|
12223
|
+
if (state.capturedPromptMessages.length > 0) {
|
|
12224
|
+
state.span.log({
|
|
12225
|
+
input: formatCapturedMessages(state.capturedPromptMessages)
|
|
12226
|
+
});
|
|
12227
|
+
}
|
|
12228
|
+
}
|
|
12229
|
+
} finally {
|
|
12230
|
+
for (const [id, subAgentSpan] of state.subAgentSpans) {
|
|
12231
|
+
if (!state.endedSubAgentSpans.has(id)) {
|
|
12232
|
+
subAgentSpan.end();
|
|
12233
|
+
}
|
|
12234
|
+
}
|
|
12235
|
+
state.subAgentSpans.clear();
|
|
12236
|
+
state.span.end();
|
|
12237
|
+
}
|
|
12238
|
+
}
|
|
11654
12239
|
var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
11655
12240
|
onEnable() {
|
|
11656
12241
|
this.subscribeToQuery();
|
|
@@ -11661,19 +12246,36 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
11661
12246
|
}
|
|
11662
12247
|
this.unsubscribers = [];
|
|
11663
12248
|
}
|
|
11664
|
-
/**
|
|
11665
|
-
* Subscribe to the query channel for agent interactions.
|
|
11666
|
-
* Handles streaming responses and traces both the top-level agent task
|
|
11667
|
-
* and individual LLM calls.
|
|
11668
|
-
*/
|
|
11669
12249
|
subscribeToQuery() {
|
|
11670
12250
|
const channel2 = claudeAgentSDKChannels.query.tracingChannel();
|
|
11671
12251
|
const spans = /* @__PURE__ */ new WeakMap();
|
|
11672
12252
|
const handlers = {
|
|
11673
12253
|
start: (event) => {
|
|
11674
|
-
const params = event.arguments[0];
|
|
11675
|
-
const
|
|
11676
|
-
const options = params
|
|
12254
|
+
const params = event.arguments[0] ?? {};
|
|
12255
|
+
const originalPrompt = params.prompt;
|
|
12256
|
+
const options = params.options ?? {};
|
|
12257
|
+
const promptIsAsyncIterable = isAsyncIterable(originalPrompt);
|
|
12258
|
+
let promptStarted = false;
|
|
12259
|
+
let capturedPromptMessages;
|
|
12260
|
+
let resolvePromptDone;
|
|
12261
|
+
const promptDone = new Promise((resolve) => {
|
|
12262
|
+
resolvePromptDone = resolve;
|
|
12263
|
+
});
|
|
12264
|
+
if (promptIsAsyncIterable) {
|
|
12265
|
+
capturedPromptMessages = [];
|
|
12266
|
+
const promptStream = originalPrompt;
|
|
12267
|
+
params.prompt = (async function* () {
|
|
12268
|
+
promptStarted = true;
|
|
12269
|
+
try {
|
|
12270
|
+
for await (const message of promptStream) {
|
|
12271
|
+
capturedPromptMessages.push(message);
|
|
12272
|
+
yield message;
|
|
12273
|
+
}
|
|
12274
|
+
} finally {
|
|
12275
|
+
resolvePromptDone?.();
|
|
12276
|
+
}
|
|
12277
|
+
})();
|
|
12278
|
+
}
|
|
11677
12279
|
const span = startSpan({
|
|
11678
12280
|
name: "Claude Agent",
|
|
11679
12281
|
spanAttributes: {
|
|
@@ -11683,163 +12285,115 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
11683
12285
|
const startTime = getCurrentUnixTimestamp();
|
|
11684
12286
|
try {
|
|
11685
12287
|
span.log({
|
|
11686
|
-
input: typeof
|
|
11687
|
-
type: "streaming",
|
|
11688
|
-
description: "AsyncIterable<ClaudeAgentSDKMessage>"
|
|
11689
|
-
},
|
|
12288
|
+
input: typeof originalPrompt === "string" ? originalPrompt : promptIsAsyncIterable ? void 0 : originalPrompt !== void 0 ? String(originalPrompt) : void 0,
|
|
11690
12289
|
metadata: filterSerializableOptions(options)
|
|
11691
12290
|
});
|
|
11692
12291
|
} catch (error) {
|
|
11693
12292
|
console.error("Error extracting input for Claude Agent SDK:", error);
|
|
11694
12293
|
}
|
|
12294
|
+
const activeToolSpans = /* @__PURE__ */ new Map();
|
|
12295
|
+
const subAgentSpans = /* @__PURE__ */ new Map();
|
|
12296
|
+
const endedSubAgentSpans = /* @__PURE__ */ new Set();
|
|
12297
|
+
const toolUseToParent = /* @__PURE__ */ new Map();
|
|
12298
|
+
const pendingSubAgentNames = /* @__PURE__ */ new Map();
|
|
12299
|
+
const optionsWithHooks = injectTracingHooks(
|
|
12300
|
+
options,
|
|
12301
|
+
async (toolUseID) => {
|
|
12302
|
+
const parentToolUseId = toolUseToParent.get(toolUseID);
|
|
12303
|
+
if (parentToolUseId) {
|
|
12304
|
+
const subAgentSpan = await ensureSubAgentSpan(
|
|
12305
|
+
pendingSubAgentNames,
|
|
12306
|
+
span,
|
|
12307
|
+
subAgentSpans,
|
|
12308
|
+
parentToolUseId
|
|
12309
|
+
);
|
|
12310
|
+
return subAgentSpan.export();
|
|
12311
|
+
}
|
|
12312
|
+
return span.export();
|
|
12313
|
+
},
|
|
12314
|
+
activeToolSpans,
|
|
12315
|
+
subAgentSpans,
|
|
12316
|
+
endedSubAgentSpans
|
|
12317
|
+
);
|
|
12318
|
+
params.options = optionsWithHooks;
|
|
12319
|
+
event.arguments[0] = params;
|
|
11695
12320
|
spans.set(event, {
|
|
11696
|
-
|
|
11697
|
-
|
|
11698
|
-
|
|
11699
|
-
currentMessages: [],
|
|
12321
|
+
accumulatedOutputTokens: 0,
|
|
12322
|
+
activeToolSpans,
|
|
12323
|
+
capturedPromptMessages,
|
|
11700
12324
|
currentMessageId: void 0,
|
|
11701
12325
|
currentMessageStartTime: startTime,
|
|
11702
|
-
|
|
12326
|
+
currentMessages: [],
|
|
12327
|
+
endedSubAgentSpans,
|
|
12328
|
+
finalResults: [],
|
|
12329
|
+
options: optionsWithHooks,
|
|
12330
|
+
originalPrompt,
|
|
12331
|
+
pendingSubAgentNames,
|
|
12332
|
+
processing: Promise.resolve(),
|
|
12333
|
+
promptDone,
|
|
12334
|
+
promptStarted: () => promptStarted,
|
|
12335
|
+
span,
|
|
12336
|
+
subAgentSpans,
|
|
12337
|
+
toolUseToParent
|
|
11703
12338
|
});
|
|
11704
12339
|
},
|
|
11705
|
-
|
|
11706
|
-
const
|
|
11707
|
-
if (!
|
|
12340
|
+
end: (event) => {
|
|
12341
|
+
const state = spans.get(event);
|
|
12342
|
+
if (!state) {
|
|
11708
12343
|
return;
|
|
11709
12344
|
}
|
|
11710
12345
|
const eventResult = event.result;
|
|
11711
12346
|
if (eventResult === void 0) {
|
|
11712
|
-
|
|
12347
|
+
state.span.end();
|
|
11713
12348
|
spans.delete(event);
|
|
11714
12349
|
return;
|
|
11715
12350
|
}
|
|
11716
12351
|
if (isAsyncIterable(eventResult)) {
|
|
11717
12352
|
patchStreamIfNeeded(eventResult, {
|
|
11718
|
-
onChunk:
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
const prompt = params?.prompt;
|
|
11722
|
-
const options = params?.options ?? {};
|
|
11723
|
-
const messageId = message.message?.id;
|
|
11724
|
-
if (messageId && messageId !== spanData.currentMessageId) {
|
|
11725
|
-
if (spanData.currentMessages.length > 0) {
|
|
11726
|
-
const finalMessage = await createLLMSpanForMessages(
|
|
11727
|
-
spanData.currentMessages,
|
|
11728
|
-
prompt,
|
|
11729
|
-
spanData.conversationHistory,
|
|
11730
|
-
options,
|
|
11731
|
-
spanData.currentMessageStartTime,
|
|
11732
|
-
await spanData.span.export()
|
|
11733
|
-
);
|
|
11734
|
-
if (finalMessage) {
|
|
11735
|
-
spanData.conversationHistory.push(finalMessage);
|
|
11736
|
-
}
|
|
11737
|
-
const lastMessage = spanData.currentMessages[spanData.currentMessages.length - 1];
|
|
11738
|
-
if (lastMessage?.message?.usage) {
|
|
11739
|
-
const outputTokens = getNumberProperty(
|
|
11740
|
-
lastMessage.message.usage,
|
|
11741
|
-
"output_tokens"
|
|
11742
|
-
) || 0;
|
|
11743
|
-
spanData.accumulatedOutputTokens += outputTokens;
|
|
11744
|
-
}
|
|
11745
|
-
spanData.currentMessages = [];
|
|
11746
|
-
}
|
|
11747
|
-
spanData.currentMessageId = messageId;
|
|
11748
|
-
spanData.currentMessageStartTime = currentTime;
|
|
11749
|
-
}
|
|
11750
|
-
if (message.type === "assistant" && message.message?.usage) {
|
|
11751
|
-
spanData.currentMessages.push(message);
|
|
11752
|
-
}
|
|
11753
|
-
if (message.type === "result" && message.usage) {
|
|
11754
|
-
const finalUsageMetrics = extractUsageFromMessage(message);
|
|
11755
|
-
if (spanData.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
|
|
11756
|
-
const lastMessage = spanData.currentMessages[spanData.currentMessages.length - 1];
|
|
11757
|
-
if (lastMessage?.message?.usage) {
|
|
11758
|
-
const adjustedTokens = finalUsageMetrics.completion_tokens - spanData.accumulatedOutputTokens;
|
|
11759
|
-
if (adjustedTokens >= 0) {
|
|
11760
|
-
lastMessage.message.usage.output_tokens = adjustedTokens;
|
|
11761
|
-
}
|
|
11762
|
-
}
|
|
11763
|
-
}
|
|
11764
|
-
const result_metadata = {};
|
|
11765
|
-
if (message.num_turns !== void 0) {
|
|
11766
|
-
result_metadata.num_turns = message.num_turns;
|
|
11767
|
-
}
|
|
11768
|
-
if (message.session_id !== void 0) {
|
|
11769
|
-
result_metadata.session_id = message.session_id;
|
|
11770
|
-
}
|
|
11771
|
-
if (Object.keys(result_metadata).length > 0) {
|
|
11772
|
-
spanData.span.log({
|
|
11773
|
-
metadata: result_metadata
|
|
11774
|
-
});
|
|
11775
|
-
}
|
|
11776
|
-
}
|
|
11777
|
-
},
|
|
11778
|
-
onComplete: async () => {
|
|
11779
|
-
try {
|
|
11780
|
-
const params = event.arguments[0];
|
|
11781
|
-
const prompt = params?.prompt;
|
|
11782
|
-
const options = params?.options ?? {};
|
|
11783
|
-
if (spanData.currentMessages.length > 0) {
|
|
11784
|
-
const finalMessage = await createLLMSpanForMessages(
|
|
11785
|
-
spanData.currentMessages,
|
|
11786
|
-
prompt,
|
|
11787
|
-
spanData.conversationHistory,
|
|
11788
|
-
options,
|
|
11789
|
-
spanData.currentMessageStartTime,
|
|
11790
|
-
await spanData.span.export()
|
|
11791
|
-
);
|
|
11792
|
-
if (finalMessage) {
|
|
11793
|
-
spanData.conversationHistory.push(finalMessage);
|
|
11794
|
-
}
|
|
11795
|
-
}
|
|
11796
|
-
spanData.span.log({
|
|
11797
|
-
output: spanData.conversationHistory.length > 0 ? spanData.conversationHistory[spanData.conversationHistory.length - 1] : void 0
|
|
11798
|
-
});
|
|
11799
|
-
} catch (error) {
|
|
12353
|
+
onChunk: (message) => {
|
|
12354
|
+
maybeTrackToolUseContext(state, message);
|
|
12355
|
+
state.processing = state.processing.then(() => handleStreamMessage(state, message)).catch((error) => {
|
|
11800
12356
|
console.error(
|
|
11801
|
-
"Error
|
|
12357
|
+
"Error processing Claude Agent SDK stream chunk:",
|
|
11802
12358
|
error
|
|
11803
12359
|
);
|
|
11804
|
-
}
|
|
11805
|
-
|
|
12360
|
+
});
|
|
12361
|
+
},
|
|
12362
|
+
onComplete: () => {
|
|
12363
|
+
void state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
|
|
11806
12364
|
spans.delete(event);
|
|
11807
|
-
}
|
|
12365
|
+
});
|
|
11808
12366
|
},
|
|
11809
12367
|
onError: (error) => {
|
|
11810
|
-
|
|
11811
|
-
|
|
12368
|
+
void state.processing.then(() => {
|
|
12369
|
+
state.span.log({
|
|
12370
|
+
error: error.message
|
|
12371
|
+
});
|
|
12372
|
+
}).then(() => finalizeQuerySpan(state)).finally(() => {
|
|
12373
|
+
spans.delete(event);
|
|
11812
12374
|
});
|
|
11813
|
-
spanData.span.end();
|
|
11814
|
-
spans.delete(event);
|
|
11815
12375
|
}
|
|
11816
12376
|
});
|
|
11817
|
-
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
|
|
11821
|
-
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
|
|
11825
|
-
|
|
11826
|
-
);
|
|
11827
|
-
} finally {
|
|
11828
|
-
spanData.span.end();
|
|
11829
|
-
spans.delete(event);
|
|
11830
|
-
}
|
|
12377
|
+
return;
|
|
12378
|
+
}
|
|
12379
|
+
try {
|
|
12380
|
+
state.span.log({ output: eventResult });
|
|
12381
|
+
} catch (error) {
|
|
12382
|
+
console.error("Error extracting output for Claude Agent SDK:", error);
|
|
12383
|
+
} finally {
|
|
12384
|
+
state.span.end();
|
|
12385
|
+
spans.delete(event);
|
|
11831
12386
|
}
|
|
11832
12387
|
},
|
|
11833
12388
|
error: (event) => {
|
|
11834
|
-
const
|
|
11835
|
-
if (!
|
|
12389
|
+
const state = spans.get(event);
|
|
12390
|
+
if (!state || !event.error) {
|
|
11836
12391
|
return;
|
|
11837
12392
|
}
|
|
11838
|
-
|
|
11839
|
-
span.log({
|
|
12393
|
+
state.span.log({
|
|
11840
12394
|
error: event.error.message
|
|
11841
12395
|
});
|
|
11842
|
-
span.end();
|
|
12396
|
+
state.span.end();
|
|
11843
12397
|
spans.delete(event);
|
|
11844
12398
|
}
|
|
11845
12399
|
};
|
|
@@ -11863,6 +12417,18 @@ var googleGenAIChannels = defineChannels("@google/genai", {
|
|
|
11863
12417
|
});
|
|
11864
12418
|
|
|
11865
12419
|
// src/instrumentation/plugins/google-genai-plugin.ts
|
|
12420
|
+
var GOOGLE_GENAI_INTERNAL_CONTEXT = {
|
|
12421
|
+
caller_filename: "<node-internal>",
|
|
12422
|
+
caller_functionname: "<node-internal>",
|
|
12423
|
+
caller_lineno: 0
|
|
12424
|
+
};
|
|
12425
|
+
function createWrapperParityEvent(args) {
|
|
12426
|
+
return {
|
|
12427
|
+
context: GOOGLE_GENAI_INTERNAL_CONTEXT,
|
|
12428
|
+
input: args.input,
|
|
12429
|
+
metadata: args.metadata
|
|
12430
|
+
};
|
|
12431
|
+
}
|
|
11866
12432
|
var GoogleGenAIPlugin = class extends BasePlugin {
|
|
11867
12433
|
onEnable() {
|
|
11868
12434
|
this.subscribeToGoogleGenAIChannels();
|
|
@@ -11871,51 +12437,282 @@ var GoogleGenAIPlugin = class extends BasePlugin {
|
|
|
11871
12437
|
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
11872
12438
|
}
|
|
11873
12439
|
subscribeToGoogleGenAIChannels() {
|
|
11874
|
-
this.
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
11884
|
-
|
|
11885
|
-
|
|
11886
|
-
|
|
11887
|
-
|
|
11888
|
-
|
|
11889
|
-
|
|
11890
|
-
|
|
11891
|
-
|
|
11892
|
-
|
|
12440
|
+
this.subscribeToGenerateContentChannel();
|
|
12441
|
+
this.subscribeToGenerateContentStreamChannel();
|
|
12442
|
+
}
|
|
12443
|
+
subscribeToGenerateContentChannel() {
|
|
12444
|
+
const tracingChannel2 = googleGenAIChannels.generateContent.tracingChannel();
|
|
12445
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
12446
|
+
const unbindCurrentSpanStore = bindCurrentSpanStoreToStart2(
|
|
12447
|
+
tracingChannel2,
|
|
12448
|
+
states,
|
|
12449
|
+
(event) => {
|
|
12450
|
+
const params = event.arguments[0];
|
|
12451
|
+
const input = serializeInput(params);
|
|
12452
|
+
const metadata = extractMetadata(params);
|
|
12453
|
+
const span = startSpan({
|
|
12454
|
+
name: "generate_content",
|
|
12455
|
+
spanAttributes: {
|
|
12456
|
+
type: "llm" /* LLM */
|
|
12457
|
+
},
|
|
12458
|
+
event: createWrapperParityEvent({ input, metadata })
|
|
12459
|
+
});
|
|
12460
|
+
return {
|
|
12461
|
+
span,
|
|
12462
|
+
startTime: getCurrentUnixTimestamp()
|
|
12463
|
+
};
|
|
12464
|
+
}
|
|
11893
12465
|
);
|
|
11894
|
-
|
|
11895
|
-
|
|
11896
|
-
|
|
11897
|
-
|
|
11898
|
-
extractInput: ([params]) => {
|
|
12466
|
+
const handlers = {
|
|
12467
|
+
start: (event) => {
|
|
12468
|
+
ensureSpanState(states, event, () => {
|
|
12469
|
+
const params = event.arguments[0];
|
|
11899
12470
|
const input = serializeInput(params);
|
|
11900
12471
|
const metadata = extractMetadata(params);
|
|
12472
|
+
const span = startSpan({
|
|
12473
|
+
name: "generate_content",
|
|
12474
|
+
spanAttributes: {
|
|
12475
|
+
type: "llm" /* LLM */
|
|
12476
|
+
},
|
|
12477
|
+
event: createWrapperParityEvent({ input, metadata })
|
|
12478
|
+
});
|
|
11901
12479
|
return {
|
|
11902
|
-
|
|
11903
|
-
|
|
12480
|
+
span,
|
|
12481
|
+
startTime: getCurrentUnixTimestamp()
|
|
11904
12482
|
};
|
|
11905
|
-
}
|
|
11906
|
-
|
|
11907
|
-
|
|
11908
|
-
|
|
11909
|
-
|
|
11910
|
-
return
|
|
11911
|
-
},
|
|
11912
|
-
aggregateChunks: (chunks, _result, _endEvent, startTime) => {
|
|
11913
|
-
return aggregateGenerateContentChunks(chunks, startTime);
|
|
12483
|
+
});
|
|
12484
|
+
},
|
|
12485
|
+
asyncEnd: (event) => {
|
|
12486
|
+
const spanState = states.get(event);
|
|
12487
|
+
if (!spanState) {
|
|
12488
|
+
return;
|
|
11914
12489
|
}
|
|
11915
|
-
|
|
11916
|
-
|
|
12490
|
+
try {
|
|
12491
|
+
spanState.span.log({
|
|
12492
|
+
metrics: cleanMetrics(
|
|
12493
|
+
extractGenerateContentMetrics(
|
|
12494
|
+
event.result,
|
|
12495
|
+
spanState.startTime
|
|
12496
|
+
)
|
|
12497
|
+
),
|
|
12498
|
+
output: event.result
|
|
12499
|
+
});
|
|
12500
|
+
} finally {
|
|
12501
|
+
spanState.span.end();
|
|
12502
|
+
states.delete(event);
|
|
12503
|
+
}
|
|
12504
|
+
},
|
|
12505
|
+
error: (event) => {
|
|
12506
|
+
logErrorAndEndSpan(states, event);
|
|
12507
|
+
}
|
|
12508
|
+
};
|
|
12509
|
+
tracingChannel2.subscribe(handlers);
|
|
12510
|
+
this.unsubscribers.push(() => {
|
|
12511
|
+
unbindCurrentSpanStore?.();
|
|
12512
|
+
tracingChannel2.unsubscribe(handlers);
|
|
12513
|
+
});
|
|
12514
|
+
}
|
|
12515
|
+
subscribeToGenerateContentStreamChannel() {
|
|
12516
|
+
const tracingChannel2 = googleGenAIChannels.generateContentStream.tracingChannel();
|
|
12517
|
+
const handlers = {
|
|
12518
|
+
start: (event) => {
|
|
12519
|
+
const streamEvent = event;
|
|
12520
|
+
const params = event.arguments[0];
|
|
12521
|
+
streamEvent.googleGenAIInput = serializeInput(params);
|
|
12522
|
+
streamEvent.googleGenAIMetadata = extractMetadata(params);
|
|
12523
|
+
},
|
|
12524
|
+
asyncEnd: (event) => {
|
|
12525
|
+
const streamEvent = event;
|
|
12526
|
+
patchGoogleGenAIStreamingResult({
|
|
12527
|
+
input: streamEvent.googleGenAIInput,
|
|
12528
|
+
metadata: streamEvent.googleGenAIMetadata,
|
|
12529
|
+
result: streamEvent.result
|
|
12530
|
+
});
|
|
12531
|
+
},
|
|
12532
|
+
error: () => {
|
|
12533
|
+
}
|
|
12534
|
+
};
|
|
12535
|
+
tracingChannel2.subscribe(handlers);
|
|
12536
|
+
this.unsubscribers.push(() => {
|
|
12537
|
+
tracingChannel2.unsubscribe(handlers);
|
|
12538
|
+
});
|
|
11917
12539
|
}
|
|
11918
12540
|
};
|
|
12541
|
+
function ensureSpanState(states, event, create) {
|
|
12542
|
+
const existing = states.get(event);
|
|
12543
|
+
if (existing) {
|
|
12544
|
+
return existing;
|
|
12545
|
+
}
|
|
12546
|
+
const created = create();
|
|
12547
|
+
states.set(event, created);
|
|
12548
|
+
return created;
|
|
12549
|
+
}
|
|
12550
|
+
function bindCurrentSpanStoreToStart2(tracingChannel2, states, create) {
|
|
12551
|
+
const state = _internalGetGlobalState();
|
|
12552
|
+
const startChannel = tracingChannel2.start;
|
|
12553
|
+
const currentSpanStore = state?.contextManager ? state.contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
|
|
12554
|
+
if (!startChannel?.bindStore || !currentSpanStore) {
|
|
12555
|
+
return void 0;
|
|
12556
|
+
}
|
|
12557
|
+
startChannel.bindStore(
|
|
12558
|
+
currentSpanStore,
|
|
12559
|
+
(event) => ensureSpanState(
|
|
12560
|
+
states,
|
|
12561
|
+
event,
|
|
12562
|
+
() => create(event)
|
|
12563
|
+
).span
|
|
12564
|
+
);
|
|
12565
|
+
return () => {
|
|
12566
|
+
startChannel.unbindStore?.(currentSpanStore);
|
|
12567
|
+
};
|
|
12568
|
+
}
|
|
12569
|
+
function logErrorAndEndSpan(states, event) {
|
|
12570
|
+
const spanState = states.get(event);
|
|
12571
|
+
if (!spanState) {
|
|
12572
|
+
return;
|
|
12573
|
+
}
|
|
12574
|
+
spanState.span.log({
|
|
12575
|
+
error: event.error.message
|
|
12576
|
+
});
|
|
12577
|
+
spanState.span.end();
|
|
12578
|
+
states.delete(event);
|
|
12579
|
+
}
|
|
12580
|
+
function patchGoogleGenAIStreamingResult(args) {
|
|
12581
|
+
const { input, metadata, result } = args;
|
|
12582
|
+
if (!input || !metadata || !result || typeof result !== "object" || typeof result.next !== "function") {
|
|
12583
|
+
return false;
|
|
12584
|
+
}
|
|
12585
|
+
const chunks = [];
|
|
12586
|
+
let firstTokenTime = null;
|
|
12587
|
+
let finalized = false;
|
|
12588
|
+
let span = null;
|
|
12589
|
+
let startTime = null;
|
|
12590
|
+
const ensureSpan = () => {
|
|
12591
|
+
if (!span) {
|
|
12592
|
+
span = startSpan({
|
|
12593
|
+
name: "generate_content_stream",
|
|
12594
|
+
spanAttributes: {
|
|
12595
|
+
type: "llm" /* LLM */
|
|
12596
|
+
},
|
|
12597
|
+
event: {
|
|
12598
|
+
input,
|
|
12599
|
+
metadata
|
|
12600
|
+
}
|
|
12601
|
+
});
|
|
12602
|
+
startTime = getCurrentUnixTimestamp();
|
|
12603
|
+
}
|
|
12604
|
+
return span;
|
|
12605
|
+
};
|
|
12606
|
+
const finalize = (options) => {
|
|
12607
|
+
if (finalized || !span) {
|
|
12608
|
+
return;
|
|
12609
|
+
}
|
|
12610
|
+
finalized = true;
|
|
12611
|
+
if (options.result) {
|
|
12612
|
+
const { end, ...metricsWithoutEnd } = options.result.metrics;
|
|
12613
|
+
span.log({
|
|
12614
|
+
metrics: cleanMetrics(metricsWithoutEnd),
|
|
12615
|
+
output: options.result.aggregated
|
|
12616
|
+
});
|
|
12617
|
+
span.end(typeof end === "number" ? { endTime: end } : void 0);
|
|
12618
|
+
return;
|
|
12619
|
+
}
|
|
12620
|
+
if (options.error !== void 0) {
|
|
12621
|
+
span.log({
|
|
12622
|
+
error: options.error instanceof Error ? options.error.message : String(options.error)
|
|
12623
|
+
});
|
|
12624
|
+
}
|
|
12625
|
+
span.end();
|
|
12626
|
+
};
|
|
12627
|
+
const patchIterator = (iterator) => {
|
|
12628
|
+
if (typeof iterator !== "object" || iterator === null || "__braintrustGoogleGenAIPatched" in iterator) {
|
|
12629
|
+
return iterator;
|
|
12630
|
+
}
|
|
12631
|
+
const iteratorRecord = iterator;
|
|
12632
|
+
const originalNext = typeof iteratorRecord.next === "function" ? iteratorRecord.next.bind(iterator) : void 0;
|
|
12633
|
+
const originalReturn = typeof iteratorRecord.return === "function" ? iteratorRecord.return.bind(iterator) : void 0;
|
|
12634
|
+
const originalThrow = typeof iteratorRecord.throw === "function" ? iteratorRecord.throw.bind(iterator) : void 0;
|
|
12635
|
+
const asyncIteratorMethod = iteratorRecord[Symbol.asyncIterator];
|
|
12636
|
+
const originalAsyncIterator = typeof asyncIteratorMethod === "function" ? asyncIteratorMethod.bind(iterator) : void 0;
|
|
12637
|
+
Object.defineProperty(iteratorRecord, "__braintrustGoogleGenAIPatched", {
|
|
12638
|
+
configurable: true,
|
|
12639
|
+
enumerable: false,
|
|
12640
|
+
value: true,
|
|
12641
|
+
writable: false
|
|
12642
|
+
});
|
|
12643
|
+
if (originalNext) {
|
|
12644
|
+
iteratorRecord.next = async (...nextArgs) => {
|
|
12645
|
+
ensureSpan();
|
|
12646
|
+
try {
|
|
12647
|
+
const nextResult = await originalNext(
|
|
12648
|
+
...nextArgs
|
|
12649
|
+
);
|
|
12650
|
+
if (!nextResult.done && nextResult.value) {
|
|
12651
|
+
if (firstTokenTime === null) {
|
|
12652
|
+
firstTokenTime = getCurrentUnixTimestamp();
|
|
12653
|
+
}
|
|
12654
|
+
chunks.push(nextResult.value);
|
|
12655
|
+
}
|
|
12656
|
+
if (nextResult.done && startTime !== null) {
|
|
12657
|
+
finalize({
|
|
12658
|
+
result: aggregateGenerateContentChunks(
|
|
12659
|
+
chunks,
|
|
12660
|
+
startTime,
|
|
12661
|
+
firstTokenTime
|
|
12662
|
+
)
|
|
12663
|
+
});
|
|
12664
|
+
}
|
|
12665
|
+
return nextResult;
|
|
12666
|
+
} catch (error) {
|
|
12667
|
+
finalize({ error });
|
|
12668
|
+
throw error;
|
|
12669
|
+
}
|
|
12670
|
+
};
|
|
12671
|
+
}
|
|
12672
|
+
if (originalReturn) {
|
|
12673
|
+
iteratorRecord.return = async (...returnArgs) => {
|
|
12674
|
+
ensureSpan();
|
|
12675
|
+
try {
|
|
12676
|
+
return await originalReturn(
|
|
12677
|
+
...returnArgs
|
|
12678
|
+
);
|
|
12679
|
+
} finally {
|
|
12680
|
+
if (startTime !== null) {
|
|
12681
|
+
finalize({
|
|
12682
|
+
result: chunks.length > 0 ? aggregateGenerateContentChunks(
|
|
12683
|
+
chunks,
|
|
12684
|
+
startTime,
|
|
12685
|
+
firstTokenTime
|
|
12686
|
+
) : void 0
|
|
12687
|
+
});
|
|
12688
|
+
} else {
|
|
12689
|
+
finalize({});
|
|
12690
|
+
}
|
|
12691
|
+
}
|
|
12692
|
+
};
|
|
12693
|
+
}
|
|
12694
|
+
if (originalThrow) {
|
|
12695
|
+
iteratorRecord.throw = async (...throwArgs) => {
|
|
12696
|
+
ensureSpan();
|
|
12697
|
+
try {
|
|
12698
|
+
return await originalThrow(
|
|
12699
|
+
...throwArgs
|
|
12700
|
+
);
|
|
12701
|
+
} catch (error) {
|
|
12702
|
+
finalize({ error });
|
|
12703
|
+
throw error;
|
|
12704
|
+
}
|
|
12705
|
+
};
|
|
12706
|
+
}
|
|
12707
|
+
iteratorRecord[Symbol.asyncIterator] = () => {
|
|
12708
|
+
const asyncIterator = originalAsyncIterator ? originalAsyncIterator() : iterator;
|
|
12709
|
+
return patchIterator(asyncIterator);
|
|
12710
|
+
};
|
|
12711
|
+
return iterator;
|
|
12712
|
+
};
|
|
12713
|
+
patchIterator(result);
|
|
12714
|
+
return true;
|
|
12715
|
+
}
|
|
11919
12716
|
function serializeInput(params) {
|
|
11920
12717
|
const input = {
|
|
11921
12718
|
model: params.model,
|
|
@@ -11924,11 +12721,13 @@ function serializeInput(params) {
|
|
|
11924
12721
|
if (params.config) {
|
|
11925
12722
|
const config = tryToDict(params.config);
|
|
11926
12723
|
if (config) {
|
|
11927
|
-
const
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
|
|
12724
|
+
const filteredConfig = {};
|
|
12725
|
+
Object.keys(config).forEach((key) => {
|
|
12726
|
+
if (key !== "tools") {
|
|
12727
|
+
filteredConfig[key] = config[key];
|
|
12728
|
+
}
|
|
12729
|
+
});
|
|
12730
|
+
input.config = filteredConfig;
|
|
11932
12731
|
}
|
|
11933
12732
|
}
|
|
11934
12733
|
return input;
|
|
@@ -12015,12 +12814,18 @@ function extractMetadata(params) {
|
|
|
12015
12814
|
});
|
|
12016
12815
|
}
|
|
12017
12816
|
}
|
|
12817
|
+
const tools = serializeTools(params);
|
|
12818
|
+
if (tools) {
|
|
12819
|
+
metadata.tools = tools;
|
|
12820
|
+
}
|
|
12018
12821
|
return metadata;
|
|
12019
12822
|
}
|
|
12020
12823
|
function extractGenerateContentMetrics(response, startTime) {
|
|
12021
12824
|
const metrics = {};
|
|
12022
|
-
if (startTime) {
|
|
12825
|
+
if (startTime !== void 0) {
|
|
12023
12826
|
const end = getCurrentUnixTimestamp();
|
|
12827
|
+
metrics.start = startTime;
|
|
12828
|
+
metrics.end = end;
|
|
12024
12829
|
metrics.duration = end - startTime;
|
|
12025
12830
|
}
|
|
12026
12831
|
if (response?.usageMetadata) {
|
|
@@ -12032,116 +12837,1141 @@ function populateUsageMetrics(metrics, usage) {
|
|
|
12032
12837
|
if (usage.promptTokenCount !== void 0) {
|
|
12033
12838
|
metrics.prompt_tokens = usage.promptTokenCount;
|
|
12034
12839
|
}
|
|
12035
|
-
if (usage.candidatesTokenCount !== void 0) {
|
|
12036
|
-
metrics.completion_tokens = usage.candidatesTokenCount;
|
|
12840
|
+
if (usage.candidatesTokenCount !== void 0) {
|
|
12841
|
+
metrics.completion_tokens = usage.candidatesTokenCount;
|
|
12842
|
+
}
|
|
12843
|
+
if (usage.totalTokenCount !== void 0) {
|
|
12844
|
+
metrics.tokens = usage.totalTokenCount;
|
|
12845
|
+
}
|
|
12846
|
+
if (usage.cachedContentTokenCount !== void 0) {
|
|
12847
|
+
metrics.prompt_cached_tokens = usage.cachedContentTokenCount;
|
|
12848
|
+
}
|
|
12849
|
+
if (usage.thoughtsTokenCount !== void 0) {
|
|
12850
|
+
metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
|
|
12851
|
+
}
|
|
12852
|
+
}
|
|
12853
|
+
function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
|
|
12854
|
+
const end = getCurrentUnixTimestamp();
|
|
12855
|
+
const metrics = {
|
|
12856
|
+
start: startTime,
|
|
12857
|
+
end,
|
|
12858
|
+
duration: end - startTime
|
|
12859
|
+
};
|
|
12860
|
+
if (firstTokenTime !== null) {
|
|
12861
|
+
metrics.time_to_first_token = firstTokenTime - startTime;
|
|
12862
|
+
}
|
|
12863
|
+
if (chunks.length === 0) {
|
|
12864
|
+
return { aggregated: {}, metrics };
|
|
12865
|
+
}
|
|
12866
|
+
let text = "";
|
|
12867
|
+
let thoughtText = "";
|
|
12868
|
+
const otherParts = [];
|
|
12869
|
+
let usageMetadata = null;
|
|
12870
|
+
let lastResponse = null;
|
|
12871
|
+
for (const chunk of chunks) {
|
|
12872
|
+
lastResponse = chunk;
|
|
12873
|
+
if (chunk.usageMetadata) {
|
|
12874
|
+
usageMetadata = chunk.usageMetadata;
|
|
12875
|
+
}
|
|
12876
|
+
if (chunk.candidates && Array.isArray(chunk.candidates)) {
|
|
12877
|
+
for (const candidate of chunk.candidates) {
|
|
12878
|
+
if (candidate.content?.parts) {
|
|
12879
|
+
for (const part of candidate.content.parts) {
|
|
12880
|
+
if (part.text !== void 0) {
|
|
12881
|
+
if (part.thought) {
|
|
12882
|
+
thoughtText += part.text;
|
|
12883
|
+
} else {
|
|
12884
|
+
text += part.text;
|
|
12885
|
+
}
|
|
12886
|
+
} else if (part.functionCall) {
|
|
12887
|
+
otherParts.push({ functionCall: part.functionCall });
|
|
12888
|
+
} else if (part.codeExecutionResult) {
|
|
12889
|
+
otherParts.push({
|
|
12890
|
+
codeExecutionResult: part.codeExecutionResult
|
|
12891
|
+
});
|
|
12892
|
+
} else if (part.executableCode) {
|
|
12893
|
+
otherParts.push({ executableCode: part.executableCode });
|
|
12894
|
+
}
|
|
12895
|
+
}
|
|
12896
|
+
}
|
|
12897
|
+
}
|
|
12898
|
+
}
|
|
12899
|
+
}
|
|
12900
|
+
const aggregated = {};
|
|
12901
|
+
const parts = [];
|
|
12902
|
+
if (thoughtText) {
|
|
12903
|
+
parts.push({ text: thoughtText, thought: true });
|
|
12904
|
+
}
|
|
12905
|
+
if (text) {
|
|
12906
|
+
parts.push({ text });
|
|
12907
|
+
}
|
|
12908
|
+
parts.push(...otherParts);
|
|
12909
|
+
if (parts.length > 0 && lastResponse?.candidates) {
|
|
12910
|
+
const candidates = [];
|
|
12911
|
+
for (const candidate of lastResponse.candidates) {
|
|
12912
|
+
const candidateDict = {
|
|
12913
|
+
content: {
|
|
12914
|
+
parts,
|
|
12915
|
+
role: "model"
|
|
12916
|
+
}
|
|
12917
|
+
};
|
|
12918
|
+
if (candidate.finishReason !== void 0) {
|
|
12919
|
+
candidateDict.finishReason = candidate.finishReason;
|
|
12920
|
+
}
|
|
12921
|
+
if (candidate.safetyRatings) {
|
|
12922
|
+
candidateDict.safetyRatings = candidate.safetyRatings;
|
|
12923
|
+
}
|
|
12924
|
+
candidates.push(candidateDict);
|
|
12925
|
+
}
|
|
12926
|
+
aggregated.candidates = candidates;
|
|
12927
|
+
}
|
|
12928
|
+
if (usageMetadata) {
|
|
12929
|
+
aggregated.usageMetadata = usageMetadata;
|
|
12930
|
+
populateUsageMetrics(metrics, usageMetadata);
|
|
12931
|
+
}
|
|
12932
|
+
if (text) {
|
|
12933
|
+
aggregated.text = text;
|
|
12934
|
+
}
|
|
12935
|
+
return { aggregated, metrics };
|
|
12936
|
+
}
|
|
12937
|
+
function cleanMetrics(metrics) {
|
|
12938
|
+
const cleaned = {};
|
|
12939
|
+
for (const [key, value] of Object.entries(metrics)) {
|
|
12940
|
+
if (value !== null && value !== void 0) {
|
|
12941
|
+
cleaned[key] = value;
|
|
12942
|
+
}
|
|
12943
|
+
}
|
|
12944
|
+
return cleaned;
|
|
12945
|
+
}
|
|
12946
|
+
function tryToDict(obj) {
|
|
12947
|
+
if (obj === null || obj === void 0) {
|
|
12948
|
+
return null;
|
|
12949
|
+
}
|
|
12950
|
+
if (typeof obj === "object") {
|
|
12951
|
+
if ("toJSON" in obj && // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
12952
|
+
typeof obj.toJSON === "function") {
|
|
12953
|
+
return obj.toJSON();
|
|
12954
|
+
}
|
|
12955
|
+
return obj;
|
|
12956
|
+
}
|
|
12957
|
+
return null;
|
|
12958
|
+
}
|
|
12959
|
+
|
|
12960
|
+
// src/instrumentation/plugins/openrouter-channels.ts
|
|
12961
|
+
var openRouterChannels = defineChannels("@openrouter/sdk", {
|
|
12962
|
+
chatSend: channel({
|
|
12963
|
+
channelName: "chat.send",
|
|
12964
|
+
kind: "async"
|
|
12965
|
+
}),
|
|
12966
|
+
embeddingsGenerate: channel({
|
|
12967
|
+
channelName: "embeddings.generate",
|
|
12968
|
+
kind: "async"
|
|
12969
|
+
}),
|
|
12970
|
+
betaResponsesSend: channel({
|
|
12971
|
+
channelName: "beta.responses.send",
|
|
12972
|
+
kind: "async"
|
|
12973
|
+
}),
|
|
12974
|
+
callModel: channel({
|
|
12975
|
+
channelName: "callModel",
|
|
12976
|
+
kind: "sync-stream"
|
|
12977
|
+
}),
|
|
12978
|
+
toolExecute: channel({
|
|
12979
|
+
channelName: "tool.execute",
|
|
12980
|
+
kind: "async"
|
|
12981
|
+
})
|
|
12982
|
+
});
|
|
12983
|
+
|
|
12984
|
+
// src/openrouter-utils.ts
|
|
12985
|
+
var TOKEN_NAME_MAP2 = {
|
|
12986
|
+
promptTokens: "prompt_tokens",
|
|
12987
|
+
inputTokens: "prompt_tokens",
|
|
12988
|
+
completionTokens: "completion_tokens",
|
|
12989
|
+
outputTokens: "completion_tokens",
|
|
12990
|
+
totalTokens: "tokens",
|
|
12991
|
+
prompt_tokens: "prompt_tokens",
|
|
12992
|
+
input_tokens: "prompt_tokens",
|
|
12993
|
+
completion_tokens: "completion_tokens",
|
|
12994
|
+
output_tokens: "completion_tokens",
|
|
12995
|
+
total_tokens: "tokens"
|
|
12996
|
+
};
|
|
12997
|
+
var TOKEN_DETAIL_PREFIX_MAP = {
|
|
12998
|
+
promptTokensDetails: "prompt",
|
|
12999
|
+
inputTokensDetails: "prompt",
|
|
13000
|
+
completionTokensDetails: "completion",
|
|
13001
|
+
outputTokensDetails: "completion",
|
|
13002
|
+
costDetails: "cost",
|
|
13003
|
+
prompt_tokens_details: "prompt",
|
|
13004
|
+
input_tokens_details: "prompt",
|
|
13005
|
+
completion_tokens_details: "completion",
|
|
13006
|
+
output_tokens_details: "completion",
|
|
13007
|
+
cost_details: "cost"
|
|
13008
|
+
};
|
|
13009
|
+
function camelToSnake(value) {
|
|
13010
|
+
return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
|
|
13011
|
+
}
|
|
13012
|
+
function parseOpenRouterMetricsFromUsage(usage) {
|
|
13013
|
+
if (!isObject(usage)) {
|
|
13014
|
+
return {};
|
|
13015
|
+
}
|
|
13016
|
+
const metrics = {};
|
|
13017
|
+
for (const [name, value] of Object.entries(usage)) {
|
|
13018
|
+
if (typeof value === "number") {
|
|
13019
|
+
metrics[TOKEN_NAME_MAP2[name] || camelToSnake(name)] = value;
|
|
13020
|
+
continue;
|
|
13021
|
+
}
|
|
13022
|
+
if (!isObject(value)) {
|
|
13023
|
+
continue;
|
|
13024
|
+
}
|
|
13025
|
+
const prefix = TOKEN_DETAIL_PREFIX_MAP[name];
|
|
13026
|
+
if (!prefix) {
|
|
13027
|
+
continue;
|
|
13028
|
+
}
|
|
13029
|
+
for (const [nestedName, nestedValue] of Object.entries(value)) {
|
|
13030
|
+
if (typeof nestedValue !== "number") {
|
|
13031
|
+
continue;
|
|
13032
|
+
}
|
|
13033
|
+
metrics[`${prefix}_${camelToSnake(nestedName)}`] = nestedValue;
|
|
13034
|
+
}
|
|
13035
|
+
}
|
|
13036
|
+
return metrics;
|
|
13037
|
+
}
|
|
13038
|
+
function extractOpenRouterUsageMetadata(usage) {
|
|
13039
|
+
if (!isObject(usage)) {
|
|
13040
|
+
return void 0;
|
|
13041
|
+
}
|
|
13042
|
+
const metadata = {};
|
|
13043
|
+
if (typeof usage.isByok === "boolean") {
|
|
13044
|
+
metadata.is_byok = usage.isByok;
|
|
13045
|
+
} else if (typeof usage.is_byok === "boolean") {
|
|
13046
|
+
metadata.is_byok = usage.is_byok;
|
|
13047
|
+
}
|
|
13048
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
13049
|
+
}
|
|
13050
|
+
|
|
13051
|
+
// src/openrouter-logging.ts
|
|
13052
|
+
var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
|
|
13053
|
+
"execute",
|
|
13054
|
+
"render",
|
|
13055
|
+
"nextTurnParams",
|
|
13056
|
+
"requireApproval"
|
|
13057
|
+
]);
|
|
13058
|
+
function parseOpenRouterModelString(model) {
|
|
13059
|
+
if (typeof model !== "string") {
|
|
13060
|
+
return { model };
|
|
13061
|
+
}
|
|
13062
|
+
const slashIndex = model.indexOf("/");
|
|
13063
|
+
if (slashIndex > 0 && slashIndex < model.length - 1) {
|
|
13064
|
+
return {
|
|
13065
|
+
provider: model.substring(0, slashIndex),
|
|
13066
|
+
model: model.substring(slashIndex + 1)
|
|
13067
|
+
};
|
|
13068
|
+
}
|
|
13069
|
+
return { model };
|
|
13070
|
+
}
|
|
13071
|
+
function isZodSchema2(value) {
|
|
13072
|
+
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
13073
|
+
}
|
|
13074
|
+
function serializeZodSchema2(schema) {
|
|
13075
|
+
try {
|
|
13076
|
+
return zodToJsonSchema(schema);
|
|
13077
|
+
} catch {
|
|
13078
|
+
return {
|
|
13079
|
+
type: "object",
|
|
13080
|
+
description: "Zod schema (conversion failed)"
|
|
13081
|
+
};
|
|
13082
|
+
}
|
|
13083
|
+
}
|
|
13084
|
+
function serializeOpenRouterTool(tool) {
|
|
13085
|
+
if (!isObject(tool)) {
|
|
13086
|
+
return tool;
|
|
13087
|
+
}
|
|
13088
|
+
const serialized = {};
|
|
13089
|
+
for (const [key, value] of Object.entries(tool)) {
|
|
13090
|
+
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
13091
|
+
continue;
|
|
13092
|
+
}
|
|
13093
|
+
if (key === "function" && isObject(value)) {
|
|
13094
|
+
serialized.function = sanitizeOpenRouterLoggedValue(value);
|
|
13095
|
+
continue;
|
|
13096
|
+
}
|
|
13097
|
+
serialized[key] = sanitizeOpenRouterLoggedValue(value);
|
|
13098
|
+
}
|
|
13099
|
+
return serialized;
|
|
13100
|
+
}
|
|
13101
|
+
function serializeOpenRouterToolsForLogging(tools) {
|
|
13102
|
+
if (!Array.isArray(tools)) {
|
|
13103
|
+
return void 0;
|
|
13104
|
+
}
|
|
13105
|
+
return tools.map((tool) => serializeOpenRouterTool(tool));
|
|
13106
|
+
}
|
|
13107
|
+
function sanitizeOpenRouterLoggedValue(value) {
|
|
13108
|
+
if (isZodSchema2(value)) {
|
|
13109
|
+
return serializeZodSchema2(value);
|
|
13110
|
+
}
|
|
13111
|
+
if (typeof value === "function") {
|
|
13112
|
+
return "[Function]";
|
|
13113
|
+
}
|
|
13114
|
+
if (Array.isArray(value)) {
|
|
13115
|
+
return value.map((entry) => sanitizeOpenRouterLoggedValue(entry));
|
|
13116
|
+
}
|
|
13117
|
+
if (!isObject(value)) {
|
|
13118
|
+
return value;
|
|
13119
|
+
}
|
|
13120
|
+
const sanitized = {};
|
|
13121
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
13122
|
+
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
13123
|
+
continue;
|
|
13124
|
+
}
|
|
13125
|
+
if (key === "tools" && Array.isArray(entry)) {
|
|
13126
|
+
sanitized.tools = serializeOpenRouterToolsForLogging(entry);
|
|
13127
|
+
continue;
|
|
13128
|
+
}
|
|
13129
|
+
sanitized[key] = sanitizeOpenRouterLoggedValue(entry);
|
|
13130
|
+
}
|
|
13131
|
+
return sanitized;
|
|
13132
|
+
}
|
|
13133
|
+
function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
|
|
13134
|
+
const sanitized = sanitizeOpenRouterLoggedValue(metadata);
|
|
13135
|
+
const metadataRecord = isObject(sanitized) ? sanitized : {};
|
|
13136
|
+
const { model, provider: providerRouting, ...rest } = metadataRecord;
|
|
13137
|
+
const normalizedModel = parseOpenRouterModelString(model);
|
|
13138
|
+
return {
|
|
13139
|
+
...rest,
|
|
13140
|
+
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
13141
|
+
...providerRouting !== void 0 ? { providerRouting } : {},
|
|
13142
|
+
...httpReferer !== void 0 ? { httpReferer } : {},
|
|
13143
|
+
...xTitle !== void 0 ? { xTitle } : {},
|
|
13144
|
+
provider: normalizedModel.provider || "openrouter"
|
|
13145
|
+
};
|
|
13146
|
+
}
|
|
13147
|
+
function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
|
|
13148
|
+
const normalized = buildOpenRouterMetadata(metadata, httpReferer, xTitle);
|
|
13149
|
+
return typeof normalized.model === "string" ? {
|
|
13150
|
+
...normalized,
|
|
13151
|
+
embedding_model: normalized.model
|
|
13152
|
+
} : normalized;
|
|
13153
|
+
}
|
|
13154
|
+
function extractOpenRouterCallModelInput(request) {
|
|
13155
|
+
return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue(request.input) : void 0;
|
|
13156
|
+
}
|
|
13157
|
+
function extractOpenRouterCallModelMetadata(request) {
|
|
13158
|
+
if (!isObject(request)) {
|
|
13159
|
+
return { provider: "openrouter" };
|
|
13160
|
+
}
|
|
13161
|
+
const { input: _input, ...metadata } = request;
|
|
13162
|
+
return buildOpenRouterMetadata(metadata, void 0, void 0);
|
|
13163
|
+
}
|
|
13164
|
+
function extractOpenRouterResponseMetadata(result) {
|
|
13165
|
+
if (!isObject(result)) {
|
|
13166
|
+
return void 0;
|
|
13167
|
+
}
|
|
13168
|
+
const { output: _output, data: _data, usage, ...metadata } = result;
|
|
13169
|
+
const sanitized = sanitizeOpenRouterLoggedValue(metadata);
|
|
13170
|
+
const metadataRecord = isObject(sanitized) ? sanitized : {};
|
|
13171
|
+
const { model, provider, ...rest } = metadataRecord;
|
|
13172
|
+
const normalizedModel = parseOpenRouterModelString(model);
|
|
13173
|
+
const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
|
|
13174
|
+
const usageMetadata = extractOpenRouterUsageMetadata(usage);
|
|
13175
|
+
const combined = {
|
|
13176
|
+
...rest,
|
|
13177
|
+
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
13178
|
+
...usageMetadata || {},
|
|
13179
|
+
...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
|
|
13180
|
+
};
|
|
13181
|
+
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
13182
|
+
}
|
|
13183
|
+
function extractOpenRouterResponseOutput(response, fallbackOutput) {
|
|
13184
|
+
if (isObject(response) && "output" in response && response.output !== void 0) {
|
|
13185
|
+
return sanitizeOpenRouterLoggedValue(response.output);
|
|
13186
|
+
}
|
|
13187
|
+
if (fallbackOutput !== void 0) {
|
|
13188
|
+
return sanitizeOpenRouterLoggedValue(fallbackOutput);
|
|
13189
|
+
}
|
|
13190
|
+
return void 0;
|
|
13191
|
+
}
|
|
13192
|
+
|
|
13193
|
+
// src/openrouter-tool-wrapping.ts
|
|
13194
|
+
var OPENROUTER_WRAPPED_TOOL = Symbol("braintrust.openrouter.wrappedTool");
|
|
13195
|
+
var OPENROUTER_WRAPPED_CALL_MODEL_RESULT = Symbol(
|
|
13196
|
+
"braintrust.openrouter.wrappedCallModelResult"
|
|
13197
|
+
);
|
|
13198
|
+
var OPENROUTER_CALL_MODEL_STREAM_METHODS = [
|
|
13199
|
+
"getFullResponsesStream",
|
|
13200
|
+
"getItemsStream",
|
|
13201
|
+
"getNewMessagesStream",
|
|
13202
|
+
"getReasoningStream",
|
|
13203
|
+
"getTextStream",
|
|
13204
|
+
"getToolCallsStream",
|
|
13205
|
+
"getToolStream"
|
|
13206
|
+
];
|
|
13207
|
+
var OPENROUTER_CALL_MODEL_CONTEXT_METHODS = [
|
|
13208
|
+
"cancel",
|
|
13209
|
+
"getPendingToolCalls",
|
|
13210
|
+
"getState",
|
|
13211
|
+
"getToolCalls",
|
|
13212
|
+
"requiresApproval"
|
|
13213
|
+
];
|
|
13214
|
+
function patchOpenRouterCallModelRequestTools(request) {
|
|
13215
|
+
if (!Array.isArray(request.tools) || request.tools.length === 0) {
|
|
13216
|
+
return void 0;
|
|
13217
|
+
}
|
|
13218
|
+
const originalTools = request.tools;
|
|
13219
|
+
const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
|
|
13220
|
+
const didPatch = wrappedTools.some(
|
|
13221
|
+
(tool, index) => tool !== originalTools[index]
|
|
13222
|
+
);
|
|
13223
|
+
if (!didPatch) {
|
|
13224
|
+
return void 0;
|
|
13225
|
+
}
|
|
13226
|
+
request.tools = wrappedTools;
|
|
13227
|
+
return () => {
|
|
13228
|
+
request.tools = originalTools;
|
|
13229
|
+
};
|
|
13230
|
+
}
|
|
13231
|
+
function patchOpenRouterCallModelResult(span, result, request) {
|
|
13232
|
+
if (!isObject(result) || isWrappedCallModelResult(result)) {
|
|
13233
|
+
return false;
|
|
13234
|
+
}
|
|
13235
|
+
const resultLike = result;
|
|
13236
|
+
const hasInstrumentableMethod = typeof resultLike.getResponse === "function" || typeof resultLike.getText === "function" || OPENROUTER_CALL_MODEL_STREAM_METHODS.some(
|
|
13237
|
+
(methodName) => typeof resultLike[methodName] === "function"
|
|
13238
|
+
);
|
|
13239
|
+
if (!hasInstrumentableMethod) {
|
|
13240
|
+
return false;
|
|
13241
|
+
}
|
|
13242
|
+
Object.defineProperty(resultLike, OPENROUTER_WRAPPED_CALL_MODEL_RESULT, {
|
|
13243
|
+
value: true,
|
|
13244
|
+
enumerable: false,
|
|
13245
|
+
configurable: false
|
|
13246
|
+
});
|
|
13247
|
+
const originalGetResponse = typeof resultLike.getResponse === "function" ? resultLike.getResponse.bind(resultLike) : void 0;
|
|
13248
|
+
const originalGetInitialResponse = typeof resultLike.getInitialResponse === "function" ? resultLike.getInitialResponse.bind(resultLike) : void 0;
|
|
13249
|
+
const originalMakeFollowupRequest = typeof resultLike.makeFollowupRequest === "function" ? resultLike.makeFollowupRequest.bind(resultLike) : void 0;
|
|
13250
|
+
let ended = false;
|
|
13251
|
+
let tracedTurnCount = 0;
|
|
13252
|
+
const endSpanWithResult = async (response, fallbackOutput) => {
|
|
13253
|
+
if (ended) {
|
|
13254
|
+
return;
|
|
13255
|
+
}
|
|
13256
|
+
ended = true;
|
|
13257
|
+
const finalResponse = getFinalOpenRouterCallModelResponse(
|
|
13258
|
+
resultLike,
|
|
13259
|
+
response
|
|
13260
|
+
);
|
|
13261
|
+
if (finalResponse) {
|
|
13262
|
+
const rounds = getOpenRouterCallModelRounds(resultLike);
|
|
13263
|
+
const metadata = extractOpenRouterCallModelResultMetadata(
|
|
13264
|
+
finalResponse,
|
|
13265
|
+
rounds.length + 1
|
|
13266
|
+
);
|
|
13267
|
+
span.log({
|
|
13268
|
+
output: extractOpenRouterResponseOutput(finalResponse, fallbackOutput),
|
|
13269
|
+
...metadata ? { metadata } : {},
|
|
13270
|
+
metrics: aggregateOpenRouterCallModelMetrics(rounds, finalResponse)
|
|
13271
|
+
});
|
|
13272
|
+
span.end();
|
|
13273
|
+
return;
|
|
13274
|
+
}
|
|
13275
|
+
if (fallbackOutput !== void 0) {
|
|
13276
|
+
span.log({
|
|
13277
|
+
output: fallbackOutput
|
|
13278
|
+
});
|
|
13279
|
+
}
|
|
13280
|
+
span.end();
|
|
13281
|
+
};
|
|
13282
|
+
const endSpanWithError = (error) => {
|
|
13283
|
+
if (ended) {
|
|
13284
|
+
return;
|
|
13285
|
+
}
|
|
13286
|
+
ended = true;
|
|
13287
|
+
span.log({
|
|
13288
|
+
error: normalizeError(error).message
|
|
13289
|
+
});
|
|
13290
|
+
span.end();
|
|
13291
|
+
};
|
|
13292
|
+
const finalizeFromResponse = async (fallbackOutput) => {
|
|
13293
|
+
if (!originalGetResponse) {
|
|
13294
|
+
await endSpanWithResult(void 0, fallbackOutput);
|
|
13295
|
+
return;
|
|
13296
|
+
}
|
|
13297
|
+
try {
|
|
13298
|
+
await endSpanWithResult(await originalGetResponse(), fallbackOutput);
|
|
13299
|
+
} catch {
|
|
13300
|
+
await endSpanWithResult(void 0, fallbackOutput);
|
|
13301
|
+
}
|
|
13302
|
+
};
|
|
13303
|
+
if (originalGetResponse) {
|
|
13304
|
+
resultLike.getResponse = async (...args) => {
|
|
13305
|
+
return await withCurrent(span, async () => {
|
|
13306
|
+
try {
|
|
13307
|
+
const response = await originalGetResponse(...args);
|
|
13308
|
+
await endSpanWithResult(response);
|
|
13309
|
+
return response;
|
|
13310
|
+
} catch (error) {
|
|
13311
|
+
endSpanWithError(error);
|
|
13312
|
+
throw error;
|
|
13313
|
+
}
|
|
13314
|
+
});
|
|
13315
|
+
};
|
|
13316
|
+
}
|
|
13317
|
+
if (typeof resultLike.getText === "function") {
|
|
13318
|
+
const originalGetText = resultLike.getText.bind(resultLike);
|
|
13319
|
+
resultLike.getText = async (...args) => {
|
|
13320
|
+
return await withCurrent(span, async () => {
|
|
13321
|
+
try {
|
|
13322
|
+
const text = await originalGetText(...args);
|
|
13323
|
+
await finalizeFromResponse(text);
|
|
13324
|
+
return text;
|
|
13325
|
+
} catch (error) {
|
|
13326
|
+
endSpanWithError(error);
|
|
13327
|
+
throw error;
|
|
13328
|
+
}
|
|
13329
|
+
});
|
|
13330
|
+
};
|
|
13331
|
+
}
|
|
13332
|
+
for (const methodName of OPENROUTER_CALL_MODEL_CONTEXT_METHODS) {
|
|
13333
|
+
if (typeof resultLike[methodName] !== "function") {
|
|
13334
|
+
continue;
|
|
13335
|
+
}
|
|
13336
|
+
const originalMethod = resultLike[methodName];
|
|
13337
|
+
resultLike[methodName] = async (...args) => {
|
|
13338
|
+
return await withCurrent(span, async () => {
|
|
13339
|
+
return await originalMethod.apply(resultLike, args);
|
|
13340
|
+
});
|
|
13341
|
+
};
|
|
13342
|
+
}
|
|
13343
|
+
for (const methodName of OPENROUTER_CALL_MODEL_STREAM_METHODS) {
|
|
13344
|
+
if (typeof resultLike[methodName] !== "function") {
|
|
13345
|
+
continue;
|
|
13346
|
+
}
|
|
13347
|
+
const originalMethod = resultLike[methodName];
|
|
13348
|
+
resultLike[methodName] = (...args) => {
|
|
13349
|
+
const stream = withCurrent(
|
|
13350
|
+
span,
|
|
13351
|
+
() => originalMethod.apply(resultLike, args)
|
|
13352
|
+
);
|
|
13353
|
+
if (!isAsyncIterable2(stream)) {
|
|
13354
|
+
return stream;
|
|
13355
|
+
}
|
|
13356
|
+
return wrapAsyncIterableWithSpan({
|
|
13357
|
+
finalize: finalizeFromResponse,
|
|
13358
|
+
iteratorFactory: () => stream[Symbol.asyncIterator](),
|
|
13359
|
+
onError: endSpanWithError,
|
|
13360
|
+
span
|
|
13361
|
+
});
|
|
13362
|
+
};
|
|
13363
|
+
}
|
|
13364
|
+
if (originalGetInitialResponse) {
|
|
13365
|
+
let initialTurnTraced = false;
|
|
13366
|
+
resultLike.getInitialResponse = async (...args) => {
|
|
13367
|
+
if (initialTurnTraced) {
|
|
13368
|
+
return await withCurrent(span, async () => {
|
|
13369
|
+
return await originalGetInitialResponse(...args);
|
|
13370
|
+
});
|
|
13371
|
+
}
|
|
13372
|
+
initialTurnTraced = true;
|
|
13373
|
+
const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
|
|
13374
|
+
const childSpan = startOpenRouterCallModelTurnSpan({
|
|
13375
|
+
request: resolvedRequest,
|
|
13376
|
+
step: tracedTurnCount + 1,
|
|
13377
|
+
stepType: tracedTurnCount === 0 ? "initial" : "continue"
|
|
13378
|
+
});
|
|
13379
|
+
return await withCurrent(childSpan, async () => {
|
|
13380
|
+
try {
|
|
13381
|
+
const response = await originalGetInitialResponse(...args);
|
|
13382
|
+
tracedTurnCount++;
|
|
13383
|
+
finishOpenRouterCallModelTurnSpan({
|
|
13384
|
+
response,
|
|
13385
|
+
step: tracedTurnCount,
|
|
13386
|
+
stepType: tracedTurnCount === 1 ? "initial" : "continue",
|
|
13387
|
+
span: childSpan
|
|
13388
|
+
});
|
|
13389
|
+
return response;
|
|
13390
|
+
} catch (error) {
|
|
13391
|
+
childSpan.log({
|
|
13392
|
+
error: normalizeError(error).message
|
|
13393
|
+
});
|
|
13394
|
+
childSpan.end();
|
|
13395
|
+
throw error;
|
|
13396
|
+
}
|
|
13397
|
+
});
|
|
13398
|
+
};
|
|
13399
|
+
}
|
|
13400
|
+
if (originalMakeFollowupRequest) {
|
|
13401
|
+
resultLike.makeFollowupRequest = async (...args) => {
|
|
13402
|
+
const currentResponse = args[0];
|
|
13403
|
+
const toolResults = Array.isArray(args[1]) ? args[1] : [];
|
|
13404
|
+
const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
|
|
13405
|
+
const followupRequest = buildOpenRouterFollowupRequest(
|
|
13406
|
+
resolvedRequest,
|
|
13407
|
+
currentResponse,
|
|
13408
|
+
toolResults
|
|
13409
|
+
);
|
|
13410
|
+
const childSpan = startOpenRouterCallModelTurnSpan({
|
|
13411
|
+
request: followupRequest,
|
|
13412
|
+
step: tracedTurnCount + 1,
|
|
13413
|
+
stepType: "continue"
|
|
13414
|
+
});
|
|
13415
|
+
return await withCurrent(childSpan, async () => {
|
|
13416
|
+
try {
|
|
13417
|
+
const response = await originalMakeFollowupRequest(...args);
|
|
13418
|
+
tracedTurnCount++;
|
|
13419
|
+
finishOpenRouterCallModelTurnSpan({
|
|
13420
|
+
response,
|
|
13421
|
+
step: tracedTurnCount,
|
|
13422
|
+
stepType: "continue",
|
|
13423
|
+
span: childSpan
|
|
13424
|
+
});
|
|
13425
|
+
return response;
|
|
13426
|
+
} catch (error) {
|
|
13427
|
+
childSpan.log({
|
|
13428
|
+
error: normalizeError(error).message
|
|
13429
|
+
});
|
|
13430
|
+
childSpan.end();
|
|
13431
|
+
throw error;
|
|
13432
|
+
}
|
|
13433
|
+
});
|
|
13434
|
+
};
|
|
13435
|
+
}
|
|
13436
|
+
return true;
|
|
13437
|
+
}
|
|
13438
|
+
function wrapOpenRouterTool(tool) {
|
|
13439
|
+
if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
|
|
13440
|
+
return tool;
|
|
13441
|
+
}
|
|
13442
|
+
const toolName = tool.function.name || "tool";
|
|
13443
|
+
const originalExecute = tool.function.execute;
|
|
13444
|
+
const wrappedTool = {
|
|
13445
|
+
...tool,
|
|
13446
|
+
function: {
|
|
13447
|
+
...tool.function,
|
|
13448
|
+
execute(...args) {
|
|
13449
|
+
return traceToolExecution({
|
|
13450
|
+
args,
|
|
13451
|
+
execute: () => Reflect.apply(originalExecute, this, args),
|
|
13452
|
+
toolCallId: getToolCallId(args[1]),
|
|
13453
|
+
toolName
|
|
13454
|
+
});
|
|
13455
|
+
}
|
|
13456
|
+
}
|
|
13457
|
+
};
|
|
13458
|
+
Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL, {
|
|
13459
|
+
value: true,
|
|
13460
|
+
enumerable: false,
|
|
13461
|
+
configurable: false
|
|
13462
|
+
});
|
|
13463
|
+
return wrappedTool;
|
|
13464
|
+
}
|
|
13465
|
+
function isWrappedTool(tool) {
|
|
13466
|
+
return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
|
|
13467
|
+
}
|
|
13468
|
+
function isWrappedCallModelResult(value) {
|
|
13469
|
+
return Boolean(
|
|
13470
|
+
isObject(value) && value[OPENROUTER_WRAPPED_CALL_MODEL_RESULT]
|
|
13471
|
+
);
|
|
13472
|
+
}
|
|
13473
|
+
function traceToolExecution(args) {
|
|
13474
|
+
const tracingChannel2 = openRouterChannels.toolExecute.tracingChannel();
|
|
13475
|
+
const input = args.args.length > 0 ? args.args[0] : void 0;
|
|
13476
|
+
const event = {
|
|
13477
|
+
arguments: [input],
|
|
13478
|
+
span_info: {
|
|
13479
|
+
name: args.toolName
|
|
13480
|
+
},
|
|
13481
|
+
toolCallId: args.toolCallId,
|
|
13482
|
+
toolName: args.toolName
|
|
13483
|
+
};
|
|
13484
|
+
tracingChannel2.start.publish(event);
|
|
13485
|
+
try {
|
|
13486
|
+
const result = args.execute();
|
|
13487
|
+
return publishToolResult(tracingChannel2, event, result);
|
|
13488
|
+
} catch (error) {
|
|
13489
|
+
event.error = normalizeError(error);
|
|
13490
|
+
tracingChannel2.error.publish(event);
|
|
13491
|
+
throw error;
|
|
13492
|
+
}
|
|
13493
|
+
}
|
|
13494
|
+
function publishToolResult(tracingChannel2, event, result) {
|
|
13495
|
+
if (isPromiseLike(result)) {
|
|
13496
|
+
return result.then(
|
|
13497
|
+
(resolved) => {
|
|
13498
|
+
event.result = resolved;
|
|
13499
|
+
tracingChannel2.asyncEnd.publish(event);
|
|
13500
|
+
return resolved;
|
|
13501
|
+
},
|
|
13502
|
+
(error) => {
|
|
13503
|
+
event.error = normalizeError(error);
|
|
13504
|
+
tracingChannel2.error.publish(event);
|
|
13505
|
+
throw error;
|
|
13506
|
+
}
|
|
13507
|
+
);
|
|
13508
|
+
}
|
|
13509
|
+
event.result = result;
|
|
13510
|
+
tracingChannel2.asyncEnd.publish(event);
|
|
13511
|
+
return result;
|
|
13512
|
+
}
|
|
13513
|
+
function getToolCallId(context) {
|
|
13514
|
+
const toolContext = context;
|
|
13515
|
+
return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
|
|
13516
|
+
}
|
|
13517
|
+
function extractOpenRouterCallModelResultMetadata(response, turnCount) {
|
|
13518
|
+
const combined = {
|
|
13519
|
+
...extractOpenRouterResponseMetadata(response) || {},
|
|
13520
|
+
...turnCount !== void 0 ? { turn_count: turnCount } : {}
|
|
13521
|
+
};
|
|
13522
|
+
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
13523
|
+
}
|
|
13524
|
+
function getFinalOpenRouterCallModelResponse(result, response) {
|
|
13525
|
+
if (isObject(response)) {
|
|
13526
|
+
return response;
|
|
12037
13527
|
}
|
|
12038
|
-
|
|
12039
|
-
|
|
13528
|
+
return isObject(result.finalResponse) ? result.finalResponse : void 0;
|
|
13529
|
+
}
|
|
13530
|
+
function getOpenRouterCallModelRounds(result) {
|
|
13531
|
+
if (!Array.isArray(result.allToolExecutionRounds)) {
|
|
13532
|
+
return [];
|
|
12040
13533
|
}
|
|
12041
|
-
|
|
12042
|
-
|
|
13534
|
+
return result.allToolExecutionRounds.filter((round) => isObject(round)).map((round) => ({
|
|
13535
|
+
response: isObject(round.response) ? round.response : void 0,
|
|
13536
|
+
round: typeof round.round === "number" ? round.round : void 0,
|
|
13537
|
+
toolResults: Array.isArray(round.toolResults) ? round.toolResults : []
|
|
13538
|
+
})).filter((round) => round.response !== void 0);
|
|
13539
|
+
}
|
|
13540
|
+
function aggregateOpenRouterCallModelMetrics(rounds, finalResponse) {
|
|
13541
|
+
const metrics = {};
|
|
13542
|
+
const responses = [
|
|
13543
|
+
...rounds.map((round) => round.response).filter(isObject),
|
|
13544
|
+
finalResponse
|
|
13545
|
+
];
|
|
13546
|
+
for (const response of responses) {
|
|
13547
|
+
const responseMetrics = parseOpenRouterMetricsFromUsage(response.usage);
|
|
13548
|
+
for (const [name, value] of Object.entries(responseMetrics)) {
|
|
13549
|
+
metrics[name] = (metrics[name] || 0) + value;
|
|
13550
|
+
}
|
|
12043
13551
|
}
|
|
12044
|
-
|
|
12045
|
-
|
|
13552
|
+
return metrics;
|
|
13553
|
+
}
|
|
13554
|
+
function buildNextOpenRouterCallModelInput(currentInput, response, toolResults) {
|
|
13555
|
+
const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
|
|
13556
|
+
const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
|
|
13557
|
+
return [...normalizedInput, ...responseOutput, ...toolResults].map(
|
|
13558
|
+
(entry) => sanitizeOpenRouterLoggedValue(entry)
|
|
13559
|
+
);
|
|
13560
|
+
}
|
|
13561
|
+
function startOpenRouterCallModelTurnSpan(args) {
|
|
13562
|
+
const requestRecord = isObject(args.request) ? args.request : void 0;
|
|
13563
|
+
const metadata = requestRecord ? extractOpenRouterCallModelMetadata(requestRecord) : { provider: "openrouter" };
|
|
13564
|
+
if (isObject(metadata) && "tools" in metadata) {
|
|
13565
|
+
delete metadata.tools;
|
|
12046
13566
|
}
|
|
13567
|
+
return startSpan({
|
|
13568
|
+
name: "openrouter.beta.responses.send",
|
|
13569
|
+
spanAttributes: {
|
|
13570
|
+
type: "llm" /* LLM */
|
|
13571
|
+
},
|
|
13572
|
+
event: {
|
|
13573
|
+
input: requestRecord ? extractOpenRouterCallModelInput(requestRecord) : void 0,
|
|
13574
|
+
metadata: {
|
|
13575
|
+
...metadata,
|
|
13576
|
+
step: args.step,
|
|
13577
|
+
step_type: args.stepType
|
|
13578
|
+
}
|
|
13579
|
+
}
|
|
13580
|
+
});
|
|
12047
13581
|
}
|
|
12048
|
-
function
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
|
|
12052
|
-
metrics.duration = end - startTime;
|
|
13582
|
+
function finishOpenRouterCallModelTurnSpan(args) {
|
|
13583
|
+
if (!isObject(args.response)) {
|
|
13584
|
+
args.span.end();
|
|
13585
|
+
return;
|
|
12053
13586
|
}
|
|
12054
|
-
|
|
12055
|
-
|
|
12056
|
-
|
|
12057
|
-
|
|
13587
|
+
args.span.log({
|
|
13588
|
+
output: extractOpenRouterResponseOutput(args.response),
|
|
13589
|
+
...extractOpenRouterResponseMetadata(args.response) ? {
|
|
13590
|
+
metadata: {
|
|
13591
|
+
...extractOpenRouterResponseMetadata(args.response),
|
|
13592
|
+
...args.step !== void 0 ? { step: args.step } : {},
|
|
13593
|
+
...args.stepType ? { step_type: args.stepType } : {}
|
|
13594
|
+
}
|
|
13595
|
+
} : {},
|
|
13596
|
+
metrics: parseOpenRouterMetricsFromUsage(args.response.usage)
|
|
13597
|
+
});
|
|
13598
|
+
args.span.end();
|
|
13599
|
+
}
|
|
13600
|
+
function getOpenRouterResolvedRequest(result, request) {
|
|
13601
|
+
if (isObject(result.resolvedRequest)) {
|
|
13602
|
+
return result.resolvedRequest;
|
|
12058
13603
|
}
|
|
12059
|
-
|
|
12060
|
-
|
|
13604
|
+
return request;
|
|
13605
|
+
}
|
|
13606
|
+
function buildOpenRouterFollowupRequest(request, currentResponse, toolResults) {
|
|
13607
|
+
if (!request) {
|
|
13608
|
+
return void 0;
|
|
12061
13609
|
}
|
|
12062
|
-
|
|
12063
|
-
|
|
12064
|
-
|
|
12065
|
-
|
|
12066
|
-
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
|
|
12070
|
-
|
|
12071
|
-
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
|
|
12077
|
-
|
|
12078
|
-
|
|
12079
|
-
|
|
12080
|
-
|
|
13610
|
+
return {
|
|
13611
|
+
...request,
|
|
13612
|
+
input: buildNextOpenRouterCallModelInput(
|
|
13613
|
+
extractOpenRouterCallModelInput(request),
|
|
13614
|
+
isObject(currentResponse) ? currentResponse : {},
|
|
13615
|
+
toolResults
|
|
13616
|
+
),
|
|
13617
|
+
stream: false
|
|
13618
|
+
};
|
|
13619
|
+
}
|
|
13620
|
+
function wrapAsyncIterableWithSpan(args) {
|
|
13621
|
+
return {
|
|
13622
|
+
[Symbol.asyncIterator]() {
|
|
13623
|
+
const iterator = args.iteratorFactory();
|
|
13624
|
+
return {
|
|
13625
|
+
next(value) {
|
|
13626
|
+
return withCurrent(
|
|
13627
|
+
args.span,
|
|
13628
|
+
() => value === void 0 ? iterator.next() : iterator.next(value)
|
|
13629
|
+
).then(
|
|
13630
|
+
async (result) => {
|
|
13631
|
+
if (result.done) {
|
|
13632
|
+
await args.finalize();
|
|
12081
13633
|
}
|
|
12082
|
-
|
|
12083
|
-
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
|
|
12087
|
-
|
|
12088
|
-
|
|
12089
|
-
|
|
13634
|
+
return result;
|
|
13635
|
+
},
|
|
13636
|
+
(error) => {
|
|
13637
|
+
args.onError(error);
|
|
13638
|
+
throw error;
|
|
13639
|
+
}
|
|
13640
|
+
);
|
|
13641
|
+
},
|
|
13642
|
+
return(value) {
|
|
13643
|
+
if (typeof iterator.return !== "function") {
|
|
13644
|
+
return args.finalize().then(() => ({
|
|
13645
|
+
done: true,
|
|
13646
|
+
value
|
|
13647
|
+
}));
|
|
13648
|
+
}
|
|
13649
|
+
return withCurrent(args.span, () => iterator.return(value)).then(
|
|
13650
|
+
async (result) => {
|
|
13651
|
+
await args.finalize();
|
|
13652
|
+
return result;
|
|
13653
|
+
},
|
|
13654
|
+
(error) => {
|
|
13655
|
+
args.onError(error);
|
|
13656
|
+
throw error;
|
|
12090
13657
|
}
|
|
13658
|
+
);
|
|
13659
|
+
},
|
|
13660
|
+
throw(error) {
|
|
13661
|
+
args.onError(error);
|
|
13662
|
+
if (typeof iterator.throw !== "function") {
|
|
13663
|
+
return Promise.reject(error);
|
|
12091
13664
|
}
|
|
13665
|
+
return withCurrent(args.span, () => iterator.throw(error));
|
|
13666
|
+
},
|
|
13667
|
+
[Symbol.asyncIterator]() {
|
|
13668
|
+
return this;
|
|
12092
13669
|
}
|
|
12093
|
-
}
|
|
13670
|
+
};
|
|
12094
13671
|
}
|
|
13672
|
+
};
|
|
13673
|
+
}
|
|
13674
|
+
function isAsyncIterable2(value) {
|
|
13675
|
+
return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
13676
|
+
}
|
|
13677
|
+
function isPromiseLike(value) {
|
|
13678
|
+
return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
|
|
13679
|
+
}
|
|
13680
|
+
function normalizeError(error) {
|
|
13681
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
13682
|
+
}
|
|
13683
|
+
|
|
13684
|
+
// src/instrumentation/plugins/openrouter-plugin.ts
|
|
13685
|
+
var OpenRouterPlugin = class extends BasePlugin {
|
|
13686
|
+
onEnable() {
|
|
13687
|
+
this.subscribeToOpenRouterChannels();
|
|
12095
13688
|
}
|
|
12096
|
-
|
|
12097
|
-
|
|
12098
|
-
if (thoughtText) {
|
|
12099
|
-
parts.push({ text: thoughtText, thought: true });
|
|
12100
|
-
}
|
|
12101
|
-
if (text) {
|
|
12102
|
-
parts.push({ text });
|
|
13689
|
+
onDisable() {
|
|
13690
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
12103
13691
|
}
|
|
12104
|
-
|
|
12105
|
-
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
13692
|
+
subscribeToOpenRouterChannels() {
|
|
13693
|
+
this.unsubscribers.push(
|
|
13694
|
+
traceStreamingChannel(openRouterChannels.chatSend, {
|
|
13695
|
+
name: "openrouter.chat.send",
|
|
13696
|
+
type: "llm" /* LLM */,
|
|
13697
|
+
extractInput: (args) => {
|
|
13698
|
+
const request = getOpenRouterRequestArg(args);
|
|
13699
|
+
const chatGenerationParams = isObject(request?.chatGenerationParams) ? request.chatGenerationParams : {};
|
|
13700
|
+
const httpReferer = request?.httpReferer;
|
|
13701
|
+
const xTitle = request?.xTitle;
|
|
13702
|
+
const { messages, ...metadata } = chatGenerationParams;
|
|
13703
|
+
return {
|
|
13704
|
+
input: messages,
|
|
13705
|
+
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
13706
|
+
};
|
|
13707
|
+
},
|
|
13708
|
+
extractOutput: (result) => {
|
|
13709
|
+
return isObject(result) ? result.choices : void 0;
|
|
13710
|
+
},
|
|
13711
|
+
extractMetrics: (result, startTime) => {
|
|
13712
|
+
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
13713
|
+
if (startTime) {
|
|
13714
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
13715
|
+
}
|
|
13716
|
+
return metrics;
|
|
13717
|
+
},
|
|
13718
|
+
aggregateChunks: aggregateOpenRouterChatChunks
|
|
13719
|
+
})
|
|
13720
|
+
);
|
|
13721
|
+
this.unsubscribers.push(
|
|
13722
|
+
traceAsyncChannel(openRouterChannels.embeddingsGenerate, {
|
|
13723
|
+
name: "openrouter.embeddings.generate",
|
|
13724
|
+
type: "llm" /* LLM */,
|
|
13725
|
+
extractInput: (args) => {
|
|
13726
|
+
const request = getOpenRouterRequestArg(args);
|
|
13727
|
+
const requestBody = isObject(request?.requestBody) ? request.requestBody : {};
|
|
13728
|
+
const httpReferer = request?.httpReferer;
|
|
13729
|
+
const xTitle = request?.xTitle;
|
|
13730
|
+
const { input, ...metadata } = requestBody;
|
|
13731
|
+
return {
|
|
13732
|
+
input,
|
|
13733
|
+
metadata: buildOpenRouterEmbeddingMetadata(
|
|
13734
|
+
metadata,
|
|
13735
|
+
httpReferer,
|
|
13736
|
+
xTitle
|
|
13737
|
+
)
|
|
13738
|
+
};
|
|
13739
|
+
},
|
|
13740
|
+
extractOutput: (result) => {
|
|
13741
|
+
if (!isObject(result)) {
|
|
13742
|
+
return void 0;
|
|
13743
|
+
}
|
|
13744
|
+
const embedding = result.data?.[0]?.embedding;
|
|
13745
|
+
return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
|
|
13746
|
+
},
|
|
13747
|
+
extractMetadata: (result) => {
|
|
13748
|
+
if (!isObject(result)) {
|
|
13749
|
+
return void 0;
|
|
13750
|
+
}
|
|
13751
|
+
return extractOpenRouterResponseMetadata(result);
|
|
13752
|
+
},
|
|
13753
|
+
extractMetrics: (result) => {
|
|
13754
|
+
return isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {};
|
|
12112
13755
|
}
|
|
12113
|
-
}
|
|
12114
|
-
|
|
12115
|
-
|
|
12116
|
-
|
|
12117
|
-
|
|
12118
|
-
|
|
13756
|
+
})
|
|
13757
|
+
);
|
|
13758
|
+
this.unsubscribers.push(
|
|
13759
|
+
traceStreamingChannel(openRouterChannels.betaResponsesSend, {
|
|
13760
|
+
name: "openrouter.beta.responses.send",
|
|
13761
|
+
type: "llm" /* LLM */,
|
|
13762
|
+
extractInput: (args) => {
|
|
13763
|
+
const request = getOpenRouterRequestArg(args);
|
|
13764
|
+
const openResponsesRequest = isObject(request?.openResponsesRequest) ? request.openResponsesRequest : {};
|
|
13765
|
+
const httpReferer = request?.httpReferer;
|
|
13766
|
+
const xTitle = request?.xTitle;
|
|
13767
|
+
const { input, ...metadata } = openResponsesRequest;
|
|
13768
|
+
return {
|
|
13769
|
+
input,
|
|
13770
|
+
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
13771
|
+
};
|
|
13772
|
+
},
|
|
13773
|
+
extractOutput: (result) => extractOpenRouterResponseOutput(result),
|
|
13774
|
+
extractMetadata: (result) => extractOpenRouterResponseMetadata(result),
|
|
13775
|
+
extractMetrics: (result, startTime) => {
|
|
13776
|
+
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
13777
|
+
if (startTime) {
|
|
13778
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
13779
|
+
}
|
|
13780
|
+
return metrics;
|
|
13781
|
+
},
|
|
13782
|
+
aggregateChunks: aggregateOpenRouterResponseStreamEvents
|
|
13783
|
+
})
|
|
13784
|
+
);
|
|
13785
|
+
this.unsubscribers.push(
|
|
13786
|
+
traceSyncStreamChannel(openRouterChannels.callModel, {
|
|
13787
|
+
name: "openrouter.callModel",
|
|
13788
|
+
type: "llm" /* LLM */,
|
|
13789
|
+
extractInput: (args) => {
|
|
13790
|
+
const request = getOpenRouterCallModelRequestArg(args);
|
|
13791
|
+
return {
|
|
13792
|
+
input: request ? extractOpenRouterCallModelInput(request) : void 0,
|
|
13793
|
+
metadata: request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" }
|
|
13794
|
+
};
|
|
13795
|
+
},
|
|
13796
|
+
patchResult: ({ endEvent, result, span }) => {
|
|
13797
|
+
return patchOpenRouterCallModelResult(
|
|
13798
|
+
span,
|
|
13799
|
+
result,
|
|
13800
|
+
getOpenRouterCallModelRequestArg(endEvent.arguments)
|
|
13801
|
+
);
|
|
13802
|
+
}
|
|
13803
|
+
})
|
|
13804
|
+
);
|
|
13805
|
+
this.unsubscribers.push(
|
|
13806
|
+
traceStreamingChannel(openRouterChannels.toolExecute, {
|
|
13807
|
+
name: "openrouter.tool",
|
|
13808
|
+
type: "tool" /* TOOL */,
|
|
13809
|
+
extractInput: (args, event) => ({
|
|
13810
|
+
input: args[0],
|
|
13811
|
+
metadata: {
|
|
13812
|
+
provider: "openrouter",
|
|
13813
|
+
tool_name: event.toolName,
|
|
13814
|
+
...event.toolCallId ? { tool_call_id: event.toolCallId } : {}
|
|
13815
|
+
}
|
|
13816
|
+
}),
|
|
13817
|
+
extractOutput: (result) => result,
|
|
13818
|
+
extractMetrics: () => ({}),
|
|
13819
|
+
aggregateChunks: (chunks) => ({
|
|
13820
|
+
output: chunks.length > 0 ? chunks[chunks.length - 1] : void 0,
|
|
13821
|
+
metrics: {}
|
|
13822
|
+
})
|
|
13823
|
+
})
|
|
13824
|
+
);
|
|
13825
|
+
const callModelChannel = openRouterChannels.callModel.tracingChannel();
|
|
13826
|
+
const callModelHandlers = {
|
|
13827
|
+
start: (event) => {
|
|
13828
|
+
const request = getOpenRouterCallModelRequestArg(event.arguments);
|
|
13829
|
+
if (!request) {
|
|
13830
|
+
return;
|
|
13831
|
+
}
|
|
13832
|
+
patchOpenRouterCallModelRequestTools(request);
|
|
12119
13833
|
}
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
13834
|
+
};
|
|
13835
|
+
callModelChannel.subscribe(callModelHandlers);
|
|
13836
|
+
this.unsubscribers.push(() => {
|
|
13837
|
+
callModelChannel.unsubscribe(callModelHandlers);
|
|
13838
|
+
});
|
|
12123
13839
|
}
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
13840
|
+
};
|
|
13841
|
+
function normalizeArgs(args) {
|
|
13842
|
+
if (Array.isArray(args)) {
|
|
13843
|
+
return args;
|
|
12127
13844
|
}
|
|
12128
|
-
if (
|
|
12129
|
-
|
|
13845
|
+
if (isArrayLike(args)) {
|
|
13846
|
+
return Array.from(args);
|
|
12130
13847
|
}
|
|
12131
|
-
return
|
|
13848
|
+
return [args];
|
|
12132
13849
|
}
|
|
12133
|
-
function
|
|
12134
|
-
|
|
12135
|
-
|
|
13850
|
+
function isArrayLike(value) {
|
|
13851
|
+
return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
|
|
13852
|
+
}
|
|
13853
|
+
function getOpenRouterRequestArg(args) {
|
|
13854
|
+
const normalizedArgs = normalizeArgs(args);
|
|
13855
|
+
const keyedCandidate = normalizedArgs.find(
|
|
13856
|
+
(arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
|
|
13857
|
+
);
|
|
13858
|
+
if (isObject(keyedCandidate)) {
|
|
13859
|
+
return keyedCandidate;
|
|
12136
13860
|
}
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
13861
|
+
const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
|
|
13862
|
+
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
13863
|
+
}
|
|
13864
|
+
function getOpenRouterCallModelRequestArg(args) {
|
|
13865
|
+
const firstObjectArg = normalizeArgs(args).find((arg) => isObject(arg));
|
|
13866
|
+
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
13867
|
+
}
|
|
13868
|
+
function aggregateOpenRouterChatChunks(chunks) {
|
|
13869
|
+
let role;
|
|
13870
|
+
let content = "";
|
|
13871
|
+
let toolCalls;
|
|
13872
|
+
let finishReason;
|
|
13873
|
+
let metrics = {};
|
|
13874
|
+
for (const chunk of chunks) {
|
|
13875
|
+
metrics = {
|
|
13876
|
+
...metrics,
|
|
13877
|
+
...parseOpenRouterMetricsFromUsage(chunk?.usage)
|
|
13878
|
+
};
|
|
13879
|
+
const choice = chunk?.choices?.[0];
|
|
13880
|
+
const delta = choice?.delta;
|
|
13881
|
+
if (!delta) {
|
|
13882
|
+
if (choice?.finish_reason !== void 0) {
|
|
13883
|
+
finishReason = choice.finish_reason;
|
|
13884
|
+
}
|
|
13885
|
+
continue;
|
|
13886
|
+
}
|
|
13887
|
+
if (!role && delta.role) {
|
|
13888
|
+
role = delta.role;
|
|
13889
|
+
}
|
|
13890
|
+
if (typeof delta.content === "string") {
|
|
13891
|
+
content += delta.content;
|
|
13892
|
+
}
|
|
13893
|
+
const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
|
|
13894
|
+
const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
|
|
13895
|
+
if (choiceFinishReason !== void 0) {
|
|
13896
|
+
finishReason = choiceFinishReason;
|
|
13897
|
+
} else if (deltaFinishReason !== void 0) {
|
|
13898
|
+
finishReason = deltaFinishReason;
|
|
13899
|
+
}
|
|
13900
|
+
const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
|
|
13901
|
+
if (!toolCallDeltas) {
|
|
13902
|
+
continue;
|
|
13903
|
+
}
|
|
13904
|
+
for (const toolDelta of toolCallDeltas) {
|
|
13905
|
+
if (!toolDelta?.function) {
|
|
13906
|
+
continue;
|
|
13907
|
+
}
|
|
13908
|
+
const toolIndex = toolDelta.index ?? 0;
|
|
13909
|
+
const existingToolCall = toolCalls?.[toolIndex];
|
|
13910
|
+
if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
|
|
13911
|
+
const nextToolCalls = [...toolCalls || []];
|
|
13912
|
+
nextToolCalls[toolIndex] = {
|
|
13913
|
+
index: toolIndex,
|
|
13914
|
+
id: toolDelta.id,
|
|
13915
|
+
type: toolDelta.type,
|
|
13916
|
+
function: {
|
|
13917
|
+
name: toolDelta.function.name,
|
|
13918
|
+
arguments: toolDelta.function.arguments || ""
|
|
13919
|
+
}
|
|
13920
|
+
};
|
|
13921
|
+
toolCalls = nextToolCalls;
|
|
13922
|
+
continue;
|
|
13923
|
+
}
|
|
13924
|
+
const current = existingToolCall;
|
|
13925
|
+
if (toolDelta.id && !current.id) {
|
|
13926
|
+
current.id = toolDelta.id;
|
|
13927
|
+
}
|
|
13928
|
+
if (toolDelta.type && !current.type) {
|
|
13929
|
+
current.type = toolDelta.type;
|
|
13930
|
+
}
|
|
13931
|
+
if (toolDelta.function.name && !current.function.name) {
|
|
13932
|
+
current.function.name = toolDelta.function.name;
|
|
13933
|
+
}
|
|
13934
|
+
current.function.arguments += toolDelta.function.arguments || "";
|
|
12141
13935
|
}
|
|
12142
|
-
return obj;
|
|
12143
13936
|
}
|
|
12144
|
-
return
|
|
13937
|
+
return {
|
|
13938
|
+
output: [
|
|
13939
|
+
{
|
|
13940
|
+
index: 0,
|
|
13941
|
+
message: {
|
|
13942
|
+
role,
|
|
13943
|
+
content: content || void 0,
|
|
13944
|
+
...toolCalls ? { tool_calls: toolCalls } : {}
|
|
13945
|
+
},
|
|
13946
|
+
logprobs: null,
|
|
13947
|
+
finish_reason: finishReason
|
|
13948
|
+
}
|
|
13949
|
+
],
|
|
13950
|
+
metrics
|
|
13951
|
+
};
|
|
13952
|
+
}
|
|
13953
|
+
function aggregateOpenRouterResponseStreamEvents(chunks) {
|
|
13954
|
+
let finalResponse;
|
|
13955
|
+
for (const chunk of chunks) {
|
|
13956
|
+
const response = chunk?.response;
|
|
13957
|
+
if (!response) {
|
|
13958
|
+
continue;
|
|
13959
|
+
}
|
|
13960
|
+
if (chunk.type === "response.completed" || chunk.type === "response.incomplete" || chunk.type === "response.failed") {
|
|
13961
|
+
finalResponse = response;
|
|
13962
|
+
}
|
|
13963
|
+
}
|
|
13964
|
+
if (!finalResponse) {
|
|
13965
|
+
return {
|
|
13966
|
+
output: void 0,
|
|
13967
|
+
metrics: {}
|
|
13968
|
+
};
|
|
13969
|
+
}
|
|
13970
|
+
return {
|
|
13971
|
+
output: extractOpenRouterResponseOutput(finalResponse),
|
|
13972
|
+
metrics: parseOpenRouterMetricsFromUsage(finalResponse.usage),
|
|
13973
|
+
...extractOpenRouterResponseMetadata(finalResponse) ? { metadata: extractOpenRouterResponseMetadata(finalResponse) } : {}
|
|
13974
|
+
};
|
|
12145
13975
|
}
|
|
12146
13976
|
|
|
12147
13977
|
// src/instrumentation/braintrust-plugin.ts
|
|
@@ -12152,6 +13982,7 @@ var BraintrustPlugin = class extends BasePlugin {
|
|
|
12152
13982
|
aiSDKPlugin = null;
|
|
12153
13983
|
claudeAgentSDKPlugin = null;
|
|
12154
13984
|
googleGenAIPlugin = null;
|
|
13985
|
+
openRouterPlugin = null;
|
|
12155
13986
|
constructor(config = {}) {
|
|
12156
13987
|
super();
|
|
12157
13988
|
this.config = config;
|
|
@@ -12178,6 +14009,10 @@ var BraintrustPlugin = class extends BasePlugin {
|
|
|
12178
14009
|
this.googleGenAIPlugin = new GoogleGenAIPlugin();
|
|
12179
14010
|
this.googleGenAIPlugin.enable();
|
|
12180
14011
|
}
|
|
14012
|
+
if (integrations.openrouter !== false) {
|
|
14013
|
+
this.openRouterPlugin = new OpenRouterPlugin();
|
|
14014
|
+
this.openRouterPlugin.enable();
|
|
14015
|
+
}
|
|
12181
14016
|
}
|
|
12182
14017
|
onDisable() {
|
|
12183
14018
|
if (this.openaiPlugin) {
|
|
@@ -12200,6 +14035,10 @@ var BraintrustPlugin = class extends BasePlugin {
|
|
|
12200
14035
|
this.googleGenAIPlugin.disable();
|
|
12201
14036
|
this.googleGenAIPlugin = null;
|
|
12202
14037
|
}
|
|
14038
|
+
if (this.openRouterPlugin) {
|
|
14039
|
+
this.openRouterPlugin.disable();
|
|
14040
|
+
this.openRouterPlugin = null;
|
|
14041
|
+
}
|
|
12203
14042
|
}
|
|
12204
14043
|
};
|
|
12205
14044
|
|
|
@@ -12271,7 +14110,8 @@ var PluginRegistry = class {
|
|
|
12271
14110
|
vercel: true,
|
|
12272
14111
|
aisdk: true,
|
|
12273
14112
|
google: true,
|
|
12274
|
-
claudeAgentSDK: true
|
|
14113
|
+
claudeAgentSDK: true,
|
|
14114
|
+
openrouter: true
|
|
12275
14115
|
};
|
|
12276
14116
|
}
|
|
12277
14117
|
/**
|
|
@@ -12301,6 +14141,7 @@ function configureNode() {
|
|
|
12301
14141
|
isomorph_default.getCallerLocation = getCallerLocation;
|
|
12302
14142
|
isomorph_default.newAsyncLocalStorage = () => new AsyncLocalStorage();
|
|
12303
14143
|
isomorph_default.newTracingChannel = (nameOrChannels) => diagnostics_channel.tracingChannel(nameOrChannels);
|
|
14144
|
+
patchTracingChannel(diagnostics_channel.tracingChannel);
|
|
12304
14145
|
isomorph_default.processOn = (event, handler) => {
|
|
12305
14146
|
process.on(event, handler);
|
|
12306
14147
|
};
|
|
@@ -12405,7 +14246,7 @@ function isAsync(fn) {
|
|
|
12405
14246
|
function isAsyncGenerator2(fn) {
|
|
12406
14247
|
return fn[Symbol.toStringTag] === "AsyncGenerator";
|
|
12407
14248
|
}
|
|
12408
|
-
function
|
|
14249
|
+
function isAsyncIterable3(obj) {
|
|
12409
14250
|
return typeof obj[Symbol.asyncIterator] === "function";
|
|
12410
14251
|
}
|
|
12411
14252
|
function wrapAsync(asyncFn) {
|
|
@@ -12455,7 +14296,7 @@ function _asyncMap(eachfn, arr, iteratee, callback) {
|
|
|
12455
14296
|
callback(err, results);
|
|
12456
14297
|
});
|
|
12457
14298
|
}
|
|
12458
|
-
function
|
|
14299
|
+
function isArrayLike2(value) {
|
|
12459
14300
|
return value && typeof value.length === "number" && value.length >= 0 && value.length % 1 === 0;
|
|
12460
14301
|
}
|
|
12461
14302
|
var breakLoop = {};
|
|
@@ -12503,7 +14344,7 @@ function createObjectIterator(obj) {
|
|
|
12503
14344
|
};
|
|
12504
14345
|
}
|
|
12505
14346
|
function createIterator(coll) {
|
|
12506
|
-
if (
|
|
14347
|
+
if (isArrayLike2(coll)) {
|
|
12507
14348
|
return createArrayIterator(coll);
|
|
12508
14349
|
}
|
|
12509
14350
|
var iterator = getIterator(coll);
|
|
@@ -12577,7 +14418,7 @@ var eachOfLimit$2 = (limit) => {
|
|
|
12577
14418
|
if (isAsyncGenerator2(obj)) {
|
|
12578
14419
|
return asyncEachOfLimit(obj, limit, iteratee, callback);
|
|
12579
14420
|
}
|
|
12580
|
-
if (
|
|
14421
|
+
if (isAsyncIterable3(obj)) {
|
|
12581
14422
|
return asyncEachOfLimit(obj[Symbol.asyncIterator](), limit, iteratee, callback);
|
|
12582
14423
|
}
|
|
12583
14424
|
var nextElem = createIterator(obj);
|
|
@@ -12649,7 +14490,7 @@ function eachOfGeneric(coll, iteratee, callback) {
|
|
|
12649
14490
|
return eachOfLimit$1(coll, Infinity, iteratee, callback);
|
|
12650
14491
|
}
|
|
12651
14492
|
function eachOf(coll, iteratee, callback) {
|
|
12652
|
-
var eachOfImplementation =
|
|
14493
|
+
var eachOfImplementation = isArrayLike2(coll) ? eachOfArrayLike : eachOfGeneric;
|
|
12653
14494
|
return eachOfImplementation(coll, wrapAsync(iteratee), callback);
|
|
12654
14495
|
}
|
|
12655
14496
|
var eachOf$1 = awaitify(eachOf, 3);
|
|
@@ -13164,7 +15005,7 @@ function filterGeneric(eachfn, coll, iteratee, callback) {
|
|
|
13164
15005
|
});
|
|
13165
15006
|
}
|
|
13166
15007
|
function _filter(eachfn, coll, iteratee, callback) {
|
|
13167
|
-
var filter2 =
|
|
15008
|
+
var filter2 = isArrayLike2(coll) ? filterArray : filterGeneric;
|
|
13168
15009
|
return filter2(eachfn, coll, wrapAsync(iteratee), callback);
|
|
13169
15010
|
}
|
|
13170
15011
|
function filter(coll, iteratee, callback) {
|
|
@@ -13239,7 +15080,7 @@ if (hasNextTick) {
|
|
|
13239
15080
|
}
|
|
13240
15081
|
var nextTick = wrap(_defer);
|
|
13241
15082
|
var _parallel = awaitify((eachfn, tasks, callback) => {
|
|
13242
|
-
var results =
|
|
15083
|
+
var results = isArrayLike2(tasks) ? [] : {};
|
|
13243
15084
|
eachfn(tasks, (task, key, taskCb) => {
|
|
13244
15085
|
wrapAsync(task)((err, ...result) => {
|
|
13245
15086
|
if (result.length < 2) {
|
|
@@ -13920,7 +15761,7 @@ function callEvaluatorData(data) {
|
|
|
13920
15761
|
baseExperiment
|
|
13921
15762
|
};
|
|
13922
15763
|
}
|
|
13923
|
-
function
|
|
15764
|
+
function isAsyncIterable4(value) {
|
|
13924
15765
|
return typeof value === "object" && value !== null && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
13925
15766
|
}
|
|
13926
15767
|
function isIterable(value) {
|
|
@@ -14125,7 +15966,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
|
|
|
14125
15966
|
}
|
|
14126
15967
|
const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
|
|
14127
15968
|
const dataIterable = (() => {
|
|
14128
|
-
if (
|
|
15969
|
+
if (isAsyncIterable4(resolvedDataResult)) {
|
|
14129
15970
|
return resolvedDataResult;
|
|
14130
15971
|
}
|
|
14131
15972
|
if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
|