braintrust 3.22.0 → 3.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +43 -0
  2. package/dev/dist/index.d.mts +1 -1
  3. package/dev/dist/index.d.ts +1 -1
  4. package/dev/dist/index.js +1354 -654
  5. package/dev/dist/index.mjs +736 -36
  6. package/dist/apply-auto-instrumentation.js +222 -186
  7. package/dist/apply-auto-instrumentation.mjs +37 -1
  8. package/dist/auto-instrumentations/bundler/esbuild.cjs +53 -1
  9. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  10. package/dist/auto-instrumentations/bundler/next.cjs +53 -1
  11. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  12. package/dist/auto-instrumentations/bundler/rollup.cjs +53 -1
  13. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  14. package/dist/auto-instrumentations/bundler/vite.cjs +53 -1
  15. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  16. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +53 -1
  17. package/dist/auto-instrumentations/bundler/webpack.cjs +53 -1
  18. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  19. package/dist/auto-instrumentations/{chunk-TKRPRPGD.mjs → chunk-EXY7QCJD.mjs} +5 -2
  20. package/dist/auto-instrumentations/{chunk-T6J4C7LX.mjs → chunk-KIMLYPRW.mjs} +1 -1
  21. package/dist/auto-instrumentations/{chunk-BRQX23KL.mjs → chunk-YXLNSAMJ.mjs} +51 -0
  22. package/dist/auto-instrumentations/hook.mjs +149 -20
  23. package/dist/auto-instrumentations/index.cjs +52 -0
  24. package/dist/auto-instrumentations/index.d.mts +3 -1
  25. package/dist/auto-instrumentations/index.d.ts +3 -1
  26. package/dist/auto-instrumentations/index.mjs +3 -1
  27. package/dist/browser.d.mts +11 -13
  28. package/dist/browser.d.ts +11 -13
  29. package/dist/browser.js +1098 -205
  30. package/dist/browser.mjs +1098 -205
  31. package/dist/{chunk-KMGUTPB7.mjs → chunk-36IPYKMG.mjs} +20 -1
  32. package/dist/{chunk-MWVVR5LR.js → chunk-B6ZQIAK3.js} +1506 -822
  33. package/dist/{chunk-BFGIH2ZJ.js → chunk-CDIKAHDZ.js} +21 -2
  34. package/dist/{chunk-ZG2O3XVF.mjs → chunk-RBXD2KYN.mjs} +719 -35
  35. package/dist/cli.js +737 -37
  36. package/dist/edge-light.d.mts +1 -1
  37. package/dist/edge-light.d.ts +1 -1
  38. package/dist/edge-light.js +1098 -205
  39. package/dist/edge-light.mjs +1098 -205
  40. package/dist/index.d.mts +11 -13
  41. package/dist/index.d.ts +11 -13
  42. package/dist/index.js +786 -593
  43. package/dist/index.mjs +346 -153
  44. package/dist/instrumentation/index.d.mts +3 -11
  45. package/dist/instrumentation/index.d.ts +3 -11
  46. package/dist/instrumentation/index.js +788 -183
  47. package/dist/instrumentation/index.mjs +788 -183
  48. package/dist/vitest-evals-reporter.js +16 -16
  49. package/dist/vitest-evals-reporter.mjs +2 -2
  50. package/dist/workerd.d.mts +1 -1
  51. package/dist/workerd.d.ts +1 -1
  52. package/dist/workerd.js +1098 -205
  53. package/dist/workerd.mjs +1098 -205
  54. package/package.json +1 -1
@@ -4583,7 +4583,7 @@ var DiskCache = class {
4583
4583
  }
4584
4584
  };
4585
4585
 
4586
- // src/prompt-cache/lru-cache.ts
4586
+ // src/lru-cache.ts
4587
4587
  var LRUCache = class {
4588
4588
  cache;
4589
4589
  maxSize;
@@ -5793,25 +5793,46 @@ var HTTPConnection = class _HTTPConnection {
5793
5793
  })
5794
5794
  );
5795
5795
  }
5796
- async post(path2, params, config) {
5796
+ async post(path2, params, config, retries = 0) {
5797
5797
  const { headers, ...rest } = config || {};
5798
5798
  const this_fetch = this.fetch;
5799
5799
  const this_base_url = this.base_url;
5800
5800
  const this_headers = this.headers;
5801
- return await checkResponse(
5802
- await this_fetch(_urljoin(this_base_url, path2), {
5803
- method: "POST",
5804
- headers: {
5805
- Accept: "application/json",
5806
- "Content-Type": "application/json",
5807
- ...this_headers,
5808
- ...headers
5809
- },
5810
- body: typeof params === "string" ? params : params ? JSON.stringify(params) : void 0,
5811
- keepalive: true,
5812
- ...rest
5813
- })
5814
- );
5801
+ const tries = retries + 1;
5802
+ for (let i = 0; i < tries; i++) {
5803
+ try {
5804
+ return await checkResponse(
5805
+ await this_fetch(_urljoin(this_base_url, path2), {
5806
+ method: "POST",
5807
+ headers: {
5808
+ Accept: "application/json",
5809
+ "Content-Type": "application/json",
5810
+ ...this_headers,
5811
+ ...headers
5812
+ },
5813
+ body: typeof params === "string" ? params : params ? JSON.stringify(params) : void 0,
5814
+ keepalive: true,
5815
+ ...rest
5816
+ })
5817
+ );
5818
+ } catch (error) {
5819
+ if (config?.signal?.aborted) {
5820
+ throw getAbortReason(config.signal);
5821
+ }
5822
+ if (i === tries - 1 || !isRetryableHTTPError(error)) {
5823
+ throw error;
5824
+ }
5825
+ debugLogger.debug(
5826
+ `Retrying API request ${path2} after ${formatHTTPError(error)}`
5827
+ );
5828
+ const sleepTimeMs = HTTP_RETRY_BASE_SLEEP_TIME_S * 1e3 * 2 ** i + Math.random() * HTTP_RETRY_JITTER_MS;
5829
+ debugLogger.info(
5830
+ `Sleeping for ${sleepTimeMs}ms before retrying API request`
5831
+ );
5832
+ await waitForRetry(sleepTimeMs, config?.signal);
5833
+ }
5834
+ }
5835
+ throw new Error("Unexpected retry state");
5815
5836
  }
5816
5837
  async get_json(object_type, args = void 0, retries = 0) {
5817
5838
  const tries = retries + 1;
@@ -6711,6 +6732,45 @@ function now() {
6711
6732
  var DEFAULT_FLUSH_BACKPRESSURE_BYTES = 10 * 1024 * 1024;
6712
6733
  var BACKGROUND_LOGGER_BASE_SLEEP_TIME_S = 1;
6713
6734
  var HTTP_RETRY_BASE_SLEEP_TIME_S = 1;
6735
+ var HTTP_RETRY_JITTER_MS = 200;
6736
+ var BTQL_HTTP_RETRIES = 3;
6737
+ var RETRYABLE_HTTP_STATUS_CODES = /* @__PURE__ */ new Set([500, 502, 503, 504]);
6738
+ function isRetryableHTTPError(error) {
6739
+ return !(error instanceof FailedHTTPResponse) || RETRYABLE_HTTP_STATUS_CODES.has(error.status);
6740
+ }
6741
+ function formatHTTPError(error) {
6742
+ if (error instanceof FailedHTTPResponse) {
6743
+ return `${error.status} ${error.text}`;
6744
+ }
6745
+ return error instanceof Error ? error.message : String(error);
6746
+ }
6747
+ function getAbortReason(signal) {
6748
+ return signal.reason ?? new Error("Request aborted");
6749
+ }
6750
+ async function waitForRetry(delayMs, signal) {
6751
+ if (!signal) {
6752
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
6753
+ return;
6754
+ }
6755
+ if (signal.aborted) {
6756
+ throw getAbortReason(signal);
6757
+ }
6758
+ await new Promise((resolve, reject2) => {
6759
+ const onAbort = () => {
6760
+ clearTimeout(timeout);
6761
+ signal.removeEventListener("abort", onAbort);
6762
+ reject2(getAbortReason(signal));
6763
+ };
6764
+ const timeout = setTimeout(() => {
6765
+ signal.removeEventListener("abort", onAbort);
6766
+ resolve();
6767
+ }, delayMs);
6768
+ signal.addEventListener("abort", onAbort, { once: true });
6769
+ if (signal.aborted) {
6770
+ onAbort();
6771
+ }
6772
+ });
6773
+ }
6714
6774
  var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
6715
6775
  apiConn;
6716
6776
  queue;
@@ -8138,15 +8198,15 @@ function parentSpanIdsUsable(spanId, rootSpanId) {
8138
8198
  return Boolean(spanId) && Boolean(rootSpanId);
8139
8199
  }
8140
8200
  function logError(span, error) {
8141
- let errorMessage = "<error>";
8201
+ let errorMessage2 = "<error>";
8142
8202
  let stackTrace = "";
8143
8203
  if (error instanceof Error) {
8144
- errorMessage = error.message;
8204
+ errorMessage2 = error.message;
8145
8205
  stackTrace = error.stack || "";
8146
8206
  } else {
8147
- errorMessage = String(error);
8207
+ errorMessage2 = String(error);
8148
8208
  }
8149
- span.log({ error: `${errorMessage}
8209
+ span.log({ error: `${errorMessage2}
8150
8210
 
8151
8211
  ${stackTrace}` });
8152
8212
  }
@@ -8525,7 +8585,8 @@ var ObjectFetcher = class {
8525
8585
  version: this.pinnedVersion
8526
8586
  } : {}
8527
8587
  },
8528
- { headers: { "Accept-Encoding": "gzip" } }
8588
+ { headers: { "Accept-Encoding": "gzip" } },
8589
+ BTQL_HTTP_RETRIES
8529
8590
  );
8530
8591
  const respJson = await resp.json();
8531
8592
  const mutate = this.mutateRecord;
@@ -17414,8 +17475,6 @@ function filterSerializableOptions(options) {
17414
17475
  "additionalDirectories",
17415
17476
  "permissionMode",
17416
17477
  "debug",
17417
- "apiKey",
17418
- "apiKeySource",
17419
17478
  "agentName",
17420
17479
  "instructions"
17421
17480
  ];
@@ -28613,6 +28672,446 @@ function isBraintrustHandler(handler) {
28613
28672
  return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
28614
28673
  }
28615
28674
 
28675
+ // src/instrumentation/plugins/langsmith-channels.ts
28676
+ var langSmithChannels = defineChannels("langsmith", {
28677
+ createRun: channel({
28678
+ channelName: "Client.createRun",
28679
+ kind: "async"
28680
+ }),
28681
+ updateRun: channel({
28682
+ channelName: "Client.updateRun",
28683
+ kind: "async"
28684
+ }),
28685
+ batchIngestRuns: channel({
28686
+ channelName: "Client.batchIngestRuns",
28687
+ kind: "async"
28688
+ })
28689
+ });
28690
+
28691
+ // src/instrumentation/plugins/langsmith-plugin.ts
28692
+ var MAX_COMPLETED_RUNS = 1e4;
28693
+ var BLOCKED_METADATA_KEYS = /* @__PURE__ */ new Set([
28694
+ "__proto__",
28695
+ "constructor",
28696
+ "prototype",
28697
+ "usage_metadata"
28698
+ ]);
28699
+ var BLOCKED_METADATA_PREFIXES = ["__pregel_", "langgraph_", "lc_"];
28700
+ var LLM_SETTING_KEYS = [
28701
+ "temperature",
28702
+ "top_p",
28703
+ "max_tokens",
28704
+ "frequency_penalty",
28705
+ "presence_penalty",
28706
+ "stop",
28707
+ "response_format"
28708
+ ];
28709
+ var LangSmithPlugin = class extends BasePlugin {
28710
+ activeRuns = /* @__PURE__ */ new Map();
28711
+ completedRuns = new LRUCache({
28712
+ max: MAX_COMPLETED_RUNS
28713
+ });
28714
+ skipLangChainRuns;
28715
+ constructor(options = {}) {
28716
+ super();
28717
+ this.skipLangChainRuns = options.skipLangChainRuns ?? true;
28718
+ }
28719
+ onEnable() {
28720
+ const createChannel = langSmithChannels.createRun.tracingChannel();
28721
+ const createHandlers = {
28722
+ start: (event) => {
28723
+ this.containLifecycleFailure("createRun", () => {
28724
+ this.processCreate(event.arguments[0]);
28725
+ });
28726
+ }
28727
+ };
28728
+ createChannel.subscribe(createHandlers);
28729
+ this.unsubscribers.push(() => createChannel.unsubscribe(createHandlers));
28730
+ const updateChannel = langSmithChannels.updateRun.tracingChannel();
28731
+ const updateHandlers = {
28732
+ start: (event) => {
28733
+ this.containLifecycleFailure("updateRun", () => {
28734
+ this.processUpdate(event.arguments[0], event.arguments[1]);
28735
+ });
28736
+ }
28737
+ };
28738
+ updateChannel.subscribe(updateHandlers);
28739
+ this.unsubscribers.push(() => updateChannel.unsubscribe(updateHandlers));
28740
+ const batchChannel = langSmithChannels.batchIngestRuns.tracingChannel();
28741
+ const batchHandlers = {
28742
+ start: (event) => {
28743
+ this.containLifecycleFailure("batchIngestRuns", () => {
28744
+ this.processBatch(event.arguments[0]);
28745
+ });
28746
+ }
28747
+ };
28748
+ batchChannel.subscribe(batchHandlers);
28749
+ this.unsubscribers.push(() => batchChannel.unsubscribe(batchHandlers));
28750
+ }
28751
+ onDisable() {
28752
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
28753
+ for (const { span } of this.activeRuns.values()) {
28754
+ span.end();
28755
+ }
28756
+ this.activeRuns.clear();
28757
+ this.completedRuns.clear();
28758
+ }
28759
+ processBatch(batch) {
28760
+ if (!isRecord2(batch)) {
28761
+ return;
28762
+ }
28763
+ const creates = ownValue(batch, "runCreates");
28764
+ if (Array.isArray(creates)) {
28765
+ const parentFirst = [...creates].sort((left, right) => {
28766
+ const leftId = stringValue2(ownValue(left, "id"));
28767
+ const rightId = stringValue2(ownValue(right, "id"));
28768
+ const leftParent = stringValue2(ownValue(left, "parent_run_id"));
28769
+ const rightParent = stringValue2(ownValue(right, "parent_run_id"));
28770
+ if (leftParent && leftParent === rightId) {
28771
+ return 1;
28772
+ }
28773
+ if (rightParent && rightParent === leftId) {
28774
+ return -1;
28775
+ }
28776
+ return dottedOrderDepth(left) - dottedOrderDepth(right);
28777
+ });
28778
+ for (const run of parentFirst) {
28779
+ this.containLifecycleFailure("batchIngestRuns create", () => {
28780
+ this.processCreate(run);
28781
+ });
28782
+ }
28783
+ }
28784
+ const updates = ownValue(batch, "runUpdates");
28785
+ if (Array.isArray(updates)) {
28786
+ for (const run of updates) {
28787
+ this.containLifecycleFailure("batchIngestRuns update", () => {
28788
+ this.processUpdate(stringValue2(ownValue(run, "id")) ?? "", run);
28789
+ });
28790
+ }
28791
+ }
28792
+ }
28793
+ processCreate(run) {
28794
+ const id = stringValue2(ownValue(run, "id"));
28795
+ if (!id || this.completedRuns.get(id)) {
28796
+ return;
28797
+ }
28798
+ if (this.shouldSkipLangChainRun(run)) {
28799
+ this.completedRuns.set(id, true);
28800
+ return;
28801
+ }
28802
+ const active = this.activeRuns.get(id);
28803
+ if (active) {
28804
+ const previous = active.run;
28805
+ active.run = mergeRuns(previous, run);
28806
+ this.logRun(
28807
+ active.span,
28808
+ active.run,
28809
+ previous,
28810
+ timestampSeconds(ownValue(active.run, "end_time")) !== void 0 || errorMessage(ownValue(active.run, "error")) !== void 0
28811
+ );
28812
+ this.endIfComplete(id, active, active.run);
28813
+ return;
28814
+ }
28815
+ const span = this.startRunSpan(id, run);
28816
+ const activeRun = { run, span };
28817
+ this.activeRuns.set(id, activeRun);
28818
+ this.logRun(
28819
+ span,
28820
+ run,
28821
+ void 0,
28822
+ timestampSeconds(ownValue(run, "end_time")) !== void 0 || errorMessage(ownValue(run, "error")) !== void 0
28823
+ );
28824
+ this.endIfComplete(id, activeRun, run);
28825
+ }
28826
+ processUpdate(explicitId, run) {
28827
+ const id = stringValue2(explicitId) ?? stringValue2(ownValue(run, "id"));
28828
+ if (!id || this.completedRuns.get(id)) {
28829
+ return;
28830
+ }
28831
+ if (this.shouldSkipLangChainRun(run)) {
28832
+ const active2 = this.activeRuns.get(id);
28833
+ active2?.span.end();
28834
+ this.activeRuns.delete(id);
28835
+ this.completedRuns.set(id, true);
28836
+ return;
28837
+ }
28838
+ let active = this.activeRuns.get(id);
28839
+ if (!active) {
28840
+ const span = this.startRunSpan(id, run);
28841
+ active = { run, span };
28842
+ this.activeRuns.set(id, active);
28843
+ }
28844
+ const previous = active.run;
28845
+ active.run = mergeRuns(previous, run);
28846
+ this.logRun(active.span, active.run, previous, true);
28847
+ this.endIfComplete(id, active, active.run);
28848
+ }
28849
+ startRunSpan(id, run) {
28850
+ const traceId = stringValue2(ownValue(run, "trace_id")) ?? id;
28851
+ const parentId = stringValue2(ownValue(run, "parent_run_id")) ?? stringValue2(ownValue(ownValue(run, "parent_run"), "id"));
28852
+ const startTime = timestampSeconds(ownValue(run, "start_time"));
28853
+ return startSpan({
28854
+ name: stringValue2(ownValue(run, "name")) ?? "LangSmith run",
28855
+ spanId: id,
28856
+ parentSpanIds: {
28857
+ parentSpanIds: parentId ? [parentId] : [],
28858
+ rootSpanId: traceId
28859
+ },
28860
+ spanAttributes: {
28861
+ type: mapRunType(ownValue(run, "run_type"))
28862
+ },
28863
+ ...startTime === void 0 ? {} : { startTime },
28864
+ event: { id }
28865
+ });
28866
+ }
28867
+ logRun(span, run, previous, includeOutput) {
28868
+ const inputs = preferOwnValue(run, previous, "inputs");
28869
+ const outputs = preferOwnValue(run, previous, "outputs");
28870
+ const error = errorMessage(preferOwnValue(run, previous, "error"));
28871
+ const metadata = extractMetadata(run, previous);
28872
+ const tags = extractTags(preferOwnValue(run, previous, "tags"));
28873
+ const metrics = extractMetrics(run, previous);
28874
+ span.log({
28875
+ ...inputs === void 0 ? {} : { input: sanitizeLoggedValue(inputs) },
28876
+ ...includeOutput && outputs !== void 0 ? { output: sanitizeLoggedValue(outputs) } : {},
28877
+ ...error === void 0 ? {} : { error },
28878
+ ...metadata === void 0 ? {} : { metadata },
28879
+ ...tags === void 0 ? {} : { tags },
28880
+ ...Object.keys(metrics).length === 0 ? {} : { metrics }
28881
+ });
28882
+ }
28883
+ endIfComplete(id, active, run) {
28884
+ const endTime = timestampSeconds(ownValue(run, "end_time"));
28885
+ if (endTime === void 0 && errorMessage(ownValue(run, "error")) === void 0) {
28886
+ return;
28887
+ }
28888
+ active.span.end(endTime === void 0 ? void 0 : { endTime });
28889
+ this.activeRuns.delete(id);
28890
+ this.completedRuns.set(id, true);
28891
+ }
28892
+ shouldSkipLangChainRun(run) {
28893
+ if (!this.skipLangChainRuns) {
28894
+ return false;
28895
+ }
28896
+ const serialized = ownValue(run, "serialized");
28897
+ return isRecord2(serialized) && ownValue(serialized, "lc") === 1;
28898
+ }
28899
+ containLifecycleFailure(operation, fn) {
28900
+ try {
28901
+ fn();
28902
+ } catch (error) {
28903
+ debugLogger.error(
28904
+ `Failed to process LangSmith ${operation} instrumentation:`,
28905
+ error
28906
+ );
28907
+ }
28908
+ }
28909
+ };
28910
+ function ownValue(value, key) {
28911
+ if (!isRecord2(value)) {
28912
+ return void 0;
28913
+ }
28914
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
28915
+ return descriptor && "value" in descriptor ? descriptor.value : void 0;
28916
+ }
28917
+ function preferOwnValue(current, previous, key) {
28918
+ const currentDescriptor = isRecord2(current) ? Object.getOwnPropertyDescriptor(current, key) : void 0;
28919
+ if (currentDescriptor && "value" in currentDescriptor) {
28920
+ return currentDescriptor.value;
28921
+ }
28922
+ return ownValue(previous, key);
28923
+ }
28924
+ function mergeRuns(previous, current) {
28925
+ const entries = /* @__PURE__ */ new Map();
28926
+ for (const value of [previous, current]) {
28927
+ if (!isRecord2(value)) {
28928
+ continue;
28929
+ }
28930
+ for (const [key, descriptor] of Object.entries(
28931
+ Object.getOwnPropertyDescriptors(value)
28932
+ )) {
28933
+ if (descriptor.enumerable && "value" in descriptor) {
28934
+ entries.set(key, descriptor.value);
28935
+ }
28936
+ }
28937
+ }
28938
+ return Object.fromEntries(entries);
28939
+ }
28940
+ function isRecord2(value) {
28941
+ return typeof value === "object" && value !== null && !Array.isArray(value);
28942
+ }
28943
+ function stringValue2(value) {
28944
+ return typeof value === "string" && value.length > 0 ? value : void 0;
28945
+ }
28946
+ function timestampSeconds(value) {
28947
+ if (value instanceof Date) {
28948
+ const timestamp = value.getTime();
28949
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
28950
+ }
28951
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
28952
+ return value > 1e10 ? value / 1e3 : value;
28953
+ }
28954
+ if (typeof value === "string") {
28955
+ const timestamp = Date.parse(value);
28956
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
28957
+ }
28958
+ return void 0;
28959
+ }
28960
+ function dottedOrderDepth(run) {
28961
+ const dottedOrder = stringValue2(ownValue(run, "dotted_order"));
28962
+ return dottedOrder ? dottedOrder.split(".").length : Number.MAX_SAFE_INTEGER;
28963
+ }
28964
+ function mapRunType(runType) {
28965
+ switch (runType) {
28966
+ case "llm":
28967
+ case "embedding":
28968
+ return "llm" /* LLM */;
28969
+ case "tool":
28970
+ case "retriever":
28971
+ return "tool" /* TOOL */;
28972
+ default:
28973
+ return "task" /* TASK */;
28974
+ }
28975
+ }
28976
+ function extractMetadata(run, previous) {
28977
+ const extra = preferOwnValue(run, previous, "extra");
28978
+ const rawMetadata = ownValue(extra, "metadata");
28979
+ if (!isRecord2(rawMetadata)) {
28980
+ return void 0;
28981
+ }
28982
+ const metadata = {};
28983
+ for (const [key, descriptor] of Object.entries(
28984
+ Object.getOwnPropertyDescriptors(rawMetadata)
28985
+ )) {
28986
+ if (!("value" in descriptor) || !descriptor.enumerable || BLOCKED_METADATA_KEYS.has(key) || BLOCKED_METADATA_PREFIXES.some((prefix) => key.startsWith(prefix)) || key.startsWith("ls_") && key !== "ls_provider" && key !== "ls_model_name" && !LLM_SETTING_KEYS.some((setting) => key === `ls_${setting}`)) {
28987
+ continue;
28988
+ }
28989
+ const normalizedKey = key === "ls_provider" ? "provider" : key === "ls_model_name" ? "model" : key.startsWith("ls_") ? key.slice(3) : key;
28990
+ const sanitized = sanitizeLoggedValue(descriptor.value);
28991
+ if (sanitized !== void 0) {
28992
+ metadata[normalizedKey] = sanitized;
28993
+ }
28994
+ }
28995
+ return Object.keys(metadata).length === 0 ? void 0 : metadata;
28996
+ }
28997
+ function extractTags(value) {
28998
+ if (!Array.isArray(value)) {
28999
+ return void 0;
29000
+ }
29001
+ const tags = value.filter(
29002
+ (tag) => typeof tag === "string" && tag.length > 0
29003
+ );
29004
+ return tags.length > 0 ? tags : void 0;
29005
+ }
29006
+ function extractMetrics(run, previous) {
29007
+ const outputs = preferOwnValue(run, previous, "outputs");
29008
+ const extra = preferOwnValue(run, previous, "extra");
29009
+ const metadata = ownValue(extra, "metadata");
29010
+ const usage = ownValue(outputs, "usage_metadata") ?? ownValue(metadata, "usage_metadata");
29011
+ const metrics = {};
29012
+ assignFirstMetric(metrics, "prompt_tokens", usage, [
29013
+ "input_tokens",
29014
+ "prompt_tokens"
29015
+ ]);
29016
+ assignFirstMetric(metrics, "completion_tokens", usage, [
29017
+ "output_tokens",
29018
+ "completion_tokens"
29019
+ ]);
29020
+ assignFirstMetric(metrics, "tokens", usage, ["total_tokens", "tokens"]);
29021
+ const inputTokenDetails = ownValue(usage, "input_token_details");
29022
+ assignFirstMetric(metrics, "prompt_cached_tokens", inputTokenDetails, [
29023
+ "cache_read",
29024
+ "cached_tokens"
29025
+ ]);
29026
+ if (metrics.prompt_cached_tokens === void 0) {
29027
+ assignFirstMetric(metrics, "prompt_cached_tokens", usage, [
29028
+ "cache_read_input_tokens",
29029
+ "prompt_cached_tokens"
29030
+ ]);
29031
+ }
29032
+ assignFirstMetric(
29033
+ metrics,
29034
+ "prompt_cache_creation_tokens",
29035
+ inputTokenDetails,
29036
+ ["cache_creation"]
29037
+ );
29038
+ if (metrics.prompt_cache_creation_tokens === void 0) {
29039
+ assignFirstMetric(metrics, "prompt_cache_creation_tokens", usage, [
29040
+ "cache_creation_input_tokens",
29041
+ "prompt_cache_creation_tokens"
29042
+ ]);
29043
+ }
29044
+ if (metrics.tokens === void 0 && (metrics.prompt_tokens !== void 0 || metrics.completion_tokens !== void 0)) {
29045
+ metrics.tokens = (metrics.prompt_tokens ?? 0) + (metrics.completion_tokens ?? 0);
29046
+ }
29047
+ const startTime = timestampSeconds(
29048
+ preferOwnValue(run, previous, "start_time")
29049
+ );
29050
+ const events = preferOwnValue(run, previous, "events");
29051
+ if (startTime !== void 0 && Array.isArray(events)) {
29052
+ for (const event of events) {
29053
+ if (ownValue(event, "name") !== "new_token") {
29054
+ continue;
29055
+ }
29056
+ const eventTime2 = timestampSeconds(ownValue(event, "time"));
29057
+ if (eventTime2 !== void 0 && eventTime2 >= startTime) {
29058
+ metrics.time_to_first_token = eventTime2 - startTime;
29059
+ }
29060
+ break;
29061
+ }
29062
+ }
29063
+ return metrics;
29064
+ }
29065
+ function assignFirstMetric(metrics, target, source, keys) {
29066
+ for (const key of keys) {
29067
+ const value = ownValue(source, key);
29068
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
29069
+ metrics[target] = value;
29070
+ return;
29071
+ }
29072
+ }
29073
+ }
29074
+ function errorMessage(value) {
29075
+ if (typeof value === "string") {
29076
+ return value;
29077
+ }
29078
+ if (value instanceof Error) {
29079
+ return value.message;
29080
+ }
29081
+ return void 0;
29082
+ }
29083
+ function sanitizeLoggedValue(value, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
29084
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
29085
+ return value;
29086
+ }
29087
+ if (typeof value === "number") {
29088
+ return Number.isFinite(value) ? value : void 0;
29089
+ }
29090
+ if (value instanceof Date) {
29091
+ return Number.isFinite(value.getTime()) ? value.toISOString() : void 0;
29092
+ }
29093
+ if (typeof value !== "object" || depth >= 20) {
29094
+ return void 0;
29095
+ }
29096
+ if (seen.has(value)) {
29097
+ return "[Circular]";
29098
+ }
29099
+ seen.add(value);
29100
+ if (Array.isArray(value)) {
29101
+ return value.map((item) => sanitizeLoggedValue(item, seen, depth + 1));
29102
+ }
29103
+ const entries = [];
29104
+ for (const [key, descriptor] of Object.entries(
29105
+ Object.getOwnPropertyDescriptors(value)
29106
+ )) {
29107
+ if (!descriptor.enumerable || !("value" in descriptor) || BLOCKED_METADATA_KEYS.has(key)) {
29108
+ continue;
29109
+ }
29110
+ entries.push([key, sanitizeLoggedValue(descriptor.value, seen, depth + 1)]);
29111
+ }
29112
+ return Object.fromEntries(entries);
29113
+ }
29114
+
28616
29115
  // src/instrumentation/plugins/pi-coding-agent-channels.ts
28617
29116
  var piCodingAgentChannels = defineChannels(
28618
29117
  "@earendil-works/pi-coding-agent",
@@ -28992,11 +29491,11 @@ function patchAssistantMessageStream(stream, promptState, llmState) {
28992
29491
  function recordPiAssistantMessageEvent(promptState, llmState, event) {
28993
29492
  recordFirstTokenMetric(llmState, event);
28994
29493
  const message = "message" in event ? event.message : void 0;
28995
- const errorMessage = "error" in event ? event.error : void 0;
29494
+ const errorMessage2 = "error" in event ? event.error : void 0;
28996
29495
  if (event.type === "done" && isPiAssistantMessage(message)) {
28997
29496
  finishPiLlmSpan(promptState, llmState, message);
28998
- } else if (event.type === "error" && isPiAssistantMessage(errorMessage)) {
28999
- finishPiLlmSpan(promptState, llmState, errorMessage);
29497
+ } else if (event.type === "error" && isPiAssistantMessage(errorMessage2)) {
29498
+ finishPiLlmSpan(promptState, llmState, errorMessage2);
29000
29499
  }
29001
29500
  }
29002
29501
  function recordFirstTokenMetric(state, event) {
@@ -29514,6 +30013,7 @@ var strandsAgentSDKChannels = defineChannels("@strands-agents/sdk", {
29514
30013
  });
29515
30014
 
29516
30015
  // src/instrumentation/plugins/strands-agent-sdk-plugin.ts
30016
+ var MAX_STRANDS_STRING_ATTACHMENT_CACHE_ENTRIES = 32;
29517
30017
  var StrandsAgentSDKPlugin = class extends BasePlugin {
29518
30018
  activeChildParents = /* @__PURE__ */ new WeakMap();
29519
30019
  onEnable() {
@@ -29658,11 +30158,16 @@ function startAgentStream(event, activeChildParents) {
29658
30158
  ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
29659
30159
  };
29660
30160
  const parentSpan = agent ? getOnlyChildParent(activeChildParents, agent) : void 0;
30161
+ const attachmentCache = createStrandsAttachmentCache();
30162
+ const input = processStrandsInputAttachments(
30163
+ event.arguments[0],
30164
+ attachmentCache
30165
+ );
29661
30166
  const span = parentSpan ? withCurrent(
29662
30167
  parentSpan,
29663
30168
  () => startSpan({
29664
30169
  event: {
29665
- input: event.arguments[0],
30170
+ input,
29666
30171
  metadata
29667
30172
  },
29668
30173
  name: formatAgentSpanName(agent),
@@ -29670,7 +30175,7 @@ function startAgentStream(event, activeChildParents) {
29670
30175
  })
29671
30176
  ) : startSpan({
29672
30177
  event: {
29673
- input: event.arguments[0],
30178
+ input,
29674
30179
  metadata
29675
30180
  },
29676
30181
  name: formatAgentSpanName(agent),
@@ -29678,6 +30183,7 @@ function startAgentStream(event, activeChildParents) {
29678
30183
  });
29679
30184
  return {
29680
30185
  activeTools: /* @__PURE__ */ new Map(),
30186
+ attachmentCache,
29681
30187
  finalized: false,
29682
30188
  metadata,
29683
30189
  span,
@@ -29693,11 +30199,12 @@ function startMultiAgentStream(event, operation, activeChildParents) {
29693
30199
  ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
29694
30200
  };
29695
30201
  const parentSpan = orchestrator ? getOnlyChildParent(activeChildParents, orchestrator) : void 0;
30202
+ const input = processStrandsInputAttachments(event.arguments[0]);
29696
30203
  const span = parentSpan ? withCurrent(
29697
30204
  parentSpan,
29698
30205
  () => startSpan({
29699
30206
  event: {
29700
- input: event.arguments[0],
30207
+ input,
29701
30208
  metadata
29702
30209
  },
29703
30210
  name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
@@ -29705,7 +30212,7 @@ function startMultiAgentStream(event, operation, activeChildParents) {
29705
30212
  })
29706
30213
  ) : startSpan({
29707
30214
  event: {
29708
- input: event.arguments[0],
30215
+ input,
29709
30216
  metadata
29710
30217
  },
29711
30218
  name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
@@ -29814,7 +30321,10 @@ function startModelSpan(state, event) {
29814
30321
  state.span,
29815
30322
  () => startSpan({
29816
30323
  event: {
29817
- input: Array.isArray(event.agent?.messages) ? event.agent.messages : void 0,
30324
+ input: Array.isArray(event.agent?.messages) ? processStrandsInputAttachments(
30325
+ event.agent.messages,
30326
+ state.attachmentCache
30327
+ ) : void 0,
29818
30328
  metadata
29819
30329
  },
29820
30330
  name: formatModelSpanName(model),
@@ -30028,6 +30538,7 @@ function finalizeAgentStream(state, error, output) {
30028
30538
  ...output !== void 0 ? { output } : {}
30029
30539
  });
30030
30540
  state.span.end();
30541
+ state.attachmentCache.strings.clear();
30031
30542
  }
30032
30543
  function finalizeMultiAgentStream(state, activeChildParents, error, output) {
30033
30544
  if (state.finalized) {
@@ -30174,6 +30685,166 @@ function extractNodeResultOutput(result) {
30174
30685
  }
30175
30686
  return result;
30176
30687
  }
30688
+ var STRANDS_MEDIA_TYPES = {
30689
+ png: "image/png",
30690
+ jpg: "image/jpeg",
30691
+ jpeg: "image/jpeg",
30692
+ gif: "image/gif",
30693
+ webp: "image/webp",
30694
+ mkv: "video/x-matroska",
30695
+ mov: "video/quicktime",
30696
+ mp4: "video/mp4",
30697
+ webm: "video/webm",
30698
+ flv: "video/x-flv",
30699
+ mpeg: "video/mpeg",
30700
+ mpg: "video/mpeg",
30701
+ wmv: "video/x-ms-wmv",
30702
+ "3gp": "video/3gpp",
30703
+ pdf: "application/pdf",
30704
+ csv: "text/csv",
30705
+ doc: "application/msword",
30706
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
30707
+ xls: "application/vnd.ms-excel",
30708
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
30709
+ html: "text/html",
30710
+ txt: "text/plain",
30711
+ md: "text/markdown",
30712
+ json: "application/json",
30713
+ xml: "application/xml"
30714
+ };
30715
+ function createStrandsAttachmentCache() {
30716
+ return {
30717
+ objects: /* @__PURE__ */ new WeakMap(),
30718
+ strings: new LRUCache({
30719
+ max: MAX_STRANDS_STRING_ATTACHMENT_CACHE_ENTRIES
30720
+ })
30721
+ };
30722
+ }
30723
+ function processStrandsInputAttachments(input, cache = createStrandsAttachmentCache()) {
30724
+ try {
30725
+ return processStrandsInputNode(input, cache);
30726
+ } catch (error) {
30727
+ logInstrumentationError5("Strands Agent SDK input attachments", error);
30728
+ return input;
30729
+ }
30730
+ }
30731
+ function processStrandsInputNode(value, cache) {
30732
+ if (value instanceof BaseAttachment) {
30733
+ return value;
30734
+ }
30735
+ if (Array.isArray(value)) {
30736
+ return value.map((child) => processStrandsInputNode(child, cache));
30737
+ }
30738
+ if (!isObject(value)) {
30739
+ return value;
30740
+ }
30741
+ const directMedia = processDirectStrandsMediaBlock(value, cache);
30742
+ if (directMedia !== void 0) {
30743
+ return directMedia;
30744
+ }
30745
+ const wrappedMedia = processWrappedStrandsMediaBlock(value, cache);
30746
+ if (wrappedMedia !== void 0) {
30747
+ return wrappedMedia;
30748
+ }
30749
+ if (value.type === "message" && Array.isArray(value.content)) {
30750
+ return {
30751
+ role: value.role,
30752
+ content: value.content.map(
30753
+ (child) => processStrandsInputNode(child, cache)
30754
+ ),
30755
+ ...value.metadata !== void 0 ? { metadata: value.metadata } : {}
30756
+ };
30757
+ }
30758
+ if (typeof value.toJSON === "function") {
30759
+ return processStrandsInputNode(value.toJSON(), cache);
30760
+ }
30761
+ return Object.fromEntries(
30762
+ Object.entries(value).map(([key, child]) => [
30763
+ key,
30764
+ processStrandsInputNode(child, cache)
30765
+ ])
30766
+ );
30767
+ }
30768
+ function processDirectStrandsMediaBlock(block, cache) {
30769
+ if (!isStrandsMediaBlock(block)) {
30770
+ return void 0;
30771
+ }
30772
+ const mediaKey = block.type === "imageBlock" ? "image" : block.type === "videoBlock" ? "video" : "document";
30773
+ return createStrandsMediaAttachment(mediaKey, block, cache);
30774
+ }
30775
+ function isStrandsMediaBlock(block) {
30776
+ return (block.type === "imageBlock" || block.type === "videoBlock" || block.type === "documentBlock") && typeof block.format === "string" && isObject(block.source);
30777
+ }
30778
+ function processWrappedStrandsMediaBlock(block, cache) {
30779
+ for (const mediaKey of ["image", "video", "document"]) {
30780
+ const media = block[mediaKey];
30781
+ if (!Object.hasOwn(block, mediaKey) || !isObject(media)) {
30782
+ continue;
30783
+ }
30784
+ const processed = createStrandsMediaAttachment(mediaKey, media, cache);
30785
+ if (processed !== void 0) {
30786
+ return processed;
30787
+ }
30788
+ }
30789
+ return void 0;
30790
+ }
30791
+ function createStrandsMediaAttachment(mediaKey, media, cache) {
30792
+ const format = media.format;
30793
+ const source = media.source;
30794
+ if (typeof format !== "string" || !isObject(source) || !Object.hasOwn(source, "bytes")) {
30795
+ return void 0;
30796
+ }
30797
+ const contentType = STRANDS_MEDIA_TYPES[format.toLowerCase()];
30798
+ if (!contentType) {
30799
+ return void 0;
30800
+ }
30801
+ const filename = mediaKey === "document" && typeof media.name === "string" && media.name.length > 0 ? media.name : `${mediaKey}.${format.toLowerCase()}`;
30802
+ const attachment = getOrCreateStrandsAttachment(
30803
+ source.bytes,
30804
+ filename,
30805
+ contentType,
30806
+ cache
30807
+ );
30808
+ if (!attachment) {
30809
+ return void 0;
30810
+ }
30811
+ const { type: _type, ...serializedMedia } = media;
30812
+ const { type: _sourceType, ...serializedSource } = source;
30813
+ return {
30814
+ [mediaKey]: {
30815
+ ...serializedMedia,
30816
+ source: {
30817
+ ...serializedSource,
30818
+ bytes: attachment
30819
+ }
30820
+ }
30821
+ };
30822
+ }
30823
+ function getOrCreateStrandsAttachment(data, filename, contentType, cache) {
30824
+ const key = `${contentType}\0${filename}`;
30825
+ const attachments = typeof data === "string" ? cache.strings.get(data) : isObject(data) ? cache.objects.get(data) : void 0;
30826
+ const cached = attachments?.get(key);
30827
+ if (cached) {
30828
+ return cached;
30829
+ }
30830
+ const blob = convertDataToBlob(data, contentType);
30831
+ if (!blob) {
30832
+ return void 0;
30833
+ }
30834
+ const attachment = new Attachment({
30835
+ data: blob,
30836
+ filename,
30837
+ contentType
30838
+ });
30839
+ const updatedAttachments = attachments ?? /* @__PURE__ */ new Map();
30840
+ updatedAttachments.set(key, attachment);
30841
+ if (typeof data === "string") {
30842
+ cache.strings.set(data, updatedAttachments);
30843
+ } else if (isObject(data)) {
30844
+ cache.objects.set(data, updatedAttachments);
30845
+ }
30846
+ return attachment;
30847
+ }
30177
30848
  function normalizeContentBlocks(blocks) {
30178
30849
  const text = blocks.map((block) => typeof block.text === "string" ? block.text : void 0).filter((part) => Boolean(part)).join("");
30179
30850
  return text.length > 0 ? text : blocks;
@@ -30303,6 +30974,7 @@ var BraintrustPlugin = class extends BasePlugin {
30303
30974
  gitHubCopilotPlugin = null;
30304
30975
  fluePlugin = null;
30305
30976
  langChainPlugin = null;
30977
+ langSmithPlugin = null;
30306
30978
  piCodingAgentPlugin = null;
30307
30979
  strandsAgentSDKPlugin = null;
30308
30980
  constructor(config = {}) {
@@ -30399,6 +31071,12 @@ var BraintrustPlugin = class extends BasePlugin {
30399
31071
  this.langChainPlugin = new LangChainPlugin();
30400
31072
  this.langChainPlugin.enable();
30401
31073
  }
31074
+ if (integrations.langsmith !== false) {
31075
+ this.langSmithPlugin = new LangSmithPlugin({
31076
+ skipLangChainRuns: integrations.langchain !== false
31077
+ });
31078
+ this.langSmithPlugin.enable();
31079
+ }
30402
31080
  }
30403
31081
  onDisable() {
30404
31082
  if (this.openaiPlugin) {
@@ -30489,6 +31167,10 @@ var BraintrustPlugin = class extends BasePlugin {
30489
31167
  this.langChainPlugin.disable();
30490
31168
  this.langChainPlugin = null;
30491
31169
  }
31170
+ if (this.langSmithPlugin) {
31171
+ this.langSmithPlugin.disable();
31172
+ this.langSmithPlugin = null;
31173
+ }
30492
31174
  }
30493
31175
  };
30494
31176
 
@@ -30553,7 +31235,8 @@ var envIntegrationAliases = {
30553
31235
  langchain: "langchain",
30554
31236
  "langchain-js": "langchain",
30555
31237
  "@langchain": "langchain",
30556
- langgraph: "langgraph"
31238
+ langgraph: "langgraph",
31239
+ langsmith: "langsmith"
30557
31240
  };
30558
31241
  function getDefaultInstrumentationIntegrations() {
30559
31242
  return {
@@ -30584,6 +31267,7 @@ function getDefaultInstrumentationIntegrations() {
30584
31267
  gitHubCopilot: true,
30585
31268
  langchain: true,
30586
31269
  langgraph: true,
31270
+ langsmith: true,
30587
31271
  piCodingAgent: true,
30588
31272
  strandsAgentSDK: true
30589
31273
  };
@@ -30824,6 +31508,15 @@ function modelMetrics(attributes) {
30824
31508
  }
30825
31509
  return Object.keys(out).length > 0 ? out : void 0;
30826
31510
  }
31511
+ function timeToFirstTokenSeconds(attributes, spanStartSeconds) {
31512
+ if (!isObject(attributes)) return void 0;
31513
+ if (spanStartSeconds === void 0) return void 0;
31514
+ const raw = attributes.completionStartTime;
31515
+ const completionStart = raw instanceof Date || typeof raw === "string" || typeof raw === "number" ? epochSeconds(raw) : void 0;
31516
+ if (completionStart === void 0) return void 0;
31517
+ const ttft = completionStart - spanStartSeconds;
31518
+ return Number.isFinite(ttft) && ttft >= 0 ? ttft : void 0;
31519
+ }
30827
31520
  function buildMetadata(exported) {
30828
31521
  const out = {};
30829
31522
  if (exported.entityId !== void 0) out.entity_id = exported.entityId;
@@ -30948,8 +31641,15 @@ var BraintrustObservabilityExporter = class {
30948
31641
  event.metadata = metadata;
30949
31642
  }
30950
31643
  const metrics = modelMetrics(exported.attributes);
30951
- if (metrics) {
30952
- event.metrics = metrics;
31644
+ const ttft = timeToFirstTokenSeconds(
31645
+ exported.attributes,
31646
+ epochSeconds(exported.startTime)
31647
+ );
31648
+ if (metrics || ttft !== void 0) {
31649
+ event.metrics = {
31650
+ ...metrics ?? {},
31651
+ ...ttft !== void 0 ? { time_to_first_token: ttft } : {}
31652
+ };
30953
31653
  }
30954
31654
  if (Object.keys(event).length > 0) {
30955
31655
  record.span.log(event);
@@ -33671,8 +34371,8 @@ function makeCheckAuthorized(allowedOrgName) {
33671
34371
  return next(createError(400, "Missing x-bt-org-name header"));
33672
34372
  }
33673
34373
  if (allowedOrgName && allowedOrgName !== orgName) {
33674
- const errorMessage = `Org '${orgName}' is not allowed. Only org '${allowedOrgName}' is allowed.`;
33675
- return next(createError(403, errorMessage));
34374
+ const errorMessage2 = `Org '${orgName}' is not allowed. Only org '${allowedOrgName}' is allowed.`;
34375
+ return next(createError(403, errorMessage2));
33676
34376
  }
33677
34377
  const state = await cachedLogin({
33678
34378
  apiKey: req.ctx?.token,