braintrust 3.7.0 → 3.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dev/dist/index.js +1859 -1338
- package/dev/dist/index.mjs +1774 -1253
- package/dist/auto-instrumentations/bundler/esbuild.cjs +12 -15
- package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
- package/dist/auto-instrumentations/bundler/rollup.cjs +12 -15
- package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
- package/dist/auto-instrumentations/bundler/vite.cjs +12 -15
- package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
- package/dist/auto-instrumentations/bundler/webpack-loader.cjs +12 -15
- package/dist/auto-instrumentations/bundler/webpack.cjs +12 -15
- package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
- package/dist/auto-instrumentations/{chunk-ZK2IYER2.mjs → chunk-NY4CGTN6.mjs} +1 -1
- package/dist/auto-instrumentations/{chunk-AKEXR4AL.mjs → chunk-YCKND42U.mjs} +12 -15
- package/dist/auto-instrumentations/hook.mjs +12 -15
- package/dist/auto-instrumentations/index.cjs +12 -15
- package/dist/auto-instrumentations/index.mjs +1 -1
- package/dist/browser.d.mts +8 -30
- package/dist/browser.d.ts +8 -30
- package/dist/browser.js +4836 -6828
- package/dist/browser.mjs +4836 -6828
- package/dist/cli.js +1507 -986
- package/dist/edge-light.js +9173 -11163
- package/dist/edge-light.mjs +9173 -11163
- package/dist/index.d.mts +8 -30
- package/dist/index.d.ts +8 -30
- package/dist/index.js +4747 -6739
- package/dist/index.mjs +4748 -6740
- package/dist/instrumentation/index.js +1735 -1236
- package/dist/instrumentation/index.mjs +1735 -1236
- package/dist/workerd.js +9173 -11163
- package/dist/workerd.mjs +9173 -11163
- package/package.json +2 -2
package/dev/dist/index.mjs
CHANGED
|
@@ -165,7 +165,7 @@ var DefaultTracingChannel = class {
|
|
|
165
165
|
}
|
|
166
166
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
167
167
|
tracePromise(fn, _message, thisArg, ...args) {
|
|
168
|
-
return
|
|
168
|
+
return fn.apply(thisArg, args);
|
|
169
169
|
}
|
|
170
170
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
171
171
|
traceCallback(fn, _position, _message, thisArg, ...args) {
|
|
@@ -185,6 +185,7 @@ var iso = {
|
|
|
185
185
|
processOn: (_0, _1) => {
|
|
186
186
|
},
|
|
187
187
|
basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
|
|
188
|
+
// eslint-disable-next-line no-restricted-properties -- preserving intentional console usage.
|
|
188
189
|
writeln: (text) => console.log(text)
|
|
189
190
|
};
|
|
190
191
|
var isomorph_default = iso;
|
|
@@ -1881,6 +1882,15 @@ var InternalAbortError = class extends Error {
|
|
|
1881
1882
|
this.name = "InternalAbortError";
|
|
1882
1883
|
}
|
|
1883
1884
|
};
|
|
1885
|
+
function filterFrom(record, keys) {
|
|
1886
|
+
const out = {};
|
|
1887
|
+
for (const k of Object.keys(record)) {
|
|
1888
|
+
if (!keys.includes(k)) {
|
|
1889
|
+
out[k] = record[k];
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
return out;
|
|
1893
|
+
}
|
|
1884
1894
|
|
|
1885
1895
|
// src/generated_types.ts
|
|
1886
1896
|
import { z as z6 } from "zod/v3";
|
|
@@ -8874,7 +8884,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
8874
8884
|
if (!completed) {
|
|
8875
8885
|
completed = true;
|
|
8876
8886
|
try {
|
|
8877
|
-
options.onComplete(chunks);
|
|
8887
|
+
await options.onComplete(chunks);
|
|
8878
8888
|
} catch (error) {
|
|
8879
8889
|
console.error("Error in stream onComplete handler:", error);
|
|
8880
8890
|
}
|
|
@@ -8886,7 +8896,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
8886
8896
|
chunks.push(chunk);
|
|
8887
8897
|
if (options.onChunk) {
|
|
8888
8898
|
try {
|
|
8889
|
-
options.onChunk(chunk);
|
|
8899
|
+
await options.onChunk(chunk);
|
|
8890
8900
|
} catch (error) {
|
|
8891
8901
|
console.error("Error in stream onChunk handler:", error);
|
|
8892
8902
|
}
|
|
@@ -8899,7 +8909,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
8899
8909
|
completed = true;
|
|
8900
8910
|
if (options.onError) {
|
|
8901
8911
|
try {
|
|
8902
|
-
options.onError(
|
|
8912
|
+
await options.onError(
|
|
8903
8913
|
error instanceof Error ? error : new Error(String(error)),
|
|
8904
8914
|
chunks
|
|
8905
8915
|
);
|
|
@@ -8917,7 +8927,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
8917
8927
|
if (!completed) {
|
|
8918
8928
|
completed = true;
|
|
8919
8929
|
try {
|
|
8920
|
-
options.onComplete(chunks);
|
|
8930
|
+
await options.onComplete(chunks);
|
|
8921
8931
|
} catch (error) {
|
|
8922
8932
|
console.error("Error in stream onComplete handler:", error);
|
|
8923
8933
|
}
|
|
@@ -8934,7 +8944,7 @@ function patchStreamIfNeeded(stream, options) {
|
|
|
8934
8944
|
const error = rawError instanceof Error ? rawError : new Error(String(rawError));
|
|
8935
8945
|
if (options.onError) {
|
|
8936
8946
|
try {
|
|
8937
|
-
options.onError(error, chunks);
|
|
8947
|
+
await options.onError(error, chunks);
|
|
8938
8948
|
} catch (handlerError) {
|
|
8939
8949
|
console.error("Error in stream onError handler:", handlerError);
|
|
8940
8950
|
}
|
|
@@ -9643,51 +9653,28 @@ function traceSyncStreamChannel(channel2, config) {
|
|
|
9643
9653
|
}
|
|
9644
9654
|
const { span, startTime } = spanData;
|
|
9645
9655
|
const endEvent = event;
|
|
9646
|
-
|
|
9647
|
-
|
|
9648
|
-
|
|
9649
|
-
|
|
9650
|
-
|
|
9651
|
-
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
|
|
9655
|
-
|
|
9656
|
-
|
|
9657
|
-
|
|
9658
|
-
|
|
9659
|
-
return;
|
|
9660
|
-
}
|
|
9661
|
-
let first = true;
|
|
9662
|
-
stream.on("chunk", () => {
|
|
9663
|
-
if (first) {
|
|
9664
|
-
span.log({
|
|
9665
|
-
metrics: {
|
|
9666
|
-
time_to_first_token: getCurrentUnixTimestamp() - startTime
|
|
9667
|
-
}
|
|
9668
|
-
});
|
|
9669
|
-
first = false;
|
|
9670
|
-
}
|
|
9671
|
-
});
|
|
9672
|
-
stream.on("chatCompletion", (completion) => {
|
|
9673
|
-
try {
|
|
9674
|
-
if (hasChoices(completion)) {
|
|
9675
|
-
span.log({
|
|
9676
|
-
output: completion.choices
|
|
9677
|
-
});
|
|
9678
|
-
}
|
|
9679
|
-
} catch (error) {
|
|
9680
|
-
console.error(
|
|
9681
|
-
`Error extracting chatCompletion for ${channelName}:`,
|
|
9682
|
-
error
|
|
9683
|
-
);
|
|
9656
|
+
const handleResolvedResult = (result) => {
|
|
9657
|
+
const resolvedEndEvent = {
|
|
9658
|
+
...endEvent,
|
|
9659
|
+
result
|
|
9660
|
+
};
|
|
9661
|
+
if (config.patchResult?.({
|
|
9662
|
+
channelName,
|
|
9663
|
+
endEvent: resolvedEndEvent,
|
|
9664
|
+
result,
|
|
9665
|
+
span,
|
|
9666
|
+
startTime
|
|
9667
|
+
})) {
|
|
9668
|
+
return;
|
|
9684
9669
|
}
|
|
9685
|
-
|
|
9686
|
-
|
|
9687
|
-
|
|
9670
|
+
const stream = result;
|
|
9671
|
+
if (!isSyncStreamLike(stream)) {
|
|
9672
|
+
span.end();
|
|
9673
|
+
states.delete(event);
|
|
9688
9674
|
return;
|
|
9689
9675
|
}
|
|
9690
|
-
|
|
9676
|
+
let first = true;
|
|
9677
|
+
stream.on("chunk", () => {
|
|
9691
9678
|
if (first) {
|
|
9692
9679
|
span.log({
|
|
9693
9680
|
metrics: {
|
|
@@ -9696,25 +9683,55 @@ function traceSyncStreamChannel(channel2, config) {
|
|
|
9696
9683
|
});
|
|
9697
9684
|
first = false;
|
|
9698
9685
|
}
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
|
|
9686
|
+
});
|
|
9687
|
+
stream.on("chatCompletion", (completion) => {
|
|
9688
|
+
try {
|
|
9689
|
+
if (hasChoices(completion)) {
|
|
9690
|
+
span.log({
|
|
9691
|
+
output: completion.choices
|
|
9692
|
+
});
|
|
9693
|
+
}
|
|
9694
|
+
} catch (error) {
|
|
9695
|
+
console.error(
|
|
9696
|
+
`Error extracting chatCompletion for ${channelName}:`,
|
|
9697
|
+
error
|
|
9698
|
+
);
|
|
9702
9699
|
}
|
|
9703
|
-
} catch (error) {
|
|
9704
|
-
console.error(`Error extracting event for ${channelName}:`, error);
|
|
9705
|
-
}
|
|
9706
|
-
});
|
|
9707
|
-
stream.on("end", () => {
|
|
9708
|
-
span.end();
|
|
9709
|
-
states.delete(event);
|
|
9710
|
-
});
|
|
9711
|
-
stream.on("error", (error) => {
|
|
9712
|
-
span.log({
|
|
9713
|
-
error: error.message
|
|
9714
9700
|
});
|
|
9715
|
-
|
|
9716
|
-
|
|
9717
|
-
|
|
9701
|
+
stream.on("event", (streamEvent) => {
|
|
9702
|
+
if (!config.extractFromEvent) {
|
|
9703
|
+
return;
|
|
9704
|
+
}
|
|
9705
|
+
try {
|
|
9706
|
+
if (first) {
|
|
9707
|
+
span.log({
|
|
9708
|
+
metrics: {
|
|
9709
|
+
time_to_first_token: getCurrentUnixTimestamp() - startTime
|
|
9710
|
+
}
|
|
9711
|
+
});
|
|
9712
|
+
first = false;
|
|
9713
|
+
}
|
|
9714
|
+
const extracted = config.extractFromEvent(streamEvent);
|
|
9715
|
+
if (extracted && Object.keys(extracted).length > 0) {
|
|
9716
|
+
span.log(extracted);
|
|
9717
|
+
}
|
|
9718
|
+
} catch (error) {
|
|
9719
|
+
console.error(`Error extracting event for ${channelName}:`, error);
|
|
9720
|
+
}
|
|
9721
|
+
});
|
|
9722
|
+
stream.on("end", () => {
|
|
9723
|
+
span.end();
|
|
9724
|
+
states.delete(event);
|
|
9725
|
+
});
|
|
9726
|
+
stream.on("error", (error) => {
|
|
9727
|
+
span.log({
|
|
9728
|
+
error: error.message
|
|
9729
|
+
});
|
|
9730
|
+
span.end();
|
|
9731
|
+
states.delete(event);
|
|
9732
|
+
});
|
|
9733
|
+
};
|
|
9734
|
+
handleResolvedResult(endEvent.result);
|
|
9718
9735
|
},
|
|
9719
9736
|
error: (event) => {
|
|
9720
9737
|
logErrorAndEnd(states, event);
|
|
@@ -10537,28 +10554,40 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
10537
10554
|
case "content_block_start":
|
|
10538
10555
|
if (event.content_block) {
|
|
10539
10556
|
contentBlocks[event.index] = event.content_block;
|
|
10540
|
-
contentBlockDeltas[event.index] = [];
|
|
10557
|
+
contentBlockDeltas[event.index] = { textDeltas: [], citations: [] };
|
|
10541
10558
|
}
|
|
10542
10559
|
break;
|
|
10543
|
-
case "content_block_delta":
|
|
10544
|
-
|
|
10545
|
-
|
|
10560
|
+
case "content_block_delta": {
|
|
10561
|
+
const acc = contentBlockDeltas[event.index];
|
|
10562
|
+
const delta = event.delta;
|
|
10563
|
+
if (!delta) break;
|
|
10564
|
+
if (delta.type === "text_delta" && "text" in delta) {
|
|
10565
|
+
const text = delta.text;
|
|
10546
10566
|
if (text) {
|
|
10547
|
-
if (
|
|
10548
|
-
|
|
10549
|
-
contentBlockDeltas[event.index].push(text);
|
|
10567
|
+
if (acc !== void 0) {
|
|
10568
|
+
acc.textDeltas.push(text);
|
|
10550
10569
|
} else {
|
|
10551
10570
|
fallbackTextDeltas.push(text);
|
|
10552
10571
|
}
|
|
10553
10572
|
}
|
|
10554
|
-
} else if (
|
|
10555
|
-
const partialJson =
|
|
10556
|
-
if (partialJson) {
|
|
10557
|
-
|
|
10558
|
-
|
|
10573
|
+
} else if (delta.type === "input_json_delta" && "partial_json" in delta) {
|
|
10574
|
+
const partialJson = delta.partial_json;
|
|
10575
|
+
if (partialJson && acc !== void 0) {
|
|
10576
|
+
acc.textDeltas.push(partialJson);
|
|
10577
|
+
}
|
|
10578
|
+
} else if (delta.type === "thinking_delta" && "thinking" in delta) {
|
|
10579
|
+
const thinking = delta.thinking;
|
|
10580
|
+
if (thinking && acc !== void 0) {
|
|
10581
|
+
acc.textDeltas.push(thinking);
|
|
10582
|
+
}
|
|
10583
|
+
} else if (delta.type === "citations_delta" && "citation" in delta) {
|
|
10584
|
+
const citation = delta.citation;
|
|
10585
|
+
if (citation && acc !== void 0) {
|
|
10586
|
+
acc.citations.push(citation);
|
|
10559
10587
|
}
|
|
10560
10588
|
}
|
|
10561
10589
|
break;
|
|
10590
|
+
}
|
|
10562
10591
|
case "content_block_stop":
|
|
10563
10592
|
finalizeContentBlock(
|
|
10564
10593
|
event.index,
|
|
@@ -10584,7 +10613,7 @@ function aggregateAnthropicStreamChunks(chunks) {
|
|
|
10584
10613
|
})).filter(({ block }) => block !== void 0).sort((left, right) => left.index - right.index).map(({ block }) => block);
|
|
10585
10614
|
let output = fallbackTextDeltas.join("");
|
|
10586
10615
|
if (orderedContent.length > 0) {
|
|
10587
|
-
if (orderedContent.every(isTextContentBlock)) {
|
|
10616
|
+
if (orderedContent.every(isTextContentBlock) && orderedContent.every((block) => !block.citations?.length)) {
|
|
10588
10617
|
output = orderedContent.map((block) => block.text).join("");
|
|
10589
10618
|
} else {
|
|
10590
10619
|
output = {
|
|
@@ -10610,7 +10639,8 @@ function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallback
|
|
|
10610
10639
|
if (!contentBlock) {
|
|
10611
10640
|
return;
|
|
10612
10641
|
}
|
|
10613
|
-
const
|
|
10642
|
+
const acc = contentBlockDeltas[index];
|
|
10643
|
+
const text = acc?.textDeltas.join("") ?? "";
|
|
10614
10644
|
if (isToolUseContentBlock(contentBlock)) {
|
|
10615
10645
|
if (!text) {
|
|
10616
10646
|
return;
|
|
@@ -10627,20 +10657,28 @@ function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallback
|
|
|
10627
10657
|
return;
|
|
10628
10658
|
}
|
|
10629
10659
|
if (isTextContentBlock(contentBlock)) {
|
|
10660
|
+
if (!text) {
|
|
10661
|
+
delete contentBlocks[index];
|
|
10662
|
+
return;
|
|
10663
|
+
}
|
|
10664
|
+
const updated = { ...contentBlock, text };
|
|
10665
|
+
if (acc?.citations.length) {
|
|
10666
|
+
updated.citations = acc.citations;
|
|
10667
|
+
}
|
|
10668
|
+
contentBlocks[index] = updated;
|
|
10669
|
+
return;
|
|
10670
|
+
}
|
|
10671
|
+
if (isThinkingContentBlock(contentBlock)) {
|
|
10630
10672
|
if (!text) {
|
|
10631
10673
|
delete contentBlocks[index];
|
|
10632
10674
|
return;
|
|
10633
10675
|
}
|
|
10634
10676
|
contentBlocks[index] = {
|
|
10635
10677
|
...contentBlock,
|
|
10636
|
-
text
|
|
10678
|
+
thinking: text
|
|
10637
10679
|
};
|
|
10638
10680
|
return;
|
|
10639
10681
|
}
|
|
10640
|
-
if (text) {
|
|
10641
|
-
fallbackTextDeltas.push(text);
|
|
10642
|
-
}
|
|
10643
|
-
delete contentBlocks[index];
|
|
10644
10682
|
}
|
|
10645
10683
|
function isTextContentBlock(contentBlock) {
|
|
10646
10684
|
return contentBlock.type === "text";
|
|
@@ -10648,6 +10686,9 @@ function isTextContentBlock(contentBlock) {
|
|
|
10648
10686
|
function isToolUseContentBlock(contentBlock) {
|
|
10649
10687
|
return contentBlock.type === "tool_use";
|
|
10650
10688
|
}
|
|
10689
|
+
function isThinkingContentBlock(contentBlock) {
|
|
10690
|
+
return contentBlock.type === "thinking";
|
|
10691
|
+
}
|
|
10651
10692
|
function isAnthropicBase64ContentBlock(input) {
|
|
10652
10693
|
return (input.type === "image" || input.type === "document") && isObject(input.source) && input.source.type === "base64";
|
|
10653
10694
|
}
|
|
@@ -10702,15 +10743,6 @@ function coalesceInput(messages, system) {
|
|
|
10702
10743
|
}
|
|
10703
10744
|
return input;
|
|
10704
10745
|
}
|
|
10705
|
-
function filterFrom(obj, fieldsToRemove) {
|
|
10706
|
-
const result = {};
|
|
10707
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
10708
|
-
if (!fieldsToRemove.includes(key)) {
|
|
10709
|
-
result[key] = value;
|
|
10710
|
-
}
|
|
10711
|
-
}
|
|
10712
|
-
return result;
|
|
10713
|
-
}
|
|
10714
10746
|
|
|
10715
10747
|
// src/wrappers/ai-sdk/normalize-logged-output.ts
|
|
10716
10748
|
var REMOVE_NORMALIZED_VALUE = Symbol("braintrust.ai-sdk.remove-normalized");
|
|
@@ -10824,10 +10856,6 @@ var aiSDKChannels = defineChannels("ai", {
|
|
|
10824
10856
|
channelName: "streamText",
|
|
10825
10857
|
kind: "async"
|
|
10826
10858
|
}),
|
|
10827
|
-
streamTextSync: channel({
|
|
10828
|
-
channelName: "streamText.sync",
|
|
10829
|
-
kind: "sync-stream"
|
|
10830
|
-
}),
|
|
10831
10859
|
generateObject: channel({
|
|
10832
10860
|
channelName: "generateObject",
|
|
10833
10861
|
kind: "async"
|
|
@@ -10836,10 +10864,6 @@ var aiSDKChannels = defineChannels("ai", {
|
|
|
10836
10864
|
channelName: "streamObject",
|
|
10837
10865
|
kind: "async"
|
|
10838
10866
|
}),
|
|
10839
|
-
streamObjectSync: channel({
|
|
10840
|
-
channelName: "streamObject.sync",
|
|
10841
|
-
kind: "sync-stream"
|
|
10842
|
-
}),
|
|
10843
10867
|
agentGenerate: channel({
|
|
10844
10868
|
channelName: "Agent.generate",
|
|
10845
10869
|
kind: "async"
|
|
@@ -10875,6 +10899,9 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
|
|
|
10875
10899
|
];
|
|
10876
10900
|
var AUTO_PATCHED_MODEL = Symbol.for("braintrust.ai-sdk.auto-patched-model");
|
|
10877
10901
|
var AUTO_PATCHED_TOOL = Symbol.for("braintrust.ai-sdk.auto-patched-tool");
|
|
10902
|
+
var RUNTIME_DENY_OUTPUT_PATHS = Symbol.for(
|
|
10903
|
+
"braintrust.ai-sdk.deny-output-paths"
|
|
10904
|
+
);
|
|
10878
10905
|
var AISDKPlugin = class extends BasePlugin {
|
|
10879
10906
|
config;
|
|
10880
10907
|
constructor(config = {}) {
|
|
@@ -10896,7 +10923,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
10896
10923
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
10897
10924
|
extractOutput: (result, endEvent) => {
|
|
10898
10925
|
finalizeAISDKChildTracing(endEvent);
|
|
10899
|
-
return processAISDKOutput(
|
|
10926
|
+
return processAISDKOutput(
|
|
10927
|
+
result,
|
|
10928
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
10929
|
+
);
|
|
10900
10930
|
},
|
|
10901
10931
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
10902
10932
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -10907,25 +10937,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
10907
10937
|
name: "streamText",
|
|
10908
10938
|
type: "llm" /* LLM */,
|
|
10909
10939
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
10910
|
-
extractOutput: (result) => processAISDKOutput(
|
|
10940
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
10941
|
+
result,
|
|
10942
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
10943
|
+
),
|
|
10911
10944
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
10912
10945
|
aggregateChunks: aggregateAISDKChunks,
|
|
10913
10946
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
10914
|
-
denyOutputPaths,
|
|
10915
|
-
endEvent,
|
|
10916
|
-
result,
|
|
10917
|
-
span,
|
|
10918
|
-
startTime
|
|
10919
|
-
})
|
|
10920
|
-
})
|
|
10921
|
-
);
|
|
10922
|
-
this.unsubscribers.push(
|
|
10923
|
-
traceSyncStreamChannel(aiSDKChannels.streamTextSync, {
|
|
10924
|
-
name: "streamText",
|
|
10925
|
-
type: "llm" /* LLM */,
|
|
10926
|
-
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
10927
|
-
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
10928
|
-
denyOutputPaths,
|
|
10947
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
10929
10948
|
endEvent,
|
|
10930
10949
|
result,
|
|
10931
10950
|
span,
|
|
@@ -10940,7 +10959,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
10940
10959
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
10941
10960
|
extractOutput: (result, endEvent) => {
|
|
10942
10961
|
finalizeAISDKChildTracing(endEvent);
|
|
10943
|
-
return processAISDKOutput(
|
|
10962
|
+
return processAISDKOutput(
|
|
10963
|
+
result,
|
|
10964
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
10965
|
+
);
|
|
10944
10966
|
},
|
|
10945
10967
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
10946
10968
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -10951,25 +10973,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
10951
10973
|
name: "streamObject",
|
|
10952
10974
|
type: "llm" /* LLM */,
|
|
10953
10975
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
10954
|
-
extractOutput: (result) => processAISDKOutput(
|
|
10976
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
10977
|
+
result,
|
|
10978
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
10979
|
+
),
|
|
10955
10980
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
10956
10981
|
aggregateChunks: aggregateAISDKChunks,
|
|
10957
10982
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
10958
|
-
denyOutputPaths,
|
|
10959
|
-
endEvent,
|
|
10960
|
-
result,
|
|
10961
|
-
span,
|
|
10962
|
-
startTime
|
|
10963
|
-
})
|
|
10964
|
-
})
|
|
10965
|
-
);
|
|
10966
|
-
this.unsubscribers.push(
|
|
10967
|
-
traceSyncStreamChannel(aiSDKChannels.streamObjectSync, {
|
|
10968
|
-
name: "streamObject",
|
|
10969
|
-
type: "llm" /* LLM */,
|
|
10970
|
-
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
10971
|
-
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
10972
|
-
denyOutputPaths,
|
|
10983
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
10973
10984
|
endEvent,
|
|
10974
10985
|
result,
|
|
10975
10986
|
span,
|
|
@@ -10984,7 +10995,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
10984
10995
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
10985
10996
|
extractOutput: (result, endEvent) => {
|
|
10986
10997
|
finalizeAISDKChildTracing(endEvent);
|
|
10987
|
-
return processAISDKOutput(
|
|
10998
|
+
return processAISDKOutput(
|
|
10999
|
+
result,
|
|
11000
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
11001
|
+
);
|
|
10988
11002
|
},
|
|
10989
11003
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
10990
11004
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -10995,11 +11009,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
10995
11009
|
name: "Agent.stream",
|
|
10996
11010
|
type: "llm" /* LLM */,
|
|
10997
11011
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
10998
|
-
extractOutput: (result) => processAISDKOutput(
|
|
11012
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
11013
|
+
result,
|
|
11014
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
11015
|
+
),
|
|
10999
11016
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
11000
11017
|
aggregateChunks: aggregateAISDKChunks,
|
|
11001
11018
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
11002
|
-
denyOutputPaths,
|
|
11019
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
11003
11020
|
endEvent,
|
|
11004
11021
|
result,
|
|
11005
11022
|
span,
|
|
@@ -11014,7 +11031,10 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
11014
11031
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
11015
11032
|
extractOutput: (result, endEvent) => {
|
|
11016
11033
|
finalizeAISDKChildTracing(endEvent);
|
|
11017
|
-
return processAISDKOutput(
|
|
11034
|
+
return processAISDKOutput(
|
|
11035
|
+
result,
|
|
11036
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
11037
|
+
);
|
|
11018
11038
|
},
|
|
11019
11039
|
extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
|
|
11020
11040
|
aggregateChunks: aggregateAISDKChunks
|
|
@@ -11025,11 +11045,14 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
11025
11045
|
name: "ToolLoopAgent.stream",
|
|
11026
11046
|
type: "llm" /* LLM */,
|
|
11027
11047
|
extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
|
|
11028
|
-
extractOutput: (result) => processAISDKOutput(
|
|
11048
|
+
extractOutput: (result, endEvent) => processAISDKOutput(
|
|
11049
|
+
result,
|
|
11050
|
+
resolveDenyOutputPaths(endEvent, denyOutputPaths)
|
|
11051
|
+
),
|
|
11029
11052
|
extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
|
|
11030
11053
|
aggregateChunks: aggregateAISDKChunks,
|
|
11031
11054
|
patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
|
|
11032
|
-
denyOutputPaths,
|
|
11055
|
+
defaultDenyOutputPaths: denyOutputPaths,
|
|
11033
11056
|
endEvent,
|
|
11034
11057
|
result,
|
|
11035
11058
|
span,
|
|
@@ -11039,118 +11062,416 @@ var AISDKPlugin = class extends BasePlugin {
|
|
|
11039
11062
|
);
|
|
11040
11063
|
}
|
|
11041
11064
|
};
|
|
11042
|
-
function
|
|
11043
|
-
if (
|
|
11044
|
-
|
|
11045
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
11046
|
-
return input;
|
|
11065
|
+
function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
|
|
11066
|
+
if (Array.isArray(event?.denyOutputPaths)) {
|
|
11067
|
+
return event.denyOutputPaths;
|
|
11047
11068
|
}
|
|
11048
|
-
const
|
|
11049
|
-
|
|
11050
|
-
|
|
11051
|
-
function prepareAISDKInput(params, event, span, denyOutputPaths) {
|
|
11052
|
-
const input = processAISDKInput(params);
|
|
11053
|
-
const metadata = extractMetadataFromParams(params, event.self);
|
|
11054
|
-
const childTracing = prepareAISDKChildTracing(
|
|
11055
|
-
params,
|
|
11056
|
-
event.self,
|
|
11057
|
-
span,
|
|
11058
|
-
denyOutputPaths
|
|
11059
|
-
);
|
|
11060
|
-
event.__braintrust_ai_sdk_model_wrapped = childTracing.modelWrapped;
|
|
11061
|
-
if (childTracing.cleanup) {
|
|
11062
|
-
event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
|
|
11069
|
+
const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
|
|
11070
|
+
if (!firstArgument || typeof firstArgument !== "object") {
|
|
11071
|
+
return defaultDenyOutputPaths;
|
|
11063
11072
|
}
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
};
|
|
11068
|
-
}
|
|
11069
|
-
function extractTopLevelAISDKMetrics(result, event, startTime) {
|
|
11070
|
-
const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
|
|
11071
|
-
if (startTime) {
|
|
11072
|
-
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
11073
|
+
const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
|
|
11074
|
+
if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path2) => typeof path2 === "string")) {
|
|
11075
|
+
return runtimeDenyOutputPaths;
|
|
11073
11076
|
}
|
|
11074
|
-
return
|
|
11077
|
+
return defaultDenyOutputPaths;
|
|
11075
11078
|
}
|
|
11076
|
-
|
|
11077
|
-
return
|
|
11078
|
-
}
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
const { model, provider } = serializeModelWithProvider(
|
|
11088
|
-
params.model ?? agentModel
|
|
11089
|
-
);
|
|
11090
|
-
if (model) {
|
|
11091
|
-
metadata.model = model;
|
|
11079
|
+
var isZodSchema2 = (value) => {
|
|
11080
|
+
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
11081
|
+
};
|
|
11082
|
+
var serializeZodSchema2 = (schema) => {
|
|
11083
|
+
try {
|
|
11084
|
+
return zodToJsonSchema(schema);
|
|
11085
|
+
} catch {
|
|
11086
|
+
return {
|
|
11087
|
+
type: "object",
|
|
11088
|
+
description: "Zod schema (conversion failed)"
|
|
11089
|
+
};
|
|
11092
11090
|
}
|
|
11093
|
-
|
|
11094
|
-
|
|
11091
|
+
};
|
|
11092
|
+
var isOutputObject = (value) => {
|
|
11093
|
+
if (value == null || typeof value !== "object") {
|
|
11094
|
+
return false;
|
|
11095
11095
|
}
|
|
11096
|
-
const
|
|
11097
|
-
if (
|
|
11098
|
-
|
|
11096
|
+
const output = value;
|
|
11097
|
+
if (!("responseFormat" in output)) {
|
|
11098
|
+
return false;
|
|
11099
11099
|
}
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
|
|
11106
|
-
|
|
11107
|
-
|
|
11108
|
-
|
|
11109
|
-
|
|
11110
|
-
|
|
11111
|
-
|
|
11112
|
-
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
|
|
11123
|
-
|
|
11124
|
-
|
|
11125
|
-
|
|
11126
|
-
|
|
11127
|
-
|
|
11128
|
-
|
|
11129
|
-
|
|
11130
|
-
|
|
11131
|
-
|
|
11132
|
-
|
|
11133
|
-
|
|
11134
|
-
|
|
11135
|
-
|
|
11136
|
-
|
|
11137
|
-
},
|
|
11138
|
-
event: {
|
|
11139
|
-
input: processAISDKInput(options),
|
|
11140
|
-
metadata: baseMetadata
|
|
11100
|
+
if (output.type === "object" || output.type === "text") {
|
|
11101
|
+
return true;
|
|
11102
|
+
}
|
|
11103
|
+
if (typeof output.responseFormat === "function" || typeof output.responseFormat === "object") {
|
|
11104
|
+
return true;
|
|
11105
|
+
}
|
|
11106
|
+
return false;
|
|
11107
|
+
};
|
|
11108
|
+
var serializeOutputObject = (output, model) => {
|
|
11109
|
+
try {
|
|
11110
|
+
const result = {
|
|
11111
|
+
response_format: null
|
|
11112
|
+
};
|
|
11113
|
+
if (output.type) {
|
|
11114
|
+
result.type = output.type;
|
|
11115
|
+
}
|
|
11116
|
+
let responseFormat;
|
|
11117
|
+
if (typeof output.responseFormat === "function") {
|
|
11118
|
+
const mockModelForSchema = {
|
|
11119
|
+
supportsStructuredOutputs: true,
|
|
11120
|
+
...model && typeof model === "object" ? model : {}
|
|
11121
|
+
};
|
|
11122
|
+
responseFormat = output.responseFormat({ model: mockModelForSchema });
|
|
11123
|
+
} else if (output.responseFormat != null && typeof output.responseFormat === "object") {
|
|
11124
|
+
responseFormat = output.responseFormat;
|
|
11125
|
+
}
|
|
11126
|
+
if (responseFormat) {
|
|
11127
|
+
if (typeof responseFormat.then === "function") {
|
|
11128
|
+
result.response_format = Promise.resolve(responseFormat).then(
|
|
11129
|
+
(resolved) => {
|
|
11130
|
+
if (resolved.schema && isZodSchema2(resolved.schema)) {
|
|
11131
|
+
return {
|
|
11132
|
+
...resolved,
|
|
11133
|
+
schema: serializeZodSchema2(resolved.schema)
|
|
11134
|
+
};
|
|
11135
|
+
}
|
|
11136
|
+
return resolved;
|
|
11141
11137
|
}
|
|
11138
|
+
);
|
|
11139
|
+
} else {
|
|
11140
|
+
const syncResponseFormat = responseFormat;
|
|
11141
|
+
if (syncResponseFormat.schema && isZodSchema2(syncResponseFormat.schema)) {
|
|
11142
|
+
responseFormat = {
|
|
11143
|
+
...syncResponseFormat,
|
|
11144
|
+
schema: serializeZodSchema2(syncResponseFormat.schema)
|
|
11145
|
+
};
|
|
11142
11146
|
}
|
|
11143
|
-
|
|
11147
|
+
result.response_format = responseFormat;
|
|
11148
|
+
}
|
|
11149
|
+
}
|
|
11150
|
+
return result;
|
|
11151
|
+
} catch {
|
|
11152
|
+
return {
|
|
11153
|
+
response_format: null
|
|
11144
11154
|
};
|
|
11145
|
-
|
|
11146
|
-
|
|
11147
|
-
|
|
11148
|
-
|
|
11155
|
+
}
|
|
11156
|
+
};
|
|
11157
|
+
var processInputAttachmentsSync = (input) => {
|
|
11158
|
+
if (!input) return { input };
|
|
11159
|
+
const processed = { ...input };
|
|
11160
|
+
if (input.messages && Array.isArray(input.messages)) {
|
|
11161
|
+
processed.messages = input.messages.map(processMessage);
|
|
11162
|
+
}
|
|
11163
|
+
if (input.prompt && typeof input.prompt === "object") {
|
|
11164
|
+
if (Array.isArray(input.prompt)) {
|
|
11165
|
+
processed.prompt = input.prompt.map(processMessage);
|
|
11166
|
+
} else {
|
|
11167
|
+
processed.prompt = processPromptContent(input.prompt);
|
|
11168
|
+
}
|
|
11169
|
+
}
|
|
11170
|
+
if (input.schema && isZodSchema2(input.schema)) {
|
|
11171
|
+
processed.schema = serializeZodSchema2(input.schema);
|
|
11172
|
+
}
|
|
11173
|
+
if (input.callOptionsSchema && isZodSchema2(input.callOptionsSchema)) {
|
|
11174
|
+
processed.callOptionsSchema = serializeZodSchema2(input.callOptionsSchema);
|
|
11175
|
+
}
|
|
11176
|
+
if (input.tools) {
|
|
11177
|
+
processed.tools = serializeAISDKToolsForLogging(input.tools);
|
|
11178
|
+
}
|
|
11179
|
+
let outputPromise;
|
|
11180
|
+
if (input.output && isOutputObject(input.output)) {
|
|
11181
|
+
const serialized = serializeOutputObject(input.output, input.model);
|
|
11182
|
+
if (serialized.response_format && typeof serialized.response_format.then === "function") {
|
|
11183
|
+
processed.output = { ...serialized, response_format: {} };
|
|
11184
|
+
outputPromise = serialized.response_format.then(
|
|
11185
|
+
(resolvedFormat) => ({
|
|
11186
|
+
output: { ...serialized, response_format: resolvedFormat }
|
|
11187
|
+
})
|
|
11188
|
+
);
|
|
11189
|
+
} else {
|
|
11190
|
+
processed.output = serialized;
|
|
11191
|
+
}
|
|
11192
|
+
}
|
|
11193
|
+
if ("prepareCall" in processed && typeof processed.prepareCall === "function") {
|
|
11194
|
+
processed.prepareCall = "[Function]";
|
|
11195
|
+
}
|
|
11196
|
+
return { input: processed, outputPromise };
|
|
11197
|
+
};
|
|
11198
|
+
var processMessage = (message) => {
|
|
11199
|
+
if (!message || typeof message !== "object") return message;
|
|
11200
|
+
if (Array.isArray(message.content)) {
|
|
11201
|
+
return {
|
|
11202
|
+
...message,
|
|
11203
|
+
content: message.content.map(processContentPart)
|
|
11204
|
+
};
|
|
11205
|
+
}
|
|
11206
|
+
if (typeof message.content === "object" && message.content !== null) {
|
|
11207
|
+
return {
|
|
11208
|
+
...message,
|
|
11209
|
+
content: processContentPart(message.content)
|
|
11210
|
+
};
|
|
11211
|
+
}
|
|
11212
|
+
return message;
|
|
11213
|
+
};
|
|
11214
|
+
var processPromptContent = (prompt) => {
|
|
11215
|
+
if (Array.isArray(prompt)) {
|
|
11216
|
+
return prompt.map(processContentPart);
|
|
11217
|
+
}
|
|
11218
|
+
if (prompt.content) {
|
|
11219
|
+
if (Array.isArray(prompt.content)) {
|
|
11220
|
+
return {
|
|
11221
|
+
...prompt,
|
|
11222
|
+
content: prompt.content.map(processContentPart)
|
|
11223
|
+
};
|
|
11224
|
+
} else if (typeof prompt.content === "object") {
|
|
11225
|
+
return {
|
|
11226
|
+
...prompt,
|
|
11227
|
+
content: processContentPart(prompt.content)
|
|
11228
|
+
};
|
|
11229
|
+
}
|
|
11230
|
+
}
|
|
11231
|
+
return prompt;
|
|
11232
|
+
};
|
|
11233
|
+
var processContentPart = (part) => {
|
|
11234
|
+
if (!part || typeof part !== "object") return part;
|
|
11235
|
+
try {
|
|
11236
|
+
if (part.type === "image" && part.image) {
|
|
11237
|
+
const imageAttachment = convertImageToAttachment(
|
|
11238
|
+
part.image,
|
|
11239
|
+
part.mimeType || part.mediaType
|
|
11240
|
+
);
|
|
11241
|
+
if (imageAttachment) {
|
|
11242
|
+
return {
|
|
11243
|
+
...part,
|
|
11244
|
+
image: imageAttachment
|
|
11245
|
+
};
|
|
11246
|
+
}
|
|
11247
|
+
}
|
|
11248
|
+
if (part.type === "file" && part.data && (part.mimeType || part.mediaType)) {
|
|
11249
|
+
const fileAttachment = convertDataToAttachment(
|
|
11250
|
+
part.data,
|
|
11251
|
+
part.mimeType || part.mediaType,
|
|
11252
|
+
part.name || part.filename
|
|
11253
|
+
);
|
|
11254
|
+
if (fileAttachment) {
|
|
11255
|
+
return {
|
|
11256
|
+
...part,
|
|
11257
|
+
data: fileAttachment
|
|
11258
|
+
};
|
|
11259
|
+
}
|
|
11260
|
+
}
|
|
11261
|
+
if (part.type === "image_url" && part.image_url) {
|
|
11262
|
+
if (typeof part.image_url === "object" && part.image_url.url) {
|
|
11263
|
+
const imageAttachment = convertImageToAttachment(part.image_url.url);
|
|
11264
|
+
if (imageAttachment) {
|
|
11265
|
+
return {
|
|
11266
|
+
...part,
|
|
11267
|
+
image_url: {
|
|
11268
|
+
...part.image_url,
|
|
11269
|
+
url: imageAttachment
|
|
11270
|
+
}
|
|
11271
|
+
};
|
|
11272
|
+
}
|
|
11273
|
+
}
|
|
11274
|
+
}
|
|
11275
|
+
} catch (error) {
|
|
11276
|
+
console.warn("Error processing content part:", error);
|
|
11277
|
+
}
|
|
11278
|
+
return part;
|
|
11279
|
+
};
|
|
11280
|
+
var convertImageToAttachment = (image, explicitMimeType) => {
|
|
11281
|
+
try {
|
|
11282
|
+
if (typeof image === "string" && image.startsWith("data:")) {
|
|
11283
|
+
const [mimeTypeSection, base64Data] = image.split(",");
|
|
11284
|
+
const mimeType = mimeTypeSection.match(/data:(.*?);/)?.[1];
|
|
11285
|
+
if (mimeType && base64Data) {
|
|
11286
|
+
const blob = convertDataToBlob(base64Data, mimeType);
|
|
11287
|
+
if (blob) {
|
|
11288
|
+
return new Attachment({
|
|
11289
|
+
data: blob,
|
|
11290
|
+
filename: `image.${getExtensionFromMediaType(mimeType)}`,
|
|
11291
|
+
contentType: mimeType
|
|
11292
|
+
});
|
|
11293
|
+
}
|
|
11294
|
+
}
|
|
11295
|
+
}
|
|
11296
|
+
if (explicitMimeType) {
|
|
11297
|
+
if (image instanceof Uint8Array) {
|
|
11298
|
+
return new Attachment({
|
|
11299
|
+
data: new Blob([image], { type: explicitMimeType }),
|
|
11300
|
+
filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
|
|
11301
|
+
contentType: explicitMimeType
|
|
11302
|
+
});
|
|
11303
|
+
}
|
|
11304
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
|
|
11305
|
+
return new Attachment({
|
|
11306
|
+
data: new Blob([image], { type: explicitMimeType }),
|
|
11307
|
+
filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
|
|
11308
|
+
contentType: explicitMimeType
|
|
11309
|
+
});
|
|
11310
|
+
}
|
|
11311
|
+
}
|
|
11312
|
+
if (image instanceof Blob && image.type) {
|
|
11313
|
+
return new Attachment({
|
|
11314
|
+
data: image,
|
|
11315
|
+
filename: `image.${getExtensionFromMediaType(image.type)}`,
|
|
11316
|
+
contentType: image.type
|
|
11317
|
+
});
|
|
11318
|
+
}
|
|
11319
|
+
if (image instanceof Attachment) {
|
|
11320
|
+
return image;
|
|
11321
|
+
}
|
|
11322
|
+
} catch (error) {
|
|
11323
|
+
console.warn("Error converting image to attachment:", error);
|
|
11324
|
+
}
|
|
11325
|
+
return null;
|
|
11326
|
+
};
|
|
11327
|
+
var convertDataToAttachment = (data, mimeType, filename) => {
|
|
11328
|
+
if (!mimeType) return null;
|
|
11329
|
+
try {
|
|
11330
|
+
let blob = null;
|
|
11331
|
+
if (typeof data === "string" && data.startsWith("data:")) {
|
|
11332
|
+
const [, base64Data] = data.split(",");
|
|
11333
|
+
if (base64Data) {
|
|
11334
|
+
blob = convertDataToBlob(base64Data, mimeType);
|
|
11335
|
+
}
|
|
11336
|
+
} else if (typeof data === "string" && data.length > 0) {
|
|
11337
|
+
blob = convertDataToBlob(data, mimeType);
|
|
11338
|
+
} else if (data instanceof Uint8Array) {
|
|
11339
|
+
blob = new Blob([data], { type: mimeType });
|
|
11340
|
+
} else if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
|
|
11341
|
+
blob = new Blob([data], { type: mimeType });
|
|
11342
|
+
} else if (data instanceof Blob) {
|
|
11343
|
+
blob = data;
|
|
11344
|
+
}
|
|
11345
|
+
if (blob) {
|
|
11346
|
+
return new Attachment({
|
|
11347
|
+
data: blob,
|
|
11348
|
+
filename: filename || `file.${getExtensionFromMediaType(mimeType)}`,
|
|
11349
|
+
contentType: mimeType
|
|
11350
|
+
});
|
|
11351
|
+
}
|
|
11352
|
+
} catch (error) {
|
|
11353
|
+
console.warn("Error converting data to attachment:", error);
|
|
11354
|
+
}
|
|
11355
|
+
return null;
|
|
11356
|
+
};
|
|
11357
|
+
function processAISDKInput(params) {
|
|
11358
|
+
return processInputAttachmentsSync(params);
|
|
11359
|
+
}
|
|
11360
|
+
function prepareAISDKInput(params, event, span, defaultDenyOutputPaths) {
|
|
11361
|
+
const { input, outputPromise } = processAISDKInput(params);
|
|
11362
|
+
if (outputPromise && input && typeof input === "object") {
|
|
11363
|
+
outputPromise.then((resolvedData) => {
|
|
11364
|
+
span.log({
|
|
11365
|
+
input: {
|
|
11366
|
+
...input,
|
|
11367
|
+
...resolvedData
|
|
11368
|
+
}
|
|
11369
|
+
});
|
|
11370
|
+
}).catch(() => {
|
|
11371
|
+
});
|
|
11372
|
+
}
|
|
11373
|
+
const metadata = extractMetadataFromParams(params, event.self);
|
|
11374
|
+
const childTracing = prepareAISDKChildTracing(
|
|
11375
|
+
params,
|
|
11376
|
+
event.self,
|
|
11377
|
+
span,
|
|
11378
|
+
defaultDenyOutputPaths,
|
|
11379
|
+
event.aiSDK
|
|
11380
|
+
);
|
|
11381
|
+
event.modelWrapped = childTracing.modelWrapped;
|
|
11382
|
+
if (childTracing.cleanup) {
|
|
11383
|
+
event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
|
|
11384
|
+
}
|
|
11385
|
+
return {
|
|
11386
|
+
input,
|
|
11387
|
+
metadata
|
|
11388
|
+
};
|
|
11389
|
+
}
|
|
11390
|
+
function extractTopLevelAISDKMetrics(result, event, startTime) {
|
|
11391
|
+
const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
|
|
11392
|
+
if (startTime) {
|
|
11393
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
11394
|
+
}
|
|
11395
|
+
return metrics;
|
|
11396
|
+
}
|
|
11397
|
+
function hasModelChildTracing(event) {
|
|
11398
|
+
return event?.modelWrapped === true || event?.__braintrust_ai_sdk_model_wrapped === true;
|
|
11399
|
+
}
|
|
11400
|
+
function extractMetadataFromParams(params, self) {
|
|
11401
|
+
const metadata = {
|
|
11402
|
+
braintrust: {
|
|
11403
|
+
integration_name: "ai-sdk",
|
|
11404
|
+
sdk_language: "typescript"
|
|
11405
|
+
}
|
|
11406
|
+
};
|
|
11407
|
+
const agentModel = self && typeof self === "object" && "model" in self && self.model ? self.model : self && typeof self === "object" && "settings" in self && self.settings?.model ? self.settings?.model : void 0;
|
|
11408
|
+
const { model, provider } = serializeModelWithProvider(
|
|
11409
|
+
params.model ?? agentModel
|
|
11410
|
+
);
|
|
11411
|
+
if (model) {
|
|
11412
|
+
metadata.model = model;
|
|
11413
|
+
}
|
|
11414
|
+
if (provider) {
|
|
11415
|
+
metadata.provider = provider;
|
|
11416
|
+
}
|
|
11417
|
+
const tools = serializeAISDKToolsForLogging(params.tools);
|
|
11418
|
+
if (tools) {
|
|
11419
|
+
metadata.tools = tools;
|
|
11420
|
+
}
|
|
11421
|
+
return metadata;
|
|
11422
|
+
}
|
|
11423
|
+
function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiSDK) {
|
|
11424
|
+
const cleanup = [];
|
|
11425
|
+
const patchedModels = /* @__PURE__ */ new WeakSet();
|
|
11426
|
+
const patchedTools = /* @__PURE__ */ new WeakSet();
|
|
11427
|
+
let modelWrapped = false;
|
|
11428
|
+
const patchModel = (model) => {
|
|
11429
|
+
const resolvedModel = resolveAISDKModel(model, aiSDK);
|
|
11430
|
+
if (!resolvedModel || typeof resolvedModel !== "object" || typeof resolvedModel.doGenerate !== "function" || patchedModels.has(resolvedModel) || resolvedModel[AUTO_PATCHED_MODEL]) {
|
|
11431
|
+
return resolvedModel;
|
|
11432
|
+
}
|
|
11433
|
+
patchedModels.add(resolvedModel);
|
|
11434
|
+
resolvedModel[AUTO_PATCHED_MODEL] = true;
|
|
11435
|
+
modelWrapped = true;
|
|
11436
|
+
const originalDoGenerate = resolvedModel.doGenerate;
|
|
11437
|
+
const originalDoStream = resolvedModel.doStream;
|
|
11438
|
+
const baseMetadata = buildAISDKChildMetadata(resolvedModel);
|
|
11439
|
+
resolvedModel.doGenerate = async function doGeneratePatched(options) {
|
|
11440
|
+
return parentSpan.traced(
|
|
11441
|
+
async (span) => {
|
|
11442
|
+
const result = await Reflect.apply(
|
|
11443
|
+
originalDoGenerate,
|
|
11444
|
+
resolvedModel,
|
|
11445
|
+
[options]
|
|
11446
|
+
);
|
|
11447
|
+
span.log({
|
|
11448
|
+
output: processAISDKOutput(result, denyOutputPaths),
|
|
11449
|
+
metrics: extractTokenMetrics(result),
|
|
11450
|
+
...buildResolvedMetadataPayload(result)
|
|
11451
|
+
});
|
|
11452
|
+
return result;
|
|
11453
|
+
},
|
|
11454
|
+
{
|
|
11455
|
+
name: "doGenerate",
|
|
11149
11456
|
spanAttributes: {
|
|
11150
11457
|
type: "llm" /* LLM */
|
|
11151
11458
|
},
|
|
11152
11459
|
event: {
|
|
11153
|
-
input: processAISDKInput(options),
|
|
11460
|
+
input: processAISDKInput(options).input,
|
|
11461
|
+
metadata: baseMetadata
|
|
11462
|
+
}
|
|
11463
|
+
}
|
|
11464
|
+
);
|
|
11465
|
+
};
|
|
11466
|
+
if (originalDoStream) {
|
|
11467
|
+
resolvedModel.doStream = async function doStreamPatched(options) {
|
|
11468
|
+
const span = parentSpan.startSpan({
|
|
11469
|
+
name: "doStream",
|
|
11470
|
+
spanAttributes: {
|
|
11471
|
+
type: "llm" /* LLM */
|
|
11472
|
+
},
|
|
11473
|
+
event: {
|
|
11474
|
+
input: processAISDKInput(options).input,
|
|
11154
11475
|
metadata: baseMetadata
|
|
11155
11476
|
}
|
|
11156
11477
|
});
|
|
@@ -11158,6 +11479,8 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
11158
11479
|
span,
|
|
11159
11480
|
() => Reflect.apply(originalDoStream, resolvedModel, [options])
|
|
11160
11481
|
);
|
|
11482
|
+
const streamStartTime = getCurrentUnixTimestamp();
|
|
11483
|
+
let firstChunkTime;
|
|
11161
11484
|
const output = {};
|
|
11162
11485
|
let text = "";
|
|
11163
11486
|
let reasoning = "";
|
|
@@ -11165,6 +11488,9 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
11165
11488
|
let object = void 0;
|
|
11166
11489
|
const transformStream = new TransformStream({
|
|
11167
11490
|
transform(chunk, controller) {
|
|
11491
|
+
if (firstChunkTime === void 0) {
|
|
11492
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
11493
|
+
}
|
|
11168
11494
|
switch (chunk.type) {
|
|
11169
11495
|
case "text-delta":
|
|
11170
11496
|
text += extractTextDelta(chunk);
|
|
@@ -11205,12 +11531,19 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
11205
11531
|
if (object !== void 0) {
|
|
11206
11532
|
output.object = object;
|
|
11207
11533
|
}
|
|
11534
|
+
const metrics = extractTokenMetrics(output);
|
|
11535
|
+
if (firstChunkTime !== void 0) {
|
|
11536
|
+
metrics.time_to_first_token = Math.max(
|
|
11537
|
+
firstChunkTime - streamStartTime,
|
|
11538
|
+
1e-6
|
|
11539
|
+
);
|
|
11540
|
+
}
|
|
11208
11541
|
span.log({
|
|
11209
11542
|
output: processAISDKOutput(
|
|
11210
11543
|
output,
|
|
11211
11544
|
denyOutputPaths
|
|
11212
11545
|
),
|
|
11213
|
-
metrics
|
|
11546
|
+
metrics,
|
|
11214
11547
|
...buildResolvedMetadataPayload(output)
|
|
11215
11548
|
});
|
|
11216
11549
|
span.end();
|
|
@@ -11232,6 +11565,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
11232
11565
|
}
|
|
11233
11566
|
delete resolvedModel[AUTO_PATCHED_MODEL];
|
|
11234
11567
|
});
|
|
11568
|
+
return resolvedModel;
|
|
11235
11569
|
};
|
|
11236
11570
|
const patchTool = (tool, name) => {
|
|
11237
11571
|
if (tool == null || typeof tool !== "object" || !("execute" in tool) || typeof tool.execute !== "function" || patchedTools.has(tool) || tool[AUTO_PATCHED_TOOL]) {
|
|
@@ -11304,17 +11638,26 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
|
|
|
11304
11638
|
}
|
|
11305
11639
|
};
|
|
11306
11640
|
if (params && typeof params === "object") {
|
|
11307
|
-
patchModel(params.model);
|
|
11641
|
+
const patchedParamModel = patchModel(params.model);
|
|
11642
|
+
if (typeof params.model === "string" && patchedParamModel && typeof patchedParamModel === "object") {
|
|
11643
|
+
params.model = patchedParamModel;
|
|
11644
|
+
}
|
|
11308
11645
|
patchTools(params.tools);
|
|
11309
11646
|
}
|
|
11310
11647
|
if (self && typeof self === "object") {
|
|
11311
11648
|
const selfRecord = self;
|
|
11312
11649
|
if (selfRecord.model !== void 0) {
|
|
11313
|
-
patchModel(selfRecord.model);
|
|
11650
|
+
const patchedSelfModel = patchModel(selfRecord.model);
|
|
11651
|
+
if (typeof selfRecord.model === "string" && patchedSelfModel && typeof patchedSelfModel === "object") {
|
|
11652
|
+
selfRecord.model = patchedSelfModel;
|
|
11653
|
+
}
|
|
11314
11654
|
}
|
|
11315
11655
|
if (selfRecord.settings && typeof selfRecord.settings === "object") {
|
|
11316
11656
|
if (selfRecord.settings.model !== void 0) {
|
|
11317
|
-
patchModel(selfRecord.settings.model);
|
|
11657
|
+
const patchedSettingsModel = patchModel(selfRecord.settings.model);
|
|
11658
|
+
if (typeof selfRecord.settings.model === "string" && patchedSettingsModel && typeof patchedSettingsModel === "object") {
|
|
11659
|
+
selfRecord.settings.model = patchedSettingsModel;
|
|
11660
|
+
}
|
|
11318
11661
|
}
|
|
11319
11662
|
if (selfRecord.settings.tools !== void 0) {
|
|
11320
11663
|
patchTools(selfRecord.settings.tools);
|
|
@@ -11338,75 +11681,194 @@ function finalizeAISDKChildTracing(event) {
|
|
|
11338
11681
|
}
|
|
11339
11682
|
}
|
|
11340
11683
|
function patchAISDKStreamingResult(args) {
|
|
11341
|
-
const {
|
|
11684
|
+
const { defaultDenyOutputPaths, endEvent, result, span, startTime } = args;
|
|
11342
11685
|
if (!result || typeof result !== "object") {
|
|
11343
11686
|
return false;
|
|
11344
11687
|
}
|
|
11345
11688
|
const resultRecord = result;
|
|
11346
|
-
|
|
11689
|
+
attachKnownResultPromiseHandlers(resultRecord);
|
|
11690
|
+
if (isReadableStreamLike(resultRecord.baseStream)) {
|
|
11691
|
+
let firstChunkTime2;
|
|
11692
|
+
const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
|
|
11693
|
+
new TransformStream({
|
|
11694
|
+
transform(chunk, controller) {
|
|
11695
|
+
if (firstChunkTime2 === void 0) {
|
|
11696
|
+
firstChunkTime2 = getCurrentUnixTimestamp();
|
|
11697
|
+
}
|
|
11698
|
+
controller.enqueue(chunk);
|
|
11699
|
+
},
|
|
11700
|
+
async flush() {
|
|
11701
|
+
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
11702
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime2 !== void 0) {
|
|
11703
|
+
metrics.time_to_first_token = firstChunkTime2 - startTime;
|
|
11704
|
+
}
|
|
11705
|
+
const output = await processAISDKStreamingOutput(
|
|
11706
|
+
result,
|
|
11707
|
+
resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
|
|
11708
|
+
);
|
|
11709
|
+
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
11710
|
+
span.log({
|
|
11711
|
+
output,
|
|
11712
|
+
...metadata ? { metadata } : {},
|
|
11713
|
+
metrics
|
|
11714
|
+
});
|
|
11715
|
+
finalizeAISDKChildTracing(endEvent);
|
|
11716
|
+
span.end();
|
|
11717
|
+
}
|
|
11718
|
+
})
|
|
11719
|
+
);
|
|
11720
|
+
Object.defineProperty(resultRecord, "baseStream", {
|
|
11721
|
+
configurable: true,
|
|
11722
|
+
enumerable: true,
|
|
11723
|
+
value: wrappedBaseStream,
|
|
11724
|
+
writable: true
|
|
11725
|
+
});
|
|
11726
|
+
return true;
|
|
11727
|
+
}
|
|
11728
|
+
const streamField = findAsyncIterableField(resultRecord, [
|
|
11729
|
+
"partialObjectStream",
|
|
11730
|
+
"textStream",
|
|
11731
|
+
"fullStream",
|
|
11732
|
+
"stream"
|
|
11733
|
+
]);
|
|
11734
|
+
if (!streamField) {
|
|
11347
11735
|
return false;
|
|
11348
11736
|
}
|
|
11349
11737
|
let firstChunkTime;
|
|
11350
|
-
const
|
|
11351
|
-
|
|
11352
|
-
|
|
11353
|
-
|
|
11354
|
-
firstChunkTime = getCurrentUnixTimestamp();
|
|
11355
|
-
}
|
|
11356
|
-
controller.enqueue(chunk);
|
|
11357
|
-
},
|
|
11358
|
-
async flush() {
|
|
11359
|
-
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
11360
|
-
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
11361
|
-
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
11362
|
-
}
|
|
11363
|
-
const output = await processAISDKStreamingOutput(
|
|
11364
|
-
result,
|
|
11365
|
-
denyOutputPaths
|
|
11366
|
-
);
|
|
11367
|
-
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
11368
|
-
span.log({
|
|
11369
|
-
output,
|
|
11370
|
-
...metadata ? { metadata } : {},
|
|
11371
|
-
metrics
|
|
11372
|
-
});
|
|
11373
|
-
finalizeAISDKChildTracing(endEvent);
|
|
11374
|
-
span.end();
|
|
11738
|
+
const wrappedStream = createPatchedAsyncIterable(streamField.stream, {
|
|
11739
|
+
onChunk: () => {
|
|
11740
|
+
if (firstChunkTime === void 0) {
|
|
11741
|
+
firstChunkTime = getCurrentUnixTimestamp();
|
|
11375
11742
|
}
|
|
11376
|
-
}
|
|
11377
|
-
|
|
11378
|
-
|
|
11743
|
+
},
|
|
11744
|
+
onComplete: async () => {
|
|
11745
|
+
const metrics = extractTopLevelAISDKMetrics(result, endEvent);
|
|
11746
|
+
if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
|
|
11747
|
+
metrics.time_to_first_token = firstChunkTime - startTime;
|
|
11748
|
+
}
|
|
11749
|
+
const output = await processAISDKStreamingOutput(
|
|
11750
|
+
result,
|
|
11751
|
+
resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
|
|
11752
|
+
);
|
|
11753
|
+
const metadata = buildResolvedMetadataPayload(result).metadata;
|
|
11754
|
+
span.log({
|
|
11755
|
+
output,
|
|
11756
|
+
...metadata ? { metadata } : {},
|
|
11757
|
+
metrics
|
|
11758
|
+
});
|
|
11759
|
+
finalizeAISDKChildTracing(endEvent);
|
|
11760
|
+
span.end();
|
|
11761
|
+
},
|
|
11762
|
+
onError: (error) => {
|
|
11763
|
+
span.log({
|
|
11764
|
+
error: error.message
|
|
11765
|
+
});
|
|
11766
|
+
finalizeAISDKChildTracing(endEvent);
|
|
11767
|
+
span.end();
|
|
11768
|
+
}
|
|
11769
|
+
});
|
|
11770
|
+
Object.defineProperty(resultRecord, streamField.field, {
|
|
11379
11771
|
configurable: true,
|
|
11380
11772
|
enumerable: true,
|
|
11381
|
-
value:
|
|
11773
|
+
value: wrappedStream,
|
|
11382
11774
|
writable: true
|
|
11383
11775
|
});
|
|
11384
11776
|
return true;
|
|
11385
11777
|
}
|
|
11778
|
+
function attachKnownResultPromiseHandlers(result) {
|
|
11779
|
+
const promiseLikeFields = [
|
|
11780
|
+
"content",
|
|
11781
|
+
"text",
|
|
11782
|
+
"object",
|
|
11783
|
+
"finishReason",
|
|
11784
|
+
"usage",
|
|
11785
|
+
"totalUsage",
|
|
11786
|
+
"steps"
|
|
11787
|
+
];
|
|
11788
|
+
for (const field of promiseLikeFields) {
|
|
11789
|
+
try {
|
|
11790
|
+
if (!(field in result)) {
|
|
11791
|
+
continue;
|
|
11792
|
+
}
|
|
11793
|
+
const value = result[field];
|
|
11794
|
+
if (isPromiseLike(value)) {
|
|
11795
|
+
void Promise.resolve(value).catch(() => {
|
|
11796
|
+
});
|
|
11797
|
+
}
|
|
11798
|
+
} catch {
|
|
11799
|
+
}
|
|
11800
|
+
}
|
|
11801
|
+
}
|
|
11386
11802
|
function isReadableStreamLike(value) {
|
|
11387
11803
|
return value != null && typeof value === "object" && typeof value.pipeThrough === "function";
|
|
11388
11804
|
}
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
|
|
11805
|
+
function isAsyncIterableLike(value) {
|
|
11806
|
+
return value != null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
|
|
11807
|
+
}
|
|
11808
|
+
function findAsyncIterableField(result, candidateFields) {
|
|
11809
|
+
for (const field of candidateFields) {
|
|
11810
|
+
try {
|
|
11811
|
+
const stream = result[field];
|
|
11812
|
+
if (isAsyncIterableLike(stream)) {
|
|
11813
|
+
return { field, stream };
|
|
11814
|
+
}
|
|
11815
|
+
} catch {
|
|
11398
11816
|
}
|
|
11399
|
-
} catch {
|
|
11400
11817
|
}
|
|
11401
|
-
|
|
11402
|
-
|
|
11403
|
-
|
|
11818
|
+
return null;
|
|
11819
|
+
}
|
|
11820
|
+
function createPatchedAsyncIterable(stream, hooks) {
|
|
11821
|
+
return {
|
|
11822
|
+
async *[Symbol.asyncIterator]() {
|
|
11823
|
+
try {
|
|
11824
|
+
for await (const chunk of stream) {
|
|
11825
|
+
hooks.onChunk(chunk);
|
|
11826
|
+
yield chunk;
|
|
11827
|
+
}
|
|
11828
|
+
await hooks.onComplete();
|
|
11829
|
+
} catch (error) {
|
|
11830
|
+
hooks.onError(
|
|
11831
|
+
error instanceof Error ? error : new Error(String(error))
|
|
11832
|
+
);
|
|
11833
|
+
throw error;
|
|
11834
|
+
}
|
|
11835
|
+
}
|
|
11836
|
+
};
|
|
11837
|
+
}
|
|
11838
|
+
async function processAISDKStreamingOutput(result, denyOutputPaths) {
|
|
11839
|
+
const output = processAISDKOutput(result, denyOutputPaths);
|
|
11840
|
+
if (!output || typeof output !== "object") {
|
|
11841
|
+
return output;
|
|
11842
|
+
}
|
|
11843
|
+
const outputRecord = output;
|
|
11844
|
+
const isObjectStreamingResult = result != null && typeof result === "object" && "partialObjectStream" in result;
|
|
11845
|
+
try {
|
|
11846
|
+
if (!isObjectStreamingResult && "text" in result) {
|
|
11847
|
+
const resolvedText = await Promise.resolve(result.text);
|
|
11848
|
+
if (typeof resolvedText === "string") {
|
|
11849
|
+
outputRecord.text = resolvedText;
|
|
11850
|
+
}
|
|
11851
|
+
}
|
|
11852
|
+
} catch {
|
|
11853
|
+
}
|
|
11854
|
+
try {
|
|
11855
|
+
if ("object" in result) {
|
|
11856
|
+
const resolvedObject = await Promise.resolve(result.object);
|
|
11404
11857
|
if (resolvedObject !== void 0) {
|
|
11405
11858
|
outputRecord.object = resolvedObject;
|
|
11406
11859
|
}
|
|
11407
11860
|
}
|
|
11408
11861
|
} catch {
|
|
11409
11862
|
}
|
|
11863
|
+
try {
|
|
11864
|
+
if ("finishReason" in result) {
|
|
11865
|
+
const resolvedFinishReason = await Promise.resolve(result.finishReason);
|
|
11866
|
+
if (resolvedFinishReason !== void 0) {
|
|
11867
|
+
outputRecord.finishReason = resolvedFinishReason;
|
|
11868
|
+
}
|
|
11869
|
+
}
|
|
11870
|
+
} catch {
|
|
11871
|
+
}
|
|
11410
11872
|
return outputRecord;
|
|
11411
11873
|
}
|
|
11412
11874
|
function buildAISDKChildMetadata(model) {
|
|
@@ -11429,16 +11891,25 @@ function buildResolvedMetadataPayload(result) {
|
|
|
11429
11891
|
if (gatewayInfo?.model) {
|
|
11430
11892
|
metadata.model = gatewayInfo.model;
|
|
11431
11893
|
}
|
|
11432
|
-
|
|
11433
|
-
|
|
11894
|
+
let finishReason;
|
|
11895
|
+
try {
|
|
11896
|
+
finishReason = result.finishReason;
|
|
11897
|
+
} catch {
|
|
11898
|
+
finishReason = void 0;
|
|
11899
|
+
}
|
|
11900
|
+
if (isPromiseLike(finishReason)) {
|
|
11901
|
+
void Promise.resolve(finishReason).catch(() => {
|
|
11902
|
+
});
|
|
11903
|
+
} else if (finishReason !== void 0) {
|
|
11904
|
+
metadata.finish_reason = finishReason;
|
|
11434
11905
|
}
|
|
11435
11906
|
return Object.keys(metadata).length > 0 ? { metadata } : {};
|
|
11436
11907
|
}
|
|
11437
|
-
function resolveAISDKModel(model) {
|
|
11908
|
+
function resolveAISDKModel(model, aiSDK) {
|
|
11438
11909
|
if (typeof model !== "string") {
|
|
11439
11910
|
return model;
|
|
11440
11911
|
}
|
|
11441
|
-
const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? null;
|
|
11912
|
+
const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? aiSDK?.gateway ?? null;
|
|
11442
11913
|
if (provider && typeof provider.languageModel === "function") {
|
|
11443
11914
|
return provider.languageModel(model);
|
|
11444
11915
|
}
|
|
@@ -11461,15 +11932,15 @@ function processAISDKOutput(output, denyOutputPaths) {
|
|
|
11461
11932
|
}
|
|
11462
11933
|
function extractTokenMetrics(result) {
|
|
11463
11934
|
const metrics = {};
|
|
11464
|
-
let usage
|
|
11465
|
-
|
|
11466
|
-
|
|
11467
|
-
|
|
11468
|
-
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
|
|
11935
|
+
let usage;
|
|
11936
|
+
const totalUsageValue = safeResultFieldRead(result, "totalUsage");
|
|
11937
|
+
if (totalUsageValue !== void 0 && !isPromiseLike(totalUsageValue)) {
|
|
11938
|
+
usage = totalUsageValue;
|
|
11939
|
+
}
|
|
11940
|
+
if (!usage) {
|
|
11941
|
+
const usageValue = safeResultFieldRead(result, "usage");
|
|
11942
|
+
if (usageValue !== void 0 && !isPromiseLike(usageValue)) {
|
|
11943
|
+
usage = usageValue;
|
|
11473
11944
|
}
|
|
11474
11945
|
}
|
|
11475
11946
|
if (!usage) {
|
|
@@ -11507,6 +11978,22 @@ function extractTokenMetrics(result) {
|
|
|
11507
11978
|
}
|
|
11508
11979
|
return metrics;
|
|
11509
11980
|
}
|
|
11981
|
+
function safeResultFieldRead(result, field) {
|
|
11982
|
+
return safeSerializableFieldRead(result, field);
|
|
11983
|
+
}
|
|
11984
|
+
function safeSerializableFieldRead(obj, field) {
|
|
11985
|
+
try {
|
|
11986
|
+
const value = obj?.[field];
|
|
11987
|
+
if (isPromiseLike(value)) {
|
|
11988
|
+
void Promise.resolve(value).catch(() => {
|
|
11989
|
+
});
|
|
11990
|
+
return void 0;
|
|
11991
|
+
}
|
|
11992
|
+
return value;
|
|
11993
|
+
} catch {
|
|
11994
|
+
return void 0;
|
|
11995
|
+
}
|
|
11996
|
+
}
|
|
11510
11997
|
function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
11511
11998
|
const lastChunk = chunks[chunks.length - 1];
|
|
11512
11999
|
const output = {};
|
|
@@ -11515,17 +12002,21 @@ function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
|
11515
12002
|
if (lastChunk) {
|
|
11516
12003
|
metrics = hasModelChildTracing(endEvent) ? {} : extractTokenMetrics(lastChunk);
|
|
11517
12004
|
metadata = buildResolvedMetadataPayload(lastChunk).metadata;
|
|
11518
|
-
|
|
11519
|
-
|
|
12005
|
+
const text = safeSerializableFieldRead(lastChunk, "text");
|
|
12006
|
+
if (text !== void 0) {
|
|
12007
|
+
output.text = text;
|
|
11520
12008
|
}
|
|
11521
|
-
|
|
11522
|
-
|
|
12009
|
+
const objectValue = safeSerializableFieldRead(lastChunk, "object");
|
|
12010
|
+
if (objectValue !== void 0) {
|
|
12011
|
+
output.object = objectValue;
|
|
11523
12012
|
}
|
|
11524
|
-
|
|
11525
|
-
|
|
12013
|
+
const finishReason = safeSerializableFieldRead(lastChunk, "finishReason");
|
|
12014
|
+
if (finishReason !== void 0) {
|
|
12015
|
+
output.finishReason = finishReason;
|
|
11526
12016
|
}
|
|
11527
|
-
|
|
11528
|
-
|
|
12017
|
+
const toolCalls = safeSerializableFieldRead(lastChunk, "toolCalls");
|
|
12018
|
+
if (toolCalls !== void 0) {
|
|
12019
|
+
output.toolCalls = toolCalls;
|
|
11529
12020
|
}
|
|
11530
12021
|
}
|
|
11531
12022
|
finalizeAISDKChildTracing(endEvent);
|
|
@@ -11534,6 +12025,7 @@ function aggregateAISDKChunks(chunks, _result, endEvent) {
|
|
|
11534
12025
|
function extractGetterValues(obj) {
|
|
11535
12026
|
const getterValues = {};
|
|
11536
12027
|
const getterNames = [
|
|
12028
|
+
"content",
|
|
11537
12029
|
"text",
|
|
11538
12030
|
"object",
|
|
11539
12031
|
"finishReason",
|
|
@@ -11549,8 +12041,17 @@ function extractGetterValues(obj) {
|
|
|
11549
12041
|
];
|
|
11550
12042
|
for (const name of getterNames) {
|
|
11551
12043
|
try {
|
|
11552
|
-
if (obj
|
|
11553
|
-
|
|
12044
|
+
if (!obj || !(name in obj)) {
|
|
12045
|
+
continue;
|
|
12046
|
+
}
|
|
12047
|
+
const value = obj[name];
|
|
12048
|
+
if (isPromiseLike(value)) {
|
|
12049
|
+
void Promise.resolve(value).catch(() => {
|
|
12050
|
+
});
|
|
12051
|
+
continue;
|
|
12052
|
+
}
|
|
12053
|
+
if (isSerializableOutputValue(value)) {
|
|
12054
|
+
getterValues[name] = value;
|
|
11554
12055
|
}
|
|
11555
12056
|
} catch {
|
|
11556
12057
|
}
|
|
@@ -11572,6 +12073,11 @@ function extractSerializableOutputFields(output) {
|
|
|
11572
12073
|
for (const name of directFieldNames) {
|
|
11573
12074
|
try {
|
|
11574
12075
|
const value = output?.[name];
|
|
12076
|
+
if (isPromiseLike(value)) {
|
|
12077
|
+
void Promise.resolve(value).catch(() => {
|
|
12078
|
+
});
|
|
12079
|
+
continue;
|
|
12080
|
+
}
|
|
11575
12081
|
if (isSerializableOutputValue(value)) {
|
|
11576
12082
|
serialized[name] = value;
|
|
11577
12083
|
}
|
|
@@ -11583,6 +12089,9 @@ function extractSerializableOutputFields(output) {
|
|
|
11583
12089
|
...extractGetterValues(output)
|
|
11584
12090
|
};
|
|
11585
12091
|
}
|
|
12092
|
+
function isPromiseLike(value) {
|
|
12093
|
+
return value != null && typeof value === "object" && typeof value.then === "function";
|
|
12094
|
+
}
|
|
11586
12095
|
function isSerializableOutputValue(value) {
|
|
11587
12096
|
if (typeof value === "function") {
|
|
11588
12097
|
return false;
|
|
@@ -11624,8 +12133,9 @@ function parseGatewayModelString(modelString) {
|
|
|
11624
12133
|
return { model: modelString };
|
|
11625
12134
|
}
|
|
11626
12135
|
function extractGatewayRoutingInfo(result) {
|
|
11627
|
-
|
|
11628
|
-
|
|
12136
|
+
const steps = safeSerializableFieldRead(result, "steps");
|
|
12137
|
+
if (Array.isArray(steps) && steps.length > 0) {
|
|
12138
|
+
const routing2 = steps[0]?.providerMetadata?.gateway?.routing;
|
|
11629
12139
|
if (routing2) {
|
|
11630
12140
|
return {
|
|
11631
12141
|
provider: routing2.resolvedProvider || routing2.finalProvider,
|
|
@@ -11633,7 +12143,11 @@ function extractGatewayRoutingInfo(result) {
|
|
|
11633
12143
|
};
|
|
11634
12144
|
}
|
|
11635
12145
|
}
|
|
11636
|
-
const
|
|
12146
|
+
const providerMetadata = safeSerializableFieldRead(
|
|
12147
|
+
result,
|
|
12148
|
+
"providerMetadata"
|
|
12149
|
+
);
|
|
12150
|
+
const routing = providerMetadata?.gateway?.routing;
|
|
11637
12151
|
if (routing) {
|
|
11638
12152
|
return {
|
|
11639
12153
|
provider: routing.resolvedProvider || routing.finalProvider,
|
|
@@ -11643,10 +12157,11 @@ function extractGatewayRoutingInfo(result) {
|
|
|
11643
12157
|
return null;
|
|
11644
12158
|
}
|
|
11645
12159
|
function extractCostFromResult(result) {
|
|
11646
|
-
|
|
12160
|
+
const steps = safeSerializableFieldRead(result, "steps");
|
|
12161
|
+
if (Array.isArray(steps) && steps.length > 0) {
|
|
11647
12162
|
let totalCost = 0;
|
|
11648
12163
|
let foundCost = false;
|
|
11649
|
-
for (const step of
|
|
12164
|
+
for (const step of steps) {
|
|
11650
12165
|
const gateway2 = step?.providerMetadata?.gateway;
|
|
11651
12166
|
const stepCost = parseGatewayCost(gateway2?.cost) || parseGatewayCost(gateway2?.marketCost);
|
|
11652
12167
|
if (stepCost !== void 0 && stepCost > 0) {
|
|
@@ -11658,7 +12173,11 @@ function extractCostFromResult(result) {
|
|
|
11658
12173
|
return totalCost;
|
|
11659
12174
|
}
|
|
11660
12175
|
}
|
|
11661
|
-
const
|
|
12176
|
+
const providerMetadata = safeSerializableFieldRead(
|
|
12177
|
+
result,
|
|
12178
|
+
"providerMetadata"
|
|
12179
|
+
);
|
|
12180
|
+
const gateway = providerMetadata?.gateway;
|
|
11662
12181
|
const directCost = parseGatewayCost(gateway?.cost) || parseGatewayCost(gateway?.marketCost);
|
|
11663
12182
|
if (directCost !== void 0 && directCost > 0) {
|
|
11664
12183
|
return directCost;
|
|
@@ -12359,20 +12878,16 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
|
|
|
12359
12878
|
);
|
|
12360
12879
|
});
|
|
12361
12880
|
},
|
|
12362
|
-
onComplete: () => {
|
|
12363
|
-
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
|
|
12367
|
-
|
|
12368
|
-
void state.processing.then(() => {
|
|
12369
|
-
state.span.log({
|
|
12370
|
-
error: error.message
|
|
12371
|
-
});
|
|
12372
|
-
}).then(() => finalizeQuerySpan(state)).finally(() => {
|
|
12373
|
-
spans.delete(event);
|
|
12881
|
+
onComplete: () => state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
|
|
12882
|
+
spans.delete(event);
|
|
12883
|
+
}),
|
|
12884
|
+
onError: (error) => state.processing.then(() => {
|
|
12885
|
+
state.span.log({
|
|
12886
|
+
error: error.message
|
|
12374
12887
|
});
|
|
12375
|
-
}
|
|
12888
|
+
}).then(() => finalizeQuerySpan(state)).finally(() => {
|
|
12889
|
+
spans.delete(event);
|
|
12890
|
+
})
|
|
12376
12891
|
});
|
|
12377
12892
|
return;
|
|
12378
12893
|
}
|
|
@@ -12520,12 +13035,14 @@ var GoogleGenAIPlugin = class extends BasePlugin {
|
|
|
12520
13035
|
const params = event.arguments[0];
|
|
12521
13036
|
streamEvent.googleGenAIInput = serializeInput(params);
|
|
12522
13037
|
streamEvent.googleGenAIMetadata = extractMetadata(params);
|
|
13038
|
+
streamEvent.googleGenAIStartTime = getCurrentUnixTimestamp();
|
|
12523
13039
|
},
|
|
12524
13040
|
asyncEnd: (event) => {
|
|
12525
13041
|
const streamEvent = event;
|
|
12526
13042
|
patchGoogleGenAIStreamingResult({
|
|
12527
13043
|
input: streamEvent.googleGenAIInput,
|
|
12528
13044
|
metadata: streamEvent.googleGenAIMetadata,
|
|
13045
|
+
startTime: streamEvent.googleGenAIStartTime,
|
|
12529
13046
|
result: streamEvent.result
|
|
12530
13047
|
});
|
|
12531
13048
|
},
|
|
@@ -12578,7 +13095,7 @@ function logErrorAndEndSpan(states, event) {
|
|
|
12578
13095
|
states.delete(event);
|
|
12579
13096
|
}
|
|
12580
13097
|
function patchGoogleGenAIStreamingResult(args) {
|
|
12581
|
-
const { input, metadata, result } = args;
|
|
13098
|
+
const { input, metadata, result, startTime } = args;
|
|
12582
13099
|
if (!input || !metadata || !result || typeof result !== "object" || typeof result.next !== "function") {
|
|
12583
13100
|
return false;
|
|
12584
13101
|
}
|
|
@@ -12586,7 +13103,7 @@ function patchGoogleGenAIStreamingResult(args) {
|
|
|
12586
13103
|
let firstTokenTime = null;
|
|
12587
13104
|
let finalized = false;
|
|
12588
13105
|
let span = null;
|
|
12589
|
-
|
|
13106
|
+
const requestStartTime = startTime ?? getCurrentUnixTimestamp();
|
|
12590
13107
|
const ensureSpan = () => {
|
|
12591
13108
|
if (!span) {
|
|
12592
13109
|
span = startSpan({
|
|
@@ -12599,7 +13116,6 @@ function patchGoogleGenAIStreamingResult(args) {
|
|
|
12599
13116
|
metadata
|
|
12600
13117
|
}
|
|
12601
13118
|
});
|
|
12602
|
-
startTime = getCurrentUnixTimestamp();
|
|
12603
13119
|
}
|
|
12604
13120
|
return span;
|
|
12605
13121
|
};
|
|
@@ -12653,11 +13169,11 @@ function patchGoogleGenAIStreamingResult(args) {
|
|
|
12653
13169
|
}
|
|
12654
13170
|
chunks.push(nextResult.value);
|
|
12655
13171
|
}
|
|
12656
|
-
if (nextResult.done
|
|
13172
|
+
if (nextResult.done) {
|
|
12657
13173
|
finalize({
|
|
12658
13174
|
result: aggregateGenerateContentChunks(
|
|
12659
13175
|
chunks,
|
|
12660
|
-
|
|
13176
|
+
requestStartTime,
|
|
12661
13177
|
firstTokenTime
|
|
12662
13178
|
)
|
|
12663
13179
|
});
|
|
@@ -12677,13 +13193,13 @@ function patchGoogleGenAIStreamingResult(args) {
|
|
|
12677
13193
|
...returnArgs
|
|
12678
13194
|
);
|
|
12679
13195
|
} finally {
|
|
12680
|
-
if (
|
|
13196
|
+
if (chunks.length > 0) {
|
|
12681
13197
|
finalize({
|
|
12682
|
-
result:
|
|
13198
|
+
result: aggregateGenerateContentChunks(
|
|
12683
13199
|
chunks,
|
|
12684
|
-
|
|
13200
|
+
requestStartTime,
|
|
12685
13201
|
firstTokenTime
|
|
12686
|
-
)
|
|
13202
|
+
)
|
|
12687
13203
|
});
|
|
12688
13204
|
} else {
|
|
12689
13205
|
finalize({});
|
|
@@ -12975,895 +13491,535 @@ var openRouterChannels = defineChannels("@openrouter/sdk", {
|
|
|
12975
13491
|
channelName: "callModel",
|
|
12976
13492
|
kind: "sync-stream"
|
|
12977
13493
|
}),
|
|
13494
|
+
callModelTurn: channel({
|
|
13495
|
+
channelName: "callModel.turn",
|
|
13496
|
+
kind: "async"
|
|
13497
|
+
}),
|
|
12978
13498
|
toolExecute: channel({
|
|
12979
13499
|
channelName: "tool.execute",
|
|
12980
13500
|
kind: "async"
|
|
12981
13501
|
})
|
|
12982
13502
|
});
|
|
12983
13503
|
|
|
12984
|
-
// src/openrouter-
|
|
12985
|
-
var
|
|
12986
|
-
|
|
12987
|
-
|
|
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);
|
|
13504
|
+
// src/instrumentation/plugins/openrouter-plugin.ts
|
|
13505
|
+
var OpenRouterPlugin = class extends BasePlugin {
|
|
13506
|
+
onEnable() {
|
|
13507
|
+
this.subscribeToOpenRouterChannels();
|
|
13130
13508
|
}
|
|
13131
|
-
|
|
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" };
|
|
13509
|
+
onDisable() {
|
|
13510
|
+
this.unsubscribers = unsubscribeAll(this.unsubscribers);
|
|
13160
13511
|
}
|
|
13161
|
-
|
|
13162
|
-
|
|
13163
|
-
|
|
13164
|
-
|
|
13165
|
-
|
|
13166
|
-
|
|
13167
|
-
|
|
13168
|
-
|
|
13169
|
-
|
|
13170
|
-
|
|
13171
|
-
|
|
13172
|
-
|
|
13173
|
-
|
|
13174
|
-
|
|
13175
|
-
|
|
13176
|
-
|
|
13177
|
-
|
|
13178
|
-
|
|
13179
|
-
|
|
13180
|
-
|
|
13181
|
-
|
|
13182
|
-
|
|
13183
|
-
|
|
13184
|
-
|
|
13185
|
-
|
|
13186
|
-
|
|
13187
|
-
|
|
13188
|
-
|
|
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
|
|
13512
|
+
subscribeToOpenRouterChannels() {
|
|
13513
|
+
this.unsubscribers.push(
|
|
13514
|
+
traceStreamingChannel(openRouterChannels.chatSend, {
|
|
13515
|
+
name: "openrouter.chat.send",
|
|
13516
|
+
type: "llm" /* LLM */,
|
|
13517
|
+
extractInput: (args) => {
|
|
13518
|
+
const request = getOpenRouterRequestArg(args);
|
|
13519
|
+
const chatGenerationParams = isObject(request?.chatGenerationParams) ? request.chatGenerationParams : {};
|
|
13520
|
+
const httpReferer = request?.httpReferer;
|
|
13521
|
+
const xTitle = request?.xTitle;
|
|
13522
|
+
const { messages, ...metadata } = chatGenerationParams;
|
|
13523
|
+
return {
|
|
13524
|
+
input: messages,
|
|
13525
|
+
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
13526
|
+
};
|
|
13527
|
+
},
|
|
13528
|
+
extractOutput: (result) => {
|
|
13529
|
+
return isObject(result) ? result.choices : void 0;
|
|
13530
|
+
},
|
|
13531
|
+
extractMetrics: (result, startTime) => {
|
|
13532
|
+
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
13533
|
+
if (startTime) {
|
|
13534
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
13535
|
+
}
|
|
13536
|
+
return metrics;
|
|
13537
|
+
},
|
|
13538
|
+
aggregateChunks: aggregateOpenRouterChatChunks
|
|
13539
|
+
})
|
|
13260
13540
|
);
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
|
|
13265
|
-
|
|
13266
|
-
|
|
13267
|
-
|
|
13268
|
-
|
|
13269
|
-
|
|
13270
|
-
|
|
13271
|
-
|
|
13272
|
-
|
|
13273
|
-
|
|
13274
|
-
|
|
13275
|
-
|
|
13276
|
-
|
|
13277
|
-
|
|
13278
|
-
|
|
13279
|
-
|
|
13280
|
-
|
|
13281
|
-
|
|
13282
|
-
|
|
13283
|
-
|
|
13284
|
-
|
|
13285
|
-
|
|
13286
|
-
|
|
13287
|
-
|
|
13288
|
-
|
|
13289
|
-
|
|
13290
|
-
|
|
13291
|
-
|
|
13292
|
-
|
|
13293
|
-
|
|
13294
|
-
|
|
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;
|
|
13541
|
+
this.unsubscribers.push(
|
|
13542
|
+
traceAsyncChannel(openRouterChannels.embeddingsGenerate, {
|
|
13543
|
+
name: "openrouter.embeddings.generate",
|
|
13544
|
+
type: "llm" /* LLM */,
|
|
13545
|
+
extractInput: (args) => {
|
|
13546
|
+
const request = getOpenRouterRequestArg(args);
|
|
13547
|
+
const requestBody = isObject(request?.requestBody) ? request.requestBody : {};
|
|
13548
|
+
const httpReferer = request?.httpReferer;
|
|
13549
|
+
const xTitle = request?.xTitle;
|
|
13550
|
+
const { input, ...metadata } = requestBody;
|
|
13551
|
+
return {
|
|
13552
|
+
input,
|
|
13553
|
+
metadata: buildOpenRouterEmbeddingMetadata(
|
|
13554
|
+
metadata,
|
|
13555
|
+
httpReferer,
|
|
13556
|
+
xTitle
|
|
13557
|
+
)
|
|
13558
|
+
};
|
|
13559
|
+
},
|
|
13560
|
+
extractOutput: (result) => {
|
|
13561
|
+
if (!isObject(result)) {
|
|
13562
|
+
return void 0;
|
|
13563
|
+
}
|
|
13564
|
+
const embedding = result.data?.[0]?.embedding;
|
|
13565
|
+
return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
|
|
13566
|
+
},
|
|
13567
|
+
extractMetadata: (result) => {
|
|
13568
|
+
if (!isObject(result)) {
|
|
13569
|
+
return void 0;
|
|
13570
|
+
}
|
|
13571
|
+
return extractOpenRouterResponseMetadata(result);
|
|
13572
|
+
},
|
|
13573
|
+
extractMetrics: (result) => {
|
|
13574
|
+
return isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {};
|
|
13328
13575
|
}
|
|
13329
|
-
})
|
|
13330
|
-
|
|
13331
|
-
|
|
13332
|
-
|
|
13333
|
-
|
|
13334
|
-
|
|
13335
|
-
|
|
13336
|
-
|
|
13337
|
-
|
|
13338
|
-
|
|
13339
|
-
|
|
13340
|
-
|
|
13341
|
-
|
|
13342
|
-
|
|
13343
|
-
|
|
13344
|
-
|
|
13345
|
-
|
|
13346
|
-
|
|
13347
|
-
|
|
13348
|
-
|
|
13349
|
-
|
|
13350
|
-
|
|
13351
|
-
|
|
13352
|
-
|
|
13353
|
-
|
|
13354
|
-
|
|
13355
|
-
|
|
13356
|
-
|
|
13357
|
-
|
|
13358
|
-
|
|
13359
|
-
|
|
13360
|
-
|
|
13361
|
-
|
|
13362
|
-
|
|
13363
|
-
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
|
|
13367
|
-
|
|
13368
|
-
|
|
13369
|
-
|
|
13370
|
-
|
|
13371
|
-
|
|
13372
|
-
|
|
13373
|
-
|
|
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
|
|
13576
|
+
})
|
|
13577
|
+
);
|
|
13578
|
+
this.unsubscribers.push(
|
|
13579
|
+
traceStreamingChannel(openRouterChannels.betaResponsesSend, {
|
|
13580
|
+
name: "openrouter.beta.responses.send",
|
|
13581
|
+
type: "llm" /* LLM */,
|
|
13582
|
+
extractInput: (args) => {
|
|
13583
|
+
const request = getOpenRouterRequestArg(args);
|
|
13584
|
+
const openResponsesRequest = isObject(request?.openResponsesRequest) ? request.openResponsesRequest : {};
|
|
13585
|
+
const httpReferer = request?.httpReferer;
|
|
13586
|
+
const xTitle = request?.xTitle;
|
|
13587
|
+
const { input, ...metadata } = openResponsesRequest;
|
|
13588
|
+
return {
|
|
13589
|
+
input,
|
|
13590
|
+
metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
|
|
13591
|
+
};
|
|
13592
|
+
},
|
|
13593
|
+
extractOutput: (result) => extractOpenRouterResponseOutput(result),
|
|
13594
|
+
extractMetadata: (result) => extractOpenRouterResponseMetadata(result),
|
|
13595
|
+
extractMetrics: (result, startTime) => {
|
|
13596
|
+
const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
|
|
13597
|
+
if (startTime) {
|
|
13598
|
+
metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
|
|
13599
|
+
}
|
|
13600
|
+
return metrics;
|
|
13601
|
+
},
|
|
13602
|
+
aggregateChunks: aggregateOpenRouterResponseStreamEvents
|
|
13603
|
+
})
|
|
13604
|
+
);
|
|
13605
|
+
this.unsubscribers.push(
|
|
13606
|
+
traceSyncStreamChannel(openRouterChannels.callModel, {
|
|
13607
|
+
name: "openrouter.callModel",
|
|
13608
|
+
type: "llm" /* LLM */,
|
|
13609
|
+
extractInput: (args) => {
|
|
13610
|
+
const request = getOpenRouterCallModelRequestArg(args);
|
|
13611
|
+
return {
|
|
13612
|
+
input: request ? extractOpenRouterCallModelInput(request) : void 0,
|
|
13613
|
+
metadata: request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" }
|
|
13614
|
+
};
|
|
13615
|
+
},
|
|
13616
|
+
patchResult: ({ endEvent, result, span }) => {
|
|
13617
|
+
return patchOpenRouterCallModelResult({
|
|
13618
|
+
request: getOpenRouterCallModelRequestArg(endEvent.arguments),
|
|
13619
|
+
result,
|
|
13620
|
+
span
|
|
13393
13621
|
});
|
|
13394
|
-
childSpan.end();
|
|
13395
|
-
throw error;
|
|
13396
13622
|
}
|
|
13397
|
-
})
|
|
13398
|
-
|
|
13399
|
-
|
|
13400
|
-
|
|
13401
|
-
|
|
13402
|
-
|
|
13403
|
-
|
|
13404
|
-
|
|
13405
|
-
|
|
13406
|
-
|
|
13407
|
-
|
|
13408
|
-
|
|
13409
|
-
|
|
13410
|
-
|
|
13411
|
-
|
|
13412
|
-
|
|
13413
|
-
|
|
13414
|
-
|
|
13415
|
-
|
|
13416
|
-
|
|
13417
|
-
|
|
13418
|
-
|
|
13419
|
-
|
|
13420
|
-
|
|
13421
|
-
|
|
13422
|
-
|
|
13423
|
-
|
|
13424
|
-
|
|
13425
|
-
|
|
13426
|
-
|
|
13427
|
-
|
|
13428
|
-
|
|
13429
|
-
|
|
13430
|
-
|
|
13431
|
-
|
|
13623
|
+
})
|
|
13624
|
+
);
|
|
13625
|
+
this.unsubscribers.push(
|
|
13626
|
+
traceAsyncChannel(openRouterChannels.callModelTurn, {
|
|
13627
|
+
name: "openrouter.beta.responses.send",
|
|
13628
|
+
type: "llm" /* LLM */,
|
|
13629
|
+
extractInput: (args, event) => {
|
|
13630
|
+
const request = getOpenRouterCallModelRequestArg(args);
|
|
13631
|
+
const metadata = request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" };
|
|
13632
|
+
if (isObject(metadata) && "tools" in metadata) {
|
|
13633
|
+
delete metadata.tools;
|
|
13634
|
+
}
|
|
13635
|
+
return {
|
|
13636
|
+
input: request ? extractOpenRouterCallModelInput(request) : void 0,
|
|
13637
|
+
metadata: {
|
|
13638
|
+
...metadata,
|
|
13639
|
+
step: event.step,
|
|
13640
|
+
step_type: event.stepType
|
|
13641
|
+
}
|
|
13642
|
+
};
|
|
13643
|
+
},
|
|
13644
|
+
extractOutput: (result) => extractOpenRouterResponseOutput(result),
|
|
13645
|
+
extractMetadata: (result, event) => {
|
|
13646
|
+
if (!isObject(result)) {
|
|
13647
|
+
return {
|
|
13648
|
+
step: event?.step,
|
|
13649
|
+
step_type: event?.stepType
|
|
13650
|
+
};
|
|
13651
|
+
}
|
|
13652
|
+
return {
|
|
13653
|
+
...extractOpenRouterResponseMetadata(result) || {},
|
|
13654
|
+
...event?.step !== void 0 ? { step: event.step } : {},
|
|
13655
|
+
...event?.stepType ? { step_type: event.stepType } : {}
|
|
13656
|
+
};
|
|
13657
|
+
},
|
|
13658
|
+
extractMetrics: (result) => isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {}
|
|
13659
|
+
})
|
|
13660
|
+
);
|
|
13661
|
+
this.unsubscribers.push(
|
|
13662
|
+
traceStreamingChannel(openRouterChannels.toolExecute, {
|
|
13663
|
+
name: "openrouter.tool",
|
|
13664
|
+
type: "tool" /* TOOL */,
|
|
13665
|
+
extractInput: (args, event) => ({
|
|
13666
|
+
input: args[0],
|
|
13667
|
+
metadata: {
|
|
13668
|
+
provider: "openrouter",
|
|
13669
|
+
tool_name: event.toolName,
|
|
13670
|
+
...event.toolCallId ? { tool_call_id: event.toolCallId } : {}
|
|
13671
|
+
}
|
|
13672
|
+
}),
|
|
13673
|
+
extractOutput: (result) => result,
|
|
13674
|
+
extractMetrics: () => ({}),
|
|
13675
|
+
aggregateChunks: (chunks) => ({
|
|
13676
|
+
output: chunks.length > 0 ? chunks[chunks.length - 1] : void 0,
|
|
13677
|
+
metrics: {}
|
|
13678
|
+
})
|
|
13679
|
+
})
|
|
13680
|
+
);
|
|
13681
|
+
const callModelChannel = openRouterChannels.callModel.tracingChannel();
|
|
13682
|
+
const callModelHandlers = {
|
|
13683
|
+
start: (event) => {
|
|
13684
|
+
const request = getOpenRouterCallModelRequestArg(event.arguments);
|
|
13685
|
+
if (!request) {
|
|
13686
|
+
return;
|
|
13432
13687
|
}
|
|
13433
|
-
|
|
13688
|
+
patchOpenRouterCallModelRequestTools(request);
|
|
13689
|
+
}
|
|
13434
13690
|
};
|
|
13691
|
+
callModelChannel.subscribe(callModelHandlers);
|
|
13692
|
+
this.unsubscribers.push(() => {
|
|
13693
|
+
callModelChannel.unsubscribe(callModelHandlers);
|
|
13694
|
+
});
|
|
13435
13695
|
}
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
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;
|
|
13696
|
+
};
|
|
13697
|
+
function normalizeArgs(args) {
|
|
13698
|
+
if (Array.isArray(args)) {
|
|
13699
|
+
return args;
|
|
13492
13700
|
}
|
|
13493
|
-
|
|
13494
|
-
|
|
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
|
-
);
|
|
13701
|
+
if (isArrayLike(args)) {
|
|
13702
|
+
return Array.from(args);
|
|
13508
13703
|
}
|
|
13509
|
-
|
|
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;
|
|
13704
|
+
return [args];
|
|
13516
13705
|
}
|
|
13517
|
-
function
|
|
13518
|
-
|
|
13519
|
-
...extractOpenRouterResponseMetadata(response) || {},
|
|
13520
|
-
...turnCount !== void 0 ? { turn_count: turnCount } : {}
|
|
13521
|
-
};
|
|
13522
|
-
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
13706
|
+
function isArrayLike(value) {
|
|
13707
|
+
return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
|
|
13523
13708
|
}
|
|
13524
|
-
function
|
|
13525
|
-
|
|
13526
|
-
|
|
13709
|
+
function getOpenRouterRequestArg(args) {
|
|
13710
|
+
const normalizedArgs = normalizeArgs(args);
|
|
13711
|
+
const keyedCandidate = normalizedArgs.find(
|
|
13712
|
+
(arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
|
|
13713
|
+
);
|
|
13714
|
+
if (isObject(keyedCandidate)) {
|
|
13715
|
+
return keyedCandidate;
|
|
13527
13716
|
}
|
|
13528
|
-
|
|
13717
|
+
const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
|
|
13718
|
+
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
13529
13719
|
}
|
|
13530
|
-
function
|
|
13531
|
-
|
|
13532
|
-
|
|
13533
|
-
}
|
|
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);
|
|
13720
|
+
function getOpenRouterCallModelRequestArg(args) {
|
|
13721
|
+
const firstObjectArg = normalizeArgs(args).find((arg) => isObject(arg));
|
|
13722
|
+
return isObject(firstObjectArg) ? firstObjectArg : void 0;
|
|
13539
13723
|
}
|
|
13540
|
-
|
|
13724
|
+
var TOKEN_NAME_MAP2 = {
|
|
13725
|
+
promptTokens: "prompt_tokens",
|
|
13726
|
+
inputTokens: "prompt_tokens",
|
|
13727
|
+
completionTokens: "completion_tokens",
|
|
13728
|
+
outputTokens: "completion_tokens",
|
|
13729
|
+
totalTokens: "tokens",
|
|
13730
|
+
prompt_tokens: "prompt_tokens",
|
|
13731
|
+
input_tokens: "prompt_tokens",
|
|
13732
|
+
completion_tokens: "completion_tokens",
|
|
13733
|
+
output_tokens: "completion_tokens",
|
|
13734
|
+
total_tokens: "tokens"
|
|
13735
|
+
};
|
|
13736
|
+
var TOKEN_DETAIL_PREFIX_MAP = {
|
|
13737
|
+
promptTokensDetails: "prompt",
|
|
13738
|
+
inputTokensDetails: "prompt",
|
|
13739
|
+
completionTokensDetails: "completion",
|
|
13740
|
+
outputTokensDetails: "completion",
|
|
13741
|
+
costDetails: "cost",
|
|
13742
|
+
prompt_tokens_details: "prompt",
|
|
13743
|
+
input_tokens_details: "prompt",
|
|
13744
|
+
completion_tokens_details: "completion",
|
|
13745
|
+
output_tokens_details: "completion",
|
|
13746
|
+
cost_details: "cost"
|
|
13747
|
+
};
|
|
13748
|
+
function camelToSnake(value) {
|
|
13749
|
+
return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
|
|
13750
|
+
}
|
|
13751
|
+
function parseOpenRouterMetricsFromUsage(usage) {
|
|
13752
|
+
if (!isObject(usage)) {
|
|
13753
|
+
return {};
|
|
13754
|
+
}
|
|
13541
13755
|
const metrics = {};
|
|
13542
|
-
const
|
|
13543
|
-
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
|
|
13548
|
-
|
|
13549
|
-
|
|
13756
|
+
for (const [name, value] of Object.entries(usage)) {
|
|
13757
|
+
if (typeof value === "number") {
|
|
13758
|
+
metrics[TOKEN_NAME_MAP2[name] || camelToSnake(name)] = value;
|
|
13759
|
+
continue;
|
|
13760
|
+
}
|
|
13761
|
+
if (!isObject(value)) {
|
|
13762
|
+
continue;
|
|
13763
|
+
}
|
|
13764
|
+
const prefix = TOKEN_DETAIL_PREFIX_MAP[name];
|
|
13765
|
+
if (!prefix) {
|
|
13766
|
+
continue;
|
|
13767
|
+
}
|
|
13768
|
+
for (const [nestedName, nestedValue] of Object.entries(value)) {
|
|
13769
|
+
if (typeof nestedValue !== "number") {
|
|
13770
|
+
continue;
|
|
13771
|
+
}
|
|
13772
|
+
metrics[`${prefix}_${camelToSnake(nestedName)}`] = nestedValue;
|
|
13550
13773
|
}
|
|
13551
13774
|
}
|
|
13552
13775
|
return metrics;
|
|
13553
13776
|
}
|
|
13554
|
-
function
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
)
|
|
13777
|
+
function extractOpenRouterUsageMetadata(usage) {
|
|
13778
|
+
if (!isObject(usage)) {
|
|
13779
|
+
return void 0;
|
|
13780
|
+
}
|
|
13781
|
+
const metadata = {};
|
|
13782
|
+
if (typeof usage.isByok === "boolean") {
|
|
13783
|
+
metadata.is_byok = usage.isByok;
|
|
13784
|
+
} else if (typeof usage.is_byok === "boolean") {
|
|
13785
|
+
metadata.is_byok = usage.is_byok;
|
|
13786
|
+
}
|
|
13787
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
13560
13788
|
}
|
|
13561
|
-
|
|
13562
|
-
|
|
13563
|
-
|
|
13564
|
-
|
|
13565
|
-
|
|
13789
|
+
var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
|
|
13790
|
+
"execute",
|
|
13791
|
+
"render",
|
|
13792
|
+
"nextTurnParams",
|
|
13793
|
+
"requireApproval"
|
|
13794
|
+
]);
|
|
13795
|
+
function parseOpenRouterModelString(model) {
|
|
13796
|
+
if (typeof model !== "string") {
|
|
13797
|
+
return { model };
|
|
13566
13798
|
}
|
|
13567
|
-
|
|
13568
|
-
|
|
13569
|
-
|
|
13570
|
-
|
|
13571
|
-
|
|
13572
|
-
|
|
13573
|
-
|
|
13574
|
-
|
|
13575
|
-
...metadata,
|
|
13576
|
-
step: args.step,
|
|
13577
|
-
step_type: args.stepType
|
|
13578
|
-
}
|
|
13579
|
-
}
|
|
13580
|
-
});
|
|
13799
|
+
const slashIndex = model.indexOf("/");
|
|
13800
|
+
if (slashIndex > 0 && slashIndex < model.length - 1) {
|
|
13801
|
+
return {
|
|
13802
|
+
provider: model.substring(0, slashIndex),
|
|
13803
|
+
model: model.substring(slashIndex + 1)
|
|
13804
|
+
};
|
|
13805
|
+
}
|
|
13806
|
+
return { model };
|
|
13581
13807
|
}
|
|
13582
|
-
function
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13808
|
+
function isZodSchema3(value) {
|
|
13809
|
+
return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
|
|
13810
|
+
}
|
|
13811
|
+
function serializeZodSchema3(schema) {
|
|
13812
|
+
try {
|
|
13813
|
+
return zodToJsonSchema(schema);
|
|
13814
|
+
} catch {
|
|
13815
|
+
return {
|
|
13816
|
+
type: "object",
|
|
13817
|
+
description: "Zod schema (conversion failed)"
|
|
13818
|
+
};
|
|
13586
13819
|
}
|
|
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
13820
|
}
|
|
13600
|
-
function
|
|
13601
|
-
if (isObject(
|
|
13602
|
-
return
|
|
13821
|
+
function serializeOpenRouterTool(tool) {
|
|
13822
|
+
if (!isObject(tool)) {
|
|
13823
|
+
return tool;
|
|
13603
13824
|
}
|
|
13604
|
-
|
|
13825
|
+
const serialized = {};
|
|
13826
|
+
for (const [key, value] of Object.entries(tool)) {
|
|
13827
|
+
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
13828
|
+
continue;
|
|
13829
|
+
}
|
|
13830
|
+
if (key === "function" && isObject(value)) {
|
|
13831
|
+
serialized.function = sanitizeOpenRouterLoggedValue(value);
|
|
13832
|
+
continue;
|
|
13833
|
+
}
|
|
13834
|
+
serialized[key] = sanitizeOpenRouterLoggedValue(value);
|
|
13835
|
+
}
|
|
13836
|
+
return serialized;
|
|
13605
13837
|
}
|
|
13606
|
-
function
|
|
13607
|
-
if (!
|
|
13838
|
+
function serializeOpenRouterToolsForLogging(tools) {
|
|
13839
|
+
if (!Array.isArray(tools)) {
|
|
13608
13840
|
return void 0;
|
|
13609
13841
|
}
|
|
13610
|
-
return
|
|
13611
|
-
...request,
|
|
13612
|
-
input: buildNextOpenRouterCallModelInput(
|
|
13613
|
-
extractOpenRouterCallModelInput(request),
|
|
13614
|
-
isObject(currentResponse) ? currentResponse : {},
|
|
13615
|
-
toolResults
|
|
13616
|
-
),
|
|
13617
|
-
stream: false
|
|
13618
|
-
};
|
|
13842
|
+
return tools.map((tool) => serializeOpenRouterTool(tool));
|
|
13619
13843
|
}
|
|
13620
|
-
function
|
|
13621
|
-
|
|
13622
|
-
|
|
13623
|
-
|
|
13624
|
-
|
|
13625
|
-
|
|
13626
|
-
|
|
13627
|
-
|
|
13628
|
-
|
|
13629
|
-
|
|
13630
|
-
|
|
13631
|
-
|
|
13632
|
-
|
|
13633
|
-
|
|
13634
|
-
|
|
13635
|
-
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
|
|
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;
|
|
13657
|
-
}
|
|
13658
|
-
);
|
|
13659
|
-
},
|
|
13660
|
-
throw(error) {
|
|
13661
|
-
args.onError(error);
|
|
13662
|
-
if (typeof iterator.throw !== "function") {
|
|
13663
|
-
return Promise.reject(error);
|
|
13664
|
-
}
|
|
13665
|
-
return withCurrent(args.span, () => iterator.throw(error));
|
|
13666
|
-
},
|
|
13667
|
-
[Symbol.asyncIterator]() {
|
|
13668
|
-
return this;
|
|
13669
|
-
}
|
|
13670
|
-
};
|
|
13844
|
+
function sanitizeOpenRouterLoggedValue(value) {
|
|
13845
|
+
if (isZodSchema3(value)) {
|
|
13846
|
+
return serializeZodSchema3(value);
|
|
13847
|
+
}
|
|
13848
|
+
if (typeof value === "function") {
|
|
13849
|
+
return "[Function]";
|
|
13850
|
+
}
|
|
13851
|
+
if (Array.isArray(value)) {
|
|
13852
|
+
return value.map((entry) => sanitizeOpenRouterLoggedValue(entry));
|
|
13853
|
+
}
|
|
13854
|
+
if (!isObject(value)) {
|
|
13855
|
+
return value;
|
|
13856
|
+
}
|
|
13857
|
+
const sanitized = {};
|
|
13858
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
13859
|
+
if (OMITTED_OPENROUTER_KEYS.has(key)) {
|
|
13860
|
+
continue;
|
|
13861
|
+
}
|
|
13862
|
+
if (key === "tools" && Array.isArray(entry)) {
|
|
13863
|
+
sanitized.tools = serializeOpenRouterToolsForLogging(entry);
|
|
13864
|
+
continue;
|
|
13671
13865
|
}
|
|
13866
|
+
sanitized[key] = sanitizeOpenRouterLoggedValue(entry);
|
|
13867
|
+
}
|
|
13868
|
+
return sanitized;
|
|
13869
|
+
}
|
|
13870
|
+
function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
|
|
13871
|
+
const sanitized = sanitizeOpenRouterLoggedValue(metadata);
|
|
13872
|
+
const metadataRecord = isObject(sanitized) ? sanitized : {};
|
|
13873
|
+
const { model, provider: providerRouting, ...rest } = metadataRecord;
|
|
13874
|
+
const normalizedModel = parseOpenRouterModelString(model);
|
|
13875
|
+
return {
|
|
13876
|
+
...rest,
|
|
13877
|
+
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
13878
|
+
...providerRouting !== void 0 ? { providerRouting } : {},
|
|
13879
|
+
...httpReferer !== void 0 ? { httpReferer } : {},
|
|
13880
|
+
...xTitle !== void 0 ? { xTitle } : {},
|
|
13881
|
+
provider: normalizedModel.provider || "openrouter"
|
|
13672
13882
|
};
|
|
13673
13883
|
}
|
|
13674
|
-
function
|
|
13675
|
-
|
|
13884
|
+
function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
|
|
13885
|
+
const normalized = buildOpenRouterMetadata(metadata, httpReferer, xTitle);
|
|
13886
|
+
return typeof normalized.model === "string" ? {
|
|
13887
|
+
...normalized,
|
|
13888
|
+
embedding_model: normalized.model
|
|
13889
|
+
} : normalized;
|
|
13676
13890
|
}
|
|
13677
|
-
function
|
|
13678
|
-
return
|
|
13891
|
+
function extractOpenRouterCallModelInput(request) {
|
|
13892
|
+
return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue(request.input) : void 0;
|
|
13679
13893
|
}
|
|
13680
|
-
function
|
|
13681
|
-
|
|
13894
|
+
function extractOpenRouterCallModelMetadata(request) {
|
|
13895
|
+
if (!isObject(request)) {
|
|
13896
|
+
return { provider: "openrouter" };
|
|
13897
|
+
}
|
|
13898
|
+
const { input: _input, ...metadata } = request;
|
|
13899
|
+
return buildOpenRouterMetadata(metadata, void 0, void 0);
|
|
13682
13900
|
}
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
onEnable() {
|
|
13687
|
-
this.subscribeToOpenRouterChannels();
|
|
13901
|
+
function extractOpenRouterResponseMetadata(result) {
|
|
13902
|
+
if (!isObject(result)) {
|
|
13903
|
+
return void 0;
|
|
13688
13904
|
}
|
|
13689
|
-
|
|
13690
|
-
|
|
13905
|
+
const { output: _output, data: _data, usage, ...metadata } = result;
|
|
13906
|
+
const sanitized = sanitizeOpenRouterLoggedValue(metadata);
|
|
13907
|
+
const metadataRecord = isObject(sanitized) ? sanitized : {};
|
|
13908
|
+
const { model, provider, ...rest } = metadataRecord;
|
|
13909
|
+
const normalizedModel = parseOpenRouterModelString(model);
|
|
13910
|
+
const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
|
|
13911
|
+
const usageMetadata = extractOpenRouterUsageMetadata(usage);
|
|
13912
|
+
const combined = {
|
|
13913
|
+
...rest,
|
|
13914
|
+
...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
|
|
13915
|
+
...usageMetadata || {},
|
|
13916
|
+
...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
|
|
13917
|
+
};
|
|
13918
|
+
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
13919
|
+
}
|
|
13920
|
+
function extractOpenRouterResponseOutput(response, fallbackOutput) {
|
|
13921
|
+
if (isObject(response) && "output" in response && response.output !== void 0) {
|
|
13922
|
+
return sanitizeOpenRouterLoggedValue(response.output);
|
|
13691
13923
|
}
|
|
13692
|
-
|
|
13693
|
-
|
|
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) : {};
|
|
13755
|
-
}
|
|
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);
|
|
13833
|
-
}
|
|
13834
|
-
};
|
|
13835
|
-
callModelChannel.subscribe(callModelHandlers);
|
|
13836
|
-
this.unsubscribers.push(() => {
|
|
13837
|
-
callModelChannel.unsubscribe(callModelHandlers);
|
|
13838
|
-
});
|
|
13924
|
+
if (fallbackOutput !== void 0) {
|
|
13925
|
+
return sanitizeOpenRouterLoggedValue(fallbackOutput);
|
|
13839
13926
|
}
|
|
13840
|
-
|
|
13841
|
-
|
|
13842
|
-
|
|
13843
|
-
|
|
13927
|
+
return void 0;
|
|
13928
|
+
}
|
|
13929
|
+
var OPENROUTER_WRAPPED_TOOL = Symbol("braintrust.openrouter.wrappedTool");
|
|
13930
|
+
function patchOpenRouterCallModelRequestTools(request) {
|
|
13931
|
+
if (!Array.isArray(request.tools) || request.tools.length === 0) {
|
|
13932
|
+
return void 0;
|
|
13844
13933
|
}
|
|
13845
|
-
|
|
13846
|
-
|
|
13934
|
+
const originalTools = request.tools;
|
|
13935
|
+
const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
|
|
13936
|
+
const didPatch = wrappedTools.some(
|
|
13937
|
+
(tool, index) => tool !== originalTools[index]
|
|
13938
|
+
);
|
|
13939
|
+
if (!didPatch) {
|
|
13940
|
+
return void 0;
|
|
13941
|
+
}
|
|
13942
|
+
request.tools = wrappedTools;
|
|
13943
|
+
return () => {
|
|
13944
|
+
request.tools = originalTools;
|
|
13945
|
+
};
|
|
13946
|
+
}
|
|
13947
|
+
function wrapOpenRouterTool(tool) {
|
|
13948
|
+
if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
|
|
13949
|
+
return tool;
|
|
13950
|
+
}
|
|
13951
|
+
const toolName = tool.function.name || "tool";
|
|
13952
|
+
const originalExecute = tool.function.execute;
|
|
13953
|
+
const wrappedTool = {
|
|
13954
|
+
...tool,
|
|
13955
|
+
function: {
|
|
13956
|
+
...tool.function,
|
|
13957
|
+
execute(...args) {
|
|
13958
|
+
return traceToolExecution({
|
|
13959
|
+
args,
|
|
13960
|
+
execute: () => Reflect.apply(originalExecute, this, args),
|
|
13961
|
+
toolCallId: getToolCallId(args[1]),
|
|
13962
|
+
toolName
|
|
13963
|
+
});
|
|
13964
|
+
}
|
|
13965
|
+
}
|
|
13966
|
+
};
|
|
13967
|
+
Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL, {
|
|
13968
|
+
value: true,
|
|
13969
|
+
enumerable: false,
|
|
13970
|
+
configurable: false
|
|
13971
|
+
});
|
|
13972
|
+
return wrappedTool;
|
|
13973
|
+
}
|
|
13974
|
+
function isWrappedTool(tool) {
|
|
13975
|
+
return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
|
|
13976
|
+
}
|
|
13977
|
+
function traceToolExecution(args) {
|
|
13978
|
+
const tracingChannel2 = openRouterChannels.toolExecute.tracingChannel();
|
|
13979
|
+
const input = args.args.length > 0 ? args.args[0] : void 0;
|
|
13980
|
+
const event = {
|
|
13981
|
+
arguments: [input],
|
|
13982
|
+
span_info: {
|
|
13983
|
+
name: args.toolName
|
|
13984
|
+
},
|
|
13985
|
+
toolCallId: args.toolCallId,
|
|
13986
|
+
toolName: args.toolName
|
|
13987
|
+
};
|
|
13988
|
+
tracingChannel2.start.publish(event);
|
|
13989
|
+
try {
|
|
13990
|
+
const result = args.execute();
|
|
13991
|
+
return publishToolResult(tracingChannel2, event, result);
|
|
13992
|
+
} catch (error) {
|
|
13993
|
+
event.error = normalizeError(error);
|
|
13994
|
+
tracingChannel2.error.publish(event);
|
|
13995
|
+
throw error;
|
|
13847
13996
|
}
|
|
13848
|
-
return [args];
|
|
13849
|
-
}
|
|
13850
|
-
function isArrayLike(value) {
|
|
13851
|
-
return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
|
|
13852
13997
|
}
|
|
13853
|
-
function
|
|
13854
|
-
|
|
13855
|
-
|
|
13856
|
-
|
|
13857
|
-
|
|
13858
|
-
|
|
13859
|
-
|
|
13998
|
+
function publishToolResult(tracingChannel2, event, result) {
|
|
13999
|
+
if (isPromiseLike2(result)) {
|
|
14000
|
+
return result.then(
|
|
14001
|
+
(resolved) => {
|
|
14002
|
+
event.result = resolved;
|
|
14003
|
+
tracingChannel2.asyncEnd.publish(event);
|
|
14004
|
+
return resolved;
|
|
14005
|
+
},
|
|
14006
|
+
(error) => {
|
|
14007
|
+
event.error = normalizeError(error);
|
|
14008
|
+
tracingChannel2.error.publish(event);
|
|
14009
|
+
throw error;
|
|
14010
|
+
}
|
|
14011
|
+
);
|
|
13860
14012
|
}
|
|
13861
|
-
|
|
13862
|
-
|
|
14013
|
+
event.result = result;
|
|
14014
|
+
tracingChannel2.asyncEnd.publish(event);
|
|
14015
|
+
return result;
|
|
13863
14016
|
}
|
|
13864
|
-
function
|
|
13865
|
-
const
|
|
13866
|
-
return
|
|
14017
|
+
function getToolCallId(context) {
|
|
14018
|
+
const toolContext = context;
|
|
14019
|
+
return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
|
|
14020
|
+
}
|
|
14021
|
+
function isPromiseLike2(value) {
|
|
14022
|
+
return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
|
|
13867
14023
|
}
|
|
13868
14024
|
function aggregateOpenRouterChatChunks(chunks) {
|
|
13869
14025
|
let role;
|
|
@@ -13884,95 +14040,438 @@ function aggregateOpenRouterChatChunks(chunks) {
|
|
|
13884
14040
|
}
|
|
13885
14041
|
continue;
|
|
13886
14042
|
}
|
|
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) {
|
|
14043
|
+
if (!role && delta.role) {
|
|
14044
|
+
role = delta.role;
|
|
14045
|
+
}
|
|
14046
|
+
if (typeof delta.content === "string") {
|
|
14047
|
+
content += delta.content;
|
|
14048
|
+
}
|
|
14049
|
+
const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
|
|
14050
|
+
const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
|
|
14051
|
+
if (choiceFinishReason !== void 0) {
|
|
14052
|
+
finishReason = choiceFinishReason;
|
|
14053
|
+
} else if (deltaFinishReason !== void 0) {
|
|
14054
|
+
finishReason = deltaFinishReason;
|
|
14055
|
+
}
|
|
14056
|
+
const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
|
|
14057
|
+
if (!toolCallDeltas) {
|
|
14058
|
+
continue;
|
|
14059
|
+
}
|
|
14060
|
+
for (const toolDelta of toolCallDeltas) {
|
|
14061
|
+
if (!toolDelta?.function) {
|
|
14062
|
+
continue;
|
|
14063
|
+
}
|
|
14064
|
+
const toolIndex = toolDelta.index ?? 0;
|
|
14065
|
+
const existingToolCall = toolCalls?.[toolIndex];
|
|
14066
|
+
if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
|
|
14067
|
+
const nextToolCalls = [...toolCalls || []];
|
|
14068
|
+
nextToolCalls[toolIndex] = {
|
|
14069
|
+
index: toolIndex,
|
|
14070
|
+
id: toolDelta.id,
|
|
14071
|
+
type: toolDelta.type,
|
|
14072
|
+
function: {
|
|
14073
|
+
name: toolDelta.function.name,
|
|
14074
|
+
arguments: toolDelta.function.arguments || ""
|
|
14075
|
+
}
|
|
14076
|
+
};
|
|
14077
|
+
toolCalls = nextToolCalls;
|
|
14078
|
+
continue;
|
|
14079
|
+
}
|
|
14080
|
+
const current = existingToolCall;
|
|
14081
|
+
if (toolDelta.id && !current.id) {
|
|
14082
|
+
current.id = toolDelta.id;
|
|
14083
|
+
}
|
|
14084
|
+
if (toolDelta.type && !current.type) {
|
|
14085
|
+
current.type = toolDelta.type;
|
|
14086
|
+
}
|
|
14087
|
+
if (toolDelta.function.name && !current.function.name) {
|
|
14088
|
+
current.function.name = toolDelta.function.name;
|
|
14089
|
+
}
|
|
14090
|
+
current.function.arguments += toolDelta.function.arguments || "";
|
|
14091
|
+
}
|
|
14092
|
+
}
|
|
14093
|
+
return {
|
|
14094
|
+
output: [
|
|
14095
|
+
{
|
|
14096
|
+
index: 0,
|
|
14097
|
+
message: {
|
|
14098
|
+
role,
|
|
14099
|
+
content: content || void 0,
|
|
14100
|
+
...toolCalls ? { tool_calls: toolCalls } : {}
|
|
14101
|
+
},
|
|
14102
|
+
logprobs: null,
|
|
14103
|
+
finish_reason: finishReason
|
|
14104
|
+
}
|
|
14105
|
+
],
|
|
14106
|
+
metrics
|
|
14107
|
+
};
|
|
14108
|
+
}
|
|
14109
|
+
function aggregateOpenRouterResponseStreamEvents(chunks) {
|
|
14110
|
+
let finalResponse;
|
|
14111
|
+
for (const chunk of chunks) {
|
|
14112
|
+
const response = chunk?.response;
|
|
14113
|
+
if (!response) {
|
|
14114
|
+
continue;
|
|
14115
|
+
}
|
|
14116
|
+
if (chunk.type === "response.completed" || chunk.type === "response.incomplete" || chunk.type === "response.failed") {
|
|
14117
|
+
finalResponse = response;
|
|
14118
|
+
}
|
|
14119
|
+
}
|
|
14120
|
+
if (!finalResponse) {
|
|
14121
|
+
return {
|
|
14122
|
+
output: void 0,
|
|
14123
|
+
metrics: {}
|
|
14124
|
+
};
|
|
14125
|
+
}
|
|
14126
|
+
return {
|
|
14127
|
+
output: extractOpenRouterResponseOutput(finalResponse),
|
|
14128
|
+
metrics: parseOpenRouterMetricsFromUsage(finalResponse.usage),
|
|
14129
|
+
...extractOpenRouterResponseMetadata(finalResponse) ? { metadata: extractOpenRouterResponseMetadata(finalResponse) } : {}
|
|
14130
|
+
};
|
|
14131
|
+
}
|
|
14132
|
+
var OPENROUTER_WRAPPED_CALL_MODEL_RESULT = Symbol(
|
|
14133
|
+
"braintrust.openrouter.wrappedCallModelResult"
|
|
14134
|
+
);
|
|
14135
|
+
var OPENROUTER_CALL_MODEL_STREAM_METHODS = [
|
|
14136
|
+
"getFullResponsesStream",
|
|
14137
|
+
"getItemsStream",
|
|
14138
|
+
"getNewMessagesStream",
|
|
14139
|
+
"getReasoningStream",
|
|
14140
|
+
"getTextStream",
|
|
14141
|
+
"getToolCallsStream",
|
|
14142
|
+
"getToolStream"
|
|
14143
|
+
];
|
|
14144
|
+
var OPENROUTER_CALL_MODEL_CONTEXT_METHODS = [
|
|
14145
|
+
"cancel",
|
|
14146
|
+
"getPendingToolCalls",
|
|
14147
|
+
"getState",
|
|
14148
|
+
"getToolCalls",
|
|
14149
|
+
"requiresApproval"
|
|
14150
|
+
];
|
|
14151
|
+
function patchOpenRouterCallModelResult(args) {
|
|
14152
|
+
const { request, result, span } = args;
|
|
14153
|
+
if (!isObject(result) || isWrappedCallModelResult(result)) {
|
|
14154
|
+
return false;
|
|
14155
|
+
}
|
|
14156
|
+
const resultLike = result;
|
|
14157
|
+
const hasInstrumentableMethod = typeof resultLike.getResponse === "function" || typeof resultLike.getText === "function" || OPENROUTER_CALL_MODEL_STREAM_METHODS.some(
|
|
14158
|
+
(methodName) => typeof resultLike[methodName] === "function"
|
|
14159
|
+
);
|
|
14160
|
+
if (!hasInstrumentableMethod) {
|
|
14161
|
+
return false;
|
|
14162
|
+
}
|
|
14163
|
+
Object.defineProperty(resultLike, OPENROUTER_WRAPPED_CALL_MODEL_RESULT, {
|
|
14164
|
+
value: true,
|
|
14165
|
+
enumerable: false,
|
|
14166
|
+
configurable: false
|
|
14167
|
+
});
|
|
14168
|
+
const originalGetResponse = typeof resultLike.getResponse === "function" ? resultLike.getResponse.bind(resultLike) : void 0;
|
|
14169
|
+
const originalGetInitialResponse = typeof resultLike.getInitialResponse === "function" ? resultLike.getInitialResponse.bind(resultLike) : void 0;
|
|
14170
|
+
const originalMakeFollowupRequest = typeof resultLike.makeFollowupRequest === "function" ? resultLike.makeFollowupRequest.bind(resultLike) : void 0;
|
|
14171
|
+
let ended = false;
|
|
14172
|
+
let tracedTurnCount = 0;
|
|
14173
|
+
const endSpanWithResult = async (response, fallbackOutput) => {
|
|
14174
|
+
if (ended) {
|
|
14175
|
+
return;
|
|
14176
|
+
}
|
|
14177
|
+
ended = true;
|
|
14178
|
+
const finalResponse = getFinalOpenRouterCallModelResponse(
|
|
14179
|
+
resultLike,
|
|
14180
|
+
response
|
|
14181
|
+
);
|
|
14182
|
+
if (finalResponse) {
|
|
14183
|
+
const rounds = getOpenRouterCallModelRounds(resultLike);
|
|
14184
|
+
const metadata = extractOpenRouterCallModelResultMetadata(
|
|
14185
|
+
finalResponse,
|
|
14186
|
+
rounds.length + 1
|
|
14187
|
+
);
|
|
14188
|
+
span.log({
|
|
14189
|
+
output: extractOpenRouterResponseOutput(finalResponse, fallbackOutput),
|
|
14190
|
+
...metadata ? { metadata } : {},
|
|
14191
|
+
metrics: aggregateOpenRouterCallModelMetrics(rounds, finalResponse)
|
|
14192
|
+
});
|
|
14193
|
+
span.end();
|
|
14194
|
+
return;
|
|
14195
|
+
}
|
|
14196
|
+
if (fallbackOutput !== void 0) {
|
|
14197
|
+
span.log({
|
|
14198
|
+
output: fallbackOutput
|
|
14199
|
+
});
|
|
14200
|
+
}
|
|
14201
|
+
span.end();
|
|
14202
|
+
};
|
|
14203
|
+
const endSpanWithError = (error) => {
|
|
14204
|
+
if (ended) {
|
|
14205
|
+
return;
|
|
14206
|
+
}
|
|
14207
|
+
ended = true;
|
|
14208
|
+
span.log({
|
|
14209
|
+
error: normalizeError(error).message
|
|
14210
|
+
});
|
|
14211
|
+
span.end();
|
|
14212
|
+
};
|
|
14213
|
+
const finalizeFromResponse = async (fallbackOutput) => {
|
|
14214
|
+
if (!originalGetResponse) {
|
|
14215
|
+
await endSpanWithResult(void 0, fallbackOutput);
|
|
14216
|
+
return;
|
|
14217
|
+
}
|
|
14218
|
+
try {
|
|
14219
|
+
await endSpanWithResult(await originalGetResponse(), fallbackOutput);
|
|
14220
|
+
} catch {
|
|
14221
|
+
await endSpanWithResult(void 0, fallbackOutput);
|
|
14222
|
+
}
|
|
14223
|
+
};
|
|
14224
|
+
if (originalGetResponse) {
|
|
14225
|
+
resultLike.getResponse = async (...args2) => {
|
|
14226
|
+
return await withCurrent(span, async () => {
|
|
14227
|
+
try {
|
|
14228
|
+
const response = await originalGetResponse(...args2);
|
|
14229
|
+
await endSpanWithResult(response);
|
|
14230
|
+
return response;
|
|
14231
|
+
} catch (error) {
|
|
14232
|
+
endSpanWithError(error);
|
|
14233
|
+
throw error;
|
|
14234
|
+
}
|
|
14235
|
+
});
|
|
14236
|
+
};
|
|
14237
|
+
}
|
|
14238
|
+
if (typeof resultLike.getText === "function") {
|
|
14239
|
+
const originalGetText = resultLike.getText.bind(resultLike);
|
|
14240
|
+
resultLike.getText = async (...args2) => {
|
|
14241
|
+
return await withCurrent(span, async () => {
|
|
14242
|
+
try {
|
|
14243
|
+
const text = await originalGetText(...args2);
|
|
14244
|
+
await finalizeFromResponse(text);
|
|
14245
|
+
return text;
|
|
14246
|
+
} catch (error) {
|
|
14247
|
+
endSpanWithError(error);
|
|
14248
|
+
throw error;
|
|
14249
|
+
}
|
|
14250
|
+
});
|
|
14251
|
+
};
|
|
14252
|
+
}
|
|
14253
|
+
for (const methodName of OPENROUTER_CALL_MODEL_CONTEXT_METHODS) {
|
|
14254
|
+
if (typeof resultLike[methodName] !== "function") {
|
|
14255
|
+
continue;
|
|
14256
|
+
}
|
|
14257
|
+
const originalMethod = resultLike[methodName];
|
|
14258
|
+
resultLike[methodName] = async (...args2) => {
|
|
14259
|
+
return await withCurrent(span, async () => {
|
|
14260
|
+
return await originalMethod.apply(resultLike, args2);
|
|
14261
|
+
});
|
|
14262
|
+
};
|
|
14263
|
+
}
|
|
14264
|
+
for (const methodName of OPENROUTER_CALL_MODEL_STREAM_METHODS) {
|
|
14265
|
+
if (typeof resultLike[methodName] !== "function") {
|
|
13902
14266
|
continue;
|
|
13903
14267
|
}
|
|
13904
|
-
|
|
13905
|
-
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
if (!
|
|
13911
|
-
|
|
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;
|
|
14268
|
+
const originalMethod = resultLike[methodName];
|
|
14269
|
+
resultLike[methodName] = (...args2) => {
|
|
14270
|
+
const stream = withCurrent(
|
|
14271
|
+
span,
|
|
14272
|
+
() => originalMethod.apply(resultLike, args2)
|
|
14273
|
+
);
|
|
14274
|
+
if (!isAsyncIterable2(stream)) {
|
|
14275
|
+
return stream;
|
|
13930
14276
|
}
|
|
13931
|
-
|
|
13932
|
-
|
|
14277
|
+
return wrapAsyncIterableWithSpan({
|
|
14278
|
+
finalize: finalizeFromResponse,
|
|
14279
|
+
iteratorFactory: () => stream[Symbol.asyncIterator](),
|
|
14280
|
+
onError: endSpanWithError,
|
|
14281
|
+
span
|
|
14282
|
+
});
|
|
14283
|
+
};
|
|
14284
|
+
}
|
|
14285
|
+
if (originalGetInitialResponse) {
|
|
14286
|
+
let initialTurnTraced = false;
|
|
14287
|
+
resultLike.getInitialResponse = async (...args2) => {
|
|
14288
|
+
if (initialTurnTraced) {
|
|
14289
|
+
return await withCurrent(span, async () => {
|
|
14290
|
+
return await originalGetInitialResponse(...args2);
|
|
14291
|
+
});
|
|
13933
14292
|
}
|
|
13934
|
-
|
|
13935
|
-
|
|
14293
|
+
initialTurnTraced = true;
|
|
14294
|
+
const step = tracedTurnCount + 1;
|
|
14295
|
+
const stepType = tracedTurnCount === 0 ? "initial" : "continue";
|
|
14296
|
+
const response = await traceOpenRouterCallModelTurn({
|
|
14297
|
+
fn: async () => {
|
|
14298
|
+
const nextResponse = await originalGetInitialResponse(...args2);
|
|
14299
|
+
tracedTurnCount++;
|
|
14300
|
+
return nextResponse;
|
|
14301
|
+
},
|
|
14302
|
+
parentSpan: span,
|
|
14303
|
+
request: getOpenRouterResolvedRequest(resultLike, request),
|
|
14304
|
+
step,
|
|
14305
|
+
stepType
|
|
14306
|
+
});
|
|
14307
|
+
return response;
|
|
14308
|
+
};
|
|
13936
14309
|
}
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
13941
|
-
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
|
|
14310
|
+
if (originalMakeFollowupRequest) {
|
|
14311
|
+
resultLike.makeFollowupRequest = async (...args2) => {
|
|
14312
|
+
const currentResponse = args2[0];
|
|
14313
|
+
const toolResults = Array.isArray(args2[1]) ? args2[1] : [];
|
|
14314
|
+
const step = tracedTurnCount + 1;
|
|
14315
|
+
const response = await traceOpenRouterCallModelTurn({
|
|
14316
|
+
fn: async () => {
|
|
14317
|
+
const nextResponse = await originalMakeFollowupRequest(...args2);
|
|
14318
|
+
tracedTurnCount++;
|
|
14319
|
+
return nextResponse;
|
|
13945
14320
|
},
|
|
13946
|
-
|
|
13947
|
-
|
|
13948
|
-
|
|
13949
|
-
|
|
13950
|
-
|
|
14321
|
+
parentSpan: span,
|
|
14322
|
+
request: buildOpenRouterFollowupRequest(
|
|
14323
|
+
getOpenRouterResolvedRequest(resultLike, request),
|
|
14324
|
+
currentResponse,
|
|
14325
|
+
toolResults
|
|
14326
|
+
),
|
|
14327
|
+
step,
|
|
14328
|
+
stepType: "continue"
|
|
14329
|
+
});
|
|
14330
|
+
return response;
|
|
14331
|
+
};
|
|
14332
|
+
}
|
|
14333
|
+
return true;
|
|
14334
|
+
}
|
|
14335
|
+
async function traceOpenRouterCallModelTurn(args) {
|
|
14336
|
+
const context = {
|
|
14337
|
+
arguments: [args.request],
|
|
14338
|
+
step: args.step,
|
|
14339
|
+
stepType: args.stepType
|
|
13951
14340
|
};
|
|
14341
|
+
return await withCurrent(
|
|
14342
|
+
args.parentSpan,
|
|
14343
|
+
() => openRouterChannels.callModelTurn.tracePromise(args.fn, context)
|
|
14344
|
+
);
|
|
13952
14345
|
}
|
|
13953
|
-
function
|
|
13954
|
-
|
|
13955
|
-
|
|
13956
|
-
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
|
|
13960
|
-
|
|
13961
|
-
|
|
14346
|
+
function isWrappedCallModelResult(value) {
|
|
14347
|
+
return Boolean(
|
|
14348
|
+
isObject(value) && value[OPENROUTER_WRAPPED_CALL_MODEL_RESULT]
|
|
14349
|
+
);
|
|
14350
|
+
}
|
|
14351
|
+
function extractOpenRouterCallModelResultMetadata(response, turnCount) {
|
|
14352
|
+
const combined = {
|
|
14353
|
+
...extractOpenRouterResponseMetadata(response) || {},
|
|
14354
|
+
...turnCount !== void 0 ? { turn_count: turnCount } : {}
|
|
14355
|
+
};
|
|
14356
|
+
return Object.keys(combined).length > 0 ? combined : void 0;
|
|
14357
|
+
}
|
|
14358
|
+
function getFinalOpenRouterCallModelResponse(result, response) {
|
|
14359
|
+
if (isObject(response)) {
|
|
14360
|
+
return response;
|
|
14361
|
+
}
|
|
14362
|
+
return isObject(result.finalResponse) ? result.finalResponse : void 0;
|
|
14363
|
+
}
|
|
14364
|
+
function getOpenRouterCallModelRounds(result) {
|
|
14365
|
+
if (!Array.isArray(result.allToolExecutionRounds)) {
|
|
14366
|
+
return [];
|
|
14367
|
+
}
|
|
14368
|
+
return result.allToolExecutionRounds.filter((round) => isObject(round)).map((round) => ({
|
|
14369
|
+
response: isObject(round.response) ? round.response : void 0,
|
|
14370
|
+
round: typeof round.round === "number" ? round.round : void 0,
|
|
14371
|
+
toolResults: Array.isArray(round.toolResults) ? round.toolResults : []
|
|
14372
|
+
})).filter((round) => round.response !== void 0);
|
|
14373
|
+
}
|
|
14374
|
+
function aggregateOpenRouterCallModelMetrics(rounds, finalResponse) {
|
|
14375
|
+
const metrics = {};
|
|
14376
|
+
const responses = [
|
|
14377
|
+
...rounds.map((round) => round.response).filter(isObject),
|
|
14378
|
+
finalResponse
|
|
14379
|
+
];
|
|
14380
|
+
for (const response of responses) {
|
|
14381
|
+
const responseMetrics = parseOpenRouterMetricsFromUsage(response.usage);
|
|
14382
|
+
for (const [name, value] of Object.entries(responseMetrics)) {
|
|
14383
|
+
metrics[name] = (metrics[name] || 0) + value;
|
|
13962
14384
|
}
|
|
13963
14385
|
}
|
|
13964
|
-
|
|
13965
|
-
|
|
13966
|
-
|
|
13967
|
-
|
|
13968
|
-
|
|
14386
|
+
return metrics;
|
|
14387
|
+
}
|
|
14388
|
+
function buildNextOpenRouterCallModelInput(currentInput, response, toolResults) {
|
|
14389
|
+
const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
|
|
14390
|
+
const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
|
|
14391
|
+
return [...normalizedInput, ...responseOutput, ...toolResults].map(
|
|
14392
|
+
(entry) => sanitizeOpenRouterLoggedValue(entry)
|
|
14393
|
+
);
|
|
14394
|
+
}
|
|
14395
|
+
function getOpenRouterResolvedRequest(result, request) {
|
|
14396
|
+
if (isObject(result.resolvedRequest)) {
|
|
14397
|
+
return result.resolvedRequest;
|
|
14398
|
+
}
|
|
14399
|
+
return request;
|
|
14400
|
+
}
|
|
14401
|
+
function buildOpenRouterFollowupRequest(request, currentResponse, toolResults) {
|
|
14402
|
+
if (!request) {
|
|
14403
|
+
return void 0;
|
|
13969
14404
|
}
|
|
13970
14405
|
return {
|
|
13971
|
-
|
|
13972
|
-
|
|
13973
|
-
|
|
14406
|
+
...request,
|
|
14407
|
+
input: buildNextOpenRouterCallModelInput(
|
|
14408
|
+
extractOpenRouterCallModelInput(request),
|
|
14409
|
+
isObject(currentResponse) ? currentResponse : {},
|
|
14410
|
+
toolResults
|
|
14411
|
+
),
|
|
14412
|
+
stream: false
|
|
14413
|
+
};
|
|
14414
|
+
}
|
|
14415
|
+
function wrapAsyncIterableWithSpan(args) {
|
|
14416
|
+
return {
|
|
14417
|
+
[Symbol.asyncIterator]() {
|
|
14418
|
+
const iterator = args.iteratorFactory();
|
|
14419
|
+
return {
|
|
14420
|
+
next(value) {
|
|
14421
|
+
return withCurrent(
|
|
14422
|
+
args.span,
|
|
14423
|
+
() => value === void 0 ? iterator.next() : iterator.next(value)
|
|
14424
|
+
).then(
|
|
14425
|
+
async (result) => {
|
|
14426
|
+
if (result.done) {
|
|
14427
|
+
await args.finalize();
|
|
14428
|
+
}
|
|
14429
|
+
return result;
|
|
14430
|
+
},
|
|
14431
|
+
(error) => {
|
|
14432
|
+
args.onError(error);
|
|
14433
|
+
throw error;
|
|
14434
|
+
}
|
|
14435
|
+
);
|
|
14436
|
+
},
|
|
14437
|
+
return(value) {
|
|
14438
|
+
if (typeof iterator.return !== "function") {
|
|
14439
|
+
return args.finalize().then(() => ({
|
|
14440
|
+
done: true,
|
|
14441
|
+
value
|
|
14442
|
+
}));
|
|
14443
|
+
}
|
|
14444
|
+
return withCurrent(args.span, () => iterator.return(value)).then(
|
|
14445
|
+
async (result) => {
|
|
14446
|
+
await args.finalize();
|
|
14447
|
+
return result;
|
|
14448
|
+
},
|
|
14449
|
+
(error) => {
|
|
14450
|
+
args.onError(error);
|
|
14451
|
+
throw error;
|
|
14452
|
+
}
|
|
14453
|
+
);
|
|
14454
|
+
},
|
|
14455
|
+
throw(error) {
|
|
14456
|
+
args.onError(error);
|
|
14457
|
+
if (typeof iterator.throw !== "function") {
|
|
14458
|
+
return Promise.reject(error);
|
|
14459
|
+
}
|
|
14460
|
+
return withCurrent(args.span, () => iterator.throw(error));
|
|
14461
|
+
},
|
|
14462
|
+
[Symbol.asyncIterator]() {
|
|
14463
|
+
return this;
|
|
14464
|
+
}
|
|
14465
|
+
};
|
|
14466
|
+
}
|
|
13974
14467
|
};
|
|
13975
14468
|
}
|
|
14469
|
+
function isAsyncIterable2(value) {
|
|
14470
|
+
return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
14471
|
+
}
|
|
14472
|
+
function normalizeError(error) {
|
|
14473
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
14474
|
+
}
|
|
13976
14475
|
|
|
13977
14476
|
// src/instrumentation/braintrust-plugin.ts
|
|
13978
14477
|
var BraintrustPlugin = class extends BasePlugin {
|
|
@@ -15695,7 +16194,28 @@ function validateParametersWithJsonSchema(parameters, schema) {
|
|
|
15695
16194
|
}).join(", ");
|
|
15696
16195
|
throw Error(`Invalid parameters: ${errorMessages}`);
|
|
15697
16196
|
}
|
|
15698
|
-
return parameters;
|
|
16197
|
+
return rehydrateRemoteParameters(parameters, schema);
|
|
16198
|
+
}
|
|
16199
|
+
function rehydrateRemoteParameters(parameters, schema) {
|
|
16200
|
+
const schemaProperties = schema.properties;
|
|
16201
|
+
if (typeof schemaProperties !== "object" || schemaProperties === null) {
|
|
16202
|
+
return parameters;
|
|
16203
|
+
}
|
|
16204
|
+
return Object.fromEntries(
|
|
16205
|
+
Object.entries(parameters).map(([name, value]) => {
|
|
16206
|
+
const propertySchema = Reflect.get(schemaProperties, name);
|
|
16207
|
+
if (typeof propertySchema !== "object" || propertySchema === null) {
|
|
16208
|
+
return [name, value];
|
|
16209
|
+
}
|
|
16210
|
+
if (Reflect.get(propertySchema, "x-bt-type") === "prompt") {
|
|
16211
|
+
return [
|
|
16212
|
+
name,
|
|
16213
|
+
Prompt2.fromPromptData(name, PromptData.parse(value))
|
|
16214
|
+
];
|
|
16215
|
+
}
|
|
16216
|
+
return [name, value];
|
|
16217
|
+
})
|
|
16218
|
+
);
|
|
15699
16219
|
}
|
|
15700
16220
|
|
|
15701
16221
|
// src/framework.ts
|
|
@@ -16930,7 +17450,8 @@ var ScorerBuilder = class {
|
|
|
16930
17450
|
type: "llm_classifier",
|
|
16931
17451
|
use_cot: opts.useCot,
|
|
16932
17452
|
choice_scores: opts.choiceScores
|
|
16933
|
-
}
|
|
17453
|
+
},
|
|
17454
|
+
...opts.templateFormat ? { template_format: opts.templateFormat } : {}
|
|
16934
17455
|
};
|
|
16935
17456
|
const codePrompt = new CodePrompt(
|
|
16936
17457
|
this.project,
|