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.
Files changed (32) hide show
  1. package/dev/dist/index.js +1859 -1338
  2. package/dev/dist/index.mjs +1774 -1253
  3. package/dist/auto-instrumentations/bundler/esbuild.cjs +12 -15
  4. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  5. package/dist/auto-instrumentations/bundler/rollup.cjs +12 -15
  6. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  7. package/dist/auto-instrumentations/bundler/vite.cjs +12 -15
  8. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +12 -15
  10. package/dist/auto-instrumentations/bundler/webpack.cjs +12 -15
  11. package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
  12. package/dist/auto-instrumentations/{chunk-ZK2IYER2.mjs → chunk-NY4CGTN6.mjs} +1 -1
  13. package/dist/auto-instrumentations/{chunk-AKEXR4AL.mjs → chunk-YCKND42U.mjs} +12 -15
  14. package/dist/auto-instrumentations/hook.mjs +12 -15
  15. package/dist/auto-instrumentations/index.cjs +12 -15
  16. package/dist/auto-instrumentations/index.mjs +1 -1
  17. package/dist/browser.d.mts +8 -30
  18. package/dist/browser.d.ts +8 -30
  19. package/dist/browser.js +4836 -6828
  20. package/dist/browser.mjs +4836 -6828
  21. package/dist/cli.js +1507 -986
  22. package/dist/edge-light.js +9173 -11163
  23. package/dist/edge-light.mjs +9173 -11163
  24. package/dist/index.d.mts +8 -30
  25. package/dist/index.d.ts +8 -30
  26. package/dist/index.js +4747 -6739
  27. package/dist/index.mjs +4748 -6740
  28. package/dist/instrumentation/index.js +1735 -1236
  29. package/dist/instrumentation/index.mjs +1735 -1236
  30. package/dist/workerd.js +9173 -11163
  31. package/dist/workerd.mjs +9173 -11163
  32. package/package.json +2 -2
package/dev/dist/index.js 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 Promise.resolve(fn.apply(thisArg, args));
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
 
@@ -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
- if (_optionalChain([config, 'access', _154 => _154.patchResult, 'optionalCall', _155 => _155({
9647
- channelName,
9648
- endEvent,
9649
- result: endEvent.result,
9650
- span,
9651
- startTime
9652
- })])) {
9653
- return;
9654
- }
9655
- const stream = endEvent.result;
9656
- if (!isSyncStreamLike(stream)) {
9657
- span.end();
9658
- states.delete(event);
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 (_optionalChain([config, 'access', _154 => _154.patchResult, 'optionalCall', _155 => _155({
9662
+ channelName,
9663
+ endEvent: resolvedEndEvent,
9664
+ result,
9665
+ span,
9666
+ startTime
9667
+ })])) {
9668
+ return;
9684
9669
  }
9685
- });
9686
- stream.on("event", (streamEvent) => {
9687
- if (!config.extractFromEvent) {
9670
+ const stream = result;
9671
+ if (!isSyncStreamLike(stream)) {
9672
+ span.end();
9673
+ states.delete(event);
9688
9674
  return;
9689
9675
  }
9690
- try {
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
- const extracted = config.extractFromEvent(streamEvent);
9700
- if (extracted && Object.keys(extracted).length > 0) {
9701
- span.log(extracted);
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
- span.end();
9716
- states.delete(event);
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
- if (_optionalChain([event, 'access', _184 => _184.delta, 'optionalAccess', _185 => _185.type]) === "text_delta") {
10545
- const text = event.delta.text;
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 (contentBlocks[event.index] !== void 0 || contentBlockDeltas[event.index] !== void 0) {
10548
- contentBlockDeltas[event.index] ??= [];
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 (_optionalChain([event, 'access', _186 => _186.delta, 'optionalAccess', _187 => _187.type]) === "input_json_delta") {
10555
- const partialJson = event.delta.partial_json;
10556
- if (partialJson) {
10557
- contentBlockDeltas[event.index] ??= [];
10558
- contentBlockDeltas[event.index].push(partialJson);
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) => !_optionalChain([block, 'access', _184 => _184.citations, 'optionalAccess', _185 => _185.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 text = _nullishCoalesce(_optionalChain([contentBlockDeltas, 'access', _188 => _188[index], 'optionalAccess', _189 => _189.join, 'call', _190 => _190("")]), () => ( ""));
10642
+ const acc = contentBlockDeltas[index];
10643
+ const text = _nullishCoalesce(_optionalChain([acc, 'optionalAccess', _186 => _186.textDeltas, 'access', _187 => _187.join, 'call', _188 => _188("")]), () => ( ""));
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 (_optionalChain([acc, 'optionalAccess', _189 => _189.citations, 'access', _190 => _190.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
 
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(result, denyOutputPaths);
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(result, denyOutputPaths),
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(result, denyOutputPaths);
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(result, denyOutputPaths),
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(result, denyOutputPaths);
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(result, denyOutputPaths),
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(result, denyOutputPaths);
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(result, denyOutputPaths),
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,125 +11062,425 @@ var AISDKPlugin = class extends BasePlugin {
11039
11062
  );
11040
11063
  }
11041
11064
  };
11042
- function processAISDKInput(params) {
11043
- if (!params) return params;
11044
- const input = processInputAttachments(params);
11045
- if (!input || typeof input !== "object" || Array.isArray(input)) {
11046
- return input;
11065
+ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
11066
+ if (Array.isArray(_optionalChain([event, 'optionalAccess', _191 => _191.denyOutputPaths]))) {
11067
+ return event.denyOutputPaths;
11047
11068
  }
11048
- const { tools: _tools, ...rest } = input;
11049
- return rest;
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 = _optionalChain([event, 'optionalAccess', _192 => _192.arguments]) && event.arguments.length > 0 ? event.arguments[0] : void 0;
11070
+ if (!firstArgument || typeof firstArgument !== "object") {
11071
+ return defaultDenyOutputPaths;
11063
11072
  }
11064
- return {
11065
- input,
11066
- metadata
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 metrics;
11075
- }
11076
- function hasModelChildTracing(event) {
11077
- return _optionalChain([event, 'optionalAccess', _191 => _191.__braintrust_ai_sdk_model_wrapped]) === true;
11077
+ return defaultDenyOutputPaths;
11078
11078
  }
11079
- function extractMetadataFromParams(params, self) {
11080
- const metadata = {
11081
- braintrust: {
11082
- integration_name: "ai-sdk",
11083
- sdk_language: "typescript"
11084
- }
11085
- };
11086
- const agentModel = self && typeof self === "object" && "model" in self && self.model ? self.model : self && typeof self === "object" && "settings" in self && _optionalChain([self, 'access', _192 => _192.settings, 'optionalAccess', _193 => _193.model]) ? _optionalChain([self, 'access', _194 => _194.settings, 'optionalAccess', _195 => _195.model]) : void 0;
11087
- const { model, provider } = serializeModelWithProvider(
11088
- _nullishCoalesce(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 (e24) {
11086
+ return {
11087
+ type: "object",
11088
+ description: "Zod schema (conversion failed)"
11089
+ };
11092
11090
  }
11093
- if (provider) {
11094
- metadata.provider = provider;
11091
+ };
11092
+ var isOutputObject = (value) => {
11093
+ if (value == null || typeof value !== "object") {
11094
+ return false;
11095
11095
  }
11096
- const tools = serializeAISDKToolsForLogging(params.tools);
11097
- if (tools) {
11098
- metadata.tools = tools;
11096
+ const output = value;
11097
+ if (!("responseFormat" in output)) {
11098
+ return false;
11099
11099
  }
11100
- return metadata;
11101
- }
11102
- function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
11103
- const cleanup = [];
11104
- const patchedModels = /* @__PURE__ */ new WeakSet();
11105
- const patchedTools = /* @__PURE__ */ new WeakSet();
11106
- let modelWrapped = false;
11107
- const patchModel = (model) => {
11108
- const resolvedModel = resolveAISDKModel(model);
11109
- if (!resolvedModel || typeof resolvedModel !== "object" || typeof resolvedModel.doGenerate !== "function" || patchedModels.has(resolvedModel) || resolvedModel[AUTO_PATCHED_MODEL]) {
11110
- return;
11111
- }
11112
- patchedModels.add(resolvedModel);
11113
- resolvedModel[AUTO_PATCHED_MODEL] = true;
11114
- modelWrapped = true;
11115
- const originalDoGenerate = resolvedModel.doGenerate;
11116
- const originalDoStream = resolvedModel.doStream;
11117
- const baseMetadata = buildAISDKChildMetadata(resolvedModel);
11118
- resolvedModel.doGenerate = async function doGeneratePatched(options) {
11119
- return parentSpan.traced(
11120
- async (span) => {
11121
- const result = await Reflect.apply(
11122
- originalDoGenerate,
11123
- resolvedModel,
11124
- [options]
11125
- );
11126
- span.log({
11127
- output: processAISDKOutput(result, denyOutputPaths),
11128
- metrics: extractTokenMetrics(result),
11129
- ...buildResolvedMetadataPayload(result)
11130
- });
11131
- return result;
11132
- },
11133
- {
11134
- name: "doGenerate",
11135
- spanAttributes: {
11136
- type: "llm" /* LLM */
11137
- },
11138
- event: {
11139
- input: processAISDKInput(options),
11140
- metadata: baseMetadata
11141
- }
11142
- }
11143
- );
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
11144
11112
  };
11145
- if (originalDoStream) {
11146
- resolvedModel.doStream = async function doStreamPatched(options) {
11147
- const span = parentSpan.startSpan({
11148
- name: "doStream",
11149
- spanAttributes: {
11150
- type: "llm" /* LLM */
11151
- },
11152
- event: {
11153
- input: processAISDKInput(options),
11154
- metadata: baseMetadata
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;
11155
11137
  }
11156
- });
11157
- const result = await withCurrent(
11158
- span,
11159
- () => Reflect.apply(originalDoStream, resolvedModel, [options])
11160
11138
  );
11139
+ } else {
11140
+ const syncResponseFormat = responseFormat;
11141
+ if (syncResponseFormat.schema && isZodSchema2(syncResponseFormat.schema)) {
11142
+ responseFormat = {
11143
+ ...syncResponseFormat,
11144
+ schema: serializeZodSchema2(syncResponseFormat.schema)
11145
+ };
11146
+ }
11147
+ result.response_format = responseFormat;
11148
+ }
11149
+ }
11150
+ return result;
11151
+ } catch (e25) {
11152
+ return {
11153
+ response_format: null
11154
+ };
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 = _optionalChain([mimeTypeSection, 'access', _193 => _193.match, 'call', _194 => _194(/data:(.*?);/), 'optionalAccess', _195 => _195[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 _optionalChain([event, 'optionalAccess', _196 => _196.modelWrapped]) === true || _optionalChain([event, 'optionalAccess', _197 => _197.__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 && _optionalChain([self, 'access', _198 => _198.settings, 'optionalAccess', _199 => _199.model]) ? _optionalChain([self, 'access', _200 => _200.settings, 'optionalAccess', _201 => _201.model]) : void 0;
11408
+ const { model, provider } = serializeModelWithProvider(
11409
+ _nullishCoalesce(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",
11456
+ spanAttributes: {
11457
+ type: "llm" /* LLM */
11458
+ },
11459
+ event: {
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,
11475
+ metadata: baseMetadata
11476
+ }
11477
+ });
11478
+ const result = await withCurrent(
11479
+ span,
11480
+ () => Reflect.apply(originalDoStream, resolvedModel, [options])
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);
@@ -11185,9 +11511,9 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
11185
11511
  case "raw":
11186
11512
  if (chunk.rawValue) {
11187
11513
  const rawVal = chunk.rawValue;
11188
- if (_optionalChain([rawVal, 'access', _196 => _196.delta, 'optionalAccess', _197 => _197.content])) {
11514
+ if (_optionalChain([rawVal, 'access', _202 => _202.delta, 'optionalAccess', _203 => _203.content])) {
11189
11515
  text += rawVal.delta.content;
11190
- } else if (_optionalChain([rawVal, 'access', _198 => _198.choices, 'optionalAccess', _199 => _199[0], 'optionalAccess', _200 => _200.delta, 'optionalAccess', _201 => _201.content])) {
11516
+ } else if (_optionalChain([rawVal, 'access', _204 => _204.choices, 'optionalAccess', _205 => _205[0], 'optionalAccess', _206 => _206.delta, 'optionalAccess', _207 => _207.content])) {
11191
11517
  text += rawVal.choices[0].delta.content;
11192
11518
  } else if (typeof rawVal.text === "string") {
11193
11519
  text += rawVal.text;
@@ -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: extractTokenMetrics(output),
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);
@@ -11324,79 +11667,189 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
11324
11667
  return {
11325
11668
  cleanup: cleanup.length > 0 ? () => {
11326
11669
  while (cleanup.length > 0) {
11327
- _optionalChain([cleanup, 'access', _202 => _202.pop, 'call', _203 => _203(), 'optionalCall', _204 => _204()]);
11670
+ _optionalChain([cleanup, 'access', _208 => _208.pop, 'call', _209 => _209(), 'optionalCall', _210 => _210()]);
11328
11671
  }
11329
11672
  } : void 0,
11330
11673
  modelWrapped
11331
11674
  };
11332
11675
  }
11333
11676
  function finalizeAISDKChildTracing(event) {
11334
- const cleanup = _optionalChain([event, 'optionalAccess', _205 => _205.__braintrust_ai_sdk_cleanup]);
11677
+ const cleanup = _optionalChain([event, 'optionalAccess', _211 => _211.__braintrust_ai_sdk_cleanup]);
11335
11678
  if (event && typeof cleanup === "function") {
11336
11679
  cleanup();
11337
11680
  delete event.__braintrust_ai_sdk_cleanup;
11338
11681
  }
11339
11682
  }
11340
11683
  function patchAISDKStreamingResult(args) {
11341
- const { denyOutputPaths, endEvent, result, span, startTime } = args;
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
- if (!isReadableStreamLike(resultRecord.baseStream)) {
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 wrappedBaseStream = resultRecord.baseStream.pipeThrough(
11351
- new TransformStream({
11352
- transform(chunk, controller) {
11353
- if (firstChunkTime === void 0) {
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
- Object.defineProperty(resultRecord, "baseStream", {
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: wrappedBaseStream,
11773
+ value: wrappedStream,
11382
11774
  writable: true
11383
11775
  });
11384
11776
  return true;
11385
11777
  }
11386
- function isReadableStreamLike(value) {
11387
- return value != null && typeof value === "object" && typeof value.pipeThrough === "function";
11388
- }
11389
- async function processAISDKStreamingOutput(result, denyOutputPaths) {
11390
- const output = processAISDKOutput(result, denyOutputPaths);
11391
- if (!output || typeof output !== "object") {
11392
- return output;
11393
- }
11394
- const outputRecord = output;
11395
- try {
11396
- if ("text" in result && typeof result.text === "string") {
11397
- outputRecord.text = result.text;
11398
- }
11399
- } catch (e24) {
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 (e26) {
11799
+ }
11800
+ }
11801
+ }
11802
+ function isReadableStreamLike(value) {
11803
+ return value != null && typeof value === "object" && typeof value.pipeThrough === "function";
11804
+ }
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 (e27) {
11816
+ }
11817
+ }
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 (e28) {
11400
11853
  }
11401
11854
  try {
11402
11855
  if ("object" in result) {
@@ -11405,7 +11858,16 @@ async function processAISDKStreamingOutput(result, denyOutputPaths) {
11405
11858
  outputRecord.object = resolvedObject;
11406
11859
  }
11407
11860
  }
11408
- } catch (e25) {
11861
+ } catch (e29) {
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 (e30) {
11409
11871
  }
11410
11872
  return outputRecord;
11411
11873
  }
@@ -11423,22 +11885,31 @@ function buildAISDKChildMetadata(model) {
11423
11885
  function buildResolvedMetadataPayload(result) {
11424
11886
  const gatewayInfo = extractGatewayRoutingInfo(result);
11425
11887
  const metadata = {};
11426
- if (_optionalChain([gatewayInfo, 'optionalAccess', _206 => _206.provider])) {
11888
+ if (_optionalChain([gatewayInfo, 'optionalAccess', _212 => _212.provider])) {
11427
11889
  metadata.provider = gatewayInfo.provider;
11428
11890
  }
11429
- if (_optionalChain([gatewayInfo, 'optionalAccess', _207 => _207.model])) {
11891
+ if (_optionalChain([gatewayInfo, 'optionalAccess', _213 => _213.model])) {
11430
11892
  metadata.model = gatewayInfo.model;
11431
11893
  }
11432
- if (result.finishReason !== void 0) {
11433
- metadata.finish_reason = result.finishReason;
11894
+ let finishReason;
11895
+ try {
11896
+ finishReason = result.finishReason;
11897
+ } catch (e31) {
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 = _nullishCoalesce(globalThis.AI_SDK_DEFAULT_PROVIDER, () => ( null));
11912
+ const provider = _nullishCoalesce(_nullishCoalesce(globalThis.AI_SDK_DEFAULT_PROVIDER, () => ( _optionalChain([aiSDK, 'optionalAccess', _214 => _214.gateway]))), () => ( null));
11442
11913
  if (provider && typeof provider.languageModel === "function") {
11443
11914
  return provider.languageModel(model);
11444
11915
  }
@@ -11461,22 +11932,22 @@ function processAISDKOutput(output, denyOutputPaths) {
11461
11932
  }
11462
11933
  function extractTokenMetrics(result) {
11463
11934
  const metrics = {};
11464
- let usage = _optionalChain([result, 'optionalAccess', _208 => _208.totalUsage]) || _optionalChain([result, 'optionalAccess', _209 => _209.usage]);
11465
- if (!usage && result) {
11466
- try {
11467
- if ("totalUsage" in result && typeof result.totalUsage !== "function") {
11468
- usage = result.totalUsage;
11469
- } else if ("usage" in result && typeof result.usage !== "function") {
11470
- usage = result.usage;
11471
- }
11472
- } catch (e26) {
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) {
11476
11947
  return metrics;
11477
11948
  }
11478
11949
  const promptTokens = firstNumber(
11479
- _optionalChain([usage, 'access', _210 => _210.inputTokens, 'optionalAccess', _211 => _211.total]),
11950
+ _optionalChain([usage, 'access', _215 => _215.inputTokens, 'optionalAccess', _216 => _216.total]),
11480
11951
  usage.inputTokens,
11481
11952
  usage.promptTokens,
11482
11953
  usage.prompt_tokens
@@ -11485,7 +11956,7 @@ function extractTokenMetrics(result) {
11485
11956
  metrics.prompt_tokens = promptTokens;
11486
11957
  }
11487
11958
  const completionTokens = firstNumber(
11488
- _optionalChain([usage, 'access', _212 => _212.outputTokens, 'optionalAccess', _213 => _213.total]),
11959
+ _optionalChain([usage, 'access', _217 => _217.outputTokens, 'optionalAccess', _218 => _218.total]),
11489
11960
  usage.outputTokens,
11490
11961
  usage.completionTokens,
11491
11962
  usage.completion_tokens
@@ -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 = _optionalChain([obj, 'optionalAccess', _219 => _219[field]]);
11987
+ if (isPromiseLike(value)) {
11988
+ void Promise.resolve(value).catch(() => {
11989
+ });
11990
+ return void 0;
11991
+ }
11992
+ return value;
11993
+ } catch (e32) {
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
- if (lastChunk.text !== void 0) {
11519
- output.text = lastChunk.text;
12005
+ const text = safeSerializableFieldRead(lastChunk, "text");
12006
+ if (text !== void 0) {
12007
+ output.text = text;
11520
12008
  }
11521
- if (lastChunk.object !== void 0) {
11522
- output.object = lastChunk.object;
12009
+ const objectValue = safeSerializableFieldRead(lastChunk, "object");
12010
+ if (objectValue !== void 0) {
12011
+ output.object = objectValue;
11523
12012
  }
11524
- if (lastChunk.finishReason !== void 0) {
11525
- output.finishReason = lastChunk.finishReason;
12013
+ const finishReason = safeSerializableFieldRead(lastChunk, "finishReason");
12014
+ if (finishReason !== void 0) {
12015
+ output.finishReason = finishReason;
11526
12016
  }
11527
- if (lastChunk.toolCalls !== void 0) {
11528
- output.toolCalls = lastChunk.toolCalls;
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,10 +12041,19 @@ function extractGetterValues(obj) {
11549
12041
  ];
11550
12042
  for (const name of getterNames) {
11551
12043
  try {
11552
- if (obj && name in obj && isSerializableOutputValue(obj[name])) {
11553
- getterValues[name] = obj[name];
12044
+ if (!obj || !(name in obj)) {
12045
+ continue;
11554
12046
  }
11555
- } catch (e27) {
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;
12055
+ }
12056
+ } catch (e33) {
11556
12057
  }
11557
12058
  }
11558
12059
  return getterValues;
@@ -11571,11 +12072,16 @@ function extractSerializableOutputFields(output) {
11571
12072
  ];
11572
12073
  for (const name of directFieldNames) {
11573
12074
  try {
11574
- const value = _optionalChain([output, 'optionalAccess', _214 => _214[name]]);
12075
+ const value = _optionalChain([output, 'optionalAccess', _220 => _220[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
  }
11578
- } catch (e28) {
12084
+ } catch (e34) {
11579
12085
  }
11580
12086
  }
11581
12087
  return {
@@ -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;
@@ -11599,8 +12108,8 @@ function isSerializableOutputValue(value) {
11599
12108
  return true;
11600
12109
  }
11601
12110
  function serializeModelWithProvider(model) {
11602
- const modelId = typeof model === "string" ? model : _optionalChain([model, 'optionalAccess', _215 => _215.modelId]);
11603
- const explicitProvider = typeof model === "object" ? _optionalChain([model, 'optionalAccess', _216 => _216.provider]) : void 0;
12111
+ const modelId = typeof model === "string" ? model : _optionalChain([model, 'optionalAccess', _221 => _221.modelId]);
12112
+ const explicitProvider = typeof model === "object" ? _optionalChain([model, 'optionalAccess', _222 => _222.provider]) : void 0;
11604
12113
  if (!modelId) {
11605
12114
  return { model: modelId, provider: explicitProvider };
11606
12115
  }
@@ -11624,8 +12133,9 @@ function parseGatewayModelString(modelString) {
11624
12133
  return { model: modelString };
11625
12134
  }
11626
12135
  function extractGatewayRoutingInfo(result) {
11627
- if (_optionalChain([result, 'optionalAccess', _217 => _217.steps]) && Array.isArray(result.steps) && result.steps.length > 0) {
11628
- const routing2 = _optionalChain([result, 'access', _218 => _218.steps, 'access', _219 => _219[0], 'optionalAccess', _220 => _220.providerMetadata, 'optionalAccess', _221 => _221.gateway, 'optionalAccess', _222 => _222.routing]);
12136
+ const steps = safeSerializableFieldRead(result, "steps");
12137
+ if (Array.isArray(steps) && steps.length > 0) {
12138
+ const routing2 = _optionalChain([steps, 'access', _223 => _223[0], 'optionalAccess', _224 => _224.providerMetadata, 'optionalAccess', _225 => _225.gateway, 'optionalAccess', _226 => _226.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 routing = _optionalChain([result, 'optionalAccess', _223 => _223.providerMetadata, 'optionalAccess', _224 => _224.gateway, 'optionalAccess', _225 => _225.routing]);
12146
+ const providerMetadata = safeSerializableFieldRead(
12147
+ result,
12148
+ "providerMetadata"
12149
+ );
12150
+ const routing = _optionalChain([providerMetadata, 'optionalAccess', _227 => _227.gateway, 'optionalAccess', _228 => _228.routing]);
11637
12151
  if (routing) {
11638
12152
  return {
11639
12153
  provider: routing.resolvedProvider || routing.finalProvider,
@@ -11643,12 +12157,13 @@ function extractGatewayRoutingInfo(result) {
11643
12157
  return null;
11644
12158
  }
11645
12159
  function extractCostFromResult(result) {
11646
- if (_optionalChain([result, 'optionalAccess', _226 => _226.steps]) && Array.isArray(result.steps) && result.steps.length > 0) {
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 result.steps) {
11650
- const gateway2 = _optionalChain([step, 'optionalAccess', _227 => _227.providerMetadata, 'optionalAccess', _228 => _228.gateway]);
11651
- const stepCost = parseGatewayCost(_optionalChain([gateway2, 'optionalAccess', _229 => _229.cost])) || parseGatewayCost(_optionalChain([gateway2, 'optionalAccess', _230 => _230.marketCost]));
12164
+ for (const step of steps) {
12165
+ const gateway2 = _optionalChain([step, 'optionalAccess', _229 => _229.providerMetadata, 'optionalAccess', _230 => _230.gateway]);
12166
+ const stepCost = parseGatewayCost(_optionalChain([gateway2, 'optionalAccess', _231 => _231.cost])) || parseGatewayCost(_optionalChain([gateway2, 'optionalAccess', _232 => _232.marketCost]));
11652
12167
  if (stepCost !== void 0 && stepCost > 0) {
11653
12168
  totalCost += stepCost;
11654
12169
  foundCost = true;
@@ -11658,8 +12173,12 @@ function extractCostFromResult(result) {
11658
12173
  return totalCost;
11659
12174
  }
11660
12175
  }
11661
- const gateway = _optionalChain([result, 'optionalAccess', _231 => _231.providerMetadata, 'optionalAccess', _232 => _232.gateway]);
11662
- const directCost = parseGatewayCost(_optionalChain([gateway, 'optionalAccess', _233 => _233.cost])) || parseGatewayCost(_optionalChain([gateway, 'optionalAccess', _234 => _234.marketCost]));
12176
+ const providerMetadata = safeSerializableFieldRead(
12177
+ result,
12178
+ "providerMetadata"
12179
+ );
12180
+ const gateway = _optionalChain([providerMetadata, 'optionalAccess', _233 => _233.gateway]);
12181
+ const directCost = parseGatewayCost(_optionalChain([gateway, 'optionalAccess', _234 => _234.cost])) || parseGatewayCost(_optionalChain([gateway, 'optionalAccess', _235 => _235.marketCost]));
11663
12182
  if (directCost !== void 0 && directCost > 0) {
11664
12183
  return directCost;
11665
12184
  }
@@ -11814,7 +12333,7 @@ function extractUsageFromMessage(message) {
11814
12333
  const metrics = {};
11815
12334
  let usage;
11816
12335
  if (message.type === "assistant") {
11817
- usage = _optionalChain([message, 'access', _235 => _235.message, 'optionalAccess', _236 => _236.usage]);
12336
+ usage = _optionalChain([message, 'access', _236 => _236.message, 'optionalAccess', _237 => _237.usage]);
11818
12337
  } else if (message.type === "result") {
11819
12338
  usage = message.usage;
11820
12339
  }
@@ -11848,8 +12367,8 @@ function buildLLMInput(prompt, conversationHistory, capturedPromptMessages) {
11848
12367
  promptMessages.push({ content: prompt, role: "user" });
11849
12368
  } else if (capturedPromptMessages && capturedPromptMessages.length > 0) {
11850
12369
  for (const msg of capturedPromptMessages) {
11851
- const role = _optionalChain([msg, 'access', _237 => _237.message, 'optionalAccess', _238 => _238.role]);
11852
- const content = _optionalChain([msg, 'access', _239 => _239.message, 'optionalAccess', _240 => _240.content]);
12370
+ const role = _optionalChain([msg, 'access', _238 => _238.message, 'optionalAccess', _239 => _239.role]);
12371
+ const content = _optionalChain([msg, 'access', _240 => _240.message, 'optionalAccess', _241 => _241.content]);
11853
12372
  if (role && content !== void 0) {
11854
12373
  promptMessages.push({ content, role });
11855
12374
  }
@@ -11866,7 +12385,7 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
11866
12385
  return void 0;
11867
12386
  }
11868
12387
  const lastMessage = messages[messages.length - 1];
11869
- if (lastMessage.type !== "assistant" || !_optionalChain([lastMessage, 'access', _241 => _241.message, 'optionalAccess', _242 => _242.usage])) {
12388
+ if (lastMessage.type !== "assistant" || !_optionalChain([lastMessage, 'access', _242 => _242.message, 'optionalAccess', _243 => _243.usage])) {
11870
12389
  return void 0;
11871
12390
  }
11872
12391
  const model = lastMessage.message.model || options.model;
@@ -11877,7 +12396,7 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
11877
12396
  capturedPromptMessages
11878
12397
  );
11879
12398
  const outputs = messages.map(
11880
- (m) => _optionalChain([m, 'access', _243 => _243.message, 'optionalAccess', _244 => _244.content]) && _optionalChain([m, 'access', _245 => _245.message, 'optionalAccess', _246 => _246.role]) ? { content: m.message.content, role: m.message.role } : void 0
12399
+ (m) => _optionalChain([m, 'access', _244 => _244.message, 'optionalAccess', _245 => _245.content]) && _optionalChain([m, 'access', _246 => _246.message, 'optionalAccess', _247 => _247.role]) ? { content: m.message.content, role: m.message.role } : void 0
11881
12400
  ).filter(
11882
12401
  (c) => c !== void 0
11883
12402
  );
@@ -11896,7 +12415,7 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
11896
12415
  output: outputs
11897
12416
  });
11898
12417
  await span.end();
11899
- return _optionalChain([lastMessage, 'access', _247 => _247.message, 'optionalAccess', _248 => _248.content]) && _optionalChain([lastMessage, 'access', _249 => _249.message, 'optionalAccess', _250 => _250.role]) ? { content: lastMessage.message.content, role: lastMessage.message.role } : void 0;
12418
+ return _optionalChain([lastMessage, 'access', _248 => _248.message, 'optionalAccess', _249 => _249.content]) && _optionalChain([lastMessage, 'access', _250 => _250.message, 'optionalAccess', _251 => _251.role]) ? { content: lastMessage.message.content, role: lastMessage.message.role } : void 0;
11900
12419
  }
11901
12420
  function getMcpServerMetadata(serverName, mcpServers) {
11902
12421
  if (!serverName || !mcpServers) {
@@ -11978,18 +12497,18 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
11978
12497
  try {
11979
12498
  const response = input.tool_response;
11980
12499
  const metadata = {};
11981
- if (_optionalChain([response, 'optionalAccess', _251 => _251.status])) {
12500
+ if (_optionalChain([response, 'optionalAccess', _252 => _252.status])) {
11982
12501
  metadata["claude_agent_sdk.status"] = response.status;
11983
12502
  }
11984
- if (_optionalChain([response, 'optionalAccess', _252 => _252.totalDurationMs])) {
12503
+ if (_optionalChain([response, 'optionalAccess', _253 => _253.totalDurationMs])) {
11985
12504
  metadata["claude_agent_sdk.duration_ms"] = response.totalDurationMs;
11986
12505
  }
11987
- if (_optionalChain([response, 'optionalAccess', _253 => _253.totalToolUseCount]) !== void 0) {
12506
+ if (_optionalChain([response, 'optionalAccess', _254 => _254.totalToolUseCount]) !== void 0) {
11988
12507
  metadata["claude_agent_sdk.tool_use_count"] = response.totalToolUseCount;
11989
12508
  }
11990
12509
  subAgentSpan.log({
11991
12510
  metadata,
11992
- output: _optionalChain([response, 'optionalAccess', _254 => _254.content])
12511
+ output: _optionalChain([response, 'optionalAccess', _255 => _255.content])
11993
12512
  });
11994
12513
  } finally {
11995
12514
  subAgentSpan.end();
@@ -12081,7 +12600,7 @@ async function finalizeCurrentMessageGroup(state) {
12081
12600
  if (state.currentMessages.length === 0) {
12082
12601
  return;
12083
12602
  }
12084
- const parentToolUseId = _nullishCoalesce(_optionalChain([state, 'access', _255 => _255.currentMessages, 'access', _256 => _256[0], 'optionalAccess', _257 => _257.parent_tool_use_id]), () => ( null));
12603
+ const parentToolUseId = _nullishCoalesce(_optionalChain([state, 'access', _256 => _256.currentMessages, 'access', _257 => _257[0], 'optionalAccess', _258 => _258.parent_tool_use_id]), () => ( null));
12085
12604
  let parentSpan = await state.span.export();
12086
12605
  if (parentToolUseId) {
12087
12606
  const subAgentSpan = state.subAgentSpans.get(parentToolUseId);
@@ -12102,13 +12621,13 @@ async function finalizeCurrentMessageGroup(state) {
12102
12621
  state.finalResults.push(finalMessage);
12103
12622
  }
12104
12623
  const lastMessage = state.currentMessages[state.currentMessages.length - 1];
12105
- if (_optionalChain([lastMessage, 'optionalAccess', _258 => _258.message, 'optionalAccess', _259 => _259.usage])) {
12624
+ if (_optionalChain([lastMessage, 'optionalAccess', _259 => _259.message, 'optionalAccess', _260 => _260.usage])) {
12106
12625
  state.accumulatedOutputTokens += getNumberProperty(lastMessage.message.usage, "output_tokens") || 0;
12107
12626
  }
12108
12627
  state.currentMessages.length = 0;
12109
12628
  }
12110
12629
  function maybeTrackToolUseContext(state, message) {
12111
- if (message.type !== "assistant" || !Array.isArray(_optionalChain([message, 'access', _260 => _260.message, 'optionalAccess', _261 => _261.content]))) {
12630
+ if (message.type !== "assistant" || !Array.isArray(_optionalChain([message, 'access', _261 => _261.message, 'optionalAccess', _262 => _262.content]))) {
12112
12631
  return;
12113
12632
  }
12114
12633
  const parentToolUseId = _nullishCoalesce(message.parent_tool_use_id, () => ( null));
@@ -12160,13 +12679,13 @@ async function ensureSubAgentSpan(pendingSubAgentNames, rootSpan, subAgentSpans,
12160
12679
  async function handleStreamMessage(state, message) {
12161
12680
  maybeTrackToolUseContext(state, message);
12162
12681
  await maybeStartSubAgentSpan(state, message);
12163
- const messageId = _optionalChain([message, 'access', _262 => _262.message, 'optionalAccess', _263 => _263.id]);
12682
+ const messageId = _optionalChain([message, 'access', _263 => _263.message, 'optionalAccess', _264 => _264.id]);
12164
12683
  if (messageId && messageId !== state.currentMessageId) {
12165
12684
  await finalizeCurrentMessageGroup(state);
12166
12685
  state.currentMessageId = messageId;
12167
12686
  state.currentMessageStartTime = getCurrentUnixTimestamp();
12168
12687
  }
12169
- if (message.type === "assistant" && _optionalChain([message, 'access', _264 => _264.message, 'optionalAccess', _265 => _265.usage])) {
12688
+ if (message.type === "assistant" && _optionalChain([message, 'access', _265 => _265.message, 'optionalAccess', _266 => _266.usage])) {
12170
12689
  state.currentMessages.push(message);
12171
12690
  }
12172
12691
  if (message.type !== "result" || !message.usage) {
@@ -12175,7 +12694,7 @@ async function handleStreamMessage(state, message) {
12175
12694
  const finalUsageMetrics = extractUsageFromMessage(message);
12176
12695
  if (state.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
12177
12696
  const lastMessage = state.currentMessages[state.currentMessages.length - 1];
12178
- if (_optionalChain([lastMessage, 'optionalAccess', _266 => _266.message, 'optionalAccess', _267 => _267.usage])) {
12697
+ if (_optionalChain([lastMessage, 'optionalAccess', _267 => _267.message, 'optionalAccess', _268 => _268.usage])) {
12179
12698
  const adjustedTokens = finalUsageMetrics.completion_tokens - state.accumulatedOutputTokens;
12180
12699
  if (adjustedTokens >= 0) {
12181
12700
  lastMessage.message.usage.output_tokens = adjustedTokens;
@@ -12272,7 +12791,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
12272
12791
  yield message;
12273
12792
  }
12274
12793
  } finally {
12275
- _optionalChain([resolvePromptDone, 'optionalCall', _268 => _268()]);
12794
+ _optionalChain([resolvePromptDone, 'optionalCall', _269 => _269()]);
12276
12795
  }
12277
12796
  })();
12278
12797
  }
@@ -12359,20 +12878,16 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
12359
12878
  );
12360
12879
  });
12361
12880
  },
12362
- onComplete: () => {
12363
- void state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
12364
- spans.delete(event);
12365
- });
12366
- },
12367
- onError: (error) => {
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
  }
@@ -12508,7 +13023,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
12508
13023
  };
12509
13024
  tracingChannel2.subscribe(handlers);
12510
13025
  this.unsubscribers.push(() => {
12511
- _optionalChain([unbindCurrentSpanStore, 'optionalCall', _269 => _269()]);
13026
+ _optionalChain([unbindCurrentSpanStore, 'optionalCall', _270 => _270()]);
12512
13027
  tracingChannel2.unsubscribe(handlers);
12513
13028
  });
12514
13029
  }
@@ -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
  },
@@ -12550,8 +13067,8 @@ function ensureSpanState(states, event, create) {
12550
13067
  function bindCurrentSpanStoreToStart2(tracingChannel2, states, create) {
12551
13068
  const state = _internalGetGlobalState();
12552
13069
  const startChannel = tracingChannel2.start;
12553
- const currentSpanStore = _optionalChain([state, 'optionalAccess', _270 => _270.contextManager]) ? state.contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
12554
- if (!_optionalChain([startChannel, 'optionalAccess', _271 => _271.bindStore]) || !currentSpanStore) {
13070
+ const currentSpanStore = _optionalChain([state, 'optionalAccess', _271 => _271.contextManager]) ? state.contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
13071
+ if (!_optionalChain([startChannel, 'optionalAccess', _272 => _272.bindStore]) || !currentSpanStore) {
12555
13072
  return void 0;
12556
13073
  }
12557
13074
  startChannel.bindStore(
@@ -12563,7 +13080,7 @@ function bindCurrentSpanStoreToStart2(tracingChannel2, states, create) {
12563
13080
  ).span
12564
13081
  );
12565
13082
  return () => {
12566
- _optionalChain([startChannel, 'access', _272 => _272.unbindStore, 'optionalCall', _273 => _273(currentSpanStore)]);
13083
+ _optionalChain([startChannel, 'access', _273 => _273.unbindStore, 'optionalCall', _274 => _274(currentSpanStore)]);
12567
13084
  };
12568
13085
  }
12569
13086
  function logErrorAndEndSpan(states, event) {
@@ -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
- let startTime = null;
13106
+ const requestStartTime = _nullishCoalesce(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 && startTime !== null) {
13172
+ if (nextResult.done) {
12657
13173
  finalize({
12658
13174
  result: aggregateGenerateContentChunks(
12659
13175
  chunks,
12660
- startTime,
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 (startTime !== null) {
13196
+ if (chunks.length > 0) {
12681
13197
  finalize({
12682
- result: chunks.length > 0 ? aggregateGenerateContentChunks(
13198
+ result: aggregateGenerateContentChunks(
12683
13199
  chunks,
12684
- startTime,
13200
+ requestStartTime,
12685
13201
  firstTokenTime
12686
- ) : void 0
13202
+ )
12687
13203
  });
12688
13204
  } else {
12689
13205
  finalize({});
@@ -12785,7 +13301,7 @@ function serializePart(part) {
12785
13301
  return part;
12786
13302
  }
12787
13303
  function serializeTools(params) {
12788
- if (!_optionalChain([params, 'access', _274 => _274.config, 'optionalAccess', _275 => _275.tools])) {
13304
+ if (!_optionalChain([params, 'access', _275 => _275.config, 'optionalAccess', _276 => _276.tools])) {
12789
13305
  return null;
12790
13306
  }
12791
13307
  try {
@@ -12795,7 +13311,7 @@ function serializeTools(params) {
12795
13311
  }
12796
13312
  return tool;
12797
13313
  });
12798
- } catch (e29) {
13314
+ } catch (e35) {
12799
13315
  return null;
12800
13316
  }
12801
13317
  }
@@ -12828,7 +13344,7 @@ function extractGenerateContentMetrics(response, startTime) {
12828
13344
  metrics.end = end;
12829
13345
  metrics.duration = end - startTime;
12830
13346
  }
12831
- if (_optionalChain([response, 'optionalAccess', _276 => _276.usageMetadata])) {
13347
+ if (_optionalChain([response, 'optionalAccess', _277 => _277.usageMetadata])) {
12832
13348
  populateUsageMetrics(metrics, response.usageMetadata);
12833
13349
  }
12834
13350
  return metrics;
@@ -12875,7 +13391,7 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
12875
13391
  }
12876
13392
  if (chunk.candidates && Array.isArray(chunk.candidates)) {
12877
13393
  for (const candidate of chunk.candidates) {
12878
- if (_optionalChain([candidate, 'access', _277 => _277.content, 'optionalAccess', _278 => _278.parts])) {
13394
+ if (_optionalChain([candidate, 'access', _278 => _278.content, 'optionalAccess', _279 => _279.parts])) {
12879
13395
  for (const part of candidate.content.parts) {
12880
13396
  if (part.text !== void 0) {
12881
13397
  if (part.thought) {
@@ -12906,7 +13422,7 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
12906
13422
  parts.push({ text });
12907
13423
  }
12908
13424
  parts.push(...otherParts);
12909
- if (parts.length > 0 && _optionalChain([lastResponse, 'optionalAccess', _279 => _279.candidates])) {
13425
+ if (parts.length > 0 && _optionalChain([lastResponse, 'optionalAccess', _280 => _280.candidates])) {
12910
13426
  const candidates = [];
12911
13427
  for (const candidate of lastResponse.candidates) {
12912
13428
  const candidateDict = {
@@ -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-utils.ts
12985
- var TOKEN_NAME_MAP2 = {
12986
- promptTokens: "prompt_tokens",
12987
- inputTokens: "prompt_tokens",
12988
- completionTokens: "completion_tokens",
12989
- outputTokens: "completion_tokens",
12990
- totalTokens: "tokens",
12991
- prompt_tokens: "prompt_tokens",
12992
- input_tokens: "prompt_tokens",
12993
- completion_tokens: "completion_tokens",
12994
- output_tokens: "completion_tokens",
12995
- total_tokens: "tokens"
12996
- };
12997
- var TOKEN_DETAIL_PREFIX_MAP = {
12998
- promptTokensDetails: "prompt",
12999
- inputTokensDetails: "prompt",
13000
- completionTokensDetails: "completion",
13001
- outputTokensDetails: "completion",
13002
- costDetails: "cost",
13003
- prompt_tokens_details: "prompt",
13004
- input_tokens_details: "prompt",
13005
- completion_tokens_details: "completion",
13006
- output_tokens_details: "completion",
13007
- cost_details: "cost"
13008
- };
13009
- function camelToSnake(value) {
13010
- return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
13011
- }
13012
- function parseOpenRouterMetricsFromUsage(usage) {
13013
- if (!isObject(usage)) {
13014
- return {};
13015
- }
13016
- const metrics = {};
13017
- for (const [name, value] of Object.entries(usage)) {
13018
- if (typeof value === "number") {
13019
- metrics[TOKEN_NAME_MAP2[name] || camelToSnake(name)] = value;
13020
- continue;
13021
- }
13022
- if (!isObject(value)) {
13023
- continue;
13024
- }
13025
- const prefix = TOKEN_DETAIL_PREFIX_MAP[name];
13026
- if (!prefix) {
13027
- continue;
13028
- }
13029
- for (const [nestedName, nestedValue] of Object.entries(value)) {
13030
- if (typeof nestedValue !== "number") {
13031
- continue;
13032
- }
13033
- metrics[`${prefix}_${camelToSnake(nestedName)}`] = nestedValue;
13034
- }
13035
- }
13036
- return metrics;
13037
- }
13038
- function extractOpenRouterUsageMetadata(usage) {
13039
- if (!isObject(usage)) {
13040
- return void 0;
13041
- }
13042
- const metadata = {};
13043
- if (typeof usage.isByok === "boolean") {
13044
- metadata.is_byok = usage.isByok;
13045
- } else if (typeof usage.is_byok === "boolean") {
13046
- metadata.is_byok = usage.is_byok;
13047
- }
13048
- return Object.keys(metadata).length > 0 ? metadata : void 0;
13049
- }
13050
-
13051
- // src/openrouter-logging.ts
13052
- var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
13053
- "execute",
13054
- "render",
13055
- "nextTurnParams",
13056
- "requireApproval"
13057
- ]);
13058
- function parseOpenRouterModelString(model) {
13059
- if (typeof model !== "string") {
13060
- return { model };
13061
- }
13062
- const slashIndex = model.indexOf("/");
13063
- if (slashIndex > 0 && slashIndex < model.length - 1) {
13064
- return {
13065
- provider: model.substring(0, slashIndex),
13066
- model: model.substring(slashIndex + 1)
13067
- };
13068
- }
13069
- return { model };
13070
- }
13071
- function isZodSchema2(value) {
13072
- return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
13073
- }
13074
- function serializeZodSchema2(schema) {
13075
- try {
13076
- return zodToJsonSchema(schema);
13077
- } catch (e30) {
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;
13504
+ // src/instrumentation/plugins/openrouter-plugin.ts
13505
+ var OpenRouterPlugin = class extends BasePlugin {
13506
+ onEnable() {
13507
+ this.subscribeToOpenRouterChannels();
13119
13508
  }
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);
13509
+ onDisable() {
13510
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
13130
13511
  }
13131
- return sanitized;
13132
- }
13133
- function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
13134
- const sanitized = sanitizeOpenRouterLoggedValue(metadata);
13135
- const metadataRecord = isObject(sanitized) ? sanitized : {};
13136
- const { model, provider: providerRouting, ...rest } = metadataRecord;
13137
- const normalizedModel = parseOpenRouterModelString(model);
13138
- return {
13139
- ...rest,
13140
- ...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
13141
- ...providerRouting !== void 0 ? { providerRouting } : {},
13142
- ...httpReferer !== void 0 ? { httpReferer } : {},
13143
- ...xTitle !== void 0 ? { xTitle } : {},
13144
- provider: normalizedModel.provider || "openrouter"
13145
- };
13146
- }
13147
- function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
13148
- const normalized = buildOpenRouterMetadata(metadata, httpReferer, xTitle);
13149
- return typeof normalized.model === "string" ? {
13150
- ...normalized,
13151
- embedding_model: normalized.model
13152
- } : normalized;
13153
- }
13154
- function extractOpenRouterCallModelInput(request) {
13155
- return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue(request.input) : void 0;
13156
- }
13157
- function extractOpenRouterCallModelMetadata(request) {
13158
- if (!isObject(request)) {
13159
- return { provider: "openrouter" };
13160
- }
13161
- const { input: _input, ...metadata } = request;
13162
- return buildOpenRouterMetadata(metadata, void 0, void 0);
13163
- }
13164
- function extractOpenRouterResponseMetadata(result) {
13165
- if (!isObject(result)) {
13166
- return void 0;
13167
- }
13168
- const { output: _output, data: _data, usage, ...metadata } = result;
13169
- const sanitized = sanitizeOpenRouterLoggedValue(metadata);
13170
- const metadataRecord = isObject(sanitized) ? sanitized : {};
13171
- const { model, provider, ...rest } = metadataRecord;
13172
- const normalizedModel = parseOpenRouterModelString(model);
13173
- const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
13174
- const usageMetadata = extractOpenRouterUsageMetadata(usage);
13175
- const combined = {
13176
- ...rest,
13177
- ...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
13178
- ...usageMetadata || {},
13179
- ...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
13180
- };
13181
- return Object.keys(combined).length > 0 ? combined : void 0;
13182
- }
13183
- function extractOpenRouterResponseOutput(response, fallbackOutput) {
13184
- if (isObject(response) && "output" in response && response.output !== void 0) {
13185
- return sanitizeOpenRouterLoggedValue(response.output);
13186
- }
13187
- if (fallbackOutput !== void 0) {
13188
- return sanitizeOpenRouterLoggedValue(fallbackOutput);
13189
- }
13190
- return void 0;
13191
- }
13192
-
13193
- // src/openrouter-tool-wrapping.ts
13194
- var OPENROUTER_WRAPPED_TOOL = Symbol("braintrust.openrouter.wrappedTool");
13195
- var OPENROUTER_WRAPPED_CALL_MODEL_RESULT = Symbol(
13196
- "braintrust.openrouter.wrappedCallModelResult"
13197
- );
13198
- var OPENROUTER_CALL_MODEL_STREAM_METHODS = [
13199
- "getFullResponsesStream",
13200
- "getItemsStream",
13201
- "getNewMessagesStream",
13202
- "getReasoningStream",
13203
- "getTextStream",
13204
- "getToolCallsStream",
13205
- "getToolStream"
13206
- ];
13207
- var OPENROUTER_CALL_MODEL_CONTEXT_METHODS = [
13208
- "cancel",
13209
- "getPendingToolCalls",
13210
- "getState",
13211
- "getToolCalls",
13212
- "requiresApproval"
13213
- ];
13214
- function patchOpenRouterCallModelRequestTools(request) {
13215
- if (!Array.isArray(request.tools) || request.tools.length === 0) {
13216
- return void 0;
13217
- }
13218
- const originalTools = request.tools;
13219
- const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
13220
- const didPatch = wrappedTools.some(
13221
- (tool, index) => tool !== originalTools[index]
13222
- );
13223
- if (!didPatch) {
13224
- return void 0;
13225
- }
13226
- request.tools = wrappedTools;
13227
- return () => {
13228
- request.tools = originalTools;
13229
- };
13230
- }
13231
- function patchOpenRouterCallModelResult(span, result, request) {
13232
- if (!isObject(result) || isWrappedCallModelResult(result)) {
13233
- return false;
13234
- }
13235
- const resultLike = result;
13236
- const hasInstrumentableMethod = typeof resultLike.getResponse === "function" || typeof resultLike.getText === "function" || OPENROUTER_CALL_MODEL_STREAM_METHODS.some(
13237
- (methodName) => typeof resultLike[methodName] === "function"
13238
- );
13239
- if (!hasInstrumentableMethod) {
13240
- return false;
13241
- }
13242
- Object.defineProperty(resultLike, OPENROUTER_WRAPPED_CALL_MODEL_RESULT, {
13243
- value: true,
13244
- enumerable: false,
13245
- configurable: false
13246
- });
13247
- const originalGetResponse = typeof resultLike.getResponse === "function" ? resultLike.getResponse.bind(resultLike) : void 0;
13248
- const originalGetInitialResponse = typeof resultLike.getInitialResponse === "function" ? resultLike.getInitialResponse.bind(resultLike) : void 0;
13249
- const originalMakeFollowupRequest = typeof resultLike.makeFollowupRequest === "function" ? resultLike.makeFollowupRequest.bind(resultLike) : void 0;
13250
- let ended = false;
13251
- let tracedTurnCount = 0;
13252
- const endSpanWithResult = async (response, fallbackOutput) => {
13253
- if (ended) {
13254
- return;
13255
- }
13256
- ended = true;
13257
- const finalResponse = getFinalOpenRouterCallModelResponse(
13258
- resultLike,
13259
- response
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(_optionalChain([request, 'optionalAccess', _281 => _281.chatGenerationParams])) ? request.chatGenerationParams : {};
13520
+ const httpReferer = _optionalChain([request, 'optionalAccess', _282 => _282.httpReferer]);
13521
+ const xTitle = _optionalChain([request, 'optionalAccess', _283 => _283.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(_optionalChain([result, 'optionalAccess', _284 => _284.usage]));
13533
+ if (startTime) {
13534
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13535
+ }
13536
+ return metrics;
13537
+ },
13538
+ aggregateChunks: aggregateOpenRouterChatChunks
13539
+ })
13260
13540
  );
13261
- if (finalResponse) {
13262
- const rounds = getOpenRouterCallModelRounds(resultLike);
13263
- const metadata = extractOpenRouterCallModelResultMetadata(
13264
- finalResponse,
13265
- rounds.length + 1
13266
- );
13267
- span.log({
13268
- output: extractOpenRouterResponseOutput(finalResponse, fallbackOutput),
13269
- ...metadata ? { metadata } : {},
13270
- metrics: aggregateOpenRouterCallModelMetrics(rounds, finalResponse)
13271
- });
13272
- span.end();
13273
- return;
13274
- }
13275
- if (fallbackOutput !== void 0) {
13276
- span.log({
13277
- output: fallbackOutput
13278
- });
13279
- }
13280
- span.end();
13281
- };
13282
- const endSpanWithError = (error) => {
13283
- if (ended) {
13284
- return;
13285
- }
13286
- ended = true;
13287
- span.log({
13288
- error: normalizeError(error).message
13289
- });
13290
- span.end();
13291
- };
13292
- const finalizeFromResponse = async (fallbackOutput) => {
13293
- if (!originalGetResponse) {
13294
- await endSpanWithResult(void 0, fallbackOutput);
13295
- return;
13296
- }
13297
- try {
13298
- await endSpanWithResult(await originalGetResponse(), fallbackOutput);
13299
- } catch (e31) {
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(_optionalChain([request, 'optionalAccess', _285 => _285.requestBody])) ? request.requestBody : {};
13548
+ const httpReferer = _optionalChain([request, 'optionalAccess', _286 => _286.httpReferer]);
13549
+ const xTitle = _optionalChain([request, 'optionalAccess', _287 => _287.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 = _optionalChain([result, 'access', _288 => _288.data, 'optionalAccess', _289 => _289[0], 'optionalAccess', _290 => _290.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
- for (const methodName of OPENROUTER_CALL_MODEL_CONTEXT_METHODS) {
13333
- if (typeof resultLike[methodName] !== "function") {
13334
- continue;
13335
- }
13336
- const originalMethod = resultLike[methodName];
13337
- resultLike[methodName] = async (...args) => {
13338
- return await withCurrent(span, async () => {
13339
- return await originalMethod.apply(resultLike, args);
13340
- });
13341
- };
13342
- }
13343
- for (const methodName of OPENROUTER_CALL_MODEL_STREAM_METHODS) {
13344
- if (typeof resultLike[methodName] !== "function") {
13345
- continue;
13346
- }
13347
- const originalMethod = resultLike[methodName];
13348
- resultLike[methodName] = (...args) => {
13349
- const stream = withCurrent(
13350
- span,
13351
- () => originalMethod.apply(resultLike, args)
13352
- );
13353
- if (!isAsyncIterable2(stream)) {
13354
- return stream;
13355
- }
13356
- return wrapAsyncIterableWithSpan({
13357
- finalize: finalizeFromResponse,
13358
- iteratorFactory: () => stream[Symbol.asyncIterator](),
13359
- onError: endSpanWithError,
13360
- span
13361
- });
13362
- };
13363
- }
13364
- if (originalGetInitialResponse) {
13365
- let initialTurnTraced = false;
13366
- resultLike.getInitialResponse = async (...args) => {
13367
- if (initialTurnTraced) {
13368
- return await withCurrent(span, async () => {
13369
- return await originalGetInitialResponse(...args);
13370
- });
13371
- }
13372
- initialTurnTraced = true;
13373
- const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
13374
- const childSpan = startOpenRouterCallModelTurnSpan({
13375
- request: resolvedRequest,
13376
- step: tracedTurnCount + 1,
13377
- stepType: tracedTurnCount === 0 ? "initial" : "continue"
13378
- });
13379
- return await withCurrent(childSpan, async () => {
13380
- try {
13381
- const response = await originalGetInitialResponse(...args);
13382
- tracedTurnCount++;
13383
- finishOpenRouterCallModelTurnSpan({
13384
- response,
13385
- step: tracedTurnCount,
13386
- stepType: tracedTurnCount === 1 ? "initial" : "continue",
13387
- span: childSpan
13388
- });
13389
- return response;
13390
- } catch (error) {
13391
- childSpan.log({
13392
- error: normalizeError(error).message
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(_optionalChain([request, 'optionalAccess', _291 => _291.openResponsesRequest])) ? request.openResponsesRequest : {};
13585
+ const httpReferer = _optionalChain([request, 'optionalAccess', _292 => _292.httpReferer]);
13586
+ const xTitle = _optionalChain([request, 'optionalAccess', _293 => _293.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(_optionalChain([result, 'optionalAccess', _294 => _294.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
- if (originalMakeFollowupRequest) {
13401
- resultLike.makeFollowupRequest = async (...args) => {
13402
- const currentResponse = args[0];
13403
- const toolResults = Array.isArray(args[1]) ? args[1] : [];
13404
- const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
13405
- const followupRequest = buildOpenRouterFollowupRequest(
13406
- resolvedRequest,
13407
- currentResponse,
13408
- toolResults
13409
- );
13410
- const childSpan = startOpenRouterCallModelTurnSpan({
13411
- request: followupRequest,
13412
- step: tracedTurnCount + 1,
13413
- stepType: "continue"
13414
- });
13415
- return await withCurrent(childSpan, async () => {
13416
- try {
13417
- const response = await originalMakeFollowupRequest(...args);
13418
- tracedTurnCount++;
13419
- finishOpenRouterCallModelTurnSpan({
13420
- response,
13421
- step: tracedTurnCount,
13422
- stepType: "continue",
13423
- span: childSpan
13424
- });
13425
- return response;
13426
- } catch (error) {
13427
- childSpan.log({
13428
- error: normalizeError(error).message
13429
- });
13430
- childSpan.end();
13431
- throw error;
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: _optionalChain([event, 'optionalAccess', _295 => _295.step]),
13649
+ step_type: _optionalChain([event, 'optionalAccess', _296 => _296.stepType])
13650
+ };
13651
+ }
13652
+ return {
13653
+ ...extractOpenRouterResponseMetadata(result) || {},
13654
+ ..._optionalChain([event, 'optionalAccess', _297 => _297.step]) !== void 0 ? { step: event.step } : {},
13655
+ ..._optionalChain([event, 'optionalAccess', _298 => _298.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
- });
13434
- };
13435
- }
13436
- return true;
13437
- }
13438
- function wrapOpenRouterTool(tool) {
13439
- if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
13440
- return tool;
13441
- }
13442
- const toolName = tool.function.name || "tool";
13443
- const originalExecute = tool.function.execute;
13444
- const wrappedTool = {
13445
- ...tool,
13446
- function: {
13447
- ...tool.function,
13448
- execute(...args) {
13449
- return traceToolExecution({
13450
- args,
13451
- execute: () => Reflect.apply(originalExecute, this, args),
13452
- toolCallId: getToolCallId(args[1]),
13453
- toolName
13454
- });
13688
+ patchOpenRouterCallModelRequestTools(request);
13455
13689
  }
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;
13690
+ };
13691
+ callModelChannel.subscribe(callModelHandlers);
13692
+ this.unsubscribers.push(() => {
13693
+ callModelChannel.unsubscribe(callModelHandlers);
13694
+ });
13492
13695
  }
13493
- }
13494
- function publishToolResult(tracingChannel2, event, result) {
13495
- if (isPromiseLike(result)) {
13496
- return result.then(
13497
- (resolved) => {
13498
- event.result = resolved;
13499
- tracingChannel2.asyncEnd.publish(event);
13500
- return resolved;
13501
- },
13502
- (error) => {
13503
- event.error = normalizeError(error);
13504
- tracingChannel2.error.publish(event);
13505
- throw error;
13506
- }
13507
- );
13696
+ };
13697
+ function normalizeArgs(args) {
13698
+ if (Array.isArray(args)) {
13699
+ return args;
13508
13700
  }
13509
- event.result = result;
13510
- tracingChannel2.asyncEnd.publish(event);
13511
- return result;
13512
- }
13513
- function getToolCallId(context) {
13514
- const toolContext = context;
13515
- return typeof _optionalChain([toolContext, 'optionalAccess', _280 => _280.toolCall, 'optionalAccess', _281 => _281.id]) === "string" ? toolContext.toolCall.id : void 0;
13701
+ if (isArrayLike(args)) {
13702
+ return Array.from(args);
13703
+ }
13704
+ return [args];
13516
13705
  }
13517
- function extractOpenRouterCallModelResultMetadata(response, turnCount) {
13518
- const combined = {
13519
- ...extractOpenRouterResponseMetadata(response) || {},
13520
- ...turnCount !== void 0 ? { turn_count: turnCount } : {}
13521
- };
13522
- return Object.keys(combined).length > 0 ? combined : void 0;
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 getFinalOpenRouterCallModelResponse(result, response) {
13525
- if (isObject(response)) {
13526
- return response;
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
- return isObject(result.finalResponse) ? result.finalResponse : void 0;
13717
+ const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
13718
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
13529
13719
  }
13530
- function getOpenRouterCallModelRounds(result) {
13531
- if (!Array.isArray(result.allToolExecutionRounds)) {
13532
- return [];
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
- function aggregateOpenRouterCallModelMetrics(rounds, finalResponse) {
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 responses = [
13543
- ...rounds.map((round) => round.response).filter(isObject),
13544
- finalResponse
13545
- ];
13546
- for (const response of responses) {
13547
- const responseMetrics = parseOpenRouterMetricsFromUsage(response.usage);
13548
- for (const [name, value] of Object.entries(responseMetrics)) {
13549
- metrics[name] = (metrics[name] || 0) + value;
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 buildNextOpenRouterCallModelInput(currentInput, response, toolResults) {
13555
- const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
13556
- const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
13557
- return [...normalizedInput, ...responseOutput, ...toolResults].map(
13558
- (entry) => sanitizeOpenRouterLoggedValue(entry)
13559
- );
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
- function startOpenRouterCallModelTurnSpan(args) {
13562
- const requestRecord = isObject(args.request) ? args.request : void 0;
13563
- const metadata = requestRecord ? extractOpenRouterCallModelMetadata(requestRecord) : { provider: "openrouter" };
13564
- if (isObject(metadata) && "tools" in metadata) {
13565
- delete metadata.tools;
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
- return startSpan({
13568
- name: "openrouter.beta.responses.send",
13569
- spanAttributes: {
13570
- type: "llm" /* LLM */
13571
- },
13572
- event: {
13573
- input: requestRecord ? extractOpenRouterCallModelInput(requestRecord) : void 0,
13574
- metadata: {
13575
- ...metadata,
13576
- step: args.step,
13577
- step_type: args.stepType
13578
- }
13579
- }
13580
- });
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 finishOpenRouterCallModelTurnSpan(args) {
13583
- if (!isObject(args.response)) {
13584
- args.span.end();
13585
- return;
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 (e36) {
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 getOpenRouterResolvedRequest(result, request) {
13601
- if (isObject(result.resolvedRequest)) {
13602
- return result.resolvedRequest;
13821
+ function serializeOpenRouterTool(tool) {
13822
+ if (!isObject(tool)) {
13823
+ return tool;
13603
13824
  }
13604
- return request;
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 buildOpenRouterFollowupRequest(request, currentResponse, toolResults) {
13607
- if (!request) {
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 wrapAsyncIterableWithSpan(args) {
13621
- return {
13622
- [Symbol.asyncIterator]() {
13623
- const iterator = args.iteratorFactory();
13624
- return {
13625
- next(value) {
13626
- return withCurrent(
13627
- args.span,
13628
- () => value === void 0 ? iterator.next() : iterator.next(value)
13629
- ).then(
13630
- async (result) => {
13631
- if (result.done) {
13632
- await args.finalize();
13633
- }
13634
- return result;
13635
- },
13636
- (error) => {
13637
- args.onError(error);
13638
- throw error;
13639
- }
13640
- );
13641
- },
13642
- return(value) {
13643
- if (typeof iterator.return !== "function") {
13644
- return args.finalize().then(() => ({
13645
- done: true,
13646
- value
13647
- }));
13648
- }
13649
- return withCurrent(args.span, () => iterator.return(value)).then(
13650
- async (result) => {
13651
- await args.finalize();
13652
- return result;
13653
- },
13654
- (error) => {
13655
- args.onError(error);
13656
- throw error;
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 isAsyncIterable2(value) {
13675
- return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
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 isPromiseLike(value) {
13678
- return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
13891
+ function extractOpenRouterCallModelInput(request) {
13892
+ return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue(request.input) : void 0;
13679
13893
  }
13680
- function normalizeError(error) {
13681
- return error instanceof Error ? error : new Error(String(error));
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
- // src/instrumentation/plugins/openrouter-plugin.ts
13685
- var OpenRouterPlugin = class extends BasePlugin {
13686
- onEnable() {
13687
- this.subscribeToOpenRouterChannels();
13901
+ function extractOpenRouterResponseMetadata(result) {
13902
+ if (!isObject(result)) {
13903
+ return void 0;
13688
13904
  }
13689
- onDisable() {
13690
- this.unsubscribers = unsubscribeAll(this.unsubscribers);
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
- subscribeToOpenRouterChannels() {
13693
- this.unsubscribers.push(
13694
- traceStreamingChannel(openRouterChannels.chatSend, {
13695
- name: "openrouter.chat.send",
13696
- type: "llm" /* LLM */,
13697
- extractInput: (args) => {
13698
- const request = getOpenRouterRequestArg(args);
13699
- const chatGenerationParams = isObject(_optionalChain([request, 'optionalAccess', _282 => _282.chatGenerationParams])) ? request.chatGenerationParams : {};
13700
- const httpReferer = _optionalChain([request, 'optionalAccess', _283 => _283.httpReferer]);
13701
- const xTitle = _optionalChain([request, 'optionalAccess', _284 => _284.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(_optionalChain([result, 'optionalAccess', _285 => _285.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(_optionalChain([request, 'optionalAccess', _286 => _286.requestBody])) ? request.requestBody : {};
13728
- const httpReferer = _optionalChain([request, 'optionalAccess', _287 => _287.httpReferer]);
13729
- const xTitle = _optionalChain([request, 'optionalAccess', _288 => _288.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 = _optionalChain([result, 'access', _289 => _289.data, 'optionalAccess', _290 => _290[0], 'optionalAccess', _291 => _291.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(_optionalChain([request, 'optionalAccess', _292 => _292.openResponsesRequest])) ? request.openResponsesRequest : {};
13765
- const httpReferer = _optionalChain([request, 'optionalAccess', _293 => _293.httpReferer]);
13766
- const xTitle = _optionalChain([request, 'optionalAccess', _294 => _294.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(_optionalChain([result, 'optionalAccess', _295 => _295.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
- function normalizeArgs(args) {
13842
- if (Array.isArray(args)) {
13843
- return args;
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
- if (isArrayLike(args)) {
13846
- return Array.from(args);
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;
13847
13941
  }
13848
- return [args];
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]);
13849
13976
  }
13850
- function isArrayLike(value) {
13851
- return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
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;
13996
+ }
13852
13997
  }
13853
- function getOpenRouterRequestArg(args) {
13854
- const normalizedArgs = normalizeArgs(args);
13855
- const keyedCandidate = normalizedArgs.find(
13856
- (arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
13857
- );
13858
- if (isObject(keyedCandidate)) {
13859
- return keyedCandidate;
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
- const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
13862
- return isObject(firstObjectArg) ? firstObjectArg : void 0;
14013
+ event.result = result;
14014
+ tracingChannel2.asyncEnd.publish(event);
14015
+ return result;
13863
14016
  }
13864
- function getOpenRouterCallModelRequestArg(args) {
13865
- const firstObjectArg = normalizeArgs(args).find((arg) => isObject(arg));
13866
- return isObject(firstObjectArg) ? firstObjectArg : void 0;
14017
+ function getToolCallId(context) {
14018
+ const toolContext = context;
14019
+ return typeof _optionalChain([toolContext, 'optionalAccess', _299 => _299.toolCall, 'optionalAccess', _300 => _300.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;
@@ -13874,105 +14030,448 @@ function aggregateOpenRouterChatChunks(chunks) {
13874
14030
  for (const chunk of chunks) {
13875
14031
  metrics = {
13876
14032
  ...metrics,
13877
- ...parseOpenRouterMetricsFromUsage(_optionalChain([chunk, 'optionalAccess', _296 => _296.usage]))
14033
+ ...parseOpenRouterMetricsFromUsage(_optionalChain([chunk, 'optionalAccess', _301 => _301.usage]))
14034
+ };
14035
+ const choice = _optionalChain([chunk, 'optionalAccess', _302 => _302.choices, 'optionalAccess', _303 => _303[0]]);
14036
+ const delta = _optionalChain([choice, 'optionalAccess', _304 => _304.delta]);
14037
+ if (!delta) {
14038
+ if (_optionalChain([choice, 'optionalAccess', _305 => _305.finish_reason]) !== void 0) {
14039
+ finishReason = choice.finish_reason;
14040
+ }
14041
+ continue;
14042
+ }
14043
+ if (!role && delta.role) {
14044
+ role = delta.role;
14045
+ }
14046
+ if (typeof delta.content === "string") {
14047
+ content += delta.content;
14048
+ }
14049
+ const choiceFinishReason = _nullishCoalesce(_nullishCoalesce(_optionalChain([choice, 'optionalAccess', _306 => _306.finishReason]), () => ( _optionalChain([choice, 'optionalAccess', _307 => _307.finish_reason]))), () => ( void 0));
14050
+ const deltaFinishReason = _nullishCoalesce(_nullishCoalesce(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 (!_optionalChain([toolDelta, 'optionalAccess', _308 => _308.function])) {
14062
+ continue;
14063
+ }
14064
+ const toolIndex = _nullishCoalesce(toolDelta.index, () => ( 0));
14065
+ const existingToolCall = _optionalChain([toolCalls, 'optionalAccess', _309 => _309[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 = _optionalChain([chunk, 'optionalAccess', _310 => _310.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 (e37) {
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
+ });
13878
14251
  };
13879
- const choice = _optionalChain([chunk, 'optionalAccess', _297 => _297.choices, 'optionalAccess', _298 => _298[0]]);
13880
- const delta = _optionalChain([choice, 'optionalAccess', _299 => _299.delta]);
13881
- if (!delta) {
13882
- if (_optionalChain([choice, 'optionalAccess', _300 => _300.finish_reason]) !== void 0) {
13883
- finishReason = choice.finish_reason;
13884
- }
14252
+ }
14253
+ for (const methodName of OPENROUTER_CALL_MODEL_CONTEXT_METHODS) {
14254
+ if (typeof resultLike[methodName] !== "function") {
13885
14255
  continue;
13886
14256
  }
13887
- if (!role && delta.role) {
13888
- role = delta.role;
13889
- }
13890
- if (typeof delta.content === "string") {
13891
- content += delta.content;
13892
- }
13893
- const choiceFinishReason = _nullishCoalesce(_nullishCoalesce(_optionalChain([choice, 'optionalAccess', _301 => _301.finishReason]), () => ( _optionalChain([choice, 'optionalAccess', _302 => _302.finish_reason]))), () => ( void 0));
13894
- const deltaFinishReason = _nullishCoalesce(_nullishCoalesce(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) {
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
- for (const toolDelta of toolCallDeltas) {
13905
- if (!_optionalChain([toolDelta, 'optionalAccess', _303 => _303.function])) {
13906
- continue;
13907
- }
13908
- const toolIndex = _nullishCoalesce(toolDelta.index, () => ( 0));
13909
- const existingToolCall = _optionalChain([toolCalls, 'optionalAccess', _304 => _304[toolIndex]]);
13910
- if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
13911
- const nextToolCalls = [...toolCalls || []];
13912
- nextToolCalls[toolIndex] = {
13913
- index: toolIndex,
13914
- id: toolDelta.id,
13915
- type: toolDelta.type,
13916
- function: {
13917
- name: toolDelta.function.name,
13918
- arguments: toolDelta.function.arguments || ""
13919
- }
13920
- };
13921
- toolCalls = nextToolCalls;
13922
- continue;
13923
- }
13924
- const current = existingToolCall;
13925
- if (toolDelta.id && !current.id) {
13926
- current.id = toolDelta.id;
13927
- }
13928
- if (toolDelta.type && !current.type) {
13929
- current.type = toolDelta.type;
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
- if (toolDelta.function.name && !current.function.name) {
13932
- current.function.name = toolDelta.function.name;
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
- current.function.arguments += toolDelta.function.arguments || "";
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
- return {
13938
- output: [
13939
- {
13940
- index: 0,
13941
- message: {
13942
- role,
13943
- content: content || void 0,
13944
- ...toolCalls ? { tool_calls: toolCalls } : {}
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
- logprobs: null,
13947
- finish_reason: finishReason
13948
- }
13949
- ],
13950
- metrics
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 aggregateOpenRouterResponseStreamEvents(chunks) {
13954
- let finalResponse;
13955
- for (const chunk of chunks) {
13956
- const response = _optionalChain([chunk, 'optionalAccess', _305 => _305.response]);
13957
- if (!response) {
13958
- continue;
13959
- }
13960
- if (chunk.type === "response.completed" || chunk.type === "response.incomplete" || chunk.type === "response.failed") {
13961
- finalResponse = response;
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
- if (!finalResponse) {
13965
- return {
13966
- output: void 0,
13967
- metrics: {}
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
- output: extractOpenRouterResponseOutput(finalResponse),
13972
- metrics: parseOpenRouterMetricsFromUsage(finalResponse.usage),
13973
- ...extractOpenRouterResponseMetadata(finalResponse) ? { metadata: extractOpenRouterResponseMetadata(finalResponse) } : {}
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 = (_class18 = class extends BasePlugin {
@@ -15365,7 +15864,7 @@ var CachedSpanFetcher = (_class20 = class {
15365
15864
  spanType
15366
15865
  );
15367
15866
  const rows = await fetcher.fetchedData();
15368
- return rows.filter((row) => _optionalChain([row, 'access', _306 => _306.span_attributes, 'optionalAccess', _307 => _307.purpose]) !== "scorer").map((row) => ({
15867
+ return rows.filter((row) => _optionalChain([row, 'access', _311 => _311.span_attributes, 'optionalAccess', _312 => _312.purpose]) !== "scorer").map((row) => ({
15369
15868
  input: row.input,
15370
15869
  output: row.output,
15371
15870
  metadata: row.metadata,
@@ -15399,7 +15898,7 @@ var CachedSpanFetcher = (_class20 = class {
15399
15898
  async fetchSpans(spanType) {
15400
15899
  const spans = await this.fetchFn(spanType);
15401
15900
  for (const span of spans) {
15402
- const type = _nullishCoalesce(_optionalChain([span, 'access', _308 => _308.span_attributes, 'optionalAccess', _309 => _309.type]), () => ( ""));
15901
+ const type = _nullishCoalesce(_optionalChain([span, 'access', _313 => _313.span_attributes, 'optionalAccess', _314 => _314.type]), () => ( ""));
15403
15902
  const existing = _nullishCoalesce(this.spanCache.get(type), () => ( []));
15404
15903
  existing.push(span);
15405
15904
  this.spanCache.set(type, existing);
@@ -15479,11 +15978,11 @@ var LocalTrace = (_class21 = class {
15479
15978
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
15480
15979
  if (cachedSpans && cachedSpans.length > 0) {
15481
15980
  let spans = cachedSpans.filter(
15482
- (span) => _optionalChain([span, 'access', _310 => _310.span_attributes, 'optionalAccess', _311 => _311.purpose]) !== "scorer"
15981
+ (span) => _optionalChain([span, 'access', _315 => _315.span_attributes, 'optionalAccess', _316 => _316.purpose]) !== "scorer"
15483
15982
  );
15484
15983
  if (spanType && spanType.length > 0) {
15485
15984
  spans = spans.filter(
15486
- (span) => spanType.includes(_nullishCoalesce(_optionalChain([span, 'access', _312 => _312.span_attributes, 'optionalAccess', _313 => _313.type]), () => ( "")))
15985
+ (span) => spanType.includes(_nullishCoalesce(_optionalChain([span, 'access', _317 => _317.span_attributes, 'optionalAccess', _318 => _318.type]), () => ( "")))
15487
15986
  );
15488
15987
  }
15489
15988
  return spans.map((span) => ({
@@ -15502,7 +16001,7 @@ var LocalTrace = (_class21 = class {
15502
16001
  * Calls the API with the project_default preprocessor (which falls back to "thread").
15503
16002
  */
15504
16003
  async getThread(options) {
15505
- const cacheKey = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _314 => _314.preprocessor]), () => ( "project_default"));
16004
+ const cacheKey = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _319 => _319.preprocessor]), () => ( "project_default"));
15506
16005
  if (!this.threadCache.has(cacheKey)) {
15507
16006
  const promise = this.fetchThread(options);
15508
16007
  this.threadCache.set(cacheKey, promise);
@@ -15513,7 +16012,7 @@ var LocalTrace = (_class21 = class {
15513
16012
  await this.ensureSpansReady();
15514
16013
  await this.state.login({});
15515
16014
  const result = await invoke({
15516
- globalFunction: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _315 => _315.preprocessor]), () => ( "project_default")),
16015
+ globalFunction: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _320 => _320.preprocessor]), () => ( "project_default")),
15517
16016
  functionType: "preprocessor",
15518
16017
  input: {
15519
16018
  trace_ref: {
@@ -15689,13 +16188,34 @@ function validateParametersWithJsonSchema(parameters, schema) {
15689
16188
  const ajv = new (0, _ajv2.default)({ coerceTypes: true, useDefaults: true, strict: false });
15690
16189
  const validate = ajv.compile(schema);
15691
16190
  if (!validate(parameters)) {
15692
- const errorMessages = _optionalChain([validate, 'access', _316 => _316.errors, 'optionalAccess', _317 => _317.map, 'call', _318 => _318((err) => {
16191
+ const errorMessages = _optionalChain([validate, 'access', _321 => _321.errors, 'optionalAccess', _322 => _322.map, 'call', _323 => _323((err) => {
15693
16192
  const path2 = err.instancePath || "root";
15694
16193
  return `${path2}: ${err.message}`;
15695
- }), 'access', _319 => _319.join, 'call', _320 => _320(", ")]);
16194
+ }), 'access', _324 => _324.join, 'call', _325 => _325(", ")]);
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
@@ -15930,7 +16450,7 @@ async function runEvaluator(experiment, evaluator, progressReporter, filters, st
15930
16450
  }
15931
16451
  async function runEvaluatorInternal(experiment, evaluator, progressReporter, filters, stream, parameters, collectResults, enableCache) {
15932
16452
  if (enableCache) {
15933
- _optionalChain([(_nullishCoalesce(evaluator.state, () => ( _internalGetGlobalState()))), 'optionalAccess', _321 => _321.spanCache, 'optionalAccess', _322 => _322.start, 'call', _323 => _323()]);
16453
+ _optionalChain([(_nullishCoalesce(evaluator.state, () => ( _internalGetGlobalState()))), 'optionalAccess', _326 => _326.spanCache, 'optionalAccess', _327 => _327.start, 'call', _328 => _328()]);
15934
16454
  }
15935
16455
  try {
15936
16456
  if (typeof evaluator.data === "string") {
@@ -15985,7 +16505,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
15985
16505
  const experimentIdPromise = experiment ? (async () => {
15986
16506
  try {
15987
16507
  return await experiment.id;
15988
- } catch (e32) {
16508
+ } catch (e38) {
15989
16509
  return void 0;
15990
16510
  }
15991
16511
  })() : void 0;
@@ -16041,7 +16561,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
16041
16561
  objectType: parentComponents ? spanObjectTypeV3ToTypedString(
16042
16562
  parentComponents.data.object_type
16043
16563
  ) : "experiment",
16044
- objectId: await _asyncNullishCoalesce(await _asyncOptionalChain([parentComponents, 'optionalAccess', async _324 => _324.data, 'access', async _325 => _325.object_id]), async () => ( (experimentIdPromise ? await _asyncNullishCoalesce(await experimentIdPromise, async () => ( "")) : ""))),
16564
+ objectId: await _asyncNullishCoalesce(await _asyncOptionalChain([parentComponents, 'optionalAccess', async _329 => _329.data, 'access', async _330 => _330.object_id]), async () => ( (experimentIdPromise ? await _asyncNullishCoalesce(await experimentIdPromise, async () => ( "")) : ""))),
16045
16565
  rootSpanId: rootSpan.rootSpanId,
16046
16566
  ensureSpansFlushed,
16047
16567
  state
@@ -16067,10 +16587,10 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
16067
16587
  span,
16068
16588
  parameters: _nullishCoalesce(parameters, () => ( {})),
16069
16589
  reportProgress: (event) => {
16070
- _optionalChain([stream, 'optionalCall', _326 => _326({
16590
+ _optionalChain([stream, 'optionalCall', _331 => _331({
16071
16591
  ...event,
16072
16592
  id: rootSpan.id,
16073
- origin: _optionalChain([baseEvent, 'access', _327 => _327.event, 'optionalAccess', _328 => _328.origin]),
16593
+ origin: _optionalChain([baseEvent, 'access', _332 => _332.event, 'optionalAccess', _333 => _333.origin]),
16074
16594
  name: evaluator.evalName,
16075
16595
  object_type: "task"
16076
16596
  })]);
@@ -16234,7 +16754,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
16234
16754
  metadata,
16235
16755
  scores: mergedScores,
16236
16756
  error,
16237
- origin: _optionalChain([baseEvent, 'access', _329 => _329.event, 'optionalAccess', _330 => _330.origin])
16757
+ origin: _optionalChain([baseEvent, 'access', _334 => _334.event, 'optionalAccess', _335 => _335.origin])
16238
16758
  });
16239
16759
  }
16240
16760
  };
@@ -16269,7 +16789,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
16269
16789
  break;
16270
16790
  }
16271
16791
  scheduledTrials++;
16272
- _optionalChain([progressReporter, 'access', _331 => _331.setTotal, 'optionalCall', _332 => _332(evaluator.evalName, scheduledTrials)]);
16792
+ _optionalChain([progressReporter, 'access', _336 => _336.setTotal, 'optionalCall', _337 => _337(evaluator.evalName, scheduledTrials)]);
16273
16793
  q.pushAsync({ datum, trialIndex }).catch((e) => {
16274
16794
  if (queueErrors.length < 5) {
16275
16795
  queueErrors.push(e);
@@ -16354,9 +16874,9 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
16354
16874
  );
16355
16875
  } finally {
16356
16876
  if (enableCache) {
16357
- const spanCache = _optionalChain([(_nullishCoalesce(evaluator.state, () => ( _internalGetGlobalState()))), 'optionalAccess', _333 => _333.spanCache]);
16358
- _optionalChain([spanCache, 'optionalAccess', _334 => _334.dispose, 'call', _335 => _335()]);
16359
- _optionalChain([spanCache, 'optionalAccess', _336 => _336.stop, 'call', _337 => _337()]);
16877
+ const spanCache = _optionalChain([(_nullishCoalesce(evaluator.state, () => ( _internalGetGlobalState()))), 'optionalAccess', _338 => _338.spanCache]);
16878
+ _optionalChain([spanCache, 'optionalAccess', _339 => _339.dispose, 'call', _340 => _340()]);
16879
+ _optionalChain([spanCache, 'optionalAccess', _341 => _341.stop, 'call', _342 => _342()]);
16360
16880
  }
16361
16881
  }
16362
16882
  }
@@ -16593,7 +17113,7 @@ async function cachedLogin(options) {
16593
17113
  }
16594
17114
  function makeCheckAuthorized(allowedOrgName) {
16595
17115
  return async (req, _res, next) => {
16596
- if (!_optionalChain([req, 'access', _338 => _338.ctx, 'optionalAccess', _339 => _339.token])) {
17116
+ if (!_optionalChain([req, 'access', _343 => _343.ctx, 'optionalAccess', _344 => _344.token])) {
16597
17117
  return next(_httperrors2.default.call(void 0, 401, "Unauthorized"));
16598
17118
  }
16599
17119
  try {
@@ -16606,7 +17126,7 @@ function makeCheckAuthorized(allowedOrgName) {
16606
17126
  return next(_httperrors2.default.call(void 0, 403, errorMessage));
16607
17127
  }
16608
17128
  const state = await cachedLogin({
16609
- apiKey: _optionalChain([req, 'access', _340 => _340.ctx, 'optionalAccess', _341 => _341.token]),
17129
+ apiKey: _optionalChain([req, 'access', _345 => _345.ctx, 'optionalAccess', _346 => _346.token]),
16610
17130
  orgName
16611
17131
  });
16612
17132
  req.ctx.state = state;
@@ -16930,7 +17450,8 @@ var ScorerBuilder = (_class24 = 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,
@@ -17355,7 +17876,7 @@ function runDevServer(evaluators, opts) {
17355
17876
  scores,
17356
17877
  stream
17357
17878
  } = evalBodySchema.parse(req.body);
17358
- if (!_optionalChain([req, 'access', _342 => _342.ctx, 'optionalAccess', _343 => _343.state])) {
17879
+ if (!_optionalChain([req, 'access', _347 => _347.ctx, 'optionalAccess', _348 => _348.state])) {
17359
17880
  res.status(500).json({ error: "Braintrust state not initialized in request" });
17360
17881
  return;
17361
17882
  }
@@ -17406,12 +17927,12 @@ function runDevServer(evaluators, opts) {
17406
17927
  ...evaluator,
17407
17928
  data: evalData.data,
17408
17929
  scores: evaluator.scores.concat(
17409
- _nullishCoalesce(_optionalChain([scores, 'optionalAccess', _344 => _344.map, 'call', _345 => _345(
17930
+ _nullishCoalesce(_optionalChain([scores, 'optionalAccess', _349 => _349.map, 'call', _350 => _350(
17410
17931
  (score) => makeScorer(
17411
17932
  state,
17412
17933
  score.name,
17413
17934
  score.function_id,
17414
- _optionalChain([req, 'access', _346 => _346.ctx, 'optionalAccess', _347 => _347.projectId])
17935
+ _optionalChain([req, 'access', _351 => _351.ctx, 'optionalAccess', _352 => _352.projectId])
17415
17936
  )
17416
17937
  )]), () => ( []))
17417
17938
  ),