braintrust 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +52 -67
  2. package/dev/dist/index.d.mts +53 -9
  3. package/dev/dist/index.d.ts +53 -9
  4. package/dev/dist/index.js +1839 -1298
  5. package/dev/dist/index.mjs +1503 -962
  6. package/dist/auto-instrumentations/bundler/esbuild.cjs +270 -23
  7. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  8. package/dist/auto-instrumentations/bundler/rollup.cjs +270 -23
  9. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  10. package/dist/auto-instrumentations/bundler/vite.cjs +270 -23
  11. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  12. package/dist/auto-instrumentations/bundler/webpack.cjs +270 -23
  13. package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
  14. package/dist/auto-instrumentations/{chunk-OLOPGWTJ.mjs → chunk-D5ZPIUEL.mjs} +1 -1
  15. package/dist/auto-instrumentations/chunk-LVWWLUMN.mjs +535 -0
  16. package/dist/auto-instrumentations/hook.mjs +306 -23
  17. package/dist/auto-instrumentations/index.cjs +270 -23
  18. package/dist/auto-instrumentations/index.d.mts +5 -5
  19. package/dist/auto-instrumentations/index.d.ts +5 -5
  20. package/dist/auto-instrumentations/index.mjs +1 -1
  21. package/dist/auto-instrumentations/loader/esm-hook.mjs +7 -8
  22. package/dist/browser.d.mts +474 -47
  23. package/dist/browser.d.ts +474 -47
  24. package/dist/browser.js +2258 -2095
  25. package/dist/browser.mjs +2258 -2095
  26. package/dist/cli.js +1817 -1232
  27. package/dist/edge-light.d.mts +1 -1
  28. package/dist/edge-light.d.ts +1 -1
  29. package/dist/edge-light.js +2188 -2027
  30. package/dist/edge-light.mjs +2188 -2027
  31. package/dist/index.d.mts +474 -47
  32. package/dist/index.d.ts +474 -47
  33. package/dist/index.js +2576 -2415
  34. package/dist/index.mjs +2259 -2098
  35. package/dist/instrumentation/index.d.mts +16 -22
  36. package/dist/instrumentation/index.d.ts +16 -22
  37. package/dist/instrumentation/index.js +1558 -1068
  38. package/dist/instrumentation/index.mjs +1558 -1068
  39. package/dist/workerd.d.mts +1 -1
  40. package/dist/workerd.d.ts +1 -1
  41. package/dist/workerd.js +2188 -2027
  42. package/dist/workerd.mjs +2188 -2027
  43. package/package.json +6 -3
  44. package/dist/auto-instrumentations/chunk-KVX7OFPD.mjs +0 -288
package/dist/cli.js CHANGED
@@ -1275,7 +1275,7 @@ var require_package = __commonJS({
1275
1275
  "package.json"(exports2, module2) {
1276
1276
  module2.exports = {
1277
1277
  name: "braintrust",
1278
- version: "3.3.0",
1278
+ version: "3.4.0",
1279
1279
  description: "SDK for integrating Braintrust",
1280
1280
  repository: {
1281
1281
  type: "git",
@@ -1382,6 +1382,7 @@ var require_package = __commonJS({
1382
1382
  ],
1383
1383
  scripts: {
1384
1384
  build: 'cross-env NODE_OPTIONS="--max-old-space-size=8192" tsup',
1385
+ "check:typings": "tsc --noEmit",
1385
1386
  watch: "tsup --watch",
1386
1387
  clean: "rm -r dist/* && rm -r dev/dist/*",
1387
1388
  docs: "npx typedoc --options typedoc.json src/node/index.ts",
@@ -1402,7 +1403,8 @@ var require_package = __commonJS({
1402
1403
  "test:vitest": "pnpm --filter @braintrust/vitest-wrapper-tests test",
1403
1404
  "test:output": "tsx scripts/test-output.ts --with-comparison --with-metrics --with-progress",
1404
1405
  lint: "eslint .",
1405
- "fix:eslint": "eslint --fix ."
1406
+ "fix:lint": "eslint --fix .",
1407
+ playground: "tsx playground.ts"
1406
1408
  },
1407
1409
  author: "",
1408
1410
  license: "MIT",
@@ -1433,6 +1435,7 @@ var require_package = __commonJS({
1433
1435
  "cross-env": "^7.0.3",
1434
1436
  "eslint-plugin-node-import": "^1.0.5",
1435
1437
  jiti: "^2.6.1",
1438
+ openai: "6.25.0",
1436
1439
  "openapi-zod-client": "^1.18.3",
1437
1440
  rollup: "^4.28.1",
1438
1441
  vite: "^5.4.14",
@@ -1461,7 +1464,7 @@ var require_package = __commonJS({
1461
1464
  "cli-progress": "^3.12.0",
1462
1465
  "cli-table3": "^0.6.5",
1463
1466
  cors: "^2.8.5",
1464
- "dc-browser": "^1.0.2",
1467
+ "dc-browser": "^1.0.3",
1465
1468
  dotenv: "^16.4.5",
1466
1469
  esbuild: "^0.27.0",
1467
1470
  "eventsource-parser": "^1.1.2",
@@ -1509,6 +1512,161 @@ var import_pluralize4 = __toESM(require("pluralize"));
1509
1512
  // src/logger.ts
1510
1513
  var import_uuid2 = require("uuid");
1511
1514
 
1515
+ // src/isomorph.ts
1516
+ var DefaultAsyncLocalStorage = class {
1517
+ constructor() {
1518
+ }
1519
+ enterWith(_) {
1520
+ }
1521
+ run(_, callback) {
1522
+ return callback();
1523
+ }
1524
+ getStore() {
1525
+ return void 0;
1526
+ }
1527
+ };
1528
+ var DefaultTracingChannel = class {
1529
+ hasSubscribers = false;
1530
+ subscribe(_handlers) {
1531
+ }
1532
+ unsubscribe(_handlers) {
1533
+ return false;
1534
+ }
1535
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1536
+ traceSync(fn, _message, thisArg, ...args) {
1537
+ return fn.apply(thisArg, args);
1538
+ }
1539
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1540
+ tracePromise(fn, _message, thisArg, ...args) {
1541
+ return Promise.resolve(fn.apply(thisArg, args));
1542
+ }
1543
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1544
+ traceCallback(fn, _position, _message, thisArg, ...args) {
1545
+ return fn.apply(thisArg, args);
1546
+ }
1547
+ };
1548
+ var iso = {
1549
+ buildType: "unknown",
1550
+ // Will be set by configureBrowser() or configureNode()
1551
+ getRepoInfo: async (_settings) => void 0,
1552
+ getPastNAncestors: async () => [],
1553
+ getEnv: (_name) => void 0,
1554
+ getCallerLocation: () => void 0,
1555
+ newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
1556
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1557
+ newTracingChannel: (_nameOrChannels) => new DefaultTracingChannel(),
1558
+ processOn: (_0, _1) => {
1559
+ },
1560
+ basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
1561
+ writeln: (text) => console.log(text)
1562
+ };
1563
+ var isomorph_default = iso;
1564
+
1565
+ // src/debug-logger.ts
1566
+ var PREFIX = "[braintrust]";
1567
+ var DEBUG_LOG_LEVEL_SYMBOL = Symbol.for("braintrust-debug-log-level");
1568
+ var LOG_LEVEL_PRIORITY = {
1569
+ error: 0,
1570
+ warn: 1,
1571
+ info: 2,
1572
+ debug: 3
1573
+ };
1574
+ var hasWarnedAboutInvalidEnvValue = false;
1575
+ var debugLogStateResolver = void 0;
1576
+ function warnInvalidEnvValue(value) {
1577
+ if (hasWarnedAboutInvalidEnvValue) {
1578
+ return;
1579
+ }
1580
+ hasWarnedAboutInvalidEnvValue = true;
1581
+ console.warn(
1582
+ PREFIX,
1583
+ `Invalid BRAINTRUST_DEBUG_LOG_LEVEL value "${value}". Expected "error", "warn", "info", or "debug".`
1584
+ );
1585
+ }
1586
+ function normalizeDebugLogLevelOption(option) {
1587
+ if (option === false) {
1588
+ return void 0;
1589
+ }
1590
+ if (option === "error" || option === "warn" || option === "info" || option === "debug") {
1591
+ return option;
1592
+ }
1593
+ throw new Error(
1594
+ `Invalid debugLogLevel value "${option}". Expected false, "error", "warn", "info", or "debug".`
1595
+ );
1596
+ }
1597
+ function parseDebugLogLevelEnv(value) {
1598
+ if (!value) {
1599
+ return void 0;
1600
+ }
1601
+ if (value === "error" || value === "warn" || value === "info" || value === "debug") {
1602
+ return value;
1603
+ }
1604
+ warnInvalidEnvValue(value);
1605
+ return void 0;
1606
+ }
1607
+ function getEnvDebugLogLevel() {
1608
+ return parseDebugLogLevelEnv(isomorph_default.getEnv("BRAINTRUST_DEBUG_LOG_LEVEL"));
1609
+ }
1610
+ function setGlobalDebugLogLevel(level) {
1611
+ globalThis[DEBUG_LOG_LEVEL_SYMBOL] = level;
1612
+ }
1613
+ function setDebugLogStateResolver(resolver) {
1614
+ debugLogStateResolver = resolver;
1615
+ }
1616
+ function resolveDebugLogLevel(state) {
1617
+ const stateLevel = state?.getDebugLogLevel?.();
1618
+ const hasStateOverride = state?.hasDebugLogLevelOverride?.() ?? false;
1619
+ if (hasStateOverride) {
1620
+ return stateLevel;
1621
+ }
1622
+ const globalLevel = (
1623
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
1624
+ globalThis[DEBUG_LOG_LEVEL_SYMBOL]
1625
+ );
1626
+ if (globalLevel !== void 0) {
1627
+ return globalLevel === false ? void 0 : globalLevel;
1628
+ }
1629
+ return getEnvDebugLogLevel();
1630
+ }
1631
+ function emit(method, state, args) {
1632
+ const level = resolveDebugLogLevel(state);
1633
+ if (!level || LOG_LEVEL_PRIORITY[method] > LOG_LEVEL_PRIORITY[level]) {
1634
+ return;
1635
+ }
1636
+ if (method === "info") {
1637
+ console.log(PREFIX, ...args);
1638
+ } else if (method === "debug") {
1639
+ console.debug(PREFIX, ...args);
1640
+ } else if (method === "warn") {
1641
+ console.warn(PREFIX, ...args);
1642
+ } else {
1643
+ console.error(PREFIX, ...args);
1644
+ }
1645
+ }
1646
+ function createDebugLogger(state) {
1647
+ const resolveState = () => state ?? debugLogStateResolver?.();
1648
+ return {
1649
+ info(...args) {
1650
+ emit("info", resolveState(), args);
1651
+ },
1652
+ debug(...args) {
1653
+ emit("debug", resolveState(), args);
1654
+ },
1655
+ warn(...args) {
1656
+ emit("warn", resolveState(), args);
1657
+ },
1658
+ error(...args) {
1659
+ emit("error", resolveState(), args);
1660
+ }
1661
+ };
1662
+ }
1663
+ var debugLogger = {
1664
+ ...createDebugLogger(),
1665
+ forState(state) {
1666
+ return createDebugLogger(state);
1667
+ }
1668
+ };
1669
+
1512
1670
  // src/queue.ts
1513
1671
  var DEFAULT_QUEUE_SIZE = 15e3;
1514
1672
  var Queue = class {
@@ -1517,7 +1675,7 @@ var Queue = class {
1517
1675
  enforceSizeLimit = false;
1518
1676
  constructor(maxSize) {
1519
1677
  if (maxSize < 1) {
1520
- console.warn(
1678
+ debugLogger.warn(
1521
1679
  `maxSize ${maxSize} is <1, using default ${DEFAULT_QUEUE_SIZE}`
1522
1680
  );
1523
1681
  maxSize = DEFAULT_QUEUE_SIZE;
@@ -5045,34 +5203,6 @@ function devNullWritableStream() {
5045
5203
  });
5046
5204
  }
5047
5205
 
5048
- // src/isomorph.ts
5049
- var DefaultAsyncLocalStorage = class {
5050
- constructor() {
5051
- }
5052
- enterWith(_) {
5053
- }
5054
- run(_, callback) {
5055
- return callback();
5056
- }
5057
- getStore() {
5058
- return void 0;
5059
- }
5060
- };
5061
- var iso = {
5062
- buildType: "unknown",
5063
- // Will be set by configureBrowser() or configureNode()
5064
- getRepoInfo: async (_settings) => void 0,
5065
- getPastNAncestors: async () => [],
5066
- getEnv: (_name) => void 0,
5067
- getCallerLocation: () => void 0,
5068
- newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
5069
- processOn: (_0, _1) => {
5070
- },
5071
- basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
5072
- writeln: (text) => console.log(text)
5073
- };
5074
- var isomorph_default = iso;
5075
-
5076
5206
  // src/prompt-cache/disk-cache.ts
5077
5207
  function canUseDiskCache() {
5078
5208
  return !!(isomorph_default.hash && isomorph_default.gunzip && isomorph_default.gzip && isomorph_default.stat && isomorph_default.readFile && isomorph_default.writeFile && isomorph_default.utimes && isomorph_default.readdir && isomorph_default.mkdir && isomorph_default.unlink && isomorph_default.homedir);
@@ -5776,7 +5906,10 @@ var loginSchema = import_v38.z.strictObject({
5776
5906
  proxyUrl: import_v38.z.string(),
5777
5907
  loginToken: import_v38.z.string(),
5778
5908
  orgId: import_v38.z.string().nullish(),
5779
- gitMetadataSettings: GitMetadataSettings.nullish()
5909
+ gitMetadataSettings: GitMetadataSettings.nullish(),
5910
+ debugLogLevel: import_v38.z.enum(["error", "warn", "info", "debug"]).optional(),
5911
+ // Distinguishes explicit false from unset so env fallback stays disabled after deserialization.
5912
+ debugLogLevelDisabled: import_v38.z.boolean().optional()
5780
5913
  });
5781
5914
  var stateNonce = 0;
5782
5915
  var BraintrustState = class _BraintrustState {
@@ -5797,6 +5930,16 @@ var BraintrustState = class _BraintrustState {
5797
5930
  this._bgLogger = new SyncLazyValue(
5798
5931
  () => new HTTPBackgroundLogger(new LazyValue(defaultGetLogConn), loginParams)
5799
5932
  );
5933
+ if (loginParams.debugLogLevel !== void 0) {
5934
+ this.debugLogLevelConfigured = true;
5935
+ this.debugLogLevel = normalizeDebugLogLevelOption(
5936
+ loginParams.debugLogLevel
5937
+ );
5938
+ setGlobalDebugLogLevel(this.debugLogLevel ?? false);
5939
+ } else {
5940
+ this.debugLogLevel = getEnvDebugLogLevel();
5941
+ setGlobalDebugLogLevel(void 0);
5942
+ }
5800
5943
  this.resetLoginInfo();
5801
5944
  const memoryCache = new LRUCache({
5802
5945
  max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_MEMORY_MAX")) ?? 1 << 10
@@ -5841,6 +5984,8 @@ var BraintrustState = class _BraintrustState {
5841
5984
  proxyUrl = null;
5842
5985
  loggedIn = false;
5843
5986
  gitMetadataSettings;
5987
+ debugLogLevel;
5988
+ debugLogLevelConfigured = false;
5844
5989
  fetch = globalThis.fetch;
5845
5990
  _appConn = null;
5846
5991
  _apiConn = null;
@@ -5906,6 +6051,11 @@ var BraintrustState = class _BraintrustState {
5906
6051
  this.proxyUrl = other.proxyUrl;
5907
6052
  this.loggedIn = other.loggedIn;
5908
6053
  this.gitMetadataSettings = other.gitMetadataSettings;
6054
+ this.debugLogLevel = other.debugLogLevel;
6055
+ this.debugLogLevelConfigured = other.debugLogLevelConfigured;
6056
+ setGlobalDebugLogLevel(
6057
+ this.debugLogLevelConfigured ? this.debugLogLevel ?? false : void 0
6058
+ );
5909
6059
  this._appConn = other._appConn;
5910
6060
  this._apiConn = other._apiConn;
5911
6061
  this.loginReplaceApiConn(this.apiConn());
@@ -5930,7 +6080,9 @@ var BraintrustState = class _BraintrustState {
5930
6080
  orgName: this.orgName,
5931
6081
  apiUrl: this.apiUrl,
5932
6082
  proxyUrl: this.proxyUrl,
5933
- gitMetadataSettings: this.gitMetadataSettings
6083
+ gitMetadataSettings: this.gitMetadataSettings,
6084
+ ...this.debugLogLevel ? { debugLogLevel: this.debugLogLevel } : {},
6085
+ ...this.debugLogLevelConfigured && !this.debugLogLevel ? { debugLogLevelDisabled: true } : {}
5934
6086
  };
5935
6087
  }
5936
6088
  static deserialize(serialized, opts) {
@@ -5957,6 +6109,10 @@ var BraintrustState = class _BraintrustState {
5957
6109
  state.proxyConn().set_token(state.loginToken);
5958
6110
  }
5959
6111
  state.loggedIn = true;
6112
+ state.debugLogLevelConfigured = "debugLogLevel" in serializedParsed.data || !!serializedParsed.data.debugLogLevelDisabled;
6113
+ setGlobalDebugLogLevel(
6114
+ state.debugLogLevelConfigured ? state.debugLogLevel ?? false : void 0
6115
+ );
5960
6116
  state.loginReplaceApiConn(state.apiConn());
5961
6117
  return state;
5962
6118
  }
@@ -5969,7 +6125,22 @@ var BraintrustState = class _BraintrustState {
5969
6125
  setMaskingFunction(maskingFunction) {
5970
6126
  this.bgLogger().setMaskingFunction(maskingFunction);
5971
6127
  }
6128
+ setDebugLogLevel(option) {
6129
+ if (option === void 0) {
6130
+ return;
6131
+ }
6132
+ this.debugLogLevelConfigured = true;
6133
+ this.debugLogLevel = normalizeDebugLogLevelOption(option);
6134
+ setGlobalDebugLogLevel(this.debugLogLevel ?? false);
6135
+ }
6136
+ getDebugLogLevel() {
6137
+ return this.debugLogLevel;
6138
+ }
6139
+ hasDebugLogLevelOverride() {
6140
+ return this.debugLogLevelConfigured;
6141
+ }
5972
6142
  async login(loginParams) {
6143
+ this.setDebugLogLevel(loginParams.debugLogLevel);
5973
6144
  if (this.apiUrl && !loginParams.forceLogin) {
5974
6145
  return;
5975
6146
  }
@@ -6080,6 +6251,7 @@ function _internalSetInitialState() {
6080
6251
  _globalState = existing;
6081
6252
  }
6082
6253
  var _internalGetGlobalState = () => _globalState;
6254
+ setDebugLogStateResolver(() => _internalGetGlobalState());
6083
6255
  var FailedHTTPResponse = class extends Error {
6084
6256
  status;
6085
6257
  text;
@@ -6194,7 +6366,7 @@ var HTTPConnection = class _HTTPConnection {
6194
6366
  return await resp.json();
6195
6367
  } catch (e) {
6196
6368
  if (i < tries - 1) {
6197
- console.log(
6369
+ debugLogger.debug(
6198
6370
  `Retrying API request ${object_type} ${JSON.stringify(args)} ${e.status} ${e.text}`
6199
6371
  );
6200
6372
  continue;
@@ -6406,7 +6578,7 @@ with a Blob/ArrayBuffer, or run the program on Node.js.`
6406
6578
  try {
6407
6579
  statSync2(data);
6408
6580
  } catch (e) {
6409
- console.warn(`Failed to read file: ${e}`);
6581
+ debugLogger.warn(`Failed to read file: ${e}`);
6410
6582
  }
6411
6583
  }
6412
6584
  };
@@ -7118,7 +7290,7 @@ var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
7118
7290
  this.queueDropLoggingPeriod = queueDropLoggingPeriodEnv;
7119
7291
  }
7120
7292
  if (isomorph_default.getEnv("BRAINTRUST_LOG_FLUSH_CHUNK_SIZE")) {
7121
- console.warn(
7293
+ debugLogger.warn(
7122
7294
  "BRAINTRUST_LOG_FLUSH_CHUNK_SIZE is deprecated and no longer has any effect. Log flushing now sends all items at once and batches them automatically. This environment variable will be removed in a future major release."
7123
7295
  );
7124
7296
  }
@@ -7180,7 +7352,10 @@ var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
7180
7352
  const versionInfo = await conn.get_json("version");
7181
7353
  serverLimit = import_v38.z.object({ logs3_payload_max_bytes: import_v38.z.number().nullish() }).parse(versionInfo).logs3_payload_max_bytes ?? null;
7182
7354
  } catch (e) {
7183
- console.warn("Failed to fetch version info for payload limit:", e);
7355
+ debugLogger.warn(
7356
+ "Failed to fetch version info for payload limit:",
7357
+ e
7358
+ );
7184
7359
  }
7185
7360
  const validServerLimit = serverLimit !== null && serverLimit > 0 ? serverLimit : null;
7186
7361
  const canUseOverflow = validServerLimit !== null;
@@ -7324,16 +7499,16 @@ var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
7324
7499
  if (isRetrying) {
7325
7500
  errmsg += ". Retrying";
7326
7501
  }
7327
- console.warn(errmsg);
7502
+ debugLogger.warn(errmsg);
7328
7503
  if (!isRetrying) {
7329
- console.warn(
7504
+ debugLogger.warn(
7330
7505
  `Failed to construct log records to flush after ${this.numTries} attempts. Dropping batch`
7331
7506
  );
7332
7507
  throw e;
7333
7508
  } else {
7334
- console.warn(e);
7509
+ debugLogger.warn(e);
7335
7510
  const sleepTimeS = BACKGROUND_LOGGER_BASE_SLEEP_TIME_S * 2 ** i;
7336
- console.info(`Sleeping for ${sleepTimeS}s`);
7511
+ debugLogger.info(`Sleeping for ${sleepTimeS}s`);
7337
7512
  await new Promise(
7338
7513
  (resolve2) => setTimeout(resolve2, sleepTimeS * 1e3)
7339
7514
  );
@@ -7434,15 +7609,15 @@ Error: ${errorText}`;
7434
7609
  this.logFailedPayloadsDir();
7435
7610
  }
7436
7611
  if (!isRetrying) {
7437
- console.warn(
7612
+ debugLogger.warn(
7438
7613
  `log request failed after ${this.numTries} retries. Dropping batch`
7439
7614
  );
7440
7615
  throw new Error(errMsg);
7441
7616
  } else {
7442
- console.warn(errMsg);
7617
+ debugLogger.warn(errMsg);
7443
7618
  if (isRetrying) {
7444
7619
  const sleepTimeS = BACKGROUND_LOGGER_BASE_SLEEP_TIME_S * 2 ** i;
7445
- console.info(`Sleeping for ${sleepTimeS}s`);
7620
+ debugLogger.info(`Sleeping for ${sleepTimeS}s`);
7446
7621
  await new Promise(
7447
7622
  (resolve2) => setTimeout(resolve2, sleepTimeS * 1e3)
7448
7623
  );
@@ -7457,7 +7632,7 @@ Error: ${errorText}`;
7457
7632
  this.queueDropLoggingState.numDropped += numItems;
7458
7633
  const timeNow = getCurrentUnixTimestamp();
7459
7634
  if (timeNow - this.queueDropLoggingState.lastLoggedTimestamp > this.queueDropLoggingPeriod) {
7460
- console.warn(
7635
+ debugLogger.warn(
7461
7636
  `Dropped ${this.queueDropLoggingState.numDropped} elements due to full queue`
7462
7637
  );
7463
7638
  if (this.failedPublishPayloadsDir) {
@@ -7489,7 +7664,7 @@ Error: ${errorText}`;
7489
7664
  await _HTTPBackgroundLogger.writePayloadToDir({ payloadDir, payload });
7490
7665
  }
7491
7666
  } catch (e) {
7492
- console.error(e);
7667
+ debugLogger.error(e);
7493
7668
  }
7494
7669
  }
7495
7670
  static async writePayloadToDir({
@@ -7497,7 +7672,7 @@ Error: ${errorText}`;
7497
7672
  payload
7498
7673
  }) {
7499
7674
  if (!(isomorph_default.pathJoin && isomorph_default.mkdir && isomorph_default.writeFile)) {
7500
- console.warn(
7675
+ debugLogger.warn(
7501
7676
  "Cannot dump payloads: filesystem-operations not supported on this platform"
7502
7677
  );
7503
7678
  return;
@@ -7510,7 +7685,7 @@ Error: ${errorText}`;
7510
7685
  await isomorph_default.mkdir(payloadDir, { recursive: true });
7511
7686
  await isomorph_default.writeFile(payloadFile, payload);
7512
7687
  } catch (e) {
7513
- console.error(
7688
+ debugLogger.error(
7514
7689
  `Failed to write failed payload to output file ${payloadFile}:
7515
7690
  `,
7516
7691
  e
@@ -7541,7 +7716,9 @@ Error: ${errorText}`;
7541
7716
  }
7542
7717
  }
7543
7718
  logFailedPayloadsDir() {
7544
- console.warn(`Logging failed payloads to ${this.failedPublishPayloadsDir}`);
7719
+ debugLogger.warn(
7720
+ `Logging failed payloads to ${this.failedPublishPayloadsDir}`
7721
+ );
7545
7722
  }
7546
7723
  // Should only be called by BraintrustState.
7547
7724
  internalReplaceApiConn(apiConn) {
@@ -7706,9 +7883,7 @@ function init(projectOrOptions, optionalOptions) {
7706
7883
  break;
7707
7884
  } catch (e) {
7708
7885
  if (args["base_experiment"] && `${"data" in e && e.data}`.includes("base experiment")) {
7709
- console.warn(
7710
- `Base experiment ${args["base_experiment"]} not found.`
7711
- );
7886
+ debugLogger.forState(state).warn(`Base experiment ${args["base_experiment"]} not found.`);
7712
7887
  delete args["base_experiment"];
7713
7888
  } else {
7714
7889
  throw e;
@@ -7850,7 +8025,11 @@ async function computeLoggerMetadata(state, {
7850
8025
  }
7851
8026
  async function login(options = {}) {
7852
8027
  const { forceLogin = false } = options || {};
8028
+ if (!_internalGetGlobalState()) {
8029
+ _internalSetInitialState();
8030
+ }
7853
8031
  const state = _internalGetGlobalState();
8032
+ state.setDebugLogLevel(options.debugLogLevel);
7854
8033
  if (state.loggedIn && !forceLogin) {
7855
8034
  let checkUpdatedParam2 = function(varname, arg, orig) {
7856
8035
  if (!isEmpty2(arg) && !isEmpty2(orig) && arg !== orig) {
@@ -7869,9 +8048,6 @@ async function login(options = {}) {
7869
8048
  checkUpdatedParam2("orgName", options.orgName, state.orgName);
7870
8049
  return state;
7871
8050
  }
7872
- if (!state) {
7873
- _internalSetInitialState();
7874
- }
7875
8051
  await state.login(options);
7876
8052
  return state;
7877
8053
  }
@@ -8283,7 +8459,14 @@ var ObjectFetcher = class {
8283
8459
  async *fetchRecordsFromApi(batchSize) {
8284
8460
  const state = await this.getState();
8285
8461
  const objectId = await this.id;
8286
- const limit = batchSize ?? DEFAULT_FETCH_BATCH_SIZE;
8462
+ const batchLimit = batchSize ?? DEFAULT_FETCH_BATCH_SIZE;
8463
+ const internalLimit = this._internal_btql?.limit;
8464
+ const limit = batchSize !== void 0 ? batchSize : internalLimit ?? batchLimit;
8465
+ const internalBtqlWithoutReservedQueryKeys = Object.fromEntries(
8466
+ Object.entries(this._internal_btql ?? {}).filter(
8467
+ ([key]) => key !== "cursor" && key !== "limit" && key !== "select" && key !== "from"
8468
+ )
8469
+ );
8287
8470
  let cursor = void 0;
8288
8471
  let iterations = 0;
8289
8472
  while (true) {
@@ -8291,7 +8474,6 @@ var ObjectFetcher = class {
8291
8474
  `btql`,
8292
8475
  {
8293
8476
  query: {
8294
- ...this._internal_btql,
8295
8477
  select: [
8296
8478
  {
8297
8479
  op: "star"
@@ -8311,7 +8493,8 @@ var ObjectFetcher = class {
8311
8493
  ]
8312
8494
  },
8313
8495
  cursor,
8314
- limit
8496
+ limit,
8497
+ ...internalBtqlWithoutReservedQueryKeys
8315
8498
  },
8316
8499
  use_columnstore: false,
8317
8500
  brainstore_realtime: true,
@@ -8584,7 +8767,7 @@ var Experiment2 = class extends ObjectFetcher {
8584
8767
  scores = results["scores"];
8585
8768
  metrics = results["metrics"];
8586
8769
  } catch (e) {
8587
- console.warn(
8770
+ debugLogger.forState(state).warn(
8588
8771
  `Failed to fetch experiment scores and metrics: ${e}
8589
8772
 
8590
8773
  View complete results in Braintrust or run experiment.summarize() again.`
@@ -8661,7 +8844,7 @@ View complete results in Braintrust or run experiment.summarize() again.`
8661
8844
  * @deprecated This function is deprecated. You can simply remove it from your code.
8662
8845
  */
8663
8846
  async close() {
8664
- console.warn(
8847
+ debugLogger.forState(this.state).warn(
8665
8848
  "close is deprecated and will be removed in a future version of braintrust. It is now a no-op and can be removed"
8666
8849
  );
8667
8850
  return this.id;
@@ -8858,8 +9041,8 @@ var SpanImpl = class _SpanImpl {
8858
9041
  ...serializableInternalData,
8859
9042
  [IS_MERGE_FIELD]: this.isMerge
8860
9043
  });
8861
- if (partialRecord.metrics?.end) {
8862
- this.loggedEndTime = partialRecord.metrics?.end;
9044
+ if (typeof partialRecord.metrics?.end === "number") {
9045
+ this.loggedEndTime = partialRecord.metrics.end;
8863
9046
  }
8864
9047
  if (this.parentObjectType === 1 /* EXPERIMENT */) {
8865
9048
  const cachedSpan = {
@@ -9094,7 +9277,7 @@ var Dataset2 = class extends ObjectFetcher {
9094
9277
  constructor(state, lazyMetadata, pinnedVersion, legacy, _internal_btql) {
9095
9278
  const isLegacyDataset = legacy ?? DEFAULT_IS_LEGACY_DATASET;
9096
9279
  if (isLegacyDataset) {
9097
- console.warn(
9280
+ debugLogger.forState(state).warn(
9098
9281
  `Records will be fetched from this dataset in the legacy format, with the "expected" field renamed to "output". Please update your code to use "expected", and use \`braintrust.initDataset()\` with \`{ useOutput: false }\`, which will become the default in a future version of Braintrust.`
9099
9282
  );
9100
9283
  }
@@ -9325,7 +9508,7 @@ var Dataset2 = class extends ObjectFetcher {
9325
9508
  * @deprecated This function is deprecated. You can simply remove it from your code.
9326
9509
  */
9327
9510
  async close() {
9328
- console.warn(
9511
+ debugLogger.forState(this.state).warn(
9329
9512
  "close is deprecated and will be removed in a future version of braintrust. It is now a no-op and can be removed"
9330
9513
  );
9331
9514
  return this.id;
@@ -11225,6 +11408,11 @@ var evalParametersSchema = import_v310.z.record(
11225
11408
  default: promptDefinitionWithToolsSchema.optional(),
11226
11409
  description: import_v310.z.string().optional()
11227
11410
  }),
11411
+ import_v310.z.object({
11412
+ type: import_v310.z.literal("model"),
11413
+ default: import_v310.z.string().optional(),
11414
+ description: import_v310.z.string().optional()
11415
+ }),
11228
11416
  import_v310.z.instanceof(import_v310.z.ZodType)
11229
11417
  // For Zod schemas
11230
11418
  ])
@@ -11267,6 +11455,17 @@ function validateParametersWithZod(parameters, parameterSchema) {
11267
11455
  throw new Error(`Parameter '${name}' is required`);
11268
11456
  }
11269
11457
  return [name, Prompt2.fromPromptData(name, promptData)];
11458
+ } else if ("type" in schema && schema.type === "model") {
11459
+ const model = value ?? schema.default;
11460
+ if (model === void 0) {
11461
+ throw new Error(`Parameter '${name}' is required`);
11462
+ }
11463
+ if (typeof model !== "string") {
11464
+ throw new Error(
11465
+ `Parameter '${name}' must be a string model identifier`
11466
+ );
11467
+ }
11468
+ return [name, model];
11270
11469
  } else {
11271
11470
  const schemaCasted = schema;
11272
11471
  return [name, schemaCasted.parse(value)];
@@ -11341,10 +11540,10 @@ function callEvaluatorData(data) {
11341
11540
  };
11342
11541
  }
11343
11542
  function isAsyncIterable2(value) {
11344
- return typeof value === "object" && value !== null && typeof value[Symbol.asyncIterator] === "function";
11543
+ return typeof value === "object" && value !== null && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
11345
11544
  }
11346
11545
  function isIterable(value) {
11347
- return typeof value === "object" && value !== null && typeof value[Symbol.iterator] === "function";
11546
+ return typeof value === "object" && value !== null && Symbol.iterator in value && typeof value[Symbol.iterator] === "function";
11348
11547
  }
11349
11548
  globalThis._evals = {
11350
11549
  functions: [],
@@ -11806,7 +12005,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
11806
12005
  const names = Object.keys(scorerErrors).join(", ");
11807
12006
  const errors = failingScorersAndResults.map((item) => item.error);
11808
12007
  unhandledScores = Object.keys(scorerErrors);
11809
- console.warn(
12008
+ debugLogger.forState(evaluator.state).warn(
11810
12009
  `Found exceptions for the following scorers: ${names}`,
11811
12010
  errors
11812
12011
  );
@@ -11924,7 +12123,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
11924
12123
  q.kill();
11925
12124
  if (e instanceof InternalAbortError) {
11926
12125
  if (isomorph_default.getEnv("BRAINTRUST_VERBOSE")) {
11927
- console.warn("Evaluator cancelled:", e.message);
12126
+ debugLogger.forState(evaluator.state).warn("Evaluator cancelled:", e.message);
11928
12127
  }
11929
12128
  }
11930
12129
  throw e;
@@ -12020,7 +12219,11 @@ function reportFailures(evaluator, failingResults, { verbose, jsonl }) {
12020
12219
  }
12021
12220
  }
12022
12221
  if (!verbose && !jsonl) {
12023
- console.error(warning("Add --verbose to see full stack traces."));
12222
+ console.error(
12223
+ warning(
12224
+ "Use --debug-logging debug to see full stack traces and troubleshooting details."
12225
+ )
12226
+ );
12024
12227
  }
12025
12228
  }
12026
12229
  }
@@ -12267,6 +12470,7 @@ var fancyReporter = {
12267
12470
 
12268
12471
  // src/node/config.ts
12269
12472
  var import_node_async_hooks = require("node:async_hooks");
12473
+ var diagnostics_channel = __toESM(require("node:diagnostics_channel"));
12270
12474
  var path = __toESM(require("node:path"));
12271
12475
  var fs = __toESM(require("node:fs/promises"));
12272
12476
  var os = __toESM(require("node:os"));
@@ -12355,7 +12559,7 @@ async function getPastNAncestors(n = 1e3, remote = void 0) {
12355
12559
  try {
12356
12560
  ancestor = await getBaseBranchAncestor(remote);
12357
12561
  } catch (e) {
12358
- console.warn(
12562
+ debugLogger.warn(
12359
12563
  "Skipping git metadata. This is likely because the repository has not been published to a remote yet.",
12360
12564
  `${e}`
12361
12565
  );
@@ -12489,9 +12693,6 @@ function getCallerLocation() {
12489
12693
  return void 0;
12490
12694
  }
12491
12695
 
12492
- // src/instrumentation/core/plugin.ts
12493
- var import_dc_browser = require("dc-browser");
12494
-
12495
12696
  // src/instrumentation/core/stream-patcher.ts
12496
12697
  function isAsyncIterable3(value) {
12497
12698
  return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
@@ -12507,7 +12708,7 @@ function patchStreamIfNeeded(stream, options) {
12507
12708
  return stream;
12508
12709
  }
12509
12710
  const originalIteratorFn = stream[Symbol.asyncIterator];
12510
- if (originalIteratorFn.__braintrust_patched) {
12711
+ if ("__braintrust_patched" in originalIteratorFn && originalIteratorFn["__braintrust_patched"]) {
12511
12712
  return stream;
12512
12713
  }
12513
12714
  try {
@@ -12548,7 +12749,10 @@ function patchStreamIfNeeded(stream, options) {
12548
12749
  completed = true;
12549
12750
  if (options.onError) {
12550
12751
  try {
12551
- options.onError(error2, chunks);
12752
+ options.onError(
12753
+ error2 instanceof Error ? error2 : new Error(String(error2)),
12754
+ chunks
12755
+ );
12552
12756
  } catch (handlerError) {
12553
12757
  console.error("Error in stream onError handler:", handlerError);
12554
12758
  }
@@ -12576,7 +12780,8 @@ function patchStreamIfNeeded(stream, options) {
12576
12780
  iterator.throw = async function(...args) {
12577
12781
  if (!completed) {
12578
12782
  completed = true;
12579
- const error2 = args[0];
12783
+ const rawError = args[0];
12784
+ const error2 = rawError instanceof Error ? rawError : new Error(String(rawError));
12580
12785
  if (options.onError) {
12581
12786
  try {
12582
12787
  options.onError(error2, chunks);
@@ -12590,7 +12795,9 @@ function patchStreamIfNeeded(stream, options) {
12590
12795
  }
12591
12796
  return iterator;
12592
12797
  };
12593
- patchedIteratorFn.__braintrust_patched = true;
12798
+ Object.defineProperty(patchedIteratorFn, "__braintrust_patched", {
12799
+ value: true
12800
+ });
12594
12801
  stream[Symbol.asyncIterator] = patchedIteratorFn;
12595
12802
  return stream;
12596
12803
  } catch (error2) {
@@ -12599,6 +12806,49 @@ function patchStreamIfNeeded(stream, options) {
12599
12806
  }
12600
12807
  }
12601
12808
 
12809
+ // src/instrumentation/core/channel-tracing-utils.ts
12810
+ function hasChannelSpanInfo(value) {
12811
+ return isObject(value) && isObject(value.span_info);
12812
+ }
12813
+ function getChannelSpanInfo(event) {
12814
+ if (isObject(event.span_info)) {
12815
+ return event.span_info;
12816
+ }
12817
+ const firstArg = event.arguments?.[0];
12818
+ if (hasChannelSpanInfo(firstArg)) {
12819
+ return firstArg.span_info;
12820
+ }
12821
+ return void 0;
12822
+ }
12823
+ function buildStartSpanArgs(config3, event) {
12824
+ const spanInfo = getChannelSpanInfo(event);
12825
+ const spanAttributes = {
12826
+ type: config3.type
12827
+ };
12828
+ if (isObject(spanInfo?.spanAttributes)) {
12829
+ mergeDicts(spanAttributes, spanInfo.spanAttributes);
12830
+ }
12831
+ return {
12832
+ name: typeof spanInfo?.name === "string" && spanInfo.name ? spanInfo.name : config3.name,
12833
+ spanAttributes,
12834
+ spanInfoMetadata: isObject(spanInfo?.metadata) ? spanInfo.metadata : void 0
12835
+ };
12836
+ }
12837
+ function mergeInputMetadata(metadata, spanInfoMetadata) {
12838
+ if (!spanInfoMetadata) {
12839
+ return isObject(metadata) ? (
12840
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
12841
+ metadata
12842
+ ) : void 0;
12843
+ }
12844
+ const mergedMetadata = {};
12845
+ mergeDicts(mergedMetadata, spanInfoMetadata);
12846
+ if (isObject(metadata)) {
12847
+ mergeDicts(mergedMetadata, metadata);
12848
+ }
12849
+ return mergedMetadata;
12850
+ }
12851
+
12602
12852
  // src/instrumentation/core/plugin.ts
12603
12853
  var BasePlugin = class {
12604
12854
  enabled = false;
@@ -12630,23 +12880,25 @@ var BasePlugin = class {
12630
12880
  * @param handlers - Event handlers
12631
12881
  */
12632
12882
  subscribe(channelName, handlers) {
12633
- const channel = (0, import_dc_browser.tracingChannel)(channelName);
12634
- channel.subscribe(handlers);
12883
+ const channel2 = isomorph_default.newTracingChannel(channelName);
12884
+ channel2.subscribe(handlers);
12635
12885
  }
12636
12886
  /**
12637
12887
  * Subscribe to a channel for async methods (non-streaming).
12638
12888
  * Creates a span and logs input/output/metrics.
12639
12889
  */
12640
12890
  subscribeToChannel(channelName, config3) {
12641
- const channel = (0, import_dc_browser.tracingChannel)(channelName);
12891
+ const channel2 = isomorph_default.newTracingChannel(channelName);
12642
12892
  const spans = /* @__PURE__ */ new WeakMap();
12643
12893
  const handlers = {
12644
12894
  start: (event) => {
12895
+ const { name, spanAttributes, spanInfoMetadata } = buildStartSpanArgs(
12896
+ config3,
12897
+ event
12898
+ );
12645
12899
  const span = startSpan({
12646
- name: config3.name,
12647
- spanAttributes: {
12648
- type: config3.type
12649
- }
12900
+ name,
12901
+ spanAttributes
12650
12902
  });
12651
12903
  const startTime = getCurrentUnixTimestamp();
12652
12904
  spans.set(event, { span, startTime });
@@ -12654,7 +12906,7 @@ var BasePlugin = class {
12654
12906
  const { input, metadata } = config3.extractInput(event.arguments);
12655
12907
  span.log({
12656
12908
  input,
12657
- metadata
12909
+ metadata: mergeInputMetadata(metadata, spanInfoMetadata)
12658
12910
  });
12659
12911
  } catch (error2) {
12660
12912
  console.error(`Error extracting input for ${channelName}:`, error2);
@@ -12667,10 +12919,12 @@ var BasePlugin = class {
12667
12919
  }
12668
12920
  const { span, startTime } = spanData;
12669
12921
  try {
12670
- const output = config3.extractOutput(event.result);
12671
- const metrics = config3.extractMetrics(event.result, startTime);
12922
+ const output = config3.extractOutput(event.result, event);
12923
+ const metrics = config3.extractMetrics(event.result, startTime, event);
12924
+ const metadata = config3.extractMetadata?.(event.result, event);
12672
12925
  span.log({
12673
12926
  output,
12927
+ ...metadata !== void 0 ? { metadata } : {},
12674
12928
  metrics
12675
12929
  });
12676
12930
  } catch (error2) {
@@ -12693,9 +12947,9 @@ var BasePlugin = class {
12693
12947
  spans.delete(event);
12694
12948
  }
12695
12949
  };
12696
- channel.subscribe(handlers);
12950
+ channel2.subscribe(handlers);
12697
12951
  this.unsubscribers.push(() => {
12698
- channel.unsubscribe(handlers);
12952
+ channel2.unsubscribe(handlers);
12699
12953
  });
12700
12954
  }
12701
12955
  /**
@@ -12703,15 +12957,17 @@ var BasePlugin = class {
12703
12957
  * Handles both streaming and non-streaming responses.
12704
12958
  */
12705
12959
  subscribeToStreamingChannel(channelName, config3) {
12706
- const channel = (0, import_dc_browser.tracingChannel)(channelName);
12960
+ const channel2 = isomorph_default.newTracingChannel(channelName);
12707
12961
  const spans = /* @__PURE__ */ new WeakMap();
12708
12962
  const handlers = {
12709
12963
  start: (event) => {
12964
+ const { name, spanAttributes, spanInfoMetadata } = buildStartSpanArgs(
12965
+ config3,
12966
+ event
12967
+ );
12710
12968
  const span = startSpan({
12711
- name: config3.name,
12712
- spanAttributes: {
12713
- type: config3.type
12714
- }
12969
+ name,
12970
+ spanAttributes
12715
12971
  });
12716
12972
  const startTime = getCurrentUnixTimestamp();
12717
12973
  spans.set(event, { span, startTime });
@@ -12719,7 +12975,7 @@ var BasePlugin = class {
12719
12975
  const { input, metadata } = config3.extractInput(event.arguments);
12720
12976
  span.log({
12721
12977
  input,
12722
- metadata
12978
+ metadata: mergeInputMetadata(metadata, spanInfoMetadata)
12723
12979
  });
12724
12980
  } catch (error2) {
12725
12981
  console.error(`Error extracting input for ${channelName}:`, error2);
@@ -12732,24 +12988,39 @@ var BasePlugin = class {
12732
12988
  }
12733
12989
  const { span, startTime } = spanData;
12734
12990
  if (isAsyncIterable3(event.result)) {
12991
+ let firstChunkTime;
12735
12992
  patchStreamIfNeeded(event.result, {
12993
+ onChunk: () => {
12994
+ if (firstChunkTime === void 0) {
12995
+ firstChunkTime = getCurrentUnixTimestamp();
12996
+ }
12997
+ },
12736
12998
  onComplete: (chunks) => {
12737
12999
  try {
12738
13000
  let output;
12739
13001
  let metrics;
13002
+ let metadata;
12740
13003
  if (config3.aggregateChunks) {
12741
- const aggregated = config3.aggregateChunks(chunks);
13004
+ const aggregated = config3.aggregateChunks(
13005
+ chunks,
13006
+ event.result,
13007
+ event
13008
+ );
12742
13009
  output = aggregated.output;
12743
13010
  metrics = aggregated.metrics;
13011
+ metadata = aggregated.metadata;
12744
13012
  } else {
12745
- output = config3.extractOutput(chunks);
12746
- metrics = config3.extractMetrics(chunks, startTime);
13013
+ output = config3.extractOutput(chunks, event);
13014
+ metrics = config3.extractMetrics(chunks, startTime, event);
12747
13015
  }
12748
- if (!metrics.time_to_first_token && chunks.length > 0) {
13016
+ if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
13017
+ metrics.time_to_first_token = firstChunkTime - startTime;
13018
+ } else if (metrics.time_to_first_token === void 0 && chunks.length > 0) {
12749
13019
  metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
12750
13020
  }
12751
13021
  span.log({
12752
13022
  output,
13023
+ ...metadata !== void 0 ? { metadata } : {},
12753
13024
  metrics
12754
13025
  });
12755
13026
  } catch (error2) {
@@ -12770,10 +13041,16 @@ var BasePlugin = class {
12770
13041
  });
12771
13042
  } else {
12772
13043
  try {
12773
- const output = config3.extractOutput(event.result);
12774
- const metrics = config3.extractMetrics(event.result, startTime);
13044
+ const output = config3.extractOutput(event.result, event);
13045
+ const metadata = config3.extractMetadata ? config3.extractMetadata(event.result, event) : void 0;
13046
+ const metrics = config3.extractMetrics(
13047
+ event.result,
13048
+ startTime,
13049
+ event
13050
+ );
12775
13051
  span.log({
12776
13052
  output,
13053
+ ...metadata !== void 0 ? { metadata } : {},
12777
13054
  metrics
12778
13055
  });
12779
13056
  } catch (error2) {
@@ -12797,9 +13074,9 @@ var BasePlugin = class {
12797
13074
  spans.delete(event);
12798
13075
  }
12799
13076
  };
12800
- channel.subscribe(handlers);
13077
+ channel2.subscribe(handlers);
12801
13078
  this.unsubscribers.push(() => {
12802
- channel.unsubscribe(handlers);
13079
+ channel2.unsubscribe(handlers);
12803
13080
  });
12804
13081
  }
12805
13082
  /**
@@ -12807,15 +13084,17 @@ var BasePlugin = class {
12807
13084
  * Used for methods like beta.chat.completions.stream() and responses.stream().
12808
13085
  */
12809
13086
  subscribeToSyncStreamChannel(channelName, config3) {
12810
- const channel = (0, import_dc_browser.tracingChannel)(channelName);
13087
+ const channel2 = isomorph_default.newTracingChannel(channelName);
12811
13088
  const spans = /* @__PURE__ */ new WeakMap();
12812
13089
  const handlers = {
12813
13090
  start: (event) => {
13091
+ const { name, spanAttributes, spanInfoMetadata } = buildStartSpanArgs(
13092
+ config3,
13093
+ event
13094
+ );
12814
13095
  const span = startSpan({
12815
- name: config3.name,
12816
- spanAttributes: {
12817
- type: config3.type
12818
- }
13096
+ name,
13097
+ spanAttributes
12819
13098
  });
12820
13099
  const startTime = getCurrentUnixTimestamp();
12821
13100
  spans.set(event, { span, startTime });
@@ -12823,7 +13102,7 @@ var BasePlugin = class {
12823
13102
  const { input, metadata } = config3.extractInput(event.arguments);
12824
13103
  span.log({
12825
13104
  input,
12826
- metadata
13105
+ metadata: mergeInputMetadata(metadata, spanInfoMetadata)
12827
13106
  });
12828
13107
  } catch (error2) {
12829
13108
  console.error(`Error extracting input for ${channelName}:`, error2);
@@ -12907,141 +13186,629 @@ var BasePlugin = class {
12907
13186
  spans.delete(event);
12908
13187
  }
12909
13188
  };
12910
- channel.subscribe(handlers);
13189
+ channel2.subscribe(handlers);
12911
13190
  this.unsubscribers.push(() => {
12912
- channel.unsubscribe(handlers);
13191
+ channel2.unsubscribe(handlers);
12913
13192
  });
12914
13193
  }
12915
13194
  };
12916
13195
 
12917
- // src/wrappers/attachment-utils.ts
12918
- function getExtensionFromMediaType(mediaType) {
12919
- const extensionMap = {
12920
- "image/png": "png",
12921
- "image/jpeg": "jpg",
12922
- "image/gif": "gif",
12923
- "image/webp": "webp",
12924
- "image/svg+xml": "svg",
12925
- "audio/mpeg": "mp3",
12926
- "audio/wav": "wav",
12927
- "audio/ogg": "ogg",
12928
- "video/mp4": "mp4",
12929
- "video/webm": "webm",
12930
- "application/pdf": "pdf",
12931
- "application/json": "json",
12932
- "text/plain": "txt",
12933
- "text/html": "html",
12934
- "text/csv": "csv"
12935
- };
12936
- return extensionMap[mediaType] || "bin";
13196
+ // src/instrumentation/core/channel-tracing.ts
13197
+ function isSyncStreamLike(value) {
13198
+ return !!value && typeof value === "object" && typeof value.on === "function";
12937
13199
  }
12938
- function convertDataToBlob(data, mediaType) {
13200
+ function hasChoices(value) {
13201
+ return !!value && typeof value === "object" && "choices" in value;
13202
+ }
13203
+ function normalizeMetadata(metadata) {
13204
+ return isObject(metadata) ? metadata : void 0;
13205
+ }
13206
+ function startSpanForEvent(config3, event, channelName) {
13207
+ const { name, spanAttributes, spanInfoMetadata } = buildStartSpanArgs(
13208
+ config3,
13209
+ event
13210
+ );
13211
+ const span = startSpan({
13212
+ name,
13213
+ spanAttributes
13214
+ });
13215
+ const startTime = getCurrentUnixTimestamp();
12939
13216
  try {
12940
- if (typeof data === "string") {
12941
- if (data.startsWith("data:")) {
12942
- const base64Match = data.match(/^data:[^;]+;base64,(.+)$/);
12943
- if (base64Match) {
12944
- const base64 = base64Match[1];
12945
- const binaryString = atob(base64);
12946
- const bytes = new Uint8Array(binaryString.length);
12947
- for (let i = 0; i < binaryString.length; i++) {
12948
- bytes[i] = binaryString.charCodeAt(i);
12949
- }
12950
- return new Blob([bytes], { type: mediaType });
12951
- }
12952
- } else if (data.startsWith("http://") || data.startsWith("https://")) {
12953
- return null;
12954
- } else {
12955
- const binaryString = atob(data);
12956
- const bytes = new Uint8Array(binaryString.length);
12957
- for (let i = 0; i < binaryString.length; i++) {
12958
- bytes[i] = binaryString.charCodeAt(i);
12959
- }
12960
- return new Blob([bytes], { type: mediaType });
12961
- }
12962
- } else if (data instanceof Uint8Array) {
12963
- return new Blob([data], { type: mediaType });
12964
- } else if (data instanceof ArrayBuffer) {
12965
- return new Blob([data], { type: mediaType });
12966
- } else if (typeof Buffer !== "undefined" && data instanceof Buffer) {
12967
- return new Blob([data], { type: mediaType });
12968
- }
12969
- } catch {
12970
- return null;
13217
+ const { input, metadata } = config3.extractInput(event.arguments);
13218
+ span.log({
13219
+ input,
13220
+ metadata: mergeInputMetadata(metadata, spanInfoMetadata)
13221
+ });
13222
+ } catch (error2) {
13223
+ console.error(`Error extracting input for ${channelName}:`, error2);
12971
13224
  }
12972
- return null;
13225
+ return { span, startTime };
12973
13226
  }
12974
- function processInputAttachments(input) {
12975
- if (!input) {
12976
- return input;
13227
+ function logErrorAndEnd(states, event) {
13228
+ const spanData = states.get(event);
13229
+ if (!spanData) {
13230
+ return;
12977
13231
  }
12978
- let attachmentIndex = 0;
12979
- const processContentPart = (part) => {
12980
- if (!part || typeof part !== "object") {
12981
- return part;
12982
- }
12983
- if (part.type === "image" && part.image) {
12984
- let mediaType = "image/png";
12985
- if (typeof part.image === "string" && part.image.startsWith("data:")) {
12986
- const mediaTypeMatch = part.image.match(/^data:([^;]+);/);
12987
- if (mediaTypeMatch) {
12988
- mediaType = mediaTypeMatch[1];
12989
- }
12990
- } else if (part.mediaType) {
12991
- mediaType = part.mediaType;
13232
+ spanData.span.log({
13233
+ error: event.error.message
13234
+ });
13235
+ spanData.span.end();
13236
+ states.delete(event);
13237
+ }
13238
+ function traceAsyncChannel(channel2, config3) {
13239
+ const tracingChannel2 = channel2.tracingChannel();
13240
+ const states = /* @__PURE__ */ new WeakMap();
13241
+ const channelName = channel2.channelName;
13242
+ const handlers = {
13243
+ start: (event) => {
13244
+ states.set(
13245
+ event,
13246
+ startSpanForEvent(
13247
+ config3,
13248
+ event,
13249
+ channelName
13250
+ )
13251
+ );
13252
+ },
13253
+ asyncEnd: (event) => {
13254
+ const spanData = states.get(event);
13255
+ if (!spanData) {
13256
+ return;
12992
13257
  }
12993
- const blob = convertDataToBlob(part.image, mediaType);
12994
- if (blob) {
12995
- const filename = `input_image_${attachmentIndex}.${getExtensionFromMediaType(mediaType)}`;
12996
- attachmentIndex++;
12997
- const attachment = new Attachment({
12998
- data: blob,
12999
- filename,
13000
- contentType: mediaType
13001
- });
13002
- return {
13003
- ...part,
13258
+ const asyncEndEvent = event;
13259
+ const { span, startTime } = spanData;
13260
+ try {
13261
+ const output = config3.extractOutput(
13262
+ asyncEndEvent.result,
13263
+ asyncEndEvent
13264
+ );
13265
+ const metrics = config3.extractMetrics(
13266
+ asyncEndEvent.result,
13267
+ startTime,
13268
+ asyncEndEvent
13269
+ );
13270
+ const metadata = config3.extractMetadata?.(
13271
+ asyncEndEvent.result,
13272
+ asyncEndEvent
13273
+ );
13274
+ span.log({
13275
+ output,
13276
+ ...normalizeMetadata(metadata) !== void 0 ? { metadata: normalizeMetadata(metadata) } : {},
13277
+ metrics
13278
+ });
13279
+ } catch (error2) {
13280
+ console.error(`Error extracting output for ${channelName}:`, error2);
13281
+ } finally {
13282
+ span.end();
13283
+ states.delete(event);
13284
+ }
13285
+ },
13286
+ error: (event) => {
13287
+ logErrorAndEnd(states, event);
13288
+ }
13289
+ };
13290
+ tracingChannel2.subscribe(handlers);
13291
+ return () => {
13292
+ tracingChannel2.unsubscribe(handlers);
13293
+ };
13294
+ }
13295
+ function traceStreamingChannel(channel2, config3) {
13296
+ const tracingChannel2 = channel2.tracingChannel();
13297
+ const states = /* @__PURE__ */ new WeakMap();
13298
+ const channelName = channel2.channelName;
13299
+ const handlers = {
13300
+ start: (event) => {
13301
+ states.set(
13302
+ event,
13303
+ startSpanForEvent(
13304
+ config3,
13305
+ event,
13306
+ channelName
13307
+ )
13308
+ );
13309
+ },
13310
+ asyncEnd: (event) => {
13311
+ const spanData = states.get(event);
13312
+ if (!spanData) {
13313
+ return;
13314
+ }
13315
+ const asyncEndEvent = event;
13316
+ const { span, startTime } = spanData;
13317
+ if (isAsyncIterable3(asyncEndEvent.result)) {
13318
+ let firstChunkTime;
13319
+ patchStreamIfNeeded(asyncEndEvent.result, {
13320
+ onChunk: () => {
13321
+ if (firstChunkTime === void 0) {
13322
+ firstChunkTime = getCurrentUnixTimestamp();
13323
+ }
13324
+ },
13325
+ onComplete: (chunks) => {
13326
+ try {
13327
+ let output;
13328
+ let metrics;
13329
+ let metadata;
13330
+ if (config3.aggregateChunks) {
13331
+ const aggregated = config3.aggregateChunks(
13332
+ chunks,
13333
+ asyncEndEvent.result,
13334
+ asyncEndEvent,
13335
+ startTime
13336
+ );
13337
+ output = aggregated.output;
13338
+ metrics = aggregated.metrics;
13339
+ metadata = aggregated.metadata;
13340
+ } else {
13341
+ output = config3.extractOutput(
13342
+ chunks,
13343
+ asyncEndEvent
13344
+ );
13345
+ metrics = config3.extractMetrics(
13346
+ chunks,
13347
+ startTime,
13348
+ asyncEndEvent
13349
+ );
13350
+ }
13351
+ if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
13352
+ metrics.time_to_first_token = firstChunkTime - startTime;
13353
+ } else if (metrics.time_to_first_token === void 0 && chunks.length > 0) {
13354
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13355
+ }
13356
+ span.log({
13357
+ output,
13358
+ ...metadata !== void 0 ? { metadata } : {},
13359
+ metrics
13360
+ });
13361
+ } catch (error2) {
13362
+ console.error(
13363
+ `Error extracting output for ${channelName}:`,
13364
+ error2
13365
+ );
13366
+ } finally {
13367
+ span.end();
13368
+ states.delete(event);
13369
+ }
13370
+ },
13371
+ onError: (error2) => {
13372
+ span.log({
13373
+ error: error2.message
13374
+ });
13375
+ span.end();
13376
+ states.delete(event);
13377
+ }
13378
+ });
13379
+ return;
13380
+ }
13381
+ try {
13382
+ const output = config3.extractOutput(
13383
+ asyncEndEvent.result,
13384
+ asyncEndEvent
13385
+ );
13386
+ const metrics = config3.extractMetrics(
13387
+ asyncEndEvent.result,
13388
+ startTime,
13389
+ asyncEndEvent
13390
+ );
13391
+ const metadata = config3.extractMetadata?.(
13392
+ asyncEndEvent.result,
13393
+ asyncEndEvent
13394
+ );
13395
+ span.log({
13396
+ output,
13397
+ ...normalizeMetadata(metadata) !== void 0 ? { metadata: normalizeMetadata(metadata) } : {},
13398
+ metrics
13399
+ });
13400
+ } catch (error2) {
13401
+ console.error(`Error extracting output for ${channelName}:`, error2);
13402
+ } finally {
13403
+ span.end();
13404
+ states.delete(event);
13405
+ }
13406
+ },
13407
+ error: (event) => {
13408
+ logErrorAndEnd(states, event);
13409
+ }
13410
+ };
13411
+ tracingChannel2.subscribe(handlers);
13412
+ return () => {
13413
+ tracingChannel2.unsubscribe(handlers);
13414
+ };
13415
+ }
13416
+ function traceSyncStreamChannel(channel2, config3) {
13417
+ const tracingChannel2 = channel2.tracingChannel();
13418
+ const states = /* @__PURE__ */ new WeakMap();
13419
+ const channelName = channel2.channelName;
13420
+ const handlers = {
13421
+ start: (event) => {
13422
+ states.set(
13423
+ event,
13424
+ startSpanForEvent(
13425
+ config3,
13426
+ event,
13427
+ channelName
13428
+ )
13429
+ );
13430
+ },
13431
+ end: (event) => {
13432
+ const spanData = states.get(event);
13433
+ if (!spanData) {
13434
+ return;
13435
+ }
13436
+ const { span, startTime } = spanData;
13437
+ const resultEvent = event;
13438
+ const stream = resultEvent.result;
13439
+ if (!isSyncStreamLike(stream)) {
13440
+ span.end();
13441
+ states.delete(event);
13442
+ return;
13443
+ }
13444
+ let first = true;
13445
+ stream.on("chunk", () => {
13446
+ if (first) {
13447
+ span.log({
13448
+ metrics: {
13449
+ time_to_first_token: getCurrentUnixTimestamp() - startTime
13450
+ }
13451
+ });
13452
+ first = false;
13453
+ }
13454
+ });
13455
+ stream.on("chatCompletion", (completion) => {
13456
+ try {
13457
+ if (hasChoices(completion)) {
13458
+ span.log({
13459
+ output: completion.choices
13460
+ });
13461
+ }
13462
+ } catch (error2) {
13463
+ console.error(
13464
+ `Error extracting chatCompletion for ${channelName}:`,
13465
+ error2
13466
+ );
13467
+ }
13468
+ });
13469
+ stream.on("event", (streamEvent) => {
13470
+ if (!config3.extractFromEvent) {
13471
+ return;
13472
+ }
13473
+ try {
13474
+ if (first) {
13475
+ span.log({
13476
+ metrics: {
13477
+ time_to_first_token: getCurrentUnixTimestamp() - startTime
13478
+ }
13479
+ });
13480
+ first = false;
13481
+ }
13482
+ const extracted = config3.extractFromEvent(streamEvent);
13483
+ if (extracted && Object.keys(extracted).length > 0) {
13484
+ span.log(extracted);
13485
+ }
13486
+ } catch (error2) {
13487
+ console.error(`Error extracting event for ${channelName}:`, error2);
13488
+ }
13489
+ });
13490
+ stream.on("end", () => {
13491
+ span.end();
13492
+ states.delete(event);
13493
+ });
13494
+ stream.on("error", (error2) => {
13495
+ span.log({
13496
+ error: error2.message
13497
+ });
13498
+ span.end();
13499
+ states.delete(event);
13500
+ });
13501
+ },
13502
+ error: (event) => {
13503
+ logErrorAndEnd(states, event);
13504
+ }
13505
+ };
13506
+ tracingChannel2.subscribe(handlers);
13507
+ return () => {
13508
+ tracingChannel2.unsubscribe(handlers);
13509
+ };
13510
+ }
13511
+ function unsubscribeAll(unsubscribers) {
13512
+ for (const unsubscribe of unsubscribers) {
13513
+ unsubscribe();
13514
+ }
13515
+ return [];
13516
+ }
13517
+
13518
+ // src/wrappers/attachment-utils.ts
13519
+ function getExtensionFromMediaType(mediaType) {
13520
+ const extensionMap = {
13521
+ "image/png": "png",
13522
+ "image/jpeg": "jpg",
13523
+ "image/gif": "gif",
13524
+ "image/webp": "webp",
13525
+ "image/svg+xml": "svg",
13526
+ "audio/mpeg": "mp3",
13527
+ "audio/wav": "wav",
13528
+ "audio/ogg": "ogg",
13529
+ "video/mp4": "mp4",
13530
+ "video/webm": "webm",
13531
+ "application/pdf": "pdf",
13532
+ "application/json": "json",
13533
+ "text/plain": "txt",
13534
+ "text/html": "html",
13535
+ "text/csv": "csv"
13536
+ };
13537
+ return extensionMap[mediaType] || "bin";
13538
+ }
13539
+ function convertDataToBlob(data, mediaType) {
13540
+ try {
13541
+ if (typeof data === "string") {
13542
+ if (data.startsWith("data:")) {
13543
+ const base64Match = data.match(/^data:[^;]+;base64,(.+)$/);
13544
+ if (base64Match) {
13545
+ const base64 = base64Match[1];
13546
+ const binaryString = atob(base64);
13547
+ const bytes = new Uint8Array(binaryString.length);
13548
+ for (let i = 0; i < binaryString.length; i++) {
13549
+ bytes[i] = binaryString.charCodeAt(i);
13550
+ }
13551
+ return new Blob([bytes], { type: mediaType });
13552
+ }
13553
+ } else if (data.startsWith("http://") || data.startsWith("https://")) {
13554
+ return null;
13555
+ } else {
13556
+ const binaryString = atob(data);
13557
+ const bytes = new Uint8Array(binaryString.length);
13558
+ for (let i = 0; i < binaryString.length; i++) {
13559
+ bytes[i] = binaryString.charCodeAt(i);
13560
+ }
13561
+ return new Blob([bytes], { type: mediaType });
13562
+ }
13563
+ } else if (data instanceof Uint8Array) {
13564
+ return new Blob([data], { type: mediaType });
13565
+ } else if (data instanceof ArrayBuffer) {
13566
+ return new Blob([data], { type: mediaType });
13567
+ } else if (typeof Buffer !== "undefined" && data instanceof Buffer) {
13568
+ return new Blob([data], { type: mediaType });
13569
+ }
13570
+ } catch {
13571
+ return null;
13572
+ }
13573
+ return null;
13574
+ }
13575
+ function processInputAttachments(input) {
13576
+ if (!input) {
13577
+ return input;
13578
+ }
13579
+ let attachmentIndex = 0;
13580
+ const inferMediaTypeFromDataUrl = (value, fallback2) => {
13581
+ const mediaTypeMatch = value.match(/^data:([^;]+);/);
13582
+ return mediaTypeMatch?.[1] || fallback2;
13583
+ };
13584
+ const toAttachment = (value, mediaType, filename) => {
13585
+ const blob = convertDataToBlob(value, mediaType);
13586
+ if (!blob) {
13587
+ return null;
13588
+ }
13589
+ return new Attachment({
13590
+ data: blob,
13591
+ filename,
13592
+ contentType: mediaType
13593
+ });
13594
+ };
13595
+ const processNode = (node) => {
13596
+ if (Array.isArray(node)) {
13597
+ return node.map(processNode);
13598
+ }
13599
+ if (!node || typeof node !== "object") {
13600
+ return node;
13601
+ }
13602
+ if (node.type === "image_url" && node.image_url && typeof node.image_url === "object" && typeof node.image_url.url === "string" && node.image_url.url.startsWith("data:")) {
13603
+ const mediaType = inferMediaTypeFromDataUrl(
13604
+ node.image_url.url,
13605
+ "image/png"
13606
+ );
13607
+ const filename = `image.${getExtensionFromMediaType(mediaType)}`;
13608
+ const attachment = toAttachment(node.image_url.url, mediaType, filename);
13609
+ if (attachment) {
13610
+ return {
13611
+ ...node,
13612
+ image_url: {
13613
+ ...node.image_url,
13614
+ url: attachment
13615
+ }
13616
+ };
13617
+ }
13618
+ }
13619
+ if (node.type === "file" && node.file && typeof node.file === "object" && typeof node.file.file_data === "string" && node.file.file_data.startsWith("data:")) {
13620
+ const mediaType = inferMediaTypeFromDataUrl(
13621
+ node.file.file_data,
13622
+ "application/octet-stream"
13623
+ );
13624
+ const filename = typeof node.file.filename === "string" && node.file.filename ? node.file.filename : `document.${getExtensionFromMediaType(mediaType)}`;
13625
+ const attachment = toAttachment(node.file.file_data, mediaType, filename);
13626
+ if (attachment) {
13627
+ return {
13628
+ ...node,
13629
+ file: {
13630
+ ...node.file,
13631
+ file_data: attachment
13632
+ }
13633
+ };
13634
+ }
13635
+ }
13636
+ if (node.type === "image" && node.image) {
13637
+ let mediaType = "image/png";
13638
+ if (typeof node.image === "string" && node.image.startsWith("data:")) {
13639
+ mediaType = inferMediaTypeFromDataUrl(node.image, mediaType);
13640
+ } else if (node.mediaType) {
13641
+ mediaType = node.mediaType;
13642
+ }
13643
+ const filename = `input_image_${attachmentIndex}.${getExtensionFromMediaType(mediaType)}`;
13644
+ const attachment = toAttachment(node.image, mediaType, filename);
13645
+ if (attachment) {
13646
+ attachmentIndex++;
13647
+ return {
13648
+ ...node,
13004
13649
  image: attachment
13005
13650
  };
13006
13651
  }
13007
13652
  }
13008
- if (part.type === "file" && part.data) {
13009
- const mediaType = part.mediaType || "application/octet-stream";
13010
- const blob = convertDataToBlob(part.data, mediaType);
13011
- if (blob) {
13012
- const filename = part.filename || `input_file_${attachmentIndex}.${getExtensionFromMediaType(mediaType)}`;
13653
+ if (node.type === "file" && node.data) {
13654
+ const mediaType = node.mediaType || "application/octet-stream";
13655
+ const filename = node.filename || `input_file_${attachmentIndex}.${getExtensionFromMediaType(mediaType)}`;
13656
+ const attachment = toAttachment(node.data, mediaType, filename);
13657
+ if (attachment) {
13013
13658
  attachmentIndex++;
13014
- const attachment = new Attachment({
13015
- data: blob,
13016
- filename,
13017
- contentType: mediaType
13018
- });
13019
13659
  return {
13020
- ...part,
13660
+ ...node,
13021
13661
  data: attachment
13022
13662
  };
13023
13663
  }
13024
13664
  }
13025
- return part;
13026
- };
13027
- const processMessage = (message) => {
13028
- if (!message || typeof message !== "object") {
13029
- return message;
13030
- }
13031
- if (Array.isArray(message.content)) {
13032
- return {
13033
- ...message,
13034
- content: message.content.map(processContentPart)
13035
- };
13665
+ const processed = {};
13666
+ for (const [key, value] of Object.entries(node)) {
13667
+ processed[key] = processNode(value);
13036
13668
  }
13037
- return message;
13669
+ return processed;
13038
13670
  };
13039
13671
  if (Array.isArray(input)) {
13040
- return input.map(processMessage);
13041
- } else if (typeof input === "object" && input.content) {
13042
- return processMessage(input);
13672
+ return input.map(processNode);
13043
13673
  }
13044
- return input;
13674
+ return processNode(input);
13675
+ }
13676
+
13677
+ // src/instrumentation/core/channel-definitions.ts
13678
+ function channel(spec) {
13679
+ return spec;
13680
+ }
13681
+ function defineChannels(pkg, channels) {
13682
+ return Object.fromEntries(
13683
+ Object.entries(channels).map(([key, spec]) => {
13684
+ const fullChannelName = `orchestrion:${pkg}:${spec.channelName}`;
13685
+ if (spec.kind === "async") {
13686
+ const asyncSpec = spec;
13687
+ const tracingChannel3 = () => isomorph_default.newTracingChannel(
13688
+ fullChannelName
13689
+ );
13690
+ return [
13691
+ key,
13692
+ {
13693
+ ...asyncSpec,
13694
+ tracingChannel: tracingChannel3,
13695
+ tracePromise: (fn, context2) => tracingChannel3().tracePromise(
13696
+ fn,
13697
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
13698
+ context2
13699
+ )
13700
+ }
13701
+ ];
13702
+ }
13703
+ const syncSpec = spec;
13704
+ const tracingChannel2 = () => isomorph_default.newTracingChannel(
13705
+ fullChannelName
13706
+ );
13707
+ return [
13708
+ key,
13709
+ {
13710
+ ...syncSpec,
13711
+ tracingChannel: tracingChannel2,
13712
+ traceSync: (fn, context2) => tracingChannel2().traceSync(
13713
+ fn,
13714
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
13715
+ context2
13716
+ )
13717
+ }
13718
+ ];
13719
+ })
13720
+ );
13721
+ }
13722
+
13723
+ // src/instrumentation/plugins/openai-channels.ts
13724
+ var openAIChannels = defineChannels("openai", {
13725
+ chatCompletionsCreate: channel({
13726
+ channelName: "chat.completions.create",
13727
+ kind: "async"
13728
+ }),
13729
+ embeddingsCreate: channel({
13730
+ channelName: "embeddings.create",
13731
+ kind: "async"
13732
+ }),
13733
+ betaChatCompletionsParse: channel({
13734
+ channelName: "beta.chat.completions.parse",
13735
+ kind: "async"
13736
+ }),
13737
+ betaChatCompletionsStream: channel({
13738
+ channelName: "beta.chat.completions.stream",
13739
+ kind: "sync-stream"
13740
+ }),
13741
+ moderationsCreate: channel({
13742
+ channelName: "moderations.create",
13743
+ kind: "async"
13744
+ }),
13745
+ responsesCreate: channel({
13746
+ channelName: "responses.create",
13747
+ kind: "async"
13748
+ }),
13749
+ responsesStream: channel({
13750
+ channelName: "responses.stream",
13751
+ kind: "sync-stream"
13752
+ }),
13753
+ responsesParse: channel({
13754
+ channelName: "responses.parse",
13755
+ kind: "async"
13756
+ })
13757
+ });
13758
+
13759
+ // src/openai-utils.ts
13760
+ var BRAINTRUST_CACHED_STREAM_METRIC = "__braintrust_cached_metric";
13761
+ var LEGACY_CACHED_HEADER = "x-cached";
13762
+ var X_CACHED_HEADER = "x-bt-cached";
13763
+ var TOKEN_NAME_MAP = {
13764
+ input_tokens: "prompt_tokens",
13765
+ output_tokens: "completion_tokens",
13766
+ total_tokens: "tokens"
13767
+ };
13768
+ var TOKEN_PREFIX_MAP = {
13769
+ input: "prompt",
13770
+ output: "completion"
13771
+ };
13772
+ function parseMetricsFromUsage(usage) {
13773
+ if (!usage) {
13774
+ return {};
13775
+ }
13776
+ const metrics = {};
13777
+ for (const [oaiName, value] of Object.entries(usage)) {
13778
+ if (typeof value === "number") {
13779
+ const metricName = TOKEN_NAME_MAP[oaiName] || oaiName;
13780
+ metrics[metricName] = value;
13781
+ continue;
13782
+ }
13783
+ if (!oaiName.endsWith("_tokens_details") || !isObject(value)) {
13784
+ continue;
13785
+ }
13786
+ const rawPrefix = oaiName.slice(0, -"_tokens_details".length);
13787
+ const prefix = TOKEN_PREFIX_MAP[rawPrefix] || rawPrefix;
13788
+ for (const [key, nestedValue] of Object.entries(value)) {
13789
+ if (typeof nestedValue !== "number") {
13790
+ continue;
13791
+ }
13792
+ metrics[`${prefix}_${key}`] = nestedValue;
13793
+ }
13794
+ }
13795
+ return metrics;
13796
+ }
13797
+ function parseCachedHeader(value) {
13798
+ if (!value) {
13799
+ return void 0;
13800
+ }
13801
+ return ["true", "hit"].includes(value.toLowerCase()) ? 1 : 0;
13802
+ }
13803
+ function getCachedMetricFromHeaders(headers) {
13804
+ if (!headers || typeof headers.get !== "function") {
13805
+ return void 0;
13806
+ }
13807
+ const cachedHeader = headers.get(X_CACHED_HEADER);
13808
+ if (cachedHeader) {
13809
+ return parseCachedHeader(cachedHeader);
13810
+ }
13811
+ return parseCachedHeader(headers.get(LEGACY_CACHED_HEADER));
13045
13812
  }
13046
13813
 
13047
13814
  // src/instrumentation/plugins/openai-plugin.ts
@@ -13050,13 +13817,11 @@ var OpenAIPlugin = class extends BasePlugin {
13050
13817
  super();
13051
13818
  }
13052
13819
  onEnable() {
13053
- this.subscribeToStreamingChannel(
13054
- "orchestrion:openai:chat.completions.create",
13055
- {
13820
+ this.unsubscribers.push(
13821
+ traceStreamingChannel(openAIChannels.chatCompletionsCreate, {
13056
13822
  name: "Chat Completion",
13057
13823
  type: "llm" /* LLM */,
13058
- extractInput: (args) => {
13059
- const params = args[0] || {};
13824
+ extractInput: ([params]) => {
13060
13825
  const { messages, ...metadata } = params;
13061
13826
  return {
13062
13827
  input: processInputAttachments(messages),
@@ -13066,208 +13831,248 @@ var OpenAIPlugin = class extends BasePlugin {
13066
13831
  extractOutput: (result) => {
13067
13832
  return result?.choices;
13068
13833
  },
13069
- extractMetrics: (result, startTime) => {
13070
- const metrics = parseMetricsFromUsage(result?.usage);
13834
+ extractMetrics: (result, startTime, endEvent) => {
13835
+ const metrics = withCachedMetric(
13836
+ parseMetricsFromUsage(result?.usage),
13837
+ result,
13838
+ endEvent
13839
+ );
13071
13840
  if (startTime) {
13072
13841
  metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13073
13842
  }
13074
13843
  return metrics;
13075
13844
  },
13076
13845
  aggregateChunks: aggregateChatCompletionChunks
13077
- }
13846
+ })
13078
13847
  );
13079
- this.subscribeToChannel("orchestrion:openai:embeddings.create", {
13080
- name: "Embedding",
13081
- type: "llm" /* LLM */,
13082
- extractInput: (args) => {
13083
- const params = args[0] || {};
13084
- const { input, ...metadata } = params;
13085
- return {
13086
- input,
13087
- metadata: { ...metadata, provider: "openai" }
13088
- };
13089
- },
13090
- extractOutput: (result) => {
13091
- return result?.data?.map((d) => d.embedding);
13092
- },
13093
- extractMetrics: (result) => {
13094
- return parseMetricsFromUsage(result?.usage);
13095
- }
13096
- });
13097
- this.subscribeToStreamingChannel(
13098
- "orchestrion:openai:beta.chat.completions.parse",
13099
- {
13848
+ this.unsubscribers.push(
13849
+ traceAsyncChannel(openAIChannels.embeddingsCreate, {
13850
+ name: "Embedding",
13851
+ type: "llm" /* LLM */,
13852
+ extractInput: ([params]) => {
13853
+ const { input, ...metadata } = params;
13854
+ return {
13855
+ input,
13856
+ metadata: { ...metadata, provider: "openai" }
13857
+ };
13858
+ },
13859
+ extractOutput: (result) => {
13860
+ const embedding = result?.data?.[0]?.embedding;
13861
+ return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
13862
+ },
13863
+ extractMetrics: (result, _startTime, endEvent) => {
13864
+ return withCachedMetric(
13865
+ parseMetricsFromUsage(result?.usage),
13866
+ result,
13867
+ endEvent
13868
+ );
13869
+ }
13870
+ })
13871
+ );
13872
+ this.unsubscribers.push(
13873
+ traceStreamingChannel(openAIChannels.betaChatCompletionsParse, {
13874
+ name: "Chat Completion",
13875
+ type: "llm" /* LLM */,
13876
+ extractInput: ([params]) => {
13877
+ const { messages, ...metadata } = params;
13878
+ return {
13879
+ input: processInputAttachments(messages),
13880
+ metadata: { ...metadata, provider: "openai" }
13881
+ };
13882
+ },
13883
+ extractOutput: (result) => {
13884
+ return result?.choices;
13885
+ },
13886
+ extractMetrics: (result, startTime, endEvent) => {
13887
+ const metrics = withCachedMetric(
13888
+ parseMetricsFromUsage(result?.usage),
13889
+ result,
13890
+ endEvent
13891
+ );
13892
+ if (startTime) {
13893
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13894
+ }
13895
+ return metrics;
13896
+ },
13897
+ aggregateChunks: aggregateChatCompletionChunks
13898
+ })
13899
+ );
13900
+ this.unsubscribers.push(
13901
+ traceSyncStreamChannel(openAIChannels.betaChatCompletionsStream, {
13100
13902
  name: "Chat Completion",
13101
13903
  type: "llm" /* LLM */,
13102
- extractInput: (args) => {
13103
- const params = args[0] || {};
13104
- const { messages, ...metadata } = params;
13904
+ extractInput: ([params]) => {
13905
+ const { messages, ...metadata } = params;
13906
+ return {
13907
+ input: processInputAttachments(messages),
13908
+ metadata: { ...metadata, provider: "openai" }
13909
+ };
13910
+ }
13911
+ })
13912
+ );
13913
+ this.unsubscribers.push(
13914
+ traceAsyncChannel(openAIChannels.moderationsCreate, {
13915
+ name: "Moderation",
13916
+ type: "llm" /* LLM */,
13917
+ extractInput: ([params]) => {
13918
+ const { input, ...metadata } = params;
13919
+ return {
13920
+ input,
13921
+ metadata: { ...metadata, provider: "openai" }
13922
+ };
13923
+ },
13924
+ extractOutput: (result) => {
13925
+ return result?.results;
13926
+ },
13927
+ extractMetrics: (result, _startTime, endEvent) => {
13928
+ return withCachedMetric(
13929
+ parseMetricsFromUsage(result?.usage),
13930
+ result,
13931
+ endEvent
13932
+ );
13933
+ }
13934
+ })
13935
+ );
13936
+ this.unsubscribers.push(
13937
+ traceStreamingChannel(openAIChannels.responsesCreate, {
13938
+ name: "openai.responses.create",
13939
+ type: "llm" /* LLM */,
13940
+ extractInput: ([params]) => {
13941
+ const { input, ...metadata } = params;
13105
13942
  return {
13106
- input: processInputAttachments(messages),
13943
+ input: processInputAttachments(input),
13107
13944
  metadata: { ...metadata, provider: "openai" }
13108
13945
  };
13109
13946
  },
13110
13947
  extractOutput: (result) => {
13111
- return result?.choices;
13948
+ return processImagesInOutput(result?.output);
13112
13949
  },
13113
- extractMetrics: (result, startTime) => {
13114
- const metrics = parseMetricsFromUsage(result?.usage);
13950
+ extractMetadata: (result) => {
13951
+ if (!result) {
13952
+ return void 0;
13953
+ }
13954
+ const { output: _output, usage: _usage, ...metadata } = result;
13955
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
13956
+ },
13957
+ extractMetrics: (result, startTime, endEvent) => {
13958
+ const metrics = withCachedMetric(
13959
+ parseMetricsFromUsage(result?.usage),
13960
+ result,
13961
+ endEvent
13962
+ );
13115
13963
  if (startTime) {
13116
13964
  metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13117
13965
  }
13118
13966
  return metrics;
13119
13967
  },
13120
- aggregateChunks: aggregateChatCompletionChunks
13121
- }
13968
+ aggregateChunks: aggregateResponseStreamEvents
13969
+ })
13122
13970
  );
13123
- this.subscribeToSyncStreamChannel(
13124
- "orchestrion:openai:beta.chat.completions.stream",
13125
- {
13126
- name: "Chat Completion",
13971
+ this.unsubscribers.push(
13972
+ traceSyncStreamChannel(openAIChannels.responsesStream, {
13973
+ name: "openai.responses.create",
13127
13974
  type: "llm" /* LLM */,
13128
- extractInput: (args) => {
13129
- const params = args[0] || {};
13130
- const { messages, ...metadata } = params;
13975
+ extractInput: ([params]) => {
13976
+ const { input, ...metadata } = params;
13131
13977
  return {
13132
- input: processInputAttachments(messages),
13978
+ input: processInputAttachments(input),
13133
13979
  metadata: { ...metadata, provider: "openai" }
13134
13980
  };
13135
- }
13136
- }
13137
- );
13138
- this.subscribeToChannel("orchestrion:openai:moderations.create", {
13139
- name: "Moderation",
13140
- type: "llm" /* LLM */,
13141
- extractInput: (args) => {
13142
- const params = args[0] || {};
13143
- const { input, ...metadata } = params;
13144
- return {
13145
- input,
13146
- metadata: { ...metadata, provider: "openai" }
13147
- };
13148
- },
13149
- extractOutput: (result) => {
13150
- return result?.results;
13151
- },
13152
- extractMetrics: () => {
13153
- return {};
13154
- }
13155
- });
13156
- this.subscribeToStreamingChannel("orchestrion:openai:responses.create", {
13157
- name: "openai.responses.create",
13158
- type: "llm" /* LLM */,
13159
- extractInput: (args) => {
13160
- const params = args[0] || {};
13161
- const { input, ...metadata } = params;
13162
- return {
13163
- input: processInputAttachments(input),
13164
- metadata: { ...metadata, provider: "openai" }
13165
- };
13166
- },
13167
- extractOutput: (result) => {
13168
- return processImagesInOutput(result?.output);
13169
- },
13170
- extractMetrics: (result, startTime) => {
13171
- const metrics = parseMetricsFromUsage(result?.usage);
13172
- if (startTime) {
13173
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13174
- }
13175
- return metrics;
13176
- }
13177
- });
13178
- this.subscribeToSyncStreamChannel("orchestrion:openai:responses.stream", {
13179
- name: "openai.responses.stream",
13180
- type: "llm" /* LLM */,
13181
- extractInput: (args) => {
13182
- const params = args[0] || {};
13183
- const { input, ...metadata } = params;
13184
- return {
13185
- input: processInputAttachments(input),
13186
- metadata: { ...metadata, provider: "openai" }
13187
- };
13188
- },
13189
- extractFromEvent: (event) => {
13190
- if (!event || !event.type || !event.response) {
13191
- return {};
13192
- }
13193
- const response = event.response;
13194
- if (event.type === "response.completed") {
13981
+ },
13982
+ extractFromEvent: (event) => {
13983
+ if (event.type !== "response.completed" || !event.response) {
13984
+ return {};
13985
+ }
13986
+ const response = event.response;
13195
13987
  const data = {};
13196
- if (response?.output !== void 0) {
13988
+ if (response.output !== void 0) {
13197
13989
  data.output = processImagesInOutput(response.output);
13198
13990
  }
13199
- if (response) {
13200
- const { usage: _usage, output: _output, ...metadata } = response;
13201
- if (Object.keys(metadata).length > 0) {
13202
- data.metadata = metadata;
13203
- }
13991
+ const { usage: _usage, output: _output, ...metadata } = response;
13992
+ if (Object.keys(metadata).length > 0) {
13993
+ data.metadata = metadata;
13204
13994
  }
13205
- data.metrics = parseMetricsFromUsage(response?.usage);
13995
+ data.metrics = parseMetricsFromUsage(response.usage);
13206
13996
  return data;
13207
13997
  }
13208
- return {};
13209
- }
13210
- });
13211
- this.subscribeToStreamingChannel("orchestrion:openai:responses.parse", {
13212
- name: "openai.responses.parse",
13213
- type: "llm" /* LLM */,
13214
- extractInput: (args) => {
13215
- const params = args[0] || {};
13216
- const { input, ...metadata } = params;
13217
- return {
13218
- input: processInputAttachments(input),
13219
- metadata: { ...metadata, provider: "openai" }
13220
- };
13221
- },
13222
- extractOutput: (result) => {
13223
- return processImagesInOutput(result?.output);
13224
- },
13225
- extractMetrics: (result, startTime) => {
13226
- const metrics = parseMetricsFromUsage(result?.usage);
13227
- if (startTime) {
13228
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13229
- }
13230
- return metrics;
13231
- }
13232
- });
13998
+ })
13999
+ );
14000
+ this.unsubscribers.push(
14001
+ traceStreamingChannel(openAIChannels.responsesParse, {
14002
+ name: "openai.responses.parse",
14003
+ type: "llm" /* LLM */,
14004
+ extractInput: ([params]) => {
14005
+ const { input, ...metadata } = params;
14006
+ return {
14007
+ input: processInputAttachments(input),
14008
+ metadata: { ...metadata, provider: "openai" }
14009
+ };
14010
+ },
14011
+ extractOutput: (result) => {
14012
+ return processImagesInOutput(result?.output);
14013
+ },
14014
+ extractMetadata: (result) => {
14015
+ if (!result) {
14016
+ return void 0;
14017
+ }
14018
+ const { output: _output, usage: _usage, ...metadata } = result;
14019
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
14020
+ },
14021
+ extractMetrics: (result, startTime, endEvent) => {
14022
+ const metrics = withCachedMetric(
14023
+ parseMetricsFromUsage(result?.usage),
14024
+ result,
14025
+ endEvent
14026
+ );
14027
+ if (startTime) {
14028
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
14029
+ }
14030
+ return metrics;
14031
+ },
14032
+ aggregateChunks: aggregateResponseStreamEvents
14033
+ })
14034
+ );
13233
14035
  }
13234
14036
  onDisable() {
14037
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
13235
14038
  }
13236
14039
  };
13237
- var TOKEN_NAME_MAP = {
13238
- input_tokens: "prompt_tokens",
13239
- output_tokens: "completion_tokens",
13240
- total_tokens: "tokens"
13241
- };
13242
- var TOKEN_PREFIX_MAP = {
13243
- input: "prompt",
13244
- output: "completion"
13245
- };
13246
- function parseMetricsFromUsage(usage) {
13247
- if (!usage) {
13248
- return {};
14040
+ function getCachedMetricFromEndEvent(endEvent) {
14041
+ if (!isObject(endEvent)) {
14042
+ return void 0;
13249
14043
  }
13250
- const metrics = {};
13251
- for (const [oai_name, value] of Object.entries(usage)) {
13252
- if (typeof value === "number") {
13253
- const metricName = TOKEN_NAME_MAP[oai_name] || oai_name;
13254
- metrics[metricName] = value;
13255
- } else if (oai_name.endsWith("_tokens_details")) {
13256
- if (!isObject(value)) {
13257
- continue;
13258
- }
13259
- const rawPrefix = oai_name.slice(0, -"_tokens_details".length);
13260
- const prefix = TOKEN_PREFIX_MAP[rawPrefix] || rawPrefix;
13261
- for (const [key, n] of Object.entries(value)) {
13262
- if (typeof n !== "number") {
13263
- continue;
13264
- }
13265
- const metricName = `${prefix}_${key}`;
13266
- metrics[metricName] = n;
13267
- }
13268
- }
14044
+ const response = endEvent.response;
14045
+ if (!isObject(response)) {
14046
+ return void 0;
13269
14047
  }
13270
- return metrics;
14048
+ const headers = response.headers;
14049
+ if (!headers || typeof headers.get !== "function") {
14050
+ return void 0;
14051
+ }
14052
+ return getCachedMetricFromHeaders(headers);
14053
+ }
14054
+ function withCachedMetric(metrics, result, endEvent) {
14055
+ if (metrics.cached !== void 0) {
14056
+ return metrics;
14057
+ }
14058
+ const cachedFromEvent = getCachedMetricFromEndEvent(endEvent);
14059
+ if (cachedFromEvent !== void 0) {
14060
+ return {
14061
+ ...metrics,
14062
+ cached: cachedFromEvent
14063
+ };
14064
+ }
14065
+ if (!isObject(result)) {
14066
+ return metrics;
14067
+ }
14068
+ const cached = result[BRAINTRUST_CACHED_STREAM_METRIC];
14069
+ if (typeof cached !== "number") {
14070
+ return metrics;
14071
+ }
14072
+ return {
14073
+ ...metrics,
14074
+ cached
14075
+ };
13271
14076
  }
13272
14077
  function processImagesInOutput(output) {
13273
14078
  if (Array.isArray(output)) {
@@ -13298,7 +14103,7 @@ function processImagesInOutput(output) {
13298
14103
  }
13299
14104
  return output;
13300
14105
  }
13301
- function aggregateChatCompletionChunks(chunks) {
14106
+ function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
13302
14107
  let role = void 0;
13303
14108
  let content = void 0;
13304
14109
  let tool_calls = void 0;
@@ -13340,6 +14145,7 @@ function aggregateChatCompletionChunks(chunks) {
13340
14145
  }
13341
14146
  }
13342
14147
  }
14148
+ metrics = withCachedMetric(metrics, streamResult, endEvent);
13343
14149
  return {
13344
14150
  metrics,
13345
14151
  output: [
@@ -13356,9 +14162,33 @@ function aggregateChatCompletionChunks(chunks) {
13356
14162
  ]
13357
14163
  };
13358
14164
  }
13359
-
13360
- // src/instrumentation/plugins/anthropic-plugin.ts
13361
- var import_dc_browser2 = require("dc-browser");
14165
+ function aggregateResponseStreamEvents(chunks, _streamResult, endEvent) {
14166
+ let output = void 0;
14167
+ let metrics = {};
14168
+ let metadata = void 0;
14169
+ for (const chunk of chunks) {
14170
+ if (!chunk || !chunk.type || !chunk.response) {
14171
+ continue;
14172
+ }
14173
+ if (chunk.type !== "response.completed") {
14174
+ continue;
14175
+ }
14176
+ const response = chunk.response;
14177
+ if (response?.output !== void 0) {
14178
+ output = processImagesInOutput(response.output);
14179
+ }
14180
+ const { usage: _usage, output: _output, ...rest } = response || {};
14181
+ if (Object.keys(rest).length > 0) {
14182
+ metadata = rest;
14183
+ }
14184
+ metrics = parseMetricsFromUsage(response?.usage);
14185
+ }
14186
+ return {
14187
+ output,
14188
+ metrics: withCachedMetric(metrics, void 0, endEvent),
14189
+ ...metadata !== void 0 ? { metadata } : {}
14190
+ };
14191
+ }
13362
14192
 
13363
14193
  // src/wrappers/anthropic-tokens-util.ts
13364
14194
  function finalizeAnthropicTokens(metrics) {
@@ -13380,20 +14210,28 @@ function extractAnthropicCacheTokens(cacheReadTokens = 0, cacheCreationTokens =
13380
14210
  return cacheTokens;
13381
14211
  }
13382
14212
 
14213
+ // src/instrumentation/plugins/anthropic-channels.ts
14214
+ var anthropicChannels = defineChannels("@anthropic-ai/sdk", {
14215
+ messagesCreate: channel({
14216
+ channelName: "messages.create",
14217
+ kind: "async"
14218
+ }),
14219
+ betaMessagesCreate: channel({
14220
+ channelName: "beta.messages.create",
14221
+ kind: "async"
14222
+ })
14223
+ });
14224
+
13383
14225
  // src/instrumentation/plugins/anthropic-plugin.ts
13384
14226
  var AnthropicPlugin = class extends BasePlugin {
13385
- unsubscribers = [];
13386
14227
  onEnable() {
13387
14228
  this.subscribeToAnthropicChannels();
13388
14229
  }
13389
14230
  onDisable() {
13390
- for (const unsubscribe of this.unsubscribers) {
13391
- unsubscribe();
13392
- }
13393
- this.unsubscribers = [];
14231
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
13394
14232
  }
13395
14233
  subscribeToAnthropicChannels() {
13396
- this.subscribeToStreamingChannel("orchestrion:anthropic:messages.create", {
14234
+ const anthropicConfig = {
13397
14235
  name: "anthropic.messages.create",
13398
14236
  type: "llm" /* LLM */,
13399
14237
  extractInput: (args) => {
@@ -13405,190 +14243,42 @@ var AnthropicPlugin = class extends BasePlugin {
13405
14243
  metadata: { ...metadata, provider: "anthropic" }
13406
14244
  };
13407
14245
  },
13408
- extractOutput: (result) => {
13409
- return result ? { role: result.role, content: result.content } : null;
14246
+ extractOutput: (message) => {
14247
+ return message ? { role: message.role, content: message.content } : null;
13410
14248
  },
13411
- extractMetrics: (result, startTime) => {
13412
- const metrics = parseMetricsFromUsage2(result?.usage);
14249
+ extractMetrics: (message, startTime) => {
14250
+ const metrics = parseMetricsFromUsage2(message?.usage);
13413
14251
  if (startTime) {
13414
14252
  metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13415
14253
  }
13416
14254
  const finalized = finalizeAnthropicTokens(metrics);
13417
14255
  return Object.fromEntries(
13418
- Object.entries(finalized).filter(([, v]) => v !== void 0)
14256
+ Object.entries(finalized).filter(
14257
+ (entry) => entry[1] !== void 0
14258
+ )
13419
14259
  );
13420
14260
  },
13421
- extractMetadata: (result) => {
13422
- const metadata = {};
13423
- const metas = ["stop_reason", "stop_sequence"];
13424
- for (const m of metas) {
13425
- if (result?.[m] !== void 0) {
13426
- metadata[m] = result[m];
13427
- }
13428
- }
13429
- return metadata;
13430
- },
13431
- aggregateChunks: aggregateAnthropicStreamChunks,
13432
- isStreaming: (args) => {
13433
- return args[0]?.stream === true;
13434
- }
13435
- });
13436
- this.subscribeToStreamingChannel(
13437
- "orchestrion:anthropic:beta.messages.create",
13438
- {
13439
- name: "anthropic.beta.messages.create",
13440
- type: "llm" /* LLM */,
13441
- extractInput: (args) => {
13442
- const params = args[0] || {};
13443
- const input = coalesceInput(params.messages || [], params.system);
13444
- const metadata = filterFrom(params, ["messages", "system"]);
13445
- return {
13446
- input: processAttachmentsInInput(input),
13447
- metadata: { ...metadata, provider: "anthropic" }
13448
- };
13449
- },
13450
- extractOutput: (result) => {
13451
- return result ? { role: result.role, content: result.content } : null;
13452
- },
13453
- extractMetrics: (result, startTime) => {
13454
- const metrics = parseMetricsFromUsage2(result?.usage);
13455
- if (startTime) {
13456
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13457
- }
13458
- const finalized = finalizeAnthropicTokens(metrics);
13459
- return Object.fromEntries(
13460
- Object.entries(finalized).filter(([, v]) => v !== void 0)
13461
- );
13462
- },
13463
- extractMetadata: (result) => {
13464
- const metadata = {};
13465
- const metas = ["stop_reason", "stop_sequence"];
13466
- for (const m of metas) {
13467
- if (result?.[m] !== void 0) {
13468
- metadata[m] = result[m];
13469
- }
13470
- }
13471
- return metadata;
13472
- },
13473
- aggregateChunks: aggregateAnthropicStreamChunks,
13474
- isStreaming: (args) => {
13475
- return args[0]?.stream === true;
13476
- }
13477
- }
13478
- );
13479
- }
13480
- /**
13481
- * Subscribe to a channel for async methods that may return streams.
13482
- * Handles both streaming and non-streaming responses based on the stream parameter.
13483
- */
13484
- subscribeToStreamingChannel(channelName, config3) {
13485
- const channel = (0, import_dc_browser2.tracingChannel)(channelName);
13486
- const spans = /* @__PURE__ */ new WeakMap();
13487
- const handlers = {
13488
- start: (event) => {
13489
- const span = startSpan({
13490
- name: config3.name,
13491
- spanAttributes: {
13492
- type: config3.type
13493
- }
13494
- });
13495
- const startTime = getCurrentUnixTimestamp();
13496
- spans.set(event, { span, startTime });
13497
- try {
13498
- const { input, metadata } = config3.extractInput(event.arguments);
13499
- span.log({
13500
- input,
13501
- metadata
13502
- });
13503
- } catch (error2) {
13504
- console.error(`Error extracting input for ${channelName}:`, error2);
13505
- }
13506
- },
13507
- asyncEnd: (event) => {
13508
- const spanData = spans.get(event);
13509
- if (!spanData) {
13510
- return;
13511
- }
13512
- const { span, startTime } = spanData;
13513
- const isStreaming = config3.isStreaming ? config3.isStreaming(event.arguments) : isAsyncIterable3(event.result);
13514
- if (isStreaming && isAsyncIterable3(event.result)) {
13515
- patchStreamIfNeeded(event.result, {
13516
- onComplete: (chunks) => {
13517
- try {
13518
- let output;
13519
- let metrics;
13520
- let metadata = {};
13521
- if (config3.aggregateChunks) {
13522
- const aggregated = config3.aggregateChunks(chunks);
13523
- output = aggregated.output;
13524
- metrics = aggregated.metrics;
13525
- metadata = aggregated.metadata || {};
13526
- } else {
13527
- output = config3.extractOutput(chunks);
13528
- metrics = config3.extractMetrics(chunks, startTime);
13529
- if (config3.extractMetadata) {
13530
- metadata = config3.extractMetadata(chunks);
13531
- }
13532
- }
13533
- if (!metrics.time_to_first_token && chunks.length > 0) {
13534
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13535
- }
13536
- span.log({
13537
- output,
13538
- metrics,
13539
- metadata
13540
- });
13541
- } catch (error2) {
13542
- console.error(
13543
- `Error extracting output for ${channelName}:`,
13544
- error2
13545
- );
13546
- } finally {
13547
- span.end();
13548
- }
13549
- },
13550
- onError: (error2) => {
13551
- span.log({
13552
- error: error2.message
13553
- });
13554
- span.end();
13555
- }
13556
- });
13557
- } else {
13558
- try {
13559
- const output = config3.extractOutput(event.result);
13560
- const metrics = config3.extractMetrics(event.result, startTime);
13561
- const metadata = config3.extractMetadata ? config3.extractMetadata(event.result) : {};
13562
- span.log({
13563
- output,
13564
- metrics,
13565
- metadata
13566
- });
13567
- } catch (error2) {
13568
- console.error(`Error extracting output for ${channelName}:`, error2);
13569
- } finally {
13570
- span.end();
13571
- spans.delete(event);
14261
+ extractMetadata: (message) => {
14262
+ const metadata = {};
14263
+ const metas = ["stop_reason", "stop_sequence"];
14264
+ for (const m of metas) {
14265
+ if (message?.[m] !== void 0) {
14266
+ metadata[m] = message[m];
13572
14267
  }
13573
14268
  }
14269
+ return metadata;
13574
14270
  },
13575
- error: (event) => {
13576
- const spanData = spans.get(event);
13577
- if (!spanData) {
13578
- return;
13579
- }
13580
- const { span } = spanData;
13581
- span.log({
13582
- error: event.error.message
13583
- });
13584
- span.end();
13585
- spans.delete(event);
13586
- }
14271
+ aggregateChunks: (chunks) => aggregateAnthropicStreamChunks(chunks)
13587
14272
  };
13588
- channel.subscribe(handlers);
13589
- this.unsubscribers.push(() => {
13590
- channel.unsubscribe(handlers);
13591
- });
14273
+ this.unsubscribers.push(
14274
+ traceStreamingChannel(anthropicChannels.messagesCreate, anthropicConfig)
14275
+ );
14276
+ this.unsubscribers.push(
14277
+ traceStreamingChannel(anthropicChannels.betaMessagesCreate, {
14278
+ ...anthropicConfig,
14279
+ name: "anthropic.beta.messages.create"
14280
+ })
14281
+ );
13592
14282
  }
13593
14283
  };
13594
14284
  function parseMetricsFromUsage2(usage) {
@@ -13612,29 +14302,29 @@ function aggregateAnthropicStreamChunks(chunks) {
13612
14302
  const deltas = [];
13613
14303
  let metrics = {};
13614
14304
  let metadata = {};
13615
- for (const chunk of chunks) {
13616
- switch (chunk?.type) {
14305
+ for (const event of chunks) {
14306
+ switch (event?.type) {
13617
14307
  case "message_start":
13618
- if (chunk.message?.usage) {
13619
- const initialMetrics = parseMetricsFromUsage2(chunk.message.usage);
14308
+ if (event.message?.usage) {
14309
+ const initialMetrics = parseMetricsFromUsage2(event.message.usage);
13620
14310
  metrics = { ...metrics, ...initialMetrics };
13621
14311
  }
13622
14312
  break;
13623
14313
  case "content_block_delta":
13624
- if (chunk.delta?.type === "text_delta") {
13625
- const text = chunk.delta?.text;
14314
+ if (event.delta?.type === "text_delta") {
14315
+ const text = event.delta.text;
13626
14316
  if (text) {
13627
14317
  deltas.push(text);
13628
14318
  }
13629
14319
  }
13630
14320
  break;
13631
14321
  case "message_delta":
13632
- if (chunk.usage) {
13633
- const finalMetrics = parseMetricsFromUsage2(chunk.usage);
14322
+ if (event.usage) {
14323
+ const finalMetrics = parseMetricsFromUsage2(event.usage);
13634
14324
  metrics = { ...metrics, ...finalMetrics };
13635
14325
  }
13636
- if (chunk.delta) {
13637
- metadata = { ...metadata, ...chunk.delta };
14326
+ if (event.delta) {
14327
+ metadata = { ...metadata, ...event.delta };
13638
14328
  }
13639
14329
  break;
13640
14330
  }
@@ -13642,7 +14332,9 @@ function aggregateAnthropicStreamChunks(chunks) {
13642
14332
  const output = deltas.join("");
13643
14333
  const finalized = finalizeAnthropicTokens(metrics);
13644
14334
  const filteredMetrics = Object.fromEntries(
13645
- Object.entries(finalized).filter(([, v]) => v !== void 0)
14335
+ Object.entries(finalized).filter(
14336
+ (entry) => entry[1] !== void 0
14337
+ )
13646
14338
  );
13647
14339
  return {
13648
14340
  output,
@@ -13650,6 +14342,9 @@ function aggregateAnthropicStreamChunks(chunks) {
13650
14342
  metadata
13651
14343
  };
13652
14344
  }
14345
+ function isAnthropicBase64ContentBlock(input) {
14346
+ return (input.type === "image" || input.type === "document") && isObject(input.source) && input.source.type === "base64";
14347
+ }
13653
14348
  function convertBase64ToAttachment(source, contentType) {
13654
14349
  const mediaType = typeof source.media_type === "string" ? source.media_type : "image/png";
13655
14350
  const base64Data = source.data;
@@ -13673,14 +14368,14 @@ function convertBase64ToAttachment(source, contentType) {
13673
14368
  data: attachment
13674
14369
  };
13675
14370
  }
13676
- return source;
14371
+ return { ...source };
13677
14372
  }
13678
14373
  function processAttachmentsInInput(input) {
13679
14374
  if (Array.isArray(input)) {
13680
14375
  return input.map(processAttachmentsInInput);
13681
14376
  }
13682
14377
  if (isObject(input)) {
13683
- if ((input.type === "image" || input.type === "document") && isObject(input.source) && input.source.type === "base64") {
14378
+ if (isAnthropicBase64ContentBlock(input)) {
13684
14379
  return {
13685
14380
  ...input,
13686
14381
  source: convertBase64ToAttachment(input.source, input.type)
@@ -13711,8 +14406,35 @@ function filterFrom(obj, fieldsToRemove) {
13711
14406
  return result;
13712
14407
  }
13713
14408
 
14409
+ // src/instrumentation/plugins/ai-sdk-channels.ts
14410
+ var aiSDKChannels = defineChannels("ai", {
14411
+ generateText: channel({
14412
+ channelName: "generateText",
14413
+ kind: "async"
14414
+ }),
14415
+ streamText: channel({
14416
+ channelName: "streamText",
14417
+ kind: "async"
14418
+ }),
14419
+ generateObject: channel({
14420
+ channelName: "generateObject",
14421
+ kind: "async"
14422
+ }),
14423
+ streamObject: channel({
14424
+ channelName: "streamObject",
14425
+ kind: "async"
14426
+ }),
14427
+ agentGenerate: channel({
14428
+ channelName: "Agent.generate",
14429
+ kind: "async"
14430
+ }),
14431
+ agentStream: channel({
14432
+ channelName: "Agent.stream",
14433
+ kind: "async"
14434
+ })
14435
+ });
14436
+
13714
14437
  // src/instrumentation/plugins/ai-sdk-plugin.ts
13715
- var import_dc_browser3 = require("dc-browser");
13716
14438
  var DEFAULT_DENY_OUTPUT_PATHS = [
13717
14439
  // v3
13718
14440
  "roundtrips[].request.body",
@@ -13728,7 +14450,6 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
13728
14450
  "steps[].response.headers"
13729
14451
  ];
13730
14452
  var AISDKPlugin = class extends BasePlugin {
13731
- unsubscribers = [];
13732
14453
  config;
13733
14454
  constructor(config3 = {}) {
13734
14455
  super();
@@ -13738,249 +14459,148 @@ var AISDKPlugin = class extends BasePlugin {
13738
14459
  this.subscribeToAISDK();
13739
14460
  }
13740
14461
  onDisable() {
13741
- for (const unsubscribe of this.unsubscribers) {
13742
- unsubscribe();
13743
- }
13744
- this.unsubscribers = [];
14462
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
13745
14463
  }
13746
14464
  subscribeToAISDK() {
13747
14465
  const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
13748
- this.subscribeToStreamingChannel("orchestrion:ai-sdk:generateText", {
13749
- name: "generateText",
13750
- type: "llm" /* LLM */,
13751
- extractInput: (args) => {
13752
- const params = args[0] || {};
13753
- return {
13754
- input: processAISDKInput(params),
13755
- metadata: extractMetadataFromParams(params)
13756
- };
13757
- },
13758
- extractOutput: (result) => {
13759
- return processAISDKOutput(result, denyOutputPaths);
13760
- },
13761
- extractMetrics: (result, startTime) => {
13762
- const metrics = extractTokenMetrics(result);
13763
- if (startTime) {
13764
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13765
- }
13766
- return metrics;
13767
- },
13768
- aggregateChunks: aggregateAISDKChunks
13769
- });
13770
- this.subscribeToStreamingChannel("orchestrion:ai-sdk:streamText", {
13771
- name: "streamText",
13772
- type: "llm" /* LLM */,
13773
- extractInput: (args) => {
13774
- const params = args[0] || {};
13775
- return {
13776
- input: processAISDKInput(params),
13777
- metadata: extractMetadataFromParams(params)
13778
- };
13779
- },
13780
- extractOutput: (result) => {
13781
- return processAISDKOutput(result, denyOutputPaths);
13782
- },
13783
- extractMetrics: (result, startTime) => {
13784
- const metrics = extractTokenMetrics(result);
13785
- if (startTime) {
13786
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13787
- }
13788
- return metrics;
13789
- },
13790
- aggregateChunks: aggregateAISDKChunks
13791
- });
13792
- this.subscribeToStreamingChannel("orchestrion:ai-sdk:generateObject", {
13793
- name: "generateObject",
13794
- type: "llm" /* LLM */,
13795
- extractInput: (args) => {
13796
- const params = args[0] || {};
13797
- return {
13798
- input: processAISDKInput(params),
13799
- metadata: extractMetadataFromParams(params)
13800
- };
13801
- },
13802
- extractOutput: (result) => {
13803
- return processAISDKOutput(result, denyOutputPaths);
13804
- },
13805
- extractMetrics: (result, startTime) => {
13806
- const metrics = extractTokenMetrics(result);
13807
- if (startTime) {
13808
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13809
- }
13810
- return metrics;
13811
- },
13812
- aggregateChunks: aggregateAISDKChunks
13813
- });
13814
- this.subscribeToStreamingChannel("orchestrion:ai-sdk:streamObject", {
13815
- name: "streamObject",
13816
- type: "llm" /* LLM */,
13817
- extractInput: (args) => {
13818
- const params = args[0] || {};
13819
- return {
13820
- input: processAISDKInput(params),
13821
- metadata: extractMetadataFromParams(params)
13822
- };
13823
- },
13824
- extractOutput: (result) => {
13825
- return processAISDKOutput(result, denyOutputPaths);
13826
- },
13827
- extractMetrics: (result, startTime) => {
13828
- const metrics = extractTokenMetrics(result);
13829
- if (startTime) {
13830
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13831
- }
13832
- return metrics;
13833
- },
13834
- aggregateChunks: aggregateAISDKChunks
13835
- });
13836
- this.subscribeToStreamingChannel("orchestrion:ai-sdk:Agent.generate", {
13837
- name: "Agent.generate",
13838
- type: "llm" /* LLM */,
13839
- extractInput: (args) => {
13840
- const params = args[0] || {};
13841
- return {
13842
- input: processAISDKInput(params),
13843
- metadata: extractMetadataFromParams(params)
13844
- };
13845
- },
13846
- extractOutput: (result) => {
13847
- return processAISDKOutput(result, denyOutputPaths);
13848
- },
13849
- extractMetrics: (result, startTime) => {
13850
- const metrics = extractTokenMetrics(result);
13851
- if (startTime) {
13852
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13853
- }
13854
- return metrics;
13855
- },
13856
- aggregateChunks: aggregateAISDKChunks
13857
- });
13858
- this.subscribeToStreamingChannel("orchestrion:ai-sdk:Agent.stream", {
13859
- name: "Agent.stream",
13860
- type: "llm" /* LLM */,
13861
- extractInput: (args) => {
13862
- const params = args[0] || {};
13863
- return {
13864
- input: processAISDKInput(params),
13865
- metadata: extractMetadataFromParams(params)
13866
- };
13867
- },
13868
- extractOutput: (result) => {
13869
- return processAISDKOutput(result, denyOutputPaths);
13870
- },
13871
- extractMetrics: (result, startTime) => {
13872
- const metrics = extractTokenMetrics(result);
13873
- if (startTime) {
13874
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13875
- }
13876
- return metrics;
13877
- },
13878
- aggregateChunks: aggregateAISDKChunks
13879
- });
13880
- }
13881
- /**
13882
- * Subscribe to a channel for async methods that may return streams.
13883
- * Handles both streaming and non-streaming responses.
13884
- */
13885
- subscribeToStreamingChannel(channelName, config3) {
13886
- const channel = (0, import_dc_browser3.tracingChannel)(channelName);
13887
- const spans = /* @__PURE__ */ new WeakMap();
13888
- const handlers = {
13889
- start: (event) => {
13890
- const span = startSpan({
13891
- name: config3.name,
13892
- spanAttributes: {
13893
- type: config3.type
14466
+ this.unsubscribers.push(
14467
+ traceStreamingChannel(aiSDKChannels.generateText, {
14468
+ name: "generateText",
14469
+ type: "llm" /* LLM */,
14470
+ extractInput: ([params]) => {
14471
+ return {
14472
+ input: processAISDKInput(params),
14473
+ metadata: extractMetadataFromParams(params)
14474
+ };
14475
+ },
14476
+ extractOutput: (result) => {
14477
+ return processAISDKOutput(result, denyOutputPaths);
14478
+ },
14479
+ extractMetrics: (result, startTime) => {
14480
+ const metrics = extractTokenMetrics(result);
14481
+ if (startTime) {
14482
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13894
14483
  }
13895
- });
13896
- const startTime = getCurrentUnixTimestamp();
13897
- spans.set(event, { span, startTime });
13898
- try {
13899
- const { input, metadata } = config3.extractInput(event.arguments);
13900
- span.log({
13901
- input,
13902
- metadata
13903
- });
13904
- } catch (error2) {
13905
- console.error(`Error extracting input for ${channelName}:`, error2);
13906
- }
13907
- },
13908
- asyncEnd: (event) => {
13909
- const spanData = spans.get(event);
13910
- if (!spanData) {
13911
- return;
13912
- }
13913
- const { span, startTime } = spanData;
13914
- if (isAsyncIterable3(event.result)) {
13915
- patchStreamIfNeeded(event.result, {
13916
- onComplete: (chunks) => {
13917
- try {
13918
- let output;
13919
- let metrics;
13920
- if (config3.aggregateChunks) {
13921
- const aggregated = config3.aggregateChunks(chunks);
13922
- output = aggregated.output;
13923
- metrics = aggregated.metrics;
13924
- } else {
13925
- output = config3.extractOutput(chunks);
13926
- metrics = config3.extractMetrics(chunks, startTime);
13927
- }
13928
- if (!metrics.time_to_first_token && chunks.length > 0) {
13929
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13930
- }
13931
- span.log({
13932
- output,
13933
- metrics
13934
- });
13935
- } catch (error2) {
13936
- console.error(
13937
- `Error extracting output for ${channelName}:`,
13938
- error2
13939
- );
13940
- } finally {
13941
- span.end();
13942
- }
13943
- },
13944
- onError: (error2) => {
13945
- span.log({
13946
- error: error2.message
13947
- });
13948
- span.end();
13949
- }
13950
- });
13951
- } else {
13952
- try {
13953
- const output = config3.extractOutput(event.result);
13954
- const metrics = config3.extractMetrics(event.result, startTime);
13955
- span.log({
13956
- output,
13957
- metrics
13958
- });
13959
- } catch (error2) {
13960
- console.error(`Error extracting output for ${channelName}:`, error2);
13961
- } finally {
13962
- span.end();
13963
- spans.delete(event);
14484
+ return metrics;
14485
+ },
14486
+ aggregateChunks: aggregateAISDKChunks
14487
+ })
14488
+ );
14489
+ this.unsubscribers.push(
14490
+ traceStreamingChannel(aiSDKChannels.streamText, {
14491
+ name: "streamText",
14492
+ type: "llm" /* LLM */,
14493
+ extractInput: ([params]) => {
14494
+ return {
14495
+ input: processAISDKInput(params),
14496
+ metadata: extractMetadataFromParams(params)
14497
+ };
14498
+ },
14499
+ extractOutput: (result) => {
14500
+ return processAISDKOutput(result, denyOutputPaths);
14501
+ },
14502
+ extractMetrics: (result, startTime) => {
14503
+ const metrics = extractTokenMetrics(result);
14504
+ if (startTime) {
14505
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
14506
+ }
14507
+ return metrics;
14508
+ },
14509
+ aggregateChunks: aggregateAISDKChunks
14510
+ })
14511
+ );
14512
+ this.unsubscribers.push(
14513
+ traceStreamingChannel(aiSDKChannels.generateObject, {
14514
+ name: "generateObject",
14515
+ type: "llm" /* LLM */,
14516
+ extractInput: ([params]) => {
14517
+ return {
14518
+ input: processAISDKInput(params),
14519
+ metadata: extractMetadataFromParams(params)
14520
+ };
14521
+ },
14522
+ extractOutput: (result) => {
14523
+ return processAISDKOutput(result, denyOutputPaths);
14524
+ },
14525
+ extractMetrics: (result, startTime) => {
14526
+ const metrics = extractTokenMetrics(result);
14527
+ if (startTime) {
14528
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
14529
+ }
14530
+ return metrics;
14531
+ },
14532
+ aggregateChunks: aggregateAISDKChunks
14533
+ })
14534
+ );
14535
+ this.unsubscribers.push(
14536
+ traceStreamingChannel(aiSDKChannels.streamObject, {
14537
+ name: "streamObject",
14538
+ type: "llm" /* LLM */,
14539
+ extractInput: ([params]) => {
14540
+ return {
14541
+ input: processAISDKInput(params),
14542
+ metadata: extractMetadataFromParams(params)
14543
+ };
14544
+ },
14545
+ extractOutput: (result) => {
14546
+ return processAISDKOutput(result, denyOutputPaths);
14547
+ },
14548
+ extractMetrics: (result, startTime) => {
14549
+ const metrics = extractTokenMetrics(result);
14550
+ if (startTime) {
14551
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
14552
+ }
14553
+ return metrics;
14554
+ },
14555
+ aggregateChunks: aggregateAISDKChunks
14556
+ })
14557
+ );
14558
+ this.unsubscribers.push(
14559
+ traceStreamingChannel(aiSDKChannels.agentGenerate, {
14560
+ name: "Agent.generate",
14561
+ type: "llm" /* LLM */,
14562
+ extractInput: ([params]) => {
14563
+ return {
14564
+ input: processAISDKInput(params),
14565
+ metadata: extractMetadataFromParams(params)
14566
+ };
14567
+ },
14568
+ extractOutput: (result) => {
14569
+ return processAISDKOutput(result, denyOutputPaths);
14570
+ },
14571
+ extractMetrics: (result, startTime) => {
14572
+ const metrics = extractTokenMetrics(result);
14573
+ if (startTime) {
14574
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
14575
+ }
14576
+ return metrics;
14577
+ },
14578
+ aggregateChunks: aggregateAISDKChunks
14579
+ })
14580
+ );
14581
+ this.unsubscribers.push(
14582
+ traceStreamingChannel(aiSDKChannels.agentStream, {
14583
+ name: "Agent.stream",
14584
+ type: "llm" /* LLM */,
14585
+ extractInput: ([params]) => {
14586
+ return {
14587
+ input: processAISDKInput(params),
14588
+ metadata: extractMetadataFromParams(params)
14589
+ };
14590
+ },
14591
+ extractOutput: (result) => {
14592
+ return processAISDKOutput(result, denyOutputPaths);
14593
+ },
14594
+ extractMetrics: (result, startTime) => {
14595
+ const metrics = extractTokenMetrics(result);
14596
+ if (startTime) {
14597
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13964
14598
  }
13965
- }
13966
- },
13967
- error: (event) => {
13968
- const spanData = spans.get(event);
13969
- if (!spanData) {
13970
- return;
13971
- }
13972
- const { span } = spanData;
13973
- span.log({
13974
- error: event.error.message
13975
- });
13976
- span.end();
13977
- spans.delete(event);
13978
- }
13979
- };
13980
- channel.subscribe(handlers);
13981
- this.unsubscribers.push(() => {
13982
- channel.unsubscribe(handlers);
13983
- });
14599
+ return metrics;
14600
+ },
14601
+ aggregateChunks: aggregateAISDKChunks
14602
+ })
14603
+ );
13984
14604
  }
13985
14605
  };
13986
14606
  function processAISDKInput(params) {
@@ -14222,7 +14842,10 @@ function omitAtPath(obj, keys) {
14222
14842
  if (Array.isArray(obj)) {
14223
14843
  obj.forEach((item) => {
14224
14844
  if (remainingKeys.length > 0) {
14225
- omitAtPath(item, remainingKeys);
14845
+ omitAtPath(
14846
+ item,
14847
+ remainingKeys
14848
+ );
14226
14849
  }
14227
14850
  });
14228
14851
  }
@@ -14232,7 +14855,10 @@ function omitAtPath(obj, keys) {
14232
14855
  }
14233
14856
  } else {
14234
14857
  if (obj && typeof obj === "object" && firstKey in obj) {
14235
- omitAtPath(obj[firstKey], remainingKeys);
14858
+ omitAtPath(
14859
+ obj[firstKey],
14860
+ remainingKeys
14861
+ );
14236
14862
  }
14237
14863
  }
14238
14864
  }
@@ -14245,8 +14871,18 @@ function omit(obj, paths) {
14245
14871
  return result;
14246
14872
  }
14247
14873
 
14874
+ // src/instrumentation/plugins/claude-agent-sdk-channels.ts
14875
+ var claudeAgentSDKChannels = defineChannels(
14876
+ "@anthropic-ai/claude-agent-sdk",
14877
+ {
14878
+ query: channel({
14879
+ channelName: "query",
14880
+ kind: "async"
14881
+ })
14882
+ }
14883
+ );
14884
+
14248
14885
  // src/instrumentation/plugins/claude-agent-sdk-plugin.ts
14249
- var import_dc_browser4 = require("dc-browser");
14250
14886
  function filterSerializableOptions(options) {
14251
14887
  const allowedKeys = [
14252
14888
  "model",
@@ -14330,7 +14966,9 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
14330
14966
  const input = buildLLMInput(prompt, conversationHistory);
14331
14967
  const outputs = messages.map(
14332
14968
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
14333
- ).filter((c) => c !== void 0);
14969
+ ).filter(
14970
+ (c) => c !== void 0
14971
+ );
14334
14972
  const span = startSpan({
14335
14973
  name: "anthropic.messages.create",
14336
14974
  spanAttributes: {
@@ -14349,7 +14987,6 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
14349
14987
  return lastMessage.message?.content && lastMessage.message?.role ? { content: lastMessage.message.content, role: lastMessage.message.role } : void 0;
14350
14988
  }
14351
14989
  var ClaudeAgentSDKPlugin = class extends BasePlugin {
14352
- unsubscribers = [];
14353
14990
  onEnable() {
14354
14991
  this.subscribeToQuery();
14355
14992
  }
@@ -14365,12 +15002,13 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
14365
15002
  * and individual LLM calls.
14366
15003
  */
14367
15004
  subscribeToQuery() {
14368
- const channel = (0, import_dc_browser4.tracingChannel)("orchestrion:claude-agent-sdk:query");
15005
+ const channel2 = claudeAgentSDKChannels.query.tracingChannel();
14369
15006
  const spans = /* @__PURE__ */ new WeakMap();
14370
15007
  const handlers = {
14371
15008
  start: (event) => {
14372
- const params = event.arguments[0] ?? {};
14373
- const { prompt, options = {} } = params;
15009
+ const params = event.arguments[0];
15010
+ const prompt = params?.prompt;
15011
+ const options = params?.options ?? {};
14374
15012
  const span = startSpan({
14375
15013
  name: "Claude Agent",
14376
15014
  spanAttributes: {
@@ -14382,7 +15020,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
14382
15020
  span.log({
14383
15021
  input: typeof prompt === "string" ? prompt : {
14384
15022
  type: "streaming",
14385
- description: "AsyncIterable<SDKMessage>"
15023
+ description: "AsyncIterable<ClaudeAgentSDKMessage>"
14386
15024
  },
14387
15025
  metadata: filterSerializableOptions(options)
14388
15026
  });
@@ -14404,12 +15042,19 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
14404
15042
  if (!spanData) {
14405
15043
  return;
14406
15044
  }
14407
- if (isAsyncIterable3(event.result)) {
14408
- patchStreamIfNeeded(event.result, {
15045
+ const eventResult = event.result;
15046
+ if (eventResult === void 0) {
15047
+ spanData.span.end();
15048
+ spans.delete(event);
15049
+ return;
15050
+ }
15051
+ if (isAsyncIterable3(eventResult)) {
15052
+ patchStreamIfNeeded(eventResult, {
14409
15053
  onChunk: async (message) => {
14410
15054
  const currentTime = getCurrentUnixTimestamp();
14411
15055
  const params = event.arguments[0];
14412
- const { prompt, options = {} } = params;
15056
+ const prompt = params?.prompt;
15057
+ const options = params?.options ?? {};
14413
15058
  const messageId = message.message?.id;
14414
15059
  if (messageId && messageId !== spanData.currentMessageId) {
14415
15060
  if (spanData.currentMessages.length > 0) {
@@ -14433,289 +15078,96 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
14433
15078
  spanData.accumulatedOutputTokens += outputTokens;
14434
15079
  }
14435
15080
  spanData.currentMessages = [];
14436
- }
14437
- spanData.currentMessageId = messageId;
14438
- spanData.currentMessageStartTime = currentTime;
14439
- }
14440
- if (message.type === "assistant" && message.message?.usage) {
14441
- spanData.currentMessages.push(message);
14442
- }
14443
- if (message.type === "result" && message.usage) {
14444
- const finalUsageMetrics = extractUsageFromMessage(message);
14445
- if (spanData.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
14446
- const lastMessage = spanData.currentMessages[spanData.currentMessages.length - 1];
14447
- if (lastMessage?.message?.usage) {
14448
- const adjustedTokens = finalUsageMetrics.completion_tokens - spanData.accumulatedOutputTokens;
14449
- if (adjustedTokens >= 0) {
14450
- lastMessage.message.usage.output_tokens = adjustedTokens;
14451
- }
14452
- }
14453
- }
14454
- const result_metadata = {};
14455
- if (message.num_turns !== void 0) {
14456
- result_metadata.num_turns = message.num_turns;
14457
- }
14458
- if (message.session_id !== void 0) {
14459
- result_metadata.session_id = message.session_id;
14460
- }
14461
- if (Object.keys(result_metadata).length > 0) {
14462
- spanData.span.log({
14463
- metadata: result_metadata
14464
- });
14465
- }
14466
- }
14467
- },
14468
- onComplete: async () => {
14469
- try {
14470
- const params = event.arguments[0];
14471
- const { prompt, options = {} } = params;
14472
- if (spanData.currentMessages.length > 0) {
14473
- const finalMessage = await createLLMSpanForMessages(
14474
- spanData.currentMessages,
14475
- prompt,
14476
- spanData.conversationHistory,
14477
- options,
14478
- spanData.currentMessageStartTime,
14479
- await spanData.span.export()
14480
- );
14481
- if (finalMessage) {
14482
- spanData.conversationHistory.push(finalMessage);
14483
- }
14484
- }
14485
- spanData.span.log({
14486
- output: spanData.conversationHistory.length > 0 ? spanData.conversationHistory[spanData.conversationHistory.length - 1] : void 0
14487
- });
14488
- } catch (error2) {
14489
- console.error(
14490
- "Error extracting output for Claude Agent SDK:",
14491
- error2
14492
- );
14493
- } finally {
14494
- spanData.span.end();
14495
- spans.delete(event);
14496
- }
14497
- },
14498
- onError: (error2) => {
14499
- spanData.span.log({
14500
- error: error2.message
14501
- });
14502
- spanData.span.end();
14503
- spans.delete(event);
14504
- }
14505
- });
14506
- } else {
14507
- try {
14508
- spanData.span.log({
14509
- output: event.result
14510
- });
14511
- } catch (error2) {
14512
- console.error(
14513
- "Error extracting output for Claude Agent SDK:",
14514
- error2
14515
- );
14516
- } finally {
14517
- spanData.span.end();
14518
- spans.delete(event);
14519
- }
14520
- }
14521
- },
14522
- error: (event) => {
14523
- const spanData = spans.get(event);
14524
- if (!spanData) {
14525
- return;
14526
- }
14527
- const { span } = spanData;
14528
- span.log({
14529
- error: event.error.message
14530
- });
14531
- span.end();
14532
- spans.delete(event);
14533
- }
14534
- };
14535
- channel.subscribe(handlers);
14536
- this.unsubscribers.push(() => {
14537
- channel.unsubscribe(handlers);
14538
- });
14539
- }
14540
- };
14541
-
14542
- // src/instrumentation/plugins/google-genai-plugin.ts
14543
- var import_dc_browser5 = require("dc-browser");
14544
- var GoogleGenAIPlugin = class extends BasePlugin {
14545
- unsubscribers = [];
14546
- onEnable() {
14547
- this.subscribeToGoogleGenAIChannels();
14548
- }
14549
- onDisable() {
14550
- for (const unsubscribe of this.unsubscribers) {
14551
- unsubscribe();
14552
- }
14553
- this.unsubscribers = [];
14554
- }
14555
- subscribeToGoogleGenAIChannels() {
14556
- this.subscribeToChannel("orchestrion:google-genai:models.generateContent", {
14557
- name: "google-genai.generateContent",
14558
- type: "llm" /* LLM */,
14559
- extractInput: (args) => {
14560
- const params = args[0] || {};
14561
- const input = serializeInput(params);
14562
- const metadata = extractMetadata(params);
14563
- return {
14564
- input,
14565
- metadata: { ...metadata, provider: "google-genai" }
14566
- };
14567
- },
14568
- extractOutput: (result) => {
14569
- return result;
14570
- },
14571
- extractMetrics: (result, startTime) => {
14572
- return extractGenerateContentMetrics(result, startTime);
14573
- }
14574
- });
14575
- this.subscribeToGoogleStreamingChannel(
14576
- "orchestrion:google-genai:models.generateContentStream",
14577
- {
14578
- name: "google-genai.generateContentStream",
14579
- type: "llm" /* LLM */,
14580
- extractInput: (args) => {
14581
- const params = args[0] || {};
14582
- const input = serializeInput(params);
14583
- const metadata = extractMetadata(params);
14584
- return {
14585
- input,
14586
- metadata: { ...metadata, provider: "google-genai" }
14587
- };
14588
- },
14589
- aggregateChunks: aggregateGenerateContentChunks
14590
- }
14591
- );
14592
- }
14593
- subscribeToChannel(channelName, config3) {
14594
- const channel = (0, import_dc_browser5.tracingChannel)(channelName);
14595
- const spans = /* @__PURE__ */ new WeakMap();
14596
- const handlers = {
14597
- start: (event) => {
14598
- const span = startSpan({
14599
- name: config3.name,
14600
- spanAttributes: {
14601
- type: config3.type
14602
- }
14603
- });
14604
- const startTime = getCurrentUnixTimestamp();
14605
- spans.set(event, { span, startTime });
14606
- try {
14607
- const { input, metadata } = config3.extractInput(event.arguments);
14608
- span.log({
14609
- input,
14610
- metadata
14611
- });
14612
- } catch (error2) {
14613
- console.error(`Error extracting input for ${channelName}:`, error2);
14614
- }
14615
- },
14616
- asyncEnd: (event) => {
14617
- const spanData = spans.get(event);
14618
- if (!spanData) {
14619
- return;
14620
- }
14621
- const { span, startTime } = spanData;
14622
- try {
14623
- const output = config3.extractOutput(event.result);
14624
- const metrics = config3.extractMetrics(event.result, startTime);
14625
- span.log({
14626
- output,
14627
- metrics
14628
- });
14629
- } catch (error2) {
14630
- console.error(`Error extracting output for ${channelName}:`, error2);
14631
- } finally {
14632
- span.end();
14633
- spans.delete(event);
14634
- }
14635
- },
14636
- error: (event) => {
14637
- const spanData = spans.get(event);
14638
- if (!spanData) {
14639
- return;
14640
- }
14641
- const { span } = spanData;
14642
- span.log({
14643
- error: event.error.message
14644
- });
14645
- span.end();
14646
- spans.delete(event);
14647
- }
14648
- };
14649
- channel.subscribe(handlers);
14650
- this.unsubscribers.push(() => {
14651
- channel.unsubscribe(handlers);
14652
- });
14653
- }
14654
- subscribeToGoogleStreamingChannel(channelName, config3) {
14655
- const channel = (0, import_dc_browser5.tracingChannel)(channelName);
14656
- const spans = /* @__PURE__ */ new WeakMap();
14657
- const handlers = {
14658
- start: (event) => {
14659
- const span = startSpan({
14660
- name: config3.name,
14661
- spanAttributes: {
14662
- type: config3.type
14663
- }
14664
- });
14665
- const startTime = getCurrentUnixTimestamp();
14666
- spans.set(event, { span, startTime });
14667
- try {
14668
- const { input, metadata } = config3.extractInput(event.arguments);
14669
- span.log({
14670
- input,
14671
- metadata
14672
- });
14673
- } catch (error2) {
14674
- console.error(`Error extracting input for ${channelName}:`, error2);
14675
- }
14676
- },
14677
- asyncEnd: (event) => {
14678
- const spanData = spans.get(event);
14679
- if (!spanData) {
14680
- return;
14681
- }
14682
- const { span, startTime } = spanData;
14683
- if (isAsyncIterable3(event.result)) {
14684
- patchStreamIfNeeded(event.result, {
14685
- onComplete: (chunks) => {
15081
+ }
15082
+ spanData.currentMessageId = messageId;
15083
+ spanData.currentMessageStartTime = currentTime;
15084
+ }
15085
+ if (message.type === "assistant" && message.message?.usage) {
15086
+ spanData.currentMessages.push(message);
15087
+ }
15088
+ if (message.type === "result" && message.usage) {
15089
+ const finalUsageMetrics = extractUsageFromMessage(message);
15090
+ if (spanData.currentMessages.length > 0 && finalUsageMetrics.completion_tokens !== void 0) {
15091
+ const lastMessage = spanData.currentMessages[spanData.currentMessages.length - 1];
15092
+ if (lastMessage?.message?.usage) {
15093
+ const adjustedTokens = finalUsageMetrics.completion_tokens - spanData.accumulatedOutputTokens;
15094
+ if (adjustedTokens >= 0) {
15095
+ lastMessage.message.usage.output_tokens = adjustedTokens;
15096
+ }
15097
+ }
15098
+ }
15099
+ const result_metadata = {};
15100
+ if (message.num_turns !== void 0) {
15101
+ result_metadata.num_turns = message.num_turns;
15102
+ }
15103
+ if (message.session_id !== void 0) {
15104
+ result_metadata.session_id = message.session_id;
15105
+ }
15106
+ if (Object.keys(result_metadata).length > 0) {
15107
+ spanData.span.log({
15108
+ metadata: result_metadata
15109
+ });
15110
+ }
15111
+ }
15112
+ },
15113
+ onComplete: async () => {
14686
15114
  try {
14687
- const { output, metrics } = config3.aggregateChunks(
14688
- chunks,
14689
- startTime
14690
- );
14691
- span.log({
14692
- output,
14693
- metrics
15115
+ const params = event.arguments[0];
15116
+ const prompt = params?.prompt;
15117
+ const options = params?.options ?? {};
15118
+ if (spanData.currentMessages.length > 0) {
15119
+ const finalMessage = await createLLMSpanForMessages(
15120
+ spanData.currentMessages,
15121
+ prompt,
15122
+ spanData.conversationHistory,
15123
+ options,
15124
+ spanData.currentMessageStartTime,
15125
+ await spanData.span.export()
15126
+ );
15127
+ if (finalMessage) {
15128
+ spanData.conversationHistory.push(finalMessage);
15129
+ }
15130
+ }
15131
+ spanData.span.log({
15132
+ output: spanData.conversationHistory.length > 0 ? spanData.conversationHistory[spanData.conversationHistory.length - 1] : void 0
14694
15133
  });
14695
15134
  } catch (error2) {
14696
15135
  console.error(
14697
- `Error extracting output for ${channelName}:`,
15136
+ "Error extracting output for Claude Agent SDK:",
14698
15137
  error2
14699
15138
  );
14700
15139
  } finally {
14701
- span.end();
15140
+ spanData.span.end();
15141
+ spans.delete(event);
14702
15142
  }
14703
15143
  },
14704
15144
  onError: (error2) => {
14705
- span.log({
15145
+ spanData.span.log({
14706
15146
  error: error2.message
14707
15147
  });
14708
- span.end();
15148
+ spanData.span.end();
15149
+ spans.delete(event);
14709
15150
  }
14710
15151
  });
14711
15152
  } else {
14712
- span.end();
14713
- spans.delete(event);
15153
+ try {
15154
+ spanData.span.log({
15155
+ output: eventResult
15156
+ });
15157
+ } catch (error2) {
15158
+ console.error(
15159
+ "Error extracting output for Claude Agent SDK:",
15160
+ error2
15161
+ );
15162
+ } finally {
15163
+ spanData.span.end();
15164
+ spans.delete(event);
15165
+ }
14714
15166
  }
14715
15167
  },
14716
15168
  error: (event) => {
14717
15169
  const spanData = spans.get(event);
14718
- if (!spanData) {
15170
+ if (!spanData || !event.error) {
14719
15171
  return;
14720
15172
  }
14721
15173
  const { span } = spanData;
@@ -14726,12 +15178,79 @@ var GoogleGenAIPlugin = class extends BasePlugin {
14726
15178
  spans.delete(event);
14727
15179
  }
14728
15180
  };
14729
- channel.subscribe(handlers);
15181
+ channel2.subscribe(handlers);
14730
15182
  this.unsubscribers.push(() => {
14731
- channel.unsubscribe(handlers);
15183
+ channel2.unsubscribe(handlers);
14732
15184
  });
14733
15185
  }
14734
15186
  };
15187
+
15188
+ // src/instrumentation/plugins/google-genai-channels.ts
15189
+ var googleGenAIChannels = defineChannels("@google/genai", {
15190
+ generateContent: channel({
15191
+ channelName: "models.generateContent",
15192
+ kind: "async"
15193
+ }),
15194
+ generateContentStream: channel({
15195
+ channelName: "models.generateContentStream",
15196
+ kind: "async"
15197
+ })
15198
+ });
15199
+
15200
+ // src/instrumentation/plugins/google-genai-plugin.ts
15201
+ var GoogleGenAIPlugin = class extends BasePlugin {
15202
+ onEnable() {
15203
+ this.subscribeToGoogleGenAIChannels();
15204
+ }
15205
+ onDisable() {
15206
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
15207
+ }
15208
+ subscribeToGoogleGenAIChannels() {
15209
+ this.unsubscribers.push(
15210
+ traceAsyncChannel(googleGenAIChannels.generateContent, {
15211
+ name: "google-genai.generateContent",
15212
+ type: "llm" /* LLM */,
15213
+ extractInput: ([params]) => {
15214
+ const input = serializeInput(params);
15215
+ const metadata = extractMetadata(params);
15216
+ return {
15217
+ input,
15218
+ metadata: { ...metadata, provider: "google-genai" }
15219
+ };
15220
+ },
15221
+ extractOutput: (result) => {
15222
+ return result;
15223
+ },
15224
+ extractMetrics: (result, startTime) => {
15225
+ return extractGenerateContentMetrics(result, startTime);
15226
+ }
15227
+ })
15228
+ );
15229
+ this.unsubscribers.push(
15230
+ traceStreamingChannel(googleGenAIChannels.generateContentStream, {
15231
+ name: "google-genai.generateContentStream",
15232
+ type: "llm" /* LLM */,
15233
+ extractInput: ([params]) => {
15234
+ const input = serializeInput(params);
15235
+ const metadata = extractMetadata(params);
15236
+ return {
15237
+ input,
15238
+ metadata: { ...metadata, provider: "google-genai" }
15239
+ };
15240
+ },
15241
+ extractOutput: (result) => {
15242
+ return result;
15243
+ },
15244
+ extractMetrics: () => {
15245
+ return {};
15246
+ },
15247
+ aggregateChunks: (chunks, _result, _endEvent, startTime) => {
15248
+ return aggregateGenerateContentChunks(chunks, startTime);
15249
+ }
15250
+ })
15251
+ );
15252
+ }
15253
+ };
14735
15254
  function serializeInput(params) {
14736
15255
  const input = {
14737
15256
  model: params.model,
@@ -14785,8 +15304,12 @@ function serializePart(part) {
14785
15304
  const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
14786
15305
  atob(data).split("").map((c) => c.charCodeAt(0))
14787
15306
  ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
15307
+ const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
15308
+ buffer.byteOffset,
15309
+ buffer.byteOffset + buffer.byteLength
15310
+ ) : buffer;
14788
15311
  const attachment = new Attachment({
14789
- data: buffer,
15312
+ data: arrayBuffer,
14790
15313
  filename,
14791
15314
  contentType: mimeType || "application/octet-stream"
14792
15315
  });
@@ -14835,33 +15358,36 @@ function extractGenerateContentMetrics(response, startTime) {
14835
15358
  const end = getCurrentUnixTimestamp();
14836
15359
  metrics.duration = end - startTime;
14837
15360
  }
14838
- if (response.usageMetadata) {
14839
- const usage = response.usageMetadata;
14840
- if (usage.promptTokenCount !== void 0) {
14841
- metrics.prompt_tokens = usage.promptTokenCount;
14842
- }
14843
- if (usage.candidatesTokenCount !== void 0) {
14844
- metrics.completion_tokens = usage.candidatesTokenCount;
14845
- }
14846
- if (usage.totalTokenCount !== void 0) {
14847
- metrics.tokens = usage.totalTokenCount;
14848
- }
14849
- if (usage.cachedContentTokenCount !== void 0) {
14850
- metrics.prompt_cached_tokens = usage.cachedContentTokenCount;
14851
- }
14852
- if (usage.thoughtsTokenCount !== void 0) {
14853
- metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
14854
- }
15361
+ if (response?.usageMetadata) {
15362
+ populateUsageMetrics(metrics, response.usageMetadata);
14855
15363
  }
14856
15364
  return metrics;
14857
15365
  }
15366
+ function populateUsageMetrics(metrics, usage) {
15367
+ if (usage.promptTokenCount !== void 0) {
15368
+ metrics.prompt_tokens = usage.promptTokenCount;
15369
+ }
15370
+ if (usage.candidatesTokenCount !== void 0) {
15371
+ metrics.completion_tokens = usage.candidatesTokenCount;
15372
+ }
15373
+ if (usage.totalTokenCount !== void 0) {
15374
+ metrics.tokens = usage.totalTokenCount;
15375
+ }
15376
+ if (usage.cachedContentTokenCount !== void 0) {
15377
+ metrics.prompt_cached_tokens = usage.cachedContentTokenCount;
15378
+ }
15379
+ if (usage.thoughtsTokenCount !== void 0) {
15380
+ metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
15381
+ }
15382
+ }
14858
15383
  function aggregateGenerateContentChunks(chunks, startTime) {
14859
- const end = getCurrentUnixTimestamp();
14860
- const metrics = {
14861
- duration: end - startTime
14862
- };
15384
+ const metrics = {};
15385
+ if (startTime !== void 0) {
15386
+ const end = getCurrentUnixTimestamp();
15387
+ metrics.duration = end - startTime;
15388
+ }
14863
15389
  let firstTokenTime = null;
14864
- if (chunks.length > 0 && firstTokenTime === null) {
15390
+ if (chunks.length > 0 && firstTokenTime === null && startTime !== void 0) {
14865
15391
  firstTokenTime = getCurrentUnixTimestamp();
14866
15392
  metrics.time_to_first_token = firstTokenTime - startTime;
14867
15393
  }
@@ -14932,21 +15458,7 @@ function aggregateGenerateContentChunks(chunks, startTime) {
14932
15458
  }
14933
15459
  if (usageMetadata) {
14934
15460
  output.usageMetadata = usageMetadata;
14935
- if (usageMetadata.promptTokenCount !== void 0) {
14936
- metrics.prompt_tokens = usageMetadata.promptTokenCount;
14937
- }
14938
- if (usageMetadata.candidatesTokenCount !== void 0) {
14939
- metrics.completion_tokens = usageMetadata.candidatesTokenCount;
14940
- }
14941
- if (usageMetadata.totalTokenCount !== void 0) {
14942
- metrics.tokens = usageMetadata.totalTokenCount;
14943
- }
14944
- if (usageMetadata.cachedContentTokenCount !== void 0) {
14945
- metrics.prompt_cached_tokens = usageMetadata.cachedContentTokenCount;
14946
- }
14947
- if (usageMetadata.thoughtsTokenCount !== void 0) {
14948
- metrics.completion_reasoning_tokens = usageMetadata.thoughtsTokenCount;
14949
- }
15461
+ populateUsageMetrics(metrics, usageMetadata);
14950
15462
  }
14951
15463
  if (text) {
14952
15464
  output.text = text;
@@ -14958,7 +15470,8 @@ function tryToDict(obj) {
14958
15470
  return null;
14959
15471
  }
14960
15472
  if (typeof obj === "object") {
14961
- if (typeof obj.toJSON === "function") {
15473
+ if ("toJSON" in obj && // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
15474
+ typeof obj.toJSON === "function") {
14962
15475
  return obj.toJSON();
14963
15476
  }
14964
15477
  return obj;
@@ -15122,6 +15635,7 @@ function configureNode() {
15122
15635
  isomorph_default.getEnv = (name) => process.env[name];
15123
15636
  isomorph_default.getCallerLocation = getCallerLocation;
15124
15637
  isomorph_default.newAsyncLocalStorage = () => new import_node_async_hooks.AsyncLocalStorage();
15638
+ isomorph_default.newTracingChannel = (nameOrChannels) => diagnostics_channel.tracingChannel(nameOrChannels);
15125
15639
  isomorph_default.processOn = (event, handler) => {
15126
15640
  process.on(event, handler);
15127
15641
  };
@@ -15219,17 +15733,6 @@ function nodeModulesPaths(basedir, options) {
15219
15733
  }
15220
15734
  return dirs;
15221
15735
  }
15222
- function findGlobalPaths() {
15223
- const { root } = path2.parse(process.cwd());
15224
- const globalPath = path2.join(root, "node_modules");
15225
- const resolvePaths = require.resolve.paths("/");
15226
- if (resolvePaths) {
15227
- const rootIndex = resolvePaths.indexOf(globalPath);
15228
- return rootIndex > -1 ? resolvePaths.slice(rootIndex + 1) : [];
15229
- }
15230
- return [];
15231
- }
15232
- var GlobalPaths = findGlobalPaths();
15233
15736
 
15234
15737
  // src/cli/functions/load-module.ts
15235
15738
  var import_node_path = __toESM(require("node:path"));
@@ -15613,6 +16116,7 @@ var CodeFunction = class {
15613
16116
  this.description = opts.description;
15614
16117
  this.type = opts.type;
15615
16118
  this.ifExists = opts.ifExists;
16119
+ this.tags = opts.tags;
15616
16120
  this.metadata = opts.metadata;
15617
16121
  this.parameters = opts.parameters;
15618
16122
  this.returns = opts.returns;
@@ -15628,6 +16132,7 @@ var CodeFunction = class {
15628
16132
  parameters;
15629
16133
  returns;
15630
16134
  ifExists;
16135
+ tags;
15631
16136
  metadata;
15632
16137
  key() {
15633
16138
  return JSON.stringify([
@@ -15647,6 +16152,7 @@ var CodePrompt = class {
15647
16152
  id;
15648
16153
  functionType;
15649
16154
  toolFunctions;
16155
+ tags;
15650
16156
  metadata;
15651
16157
  constructor(project, prompt, toolFunctions, opts, functionType) {
15652
16158
  this.project = project;
@@ -15658,6 +16164,7 @@ var CodePrompt = class {
15658
16164
  this.description = opts.description;
15659
16165
  this.id = opts.id;
15660
16166
  this.functionType = functionType;
16167
+ this.tags = opts.tags;
15661
16168
  this.metadata = opts.metadata;
15662
16169
  }
15663
16170
  async toFunctionDefinition(projectNameToId) {
@@ -15692,6 +16199,7 @@ var CodePrompt = class {
15692
16199
  function_type: this.functionType,
15693
16200
  prompt_data,
15694
16201
  if_exists: this.ifExists,
16202
+ tags: this.tags,
15695
16203
  metadata: this.metadata
15696
16204
  };
15697
16205
  }
@@ -15720,6 +16228,7 @@ var PromptBuilder = class {
15720
16228
  name: opts.name,
15721
16229
  slug,
15722
16230
  prompt_data: promptData,
16231
+ tags: opts.tags,
15723
16232
  ...this.project.id !== void 0 ? { project_id: this.project.id } : {}
15724
16233
  };
15725
16234
  const prompt = new Prompt2(
@@ -15801,6 +16310,15 @@ function serializeEvalParametersToStaticParametersSchema(parameters) {
15801
16310
  description: value.description
15802
16311
  }
15803
16312
  ];
16313
+ } else if ("type" in value && value.type === "model") {
16314
+ return [
16315
+ name,
16316
+ {
16317
+ type: "model",
16318
+ default: value.default,
16319
+ description: value.description
16320
+ }
16321
+ ];
15804
16322
  } else {
15805
16323
  const schemaObj = zodToJsonSchema(value);
15806
16324
  return [
@@ -15831,6 +16349,16 @@ function serializeEvalParameterstoParametersSchema(parameters) {
15831
16349
  if (!defaultPromptData) {
15832
16350
  required.push(name);
15833
16351
  }
16352
+ } else if ("type" in value && value.type === "model") {
16353
+ properties[name] = {
16354
+ type: "string",
16355
+ "x-bt-type": "model",
16356
+ ...value.description ? { description: value.description } : {},
16357
+ ..."default" in value ? { default: value.default } : {}
16358
+ };
16359
+ if (!("default" in value)) {
16360
+ required.push(name);
16361
+ }
15834
16362
  } else {
15835
16363
  const schemaObj = zodToJsonSchema(value);
15836
16364
  properties[name] = schemaObj;
@@ -15926,7 +16454,7 @@ async function uploadHandleBundles({
15926
16454
  bundlePromises,
15927
16455
  handles,
15928
16456
  setCurrent,
15929
- verbose,
16457
+ showDetailedErrors,
15930
16458
  defaultIfExists
15931
16459
  }) {
15932
16460
  console.error(
@@ -15959,6 +16487,7 @@ async function uploadHandleBundles({
15959
16487
  returns: fn.returns ? zodToJsonSchema(fn.returns) : void 0
15960
16488
  } : void 0,
15961
16489
  if_exists: fn.ifExists,
16490
+ tags: fn.tags,
15962
16491
  metadata: fn.metadata
15963
16492
  });
15964
16493
  }
@@ -15983,41 +16512,6 @@ async function uploadHandleBundles({
15983
16512
  object_id: experimentId,
15984
16513
  internal: !setCurrent
15985
16514
  } : void 0;
15986
- if (setCurrent) {
15987
- const sourceStem = import_node_path3.default.basename(sourceFile, import_node_path3.default.extname(sourceFile)).replace(/\.eval$/, "");
15988
- const evalName = evaluator.evaluator.evalName;
15989
- const sandboxGroupName = sourceStem;
15990
- const resolvedParameters = evaluator.evaluator.parameters ? await Promise.resolve(evaluator.evaluator.parameters) : void 0;
15991
- const evaluatorDefinition = {
15992
- ...resolvedParameters ? {
15993
- parameters: serializeRemoteEvalParametersContainer(resolvedParameters)
15994
- } : {},
15995
- scores: evaluator.evaluator.scores.map((score, i) => ({
15996
- name: scorerName(score, i)
15997
- }))
15998
- };
15999
- bundleSpecs.push({
16000
- ...baseInfo,
16001
- name: `Eval ${evalName} sandbox`,
16002
- slug: slugify(`${sourceStem}-${evalName}-sandbox`),
16003
- description: `Sandbox eval ${evalName}`,
16004
- location: {
16005
- type: "sandbox",
16006
- sandbox_spec: {
16007
- provider: "lambda"
16008
- },
16009
- entrypoints: [sourceFile],
16010
- eval_name: evalName,
16011
- evaluator_definition: evaluatorDefinition
16012
- },
16013
- function_type: "sandbox",
16014
- metadata: {
16015
- [SANDBOX_GROUP_NAME_METADATA_KEY]: sandboxGroupName
16016
- },
16017
- origin
16018
- });
16019
- continue;
16020
- }
16021
16515
  const fileSpecs = [
16022
16516
  {
16023
16517
  ...baseInfo,
@@ -16052,6 +16546,40 @@ async function uploadHandleBundles({
16052
16546
  })
16053
16547
  ];
16054
16548
  bundleSpecs.push(...fileSpecs);
16549
+ if (setCurrent) {
16550
+ const sourceStem = import_node_path3.default.basename(sourceFile, import_node_path3.default.extname(sourceFile)).replace(/\.eval$/, "");
16551
+ const evalName = evaluator.evaluator.evalName;
16552
+ const sandboxGroupName = sourceStem;
16553
+ const resolvedParameters = evaluator.evaluator.parameters ? await Promise.resolve(evaluator.evaluator.parameters) : void 0;
16554
+ const evaluatorDefinition = {
16555
+ ...resolvedParameters ? {
16556
+ parameters: serializeRemoteEvalParametersContainer(resolvedParameters)
16557
+ } : {},
16558
+ scores: evaluator.evaluator.scores.map((score, i) => ({
16559
+ name: scorerName(score, i)
16560
+ }))
16561
+ };
16562
+ bundleSpecs.push({
16563
+ ...baseInfo,
16564
+ name: `Eval ${evalName} sandbox`,
16565
+ slug: slugify(`${sourceStem}-${evalName}-sandbox`),
16566
+ description: `Sandbox eval ${evalName}`,
16567
+ location: {
16568
+ type: "sandbox",
16569
+ sandbox_spec: {
16570
+ provider: "lambda"
16571
+ },
16572
+ entrypoints: [sourceFile],
16573
+ eval_name: evalName,
16574
+ evaluator_definition: evaluatorDefinition
16575
+ },
16576
+ function_type: "sandbox",
16577
+ metadata: {
16578
+ [SANDBOX_GROUP_NAME_METADATA_KEY]: sandboxGroupName
16579
+ },
16580
+ origin
16581
+ });
16582
+ }
16055
16583
  }
16056
16584
  const slugs = /* @__PURE__ */ new Set();
16057
16585
  for (const spec of bundleSpecs) {
@@ -16073,7 +16601,7 @@ async function uploadHandleBundles({
16073
16601
  bundlePromises,
16074
16602
  handles,
16075
16603
  defaultIfExists,
16076
- verbose
16604
+ showDetailedErrors
16077
16605
  });
16078
16606
  });
16079
16607
  const uploadResults = await Promise.all(uploadPromises);
@@ -16095,7 +16623,7 @@ async function uploadBundles({
16095
16623
  bundlePromises,
16096
16624
  handles,
16097
16625
  defaultIfExists,
16098
- verbose
16626
+ showDetailedErrors
16099
16627
  }) {
16100
16628
  const orgId = _internalGetGlobalState().orgId;
16101
16629
  if (!orgId) {
@@ -16126,7 +16654,7 @@ async function uploadBundles({
16126
16654
  })
16127
16655
  );
16128
16656
  } catch (e) {
16129
- if (verbose) {
16657
+ if (showDetailedErrors) {
16130
16658
  console.error(e);
16131
16659
  }
16132
16660
  const msg = e instanceof FailedHTTPResponse ? `Unable to upload your code. ${e.status} (${e.text}): ${e.data}` : `Unable to upload your code. You most likely need to update the API: ${e}`;
@@ -16174,30 +16702,14 @@ async function uploadBundles({
16174
16702
  ...prompts,
16175
16703
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
16176
16704
  ...await Promise.all(
16177
- bundleSpecs.map(async (spec) => ({
16178
- project_id: spec.project_id,
16179
- name: spec.name,
16180
- slug: spec.slug,
16181
- description: spec.description,
16182
- function_data: {
16183
- type: "code",
16184
- data: {
16185
- type: "bundle",
16186
- runtime_context,
16187
- location: spec.location,
16188
- bundle_id: pathInfo.bundleId,
16189
- preview: sourceMapContext ? await findCodeDefinition({
16190
- location: spec.location,
16191
- ctx: sourceMapContext
16192
- }) : void 0
16193
- }
16194
- },
16195
- origin: spec.origin,
16196
- function_type: spec.function_type,
16197
- function_schema: spec.function_schema,
16198
- if_exists: spec.if_exists,
16199
- metadata: spec.metadata
16200
- }))
16705
+ bundleSpecs.map(
16706
+ (spec) => buildBundledFunctionEntry({
16707
+ spec,
16708
+ runtime_context,
16709
+ bundleId: pathInfo.bundleId,
16710
+ sourceMapContext
16711
+ })
16712
+ )
16201
16713
  )
16202
16714
  ].map((fn) => ({
16203
16715
  ...fn,
@@ -16209,7 +16721,7 @@ async function uploadBundles({
16209
16721
  functions: functionEntries
16210
16722
  });
16211
16723
  } catch (e) {
16212
- if (verbose) {
16724
+ if (showDetailedErrors) {
16213
16725
  console.error(e);
16214
16726
  }
16215
16727
  const msg = e instanceof FailedHTTPResponse ? `Failed to save function definitions for '${sourceFile}'. ${e.status} (${e.text}): ${e.data}` : `Failed to save function definitions for '${sourceFile}'. You most likely need to update the API: ${e}`;
@@ -16231,11 +16743,66 @@ function formatNameAndSlug(pieces) {
16231
16743
  slug: slugify(nonEmptyPieces.join("-"))
16232
16744
  };
16233
16745
  }
16746
+ async function buildBundledFunctionEntry({
16747
+ spec,
16748
+ runtime_context,
16749
+ bundleId,
16750
+ sourceMapContext
16751
+ }) {
16752
+ return {
16753
+ project_id: spec.project_id,
16754
+ name: spec.name,
16755
+ slug: spec.slug,
16756
+ description: spec.description,
16757
+ function_data: {
16758
+ type: "code",
16759
+ data: {
16760
+ type: "bundle",
16761
+ runtime_context,
16762
+ location: spec.location,
16763
+ bundle_id: bundleId,
16764
+ preview: sourceMapContext ? await findCodeDefinition({
16765
+ location: spec.location,
16766
+ ctx: sourceMapContext
16767
+ }) : void 0
16768
+ }
16769
+ },
16770
+ origin: spec.origin,
16771
+ function_type: spec.function_type ?? void 0,
16772
+ function_schema: spec.function_schema,
16773
+ if_exists: spec.if_exists,
16774
+ tags: spec.tags,
16775
+ metadata: spec.metadata
16776
+ };
16777
+ }
16234
16778
 
16235
16779
  // src/cli/util/bundle.ts
16236
16780
  var import_env = require("@next/env");
16237
16781
  var dotenv = __toESM(require("dotenv"));
16782
+
16783
+ // src/cli/util/debug-logging.ts
16784
+ var VERBOSE_DEPRECATION_MESSAGE = "--verbose is deprecated and will be removed in a future version of braintrust. Use --debug-logging debug to see full stack traces and troubleshooting details.";
16785
+ var hasWarnedAboutVerboseFlag = false;
16786
+ function shouldShowDetailedErrors(debugLogLevel) {
16787
+ return debugLogLevel === "debug";
16788
+ }
16789
+ function normalizeDebugLoggingArgs(args) {
16790
+ if (!args.verbose) {
16791
+ return args;
16792
+ }
16793
+ if (!hasWarnedAboutVerboseFlag) {
16794
+ hasWarnedAboutVerboseFlag = true;
16795
+ console.warn(warning(VERBOSE_DEPRECATION_MESSAGE));
16796
+ }
16797
+ if (!args.debug_logging) {
16798
+ args.debug_logging = "debug";
16799
+ }
16800
+ return args;
16801
+ }
16802
+
16803
+ // src/cli/util/bundle.ts
16238
16804
  async function loadCLIEnv(args) {
16805
+ normalizeDebugLoggingArgs(args);
16239
16806
  (0, import_env.loadEnvConfig)(process.cwd(), true);
16240
16807
  if (args.env_file) {
16241
16808
  const loaded = dotenv.config({ path: args.env_file });
@@ -16247,11 +16814,13 @@ async function loadCLIEnv(args) {
16247
16814
  await login({
16248
16815
  apiKey: args.api_key,
16249
16816
  orgName: args.org_name,
16250
- appUrl: args.app_url
16817
+ appUrl: args.app_url,
16818
+ debugLogLevel: args.debug_logging
16251
16819
  });
16252
16820
  }
16253
16821
  async function bundleCommand(args) {
16254
16822
  await loadCLIEnv(args);
16823
+ const showDetailedErrors = shouldShowDetailedErrors(args.debug_logging);
16255
16824
  const handles = await initializeHandles({
16256
16825
  mode: "bundle",
16257
16826
  files: args.files,
@@ -16275,7 +16844,7 @@ async function bundleCommand(args) {
16275
16844
  handleBuildFailure({
16276
16845
  result: buildResult,
16277
16846
  terminateOnFailure: args.terminate_on_failure,
16278
- verbose: args.verbose
16847
+ showDetailedErrors
16279
16848
  });
16280
16849
  } else {
16281
16850
  buildResults.push(buildResult);
@@ -16286,7 +16855,7 @@ async function bundleCommand(args) {
16286
16855
  bundlePromises,
16287
16856
  handles,
16288
16857
  setCurrent: true,
16289
- verbose: args.verbose,
16858
+ showDetailedErrors,
16290
16859
  defaultIfExists: args.if_exists
16291
16860
  });
16292
16861
  if (numFailed > 0) {
@@ -16797,6 +17366,11 @@ var staticParametersSchema = import_v315.z.record(
16797
17366
  default: PromptData.optional(),
16798
17367
  description: import_v315.z.string().optional()
16799
17368
  }),
17369
+ import_v315.z.object({
17370
+ type: import_v315.z.literal("model"),
17371
+ default: import_v315.z.string().optional(),
17372
+ description: import_v315.z.string().optional()
17373
+ }),
16800
17374
  import_v315.z.object({
16801
17375
  type: import_v315.z.literal("data"),
16802
17376
  schema: import_v315.z.record(import_v315.z.unknown()),
@@ -17243,7 +17817,7 @@ function buildWatchPluginForEvaluator(inFile, opts) {
17243
17817
  build2.onEnd(async (result) => {
17244
17818
  console.error(`Done building ${inFile}`);
17245
17819
  if (!result.outputFiles) {
17246
- if (opts.verbose) {
17820
+ if (opts.showDetailedErrors) {
17247
17821
  console.warn(`Failed to compile ${inFile}`);
17248
17822
  console.warn(result.errors);
17249
17823
  } else {
@@ -17296,7 +17870,7 @@ function buildWatchPluginForEvaluator(inFile, opts) {
17296
17870
  evaluator,
17297
17871
  evaluatorResult,
17298
17872
  {
17299
- verbose: opts.verbose,
17873
+ verbose: opts.showDetailedErrors,
17300
17874
  jsonl: opts.jsonl
17301
17875
  }
17302
17876
  );
@@ -17385,11 +17959,11 @@ async function initFile({
17385
17959
  function handleBuildFailure({
17386
17960
  result,
17387
17961
  terminateOnFailure,
17388
- verbose
17962
+ showDetailedErrors
17389
17963
  }) {
17390
17964
  if (terminateOnFailure) {
17391
17965
  throw result.error;
17392
- } else if (verbose) {
17966
+ } else if (showDetailedErrors) {
17393
17967
  console.warn(`Failed to compile ${result.sourceFile}`);
17394
17968
  console.warn(result.error);
17395
17969
  } else {
@@ -17404,7 +17978,7 @@ function updateEvaluators(evaluators, buildResults, opts) {
17404
17978
  handleBuildFailure({
17405
17979
  result,
17406
17980
  terminateOnFailure: opts.terminateOnFailure,
17407
- verbose: opts.verbose
17981
+ showDetailedErrors: opts.showDetailedErrors
17408
17982
  });
17409
17983
  continue;
17410
17984
  }
@@ -17523,7 +18097,7 @@ async function runOnce(handles, opts) {
17523
18097
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
17524
18098
  allEvalsResults[idx],
17525
18099
  {
17526
- verbose: opts.verbose,
18100
+ verbose: opts.showDetailedErrors,
17527
18101
  jsonl: opts.jsonl
17528
18102
  }
17529
18103
  );
@@ -17540,7 +18114,7 @@ async function runOnce(handles, opts) {
17540
18114
  handles,
17541
18115
  setCurrent: opts.setCurrent,
17542
18116
  defaultIfExists: "replace",
17543
- verbose: opts.verbose
18117
+ showDetailedErrors: opts.showDetailedErrors
17544
18118
  });
17545
18119
  }
17546
18120
  let allSuccess = true;
@@ -17751,6 +18325,7 @@ async function initializeHandles({
17751
18325
  return handles;
17752
18326
  }
17753
18327
  async function run(args) {
18328
+ normalizeDebugLoggingArgs(args);
17754
18329
  (0, import_env2.loadEnvConfig)(process.cwd(), true);
17755
18330
  if (args.env_file) {
17756
18331
  const loaded = dotenv2.config({ path: args.env_file });
@@ -17760,7 +18335,7 @@ async function run(args) {
17760
18335
  }
17761
18336
  }
17762
18337
  const evaluatorOpts = {
17763
- verbose: args.verbose,
18338
+ showDetailedErrors: shouldShowDetailedErrors(args.debug_logging),
17764
18339
  apiKey: args.api_key,
17765
18340
  orgName: args.org_name,
17766
18341
  appUrl: args.app_url,
@@ -17806,7 +18381,8 @@ async function run(args) {
17806
18381
  await login({
17807
18382
  apiKey: args.api_key,
17808
18383
  orgName: args.org_name,
17809
- appUrl: args.app_url
18384
+ appUrl: args.app_url,
18385
+ debugLogLevel: args.debug_logging
17810
18386
  });
17811
18387
  }
17812
18388
  if (args.watch) {
@@ -17842,6 +18418,12 @@ function addAuthArgs(parser) {
17842
18418
  help: "A path to a .env file containing environment variables to load (via dotenv)."
17843
18419
  });
17844
18420
  }
18421
+ function addDebugLoggingArg(parser) {
18422
+ parser.add_argument("--debug-logging", {
18423
+ choices: ["error", "warn", "info", "debug"],
18424
+ help: "Enable internal Braintrust SDK troubleshooting output. Use 'error', 'warn', 'info', or 'debug' to control the log level."
18425
+ });
18426
+ }
17845
18427
  function addCompileArgs(parser) {
17846
18428
  parser.add_argument("--terminate-on-failure", {
17847
18429
  action: "store_true",
@@ -17863,7 +18445,7 @@ async function main() {
17863
18445
  const parentParser = new import_argparse.ArgumentParser({ add_help: false });
17864
18446
  parentParser.add_argument("--verbose", {
17865
18447
  action: "store_true",
17866
- help: "Include additional details, including full stack traces on errors."
18448
+ help: "Deprecated alias for --debug-logging debug. Use --debug-logging debug to include full stack traces and detailed troubleshooting output."
17867
18449
  });
17868
18450
  const subparser = parser.add_subparsers({
17869
18451
  required: true
@@ -17873,6 +18455,7 @@ async function main() {
17873
18455
  parents: [parentParser]
17874
18456
  });
17875
18457
  addAuthArgs(parser_run);
18458
+ addDebugLoggingArg(parser_run);
17876
18459
  parser_run.add_argument("--filter", {
17877
18460
  help: "Only run evaluators that match these filters. Each filter is a regular expression (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp). For example, --filter metadata.priority='^P0$' input.name='foo.*bar' will only run evaluators that have metadata.priority equal to 'P0' and input.name matching the regular expression 'foo.*bar'.",
17878
18461
  nargs: "*"
@@ -17933,6 +18516,7 @@ async function main() {
17933
18516
  help: "Bundle prompts, tools, scorers, and other resources into Braintrust"
17934
18517
  });
17935
18518
  addAuthArgs(parser_push);
18519
+ addDebugLoggingArg(parser_push);
17936
18520
  addCompileArgs(parser_push);
17937
18521
  parser_push.add_argument("files", {
17938
18522
  nargs: "*",
@@ -17947,6 +18531,7 @@ async function main() {
17947
18531
  const parser_pull = subparser.add_parser("pull", {
17948
18532
  help: "Pull prompts, tools, scorers, and other resources from Braintrust to save in your codebase."
17949
18533
  });
18534
+ addDebugLoggingArg(parser_pull);
17950
18535
  parser_pull.add_argument("--output-dir", {
17951
18536
  help: "The directory to output the pulled resources to. If not specified, the current directory is used."
17952
18537
  });
@@ -17970,11 +18555,11 @@ async function main() {
17970
18555
  help: "Overwrite local files if they have uncommitted changes."
17971
18556
  });
17972
18557
  parser_pull.set_defaults({ func: pullCommand });
17973
- const parsed = parser.parse_args();
18558
+ const parsed = normalizeDebugLoggingArgs(parser.parse_args());
17974
18559
  try {
17975
18560
  await parsed.func(parsed);
17976
18561
  } catch (e) {
17977
- logError2(e, parsed.verbose);
18562
+ logError2(e, shouldShowDetailedErrors(parsed.debug_logging));
17978
18563
  process.exit(1);
17979
18564
  }
17980
18565
  }