braintrust 3.21.0 → 3.23.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 (54) hide show
  1. package/README.md +47 -0
  2. package/dev/dist/index.d.mts +1030 -1
  3. package/dev/dist/index.d.ts +1030 -1
  4. package/dev/dist/index.js +1429 -663
  5. package/dev/dist/index.mjs +811 -45
  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 +224 -31
  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 +3273 -93
  28. package/dist/browser.d.ts +3273 -93
  29. package/dist/browser.js +2495 -63
  30. package/dist/browser.mjs +2495 -63
  31. package/dist/{chunk-KMGUTPB7.mjs → chunk-36IPYKMG.mjs} +20 -1
  32. package/dist/{chunk-BFGIH2ZJ.js → chunk-CDIKAHDZ.js} +21 -2
  33. package/dist/{chunk-FY7DAKA5.js → chunk-FZWPFCVE.js} +1590 -832
  34. package/dist/{chunk-O2P765XK.mjs → chunk-IXL4PMY4.mjs} +802 -44
  35. package/dist/cli.js +816 -47
  36. package/dist/edge-light.d.mts +1 -1
  37. package/dist/edge-light.d.ts +1 -1
  38. package/dist/edge-light.js +2495 -63
  39. package/dist/edge-light.mjs +2495 -63
  40. package/dist/index.d.mts +3273 -93
  41. package/dist/index.d.ts +3273 -93
  42. package/dist/index.js +2078 -416
  43. package/dist/index.mjs +1664 -2
  44. package/dist/instrumentation/index.d.mts +912 -2
  45. package/dist/instrumentation/index.d.ts +912 -2
  46. package/dist/instrumentation/index.js +2202 -42
  47. package/dist/instrumentation/index.mjs +2200 -42
  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 +2495 -63
  53. package/dist/workerd.mjs +2495 -63
  54. package/package.json +5 -2
@@ -2191,19 +2191,30 @@ var CallEvent = z6.union([
2191
2191
  var ChatCompletionContentPartTextWithTitle = z6.object({
2192
2192
  text: z6.string().default(""),
2193
2193
  type: z6.literal("text"),
2194
- cache_control: z6.object({ type: z6.literal("ephemeral") }).optional()
2194
+ cache_control: z6.object({
2195
+ type: z6.literal("ephemeral"),
2196
+ ttl: z6.enum(["5m", "1h"]).optional()
2197
+ }).optional()
2195
2198
  });
2196
2199
  var ChatCompletionContentPartImageWithTitle = z6.object({
2197
2200
  image_url: z6.object({
2198
2201
  url: z6.string(),
2199
2202
  detail: z6.union([z6.literal("auto"), z6.literal("low"), z6.literal("high")]).optional()
2200
2203
  }),
2201
- type: z6.literal("image_url")
2204
+ type: z6.literal("image_url"),
2205
+ cache_control: z6.object({
2206
+ type: z6.literal("ephemeral"),
2207
+ ttl: z6.enum(["5m", "1h"]).optional()
2208
+ }).optional()
2202
2209
  });
2203
2210
  var ChatCompletionContentPartFileFile = z6.object({ file_data: z6.string(), filename: z6.string(), file_id: z6.string() }).partial();
2204
2211
  var ChatCompletionContentPartFileWithTitle = z6.object({
2205
2212
  file: ChatCompletionContentPartFileFile,
2206
- type: z6.literal("file")
2213
+ type: z6.literal("file"),
2214
+ cache_control: z6.object({
2215
+ type: z6.literal("ephemeral"),
2216
+ ttl: z6.enum(["5m", "1h"]).optional()
2217
+ }).optional()
2207
2218
  });
2208
2219
  var ChatCompletionContentPart = z6.union([
2209
2220
  ChatCompletionContentPartTextWithTitle,
@@ -2213,7 +2224,10 @@ var ChatCompletionContentPart = z6.union([
2213
2224
  var ChatCompletionContentPartText = z6.object({
2214
2225
  text: z6.string().default(""),
2215
2226
  type: z6.literal("text"),
2216
- cache_control: z6.object({ type: z6.literal("ephemeral") }).optional()
2227
+ cache_control: z6.object({
2228
+ type: z6.literal("ephemeral"),
2229
+ ttl: z6.enum(["5m", "1h"]).optional()
2230
+ }).optional()
2217
2231
  });
2218
2232
  var ChatCompletionMessageToolCall = z6.object({
2219
2233
  id: z6.string(),
@@ -4250,7 +4264,7 @@ var DiskCache = class {
4250
4264
  }
4251
4265
  };
4252
4266
 
4253
- // src/prompt-cache/lru-cache.ts
4267
+ // src/lru-cache.ts
4254
4268
  var LRUCache = class {
4255
4269
  cache;
4256
4270
  maxSize;
@@ -4266,13 +4280,23 @@ var LRUCache = class {
4266
4280
  * @returns The cached value if found, undefined otherwise.
4267
4281
  */
4268
4282
  get(key) {
4269
- const value = this.cache.get(key);
4270
- if (value === void 0) {
4283
+ const entry = this.cache.get(key);
4284
+ if (entry === void 0) {
4271
4285
  return void 0;
4272
4286
  }
4273
4287
  this.cache.delete(key);
4274
- this.cache.set(key, value);
4275
- return value;
4288
+ this.cache.set(key, entry);
4289
+ return entry.value;
4290
+ }
4291
+ /**
4292
+ * Checks whether a key exists and marks it as most recently used.
4293
+ */
4294
+ has(key) {
4295
+ if (!this.cache.has(key)) {
4296
+ return false;
4297
+ }
4298
+ this.get(key);
4299
+ return true;
4276
4300
  }
4277
4301
  /**
4278
4302
  * Stores a value in the cache.
@@ -4289,7 +4313,38 @@ var LRUCache = class {
4289
4313
  const first = this.cache.keys().next().value;
4290
4314
  this.cache.delete(first);
4291
4315
  }
4292
- this.cache.set(key, value);
4316
+ this.cache.set(key, { value });
4317
+ }
4318
+ /**
4319
+ * Removes an item from the cache.
4320
+ */
4321
+ delete(key) {
4322
+ return this.cache.delete(key);
4323
+ }
4324
+ /**
4325
+ * Iterates over cache entries from least to most recently used.
4326
+ */
4327
+ *entries() {
4328
+ for (const [key, entry] of this.cache) {
4329
+ yield [key, entry.value];
4330
+ }
4331
+ }
4332
+ /**
4333
+ * Iterates over cache keys from least to most recently used.
4334
+ */
4335
+ keys() {
4336
+ return this.cache.keys();
4337
+ }
4338
+ /**
4339
+ * Iterates over cache values from least to most recently used.
4340
+ */
4341
+ *values() {
4342
+ for (const entry of this.cache.values()) {
4343
+ yield entry.value;
4344
+ }
4345
+ }
4346
+ [Symbol.iterator]() {
4347
+ return this.entries();
4293
4348
  }
4294
4349
  /**
4295
4350
  * Removes all items from the cache.
@@ -4847,6 +4902,9 @@ function applyMaskingToField(maskingFunction, data, fieldName) {
4847
4902
  return `ERROR: Failed to mask field '${fieldName}' - ${errorType}`;
4848
4903
  }
4849
4904
  }
4905
+ var INITIAL_SPAN_WRITE_AS_MERGE = /* @__PURE__ */ Symbol(
4906
+ "braintrust.initial-span-write-as-merge"
4907
+ );
4850
4908
  var BRAINTRUST_CURRENT_SPAN_STORE = /* @__PURE__ */ Symbol.for(
4851
4909
  "braintrust.currentSpanStore"
4852
4910
  );
@@ -5448,25 +5506,46 @@ var HTTPConnection = class _HTTPConnection {
5448
5506
  })
5449
5507
  );
5450
5508
  }
5451
- async post(path, params, config) {
5509
+ async post(path, params, config, retries = 0) {
5452
5510
  const { headers, ...rest } = config || {};
5453
5511
  const this_fetch = this.fetch;
5454
5512
  const this_base_url = this.base_url;
5455
5513
  const this_headers = this.headers;
5456
- return await checkResponse(
5457
- await this_fetch(_urljoin(this_base_url, path), {
5458
- method: "POST",
5459
- headers: {
5460
- Accept: "application/json",
5461
- "Content-Type": "application/json",
5462
- ...this_headers,
5463
- ...headers
5464
- },
5465
- body: typeof params === "string" ? params : params ? JSON.stringify(params) : void 0,
5466
- keepalive: true,
5467
- ...rest
5468
- })
5469
- );
5514
+ const tries = retries + 1;
5515
+ for (let i = 0; i < tries; i++) {
5516
+ try {
5517
+ return await checkResponse(
5518
+ await this_fetch(_urljoin(this_base_url, path), {
5519
+ method: "POST",
5520
+ headers: {
5521
+ Accept: "application/json",
5522
+ "Content-Type": "application/json",
5523
+ ...this_headers,
5524
+ ...headers
5525
+ },
5526
+ body: typeof params === "string" ? params : params ? JSON.stringify(params) : void 0,
5527
+ keepalive: true,
5528
+ ...rest
5529
+ })
5530
+ );
5531
+ } catch (error) {
5532
+ if (config?.signal?.aborted) {
5533
+ throw getAbortReason(config.signal);
5534
+ }
5535
+ if (i === tries - 1 || !isRetryableHTTPError(error)) {
5536
+ throw error;
5537
+ }
5538
+ debugLogger.debug(
5539
+ `Retrying API request ${path} after ${formatHTTPError(error)}`
5540
+ );
5541
+ const sleepTimeMs = HTTP_RETRY_BASE_SLEEP_TIME_S * 1e3 * 2 ** i + Math.random() * HTTP_RETRY_JITTER_MS;
5542
+ debugLogger.info(
5543
+ `Sleeping for ${sleepTimeMs}ms before retrying API request`
5544
+ );
5545
+ await waitForRetry(sleepTimeMs, config?.signal);
5546
+ }
5547
+ }
5548
+ throw new Error("Unexpected retry state");
5470
5549
  }
5471
5550
  async get_json(object_type, args = void 0, retries = 0) {
5472
5551
  const tries = retries + 1;
@@ -6563,6 +6642,45 @@ var TestBackgroundLogger = class {
6563
6642
  };
6564
6643
  var BACKGROUND_LOGGER_BASE_SLEEP_TIME_S = 1;
6565
6644
  var HTTP_RETRY_BASE_SLEEP_TIME_S = 1;
6645
+ var HTTP_RETRY_JITTER_MS = 200;
6646
+ var BTQL_HTTP_RETRIES = 3;
6647
+ var RETRYABLE_HTTP_STATUS_CODES = /* @__PURE__ */ new Set([500, 502, 503, 504]);
6648
+ function isRetryableHTTPError(error) {
6649
+ return !(error instanceof FailedHTTPResponse) || RETRYABLE_HTTP_STATUS_CODES.has(error.status);
6650
+ }
6651
+ function formatHTTPError(error) {
6652
+ if (error instanceof FailedHTTPResponse) {
6653
+ return `${error.status} ${error.text}`;
6654
+ }
6655
+ return error instanceof Error ? error.message : String(error);
6656
+ }
6657
+ function getAbortReason(signal) {
6658
+ return signal.reason ?? new Error("Request aborted");
6659
+ }
6660
+ async function waitForRetry(delayMs, signal) {
6661
+ if (!signal) {
6662
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
6663
+ return;
6664
+ }
6665
+ if (signal.aborted) {
6666
+ throw getAbortReason(signal);
6667
+ }
6668
+ await new Promise((resolve, reject2) => {
6669
+ const onAbort = () => {
6670
+ clearTimeout(timeout);
6671
+ signal.removeEventListener("abort", onAbort);
6672
+ reject2(getAbortReason(signal));
6673
+ };
6674
+ const timeout = setTimeout(() => {
6675
+ signal.removeEventListener("abort", onAbort);
6676
+ resolve();
6677
+ }, delayMs);
6678
+ signal.addEventListener("abort", onAbort, { once: true });
6679
+ if (signal.aborted) {
6680
+ onAbort();
6681
+ }
6682
+ });
6683
+ }
6566
6684
  var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
6567
6685
  apiConn;
6568
6686
  queue;
@@ -8301,15 +8419,15 @@ function parentSpanIdsUsable(spanId, rootSpanId) {
8301
8419
  return Boolean(spanId) && Boolean(rootSpanId);
8302
8420
  }
8303
8421
  function logError(span, error) {
8304
- let errorMessage = "<error>";
8422
+ let errorMessage2 = "<error>";
8305
8423
  let stackTrace = "";
8306
8424
  if (error instanceof Error) {
8307
- errorMessage = error.message;
8425
+ errorMessage2 = error.message;
8308
8426
  stackTrace = error.stack || "";
8309
8427
  } else {
8310
- errorMessage = String(error);
8428
+ errorMessage2 = String(error);
8311
8429
  }
8312
- span.log({ error: `${errorMessage}
8430
+ span.log({ error: `${errorMessage2}
8313
8431
 
8314
8432
  ${stackTrace}` });
8315
8433
  }
@@ -8497,6 +8615,12 @@ var traceable = wrapTraced;
8497
8615
  function startSpan(args) {
8498
8616
  return startSpanAndIsLogger(args).span;
8499
8617
  }
8618
+ function _internalStartSpanWithInitialMerge(args) {
8619
+ return startSpanAndIsLogger({
8620
+ ...args,
8621
+ [INITIAL_SPAN_WRITE_AS_MERGE]: true
8622
+ }).span;
8623
+ }
8500
8624
  async function flush(options) {
8501
8625
  const state = options?.state ?? _globalState;
8502
8626
  return await state.bgLogger().flush();
@@ -8890,7 +9014,8 @@ var ObjectFetcher = class {
8890
9014
  version: this.pinnedVersion
8891
9015
  } : {}
8892
9016
  },
8893
- { headers: { "Accept-Encoding": "gzip" } }
9017
+ { headers: { "Accept-Encoding": "gzip" } },
9018
+ BTQL_HTTP_RETRIES
8894
9019
  );
8895
9020
  const respJson = await resp.json();
8896
9021
  const mutate = this.mutateRecord;
@@ -9407,7 +9532,7 @@ var SpanImpl = class _SpanImpl {
9407
9532
  this._spanId = resolvedIds.spanId;
9408
9533
  this._rootSpanId = resolvedIds.rootSpanId;
9409
9534
  this._spanParents = resolvedIds.spanParents;
9410
- this.isMerge = false;
9535
+ this.isMerge = args[INITIAL_SPAN_WRITE_AS_MERGE] === true;
9411
9536
  this.logInternal({ event, internalData });
9412
9537
  this.isMerge = true;
9413
9538
  }
@@ -10614,7 +10739,8 @@ async function getPromptVersions(projectId, promptId) {
10614
10739
  use_columnstore: false,
10615
10740
  brainstore_realtime: true
10616
10741
  },
10617
- { headers: { "Accept-Encoding": "gzip" } }
10742
+ { headers: { "Accept-Encoding": "gzip" } },
10743
+ BTQL_HTTP_RETRIES
10618
10744
  );
10619
10745
  if (!response.ok) {
10620
10746
  throw new Error(
@@ -29198,6 +29324,446 @@ function isBraintrustHandler(handler) {
29198
29324
  return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
29199
29325
  }
29200
29326
 
29327
+ // src/instrumentation/plugins/langsmith-channels.ts
29328
+ var langSmithChannels = defineChannels("langsmith", {
29329
+ createRun: channel({
29330
+ channelName: "Client.createRun",
29331
+ kind: "async"
29332
+ }),
29333
+ updateRun: channel({
29334
+ channelName: "Client.updateRun",
29335
+ kind: "async"
29336
+ }),
29337
+ batchIngestRuns: channel({
29338
+ channelName: "Client.batchIngestRuns",
29339
+ kind: "async"
29340
+ })
29341
+ });
29342
+
29343
+ // src/instrumentation/plugins/langsmith-plugin.ts
29344
+ var MAX_COMPLETED_RUNS = 1e4;
29345
+ var BLOCKED_METADATA_KEYS = /* @__PURE__ */ new Set([
29346
+ "__proto__",
29347
+ "constructor",
29348
+ "prototype",
29349
+ "usage_metadata"
29350
+ ]);
29351
+ var BLOCKED_METADATA_PREFIXES = ["__pregel_", "langgraph_", "lc_"];
29352
+ var LLM_SETTING_KEYS = [
29353
+ "temperature",
29354
+ "top_p",
29355
+ "max_tokens",
29356
+ "frequency_penalty",
29357
+ "presence_penalty",
29358
+ "stop",
29359
+ "response_format"
29360
+ ];
29361
+ var LangSmithPlugin = class extends BasePlugin {
29362
+ activeRuns = /* @__PURE__ */ new Map();
29363
+ completedRuns = new LRUCache({
29364
+ max: MAX_COMPLETED_RUNS
29365
+ });
29366
+ skipLangChainRuns;
29367
+ constructor(options = {}) {
29368
+ super();
29369
+ this.skipLangChainRuns = options.skipLangChainRuns ?? true;
29370
+ }
29371
+ onEnable() {
29372
+ const createChannel = langSmithChannels.createRun.tracingChannel();
29373
+ const createHandlers = {
29374
+ start: (event) => {
29375
+ this.containLifecycleFailure("createRun", () => {
29376
+ this.processCreate(event.arguments[0]);
29377
+ });
29378
+ }
29379
+ };
29380
+ createChannel.subscribe(createHandlers);
29381
+ this.unsubscribers.push(() => createChannel.unsubscribe(createHandlers));
29382
+ const updateChannel = langSmithChannels.updateRun.tracingChannel();
29383
+ const updateHandlers = {
29384
+ start: (event) => {
29385
+ this.containLifecycleFailure("updateRun", () => {
29386
+ this.processUpdate(event.arguments[0], event.arguments[1]);
29387
+ });
29388
+ }
29389
+ };
29390
+ updateChannel.subscribe(updateHandlers);
29391
+ this.unsubscribers.push(() => updateChannel.unsubscribe(updateHandlers));
29392
+ const batchChannel = langSmithChannels.batchIngestRuns.tracingChannel();
29393
+ const batchHandlers = {
29394
+ start: (event) => {
29395
+ this.containLifecycleFailure("batchIngestRuns", () => {
29396
+ this.processBatch(event.arguments[0]);
29397
+ });
29398
+ }
29399
+ };
29400
+ batchChannel.subscribe(batchHandlers);
29401
+ this.unsubscribers.push(() => batchChannel.unsubscribe(batchHandlers));
29402
+ }
29403
+ onDisable() {
29404
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
29405
+ for (const { span } of this.activeRuns.values()) {
29406
+ span.end();
29407
+ }
29408
+ this.activeRuns.clear();
29409
+ this.completedRuns.clear();
29410
+ }
29411
+ processBatch(batch) {
29412
+ if (!isRecord2(batch)) {
29413
+ return;
29414
+ }
29415
+ const creates = ownValue(batch, "runCreates");
29416
+ if (Array.isArray(creates)) {
29417
+ const parentFirst = [...creates].sort((left, right) => {
29418
+ const leftId = stringValue2(ownValue(left, "id"));
29419
+ const rightId = stringValue2(ownValue(right, "id"));
29420
+ const leftParent = stringValue2(ownValue(left, "parent_run_id"));
29421
+ const rightParent = stringValue2(ownValue(right, "parent_run_id"));
29422
+ if (leftParent && leftParent === rightId) {
29423
+ return 1;
29424
+ }
29425
+ if (rightParent && rightParent === leftId) {
29426
+ return -1;
29427
+ }
29428
+ return dottedOrderDepth(left) - dottedOrderDepth(right);
29429
+ });
29430
+ for (const run of parentFirst) {
29431
+ this.containLifecycleFailure("batchIngestRuns create", () => {
29432
+ this.processCreate(run);
29433
+ });
29434
+ }
29435
+ }
29436
+ const updates = ownValue(batch, "runUpdates");
29437
+ if (Array.isArray(updates)) {
29438
+ for (const run of updates) {
29439
+ this.containLifecycleFailure("batchIngestRuns update", () => {
29440
+ this.processUpdate(stringValue2(ownValue(run, "id")) ?? "", run);
29441
+ });
29442
+ }
29443
+ }
29444
+ }
29445
+ processCreate(run) {
29446
+ const id = stringValue2(ownValue(run, "id"));
29447
+ if (!id || this.completedRuns.get(id)) {
29448
+ return;
29449
+ }
29450
+ if (this.shouldSkipLangChainRun(run)) {
29451
+ this.completedRuns.set(id, true);
29452
+ return;
29453
+ }
29454
+ const active = this.activeRuns.get(id);
29455
+ if (active) {
29456
+ const previous = active.run;
29457
+ active.run = mergeRuns(previous, run);
29458
+ this.logRun(
29459
+ active.span,
29460
+ active.run,
29461
+ previous,
29462
+ timestampSeconds(ownValue(active.run, "end_time")) !== void 0 || errorMessage(ownValue(active.run, "error")) !== void 0
29463
+ );
29464
+ this.endIfComplete(id, active, active.run);
29465
+ return;
29466
+ }
29467
+ const span = this.startRunSpan(id, run);
29468
+ const activeRun = { run, span };
29469
+ this.activeRuns.set(id, activeRun);
29470
+ this.logRun(
29471
+ span,
29472
+ run,
29473
+ void 0,
29474
+ timestampSeconds(ownValue(run, "end_time")) !== void 0 || errorMessage(ownValue(run, "error")) !== void 0
29475
+ );
29476
+ this.endIfComplete(id, activeRun, run);
29477
+ }
29478
+ processUpdate(explicitId, run) {
29479
+ const id = stringValue2(explicitId) ?? stringValue2(ownValue(run, "id"));
29480
+ if (!id || this.completedRuns.get(id)) {
29481
+ return;
29482
+ }
29483
+ if (this.shouldSkipLangChainRun(run)) {
29484
+ const active2 = this.activeRuns.get(id);
29485
+ active2?.span.end();
29486
+ this.activeRuns.delete(id);
29487
+ this.completedRuns.set(id, true);
29488
+ return;
29489
+ }
29490
+ let active = this.activeRuns.get(id);
29491
+ if (!active) {
29492
+ const span = this.startRunSpan(id, run);
29493
+ active = { run, span };
29494
+ this.activeRuns.set(id, active);
29495
+ }
29496
+ const previous = active.run;
29497
+ active.run = mergeRuns(previous, run);
29498
+ this.logRun(active.span, active.run, previous, true);
29499
+ this.endIfComplete(id, active, active.run);
29500
+ }
29501
+ startRunSpan(id, run) {
29502
+ const traceId = stringValue2(ownValue(run, "trace_id")) ?? id;
29503
+ const parentId = stringValue2(ownValue(run, "parent_run_id")) ?? stringValue2(ownValue(ownValue(run, "parent_run"), "id"));
29504
+ const startTime = timestampSeconds(ownValue(run, "start_time"));
29505
+ return startSpan({
29506
+ name: stringValue2(ownValue(run, "name")) ?? "LangSmith run",
29507
+ spanId: id,
29508
+ parentSpanIds: {
29509
+ parentSpanIds: parentId ? [parentId] : [],
29510
+ rootSpanId: traceId
29511
+ },
29512
+ spanAttributes: {
29513
+ type: mapRunType(ownValue(run, "run_type"))
29514
+ },
29515
+ ...startTime === void 0 ? {} : { startTime },
29516
+ event: { id }
29517
+ });
29518
+ }
29519
+ logRun(span, run, previous, includeOutput) {
29520
+ const inputs = preferOwnValue(run, previous, "inputs");
29521
+ const outputs = preferOwnValue(run, previous, "outputs");
29522
+ const error = errorMessage(preferOwnValue(run, previous, "error"));
29523
+ const metadata = extractMetadata(run, previous);
29524
+ const tags = extractTags(preferOwnValue(run, previous, "tags"));
29525
+ const metrics = extractMetrics(run, previous);
29526
+ span.log({
29527
+ ...inputs === void 0 ? {} : { input: sanitizeLoggedValue(inputs) },
29528
+ ...includeOutput && outputs !== void 0 ? { output: sanitizeLoggedValue(outputs) } : {},
29529
+ ...error === void 0 ? {} : { error },
29530
+ ...metadata === void 0 ? {} : { metadata },
29531
+ ...tags === void 0 ? {} : { tags },
29532
+ ...Object.keys(metrics).length === 0 ? {} : { metrics }
29533
+ });
29534
+ }
29535
+ endIfComplete(id, active, run) {
29536
+ const endTime = timestampSeconds(ownValue(run, "end_time"));
29537
+ if (endTime === void 0 && errorMessage(ownValue(run, "error")) === void 0) {
29538
+ return;
29539
+ }
29540
+ active.span.end(endTime === void 0 ? void 0 : { endTime });
29541
+ this.activeRuns.delete(id);
29542
+ this.completedRuns.set(id, true);
29543
+ }
29544
+ shouldSkipLangChainRun(run) {
29545
+ if (!this.skipLangChainRuns) {
29546
+ return false;
29547
+ }
29548
+ const serialized = ownValue(run, "serialized");
29549
+ return isRecord2(serialized) && ownValue(serialized, "lc") === 1;
29550
+ }
29551
+ containLifecycleFailure(operation, fn) {
29552
+ try {
29553
+ fn();
29554
+ } catch (error) {
29555
+ debugLogger.error(
29556
+ `Failed to process LangSmith ${operation} instrumentation:`,
29557
+ error
29558
+ );
29559
+ }
29560
+ }
29561
+ };
29562
+ function ownValue(value, key) {
29563
+ if (!isRecord2(value)) {
29564
+ return void 0;
29565
+ }
29566
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
29567
+ return descriptor && "value" in descriptor ? descriptor.value : void 0;
29568
+ }
29569
+ function preferOwnValue(current, previous, key) {
29570
+ const currentDescriptor = isRecord2(current) ? Object.getOwnPropertyDescriptor(current, key) : void 0;
29571
+ if (currentDescriptor && "value" in currentDescriptor) {
29572
+ return currentDescriptor.value;
29573
+ }
29574
+ return ownValue(previous, key);
29575
+ }
29576
+ function mergeRuns(previous, current) {
29577
+ const entries = /* @__PURE__ */ new Map();
29578
+ for (const value of [previous, current]) {
29579
+ if (!isRecord2(value)) {
29580
+ continue;
29581
+ }
29582
+ for (const [key, descriptor] of Object.entries(
29583
+ Object.getOwnPropertyDescriptors(value)
29584
+ )) {
29585
+ if (descriptor.enumerable && "value" in descriptor) {
29586
+ entries.set(key, descriptor.value);
29587
+ }
29588
+ }
29589
+ }
29590
+ return Object.fromEntries(entries);
29591
+ }
29592
+ function isRecord2(value) {
29593
+ return typeof value === "object" && value !== null && !Array.isArray(value);
29594
+ }
29595
+ function stringValue2(value) {
29596
+ return typeof value === "string" && value.length > 0 ? value : void 0;
29597
+ }
29598
+ function timestampSeconds(value) {
29599
+ if (value instanceof Date) {
29600
+ const timestamp = value.getTime();
29601
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
29602
+ }
29603
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
29604
+ return value > 1e10 ? value / 1e3 : value;
29605
+ }
29606
+ if (typeof value === "string") {
29607
+ const timestamp = Date.parse(value);
29608
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
29609
+ }
29610
+ return void 0;
29611
+ }
29612
+ function dottedOrderDepth(run) {
29613
+ const dottedOrder = stringValue2(ownValue(run, "dotted_order"));
29614
+ return dottedOrder ? dottedOrder.split(".").length : Number.MAX_SAFE_INTEGER;
29615
+ }
29616
+ function mapRunType(runType) {
29617
+ switch (runType) {
29618
+ case "llm":
29619
+ case "embedding":
29620
+ return "llm" /* LLM */;
29621
+ case "tool":
29622
+ case "retriever":
29623
+ return "tool" /* TOOL */;
29624
+ default:
29625
+ return "task" /* TASK */;
29626
+ }
29627
+ }
29628
+ function extractMetadata(run, previous) {
29629
+ const extra = preferOwnValue(run, previous, "extra");
29630
+ const rawMetadata = ownValue(extra, "metadata");
29631
+ if (!isRecord2(rawMetadata)) {
29632
+ return void 0;
29633
+ }
29634
+ const metadata = {};
29635
+ for (const [key, descriptor] of Object.entries(
29636
+ Object.getOwnPropertyDescriptors(rawMetadata)
29637
+ )) {
29638
+ 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}`)) {
29639
+ continue;
29640
+ }
29641
+ const normalizedKey = key === "ls_provider" ? "provider" : key === "ls_model_name" ? "model" : key.startsWith("ls_") ? key.slice(3) : key;
29642
+ const sanitized = sanitizeLoggedValue(descriptor.value);
29643
+ if (sanitized !== void 0) {
29644
+ metadata[normalizedKey] = sanitized;
29645
+ }
29646
+ }
29647
+ return Object.keys(metadata).length === 0 ? void 0 : metadata;
29648
+ }
29649
+ function extractTags(value) {
29650
+ if (!Array.isArray(value)) {
29651
+ return void 0;
29652
+ }
29653
+ const tags = value.filter(
29654
+ (tag) => typeof tag === "string" && tag.length > 0
29655
+ );
29656
+ return tags.length > 0 ? tags : void 0;
29657
+ }
29658
+ function extractMetrics(run, previous) {
29659
+ const outputs = preferOwnValue(run, previous, "outputs");
29660
+ const extra = preferOwnValue(run, previous, "extra");
29661
+ const metadata = ownValue(extra, "metadata");
29662
+ const usage = ownValue(outputs, "usage_metadata") ?? ownValue(metadata, "usage_metadata");
29663
+ const metrics = {};
29664
+ assignFirstMetric(metrics, "prompt_tokens", usage, [
29665
+ "input_tokens",
29666
+ "prompt_tokens"
29667
+ ]);
29668
+ assignFirstMetric(metrics, "completion_tokens", usage, [
29669
+ "output_tokens",
29670
+ "completion_tokens"
29671
+ ]);
29672
+ assignFirstMetric(metrics, "tokens", usage, ["total_tokens", "tokens"]);
29673
+ const inputTokenDetails = ownValue(usage, "input_token_details");
29674
+ assignFirstMetric(metrics, "prompt_cached_tokens", inputTokenDetails, [
29675
+ "cache_read",
29676
+ "cached_tokens"
29677
+ ]);
29678
+ if (metrics.prompt_cached_tokens === void 0) {
29679
+ assignFirstMetric(metrics, "prompt_cached_tokens", usage, [
29680
+ "cache_read_input_tokens",
29681
+ "prompt_cached_tokens"
29682
+ ]);
29683
+ }
29684
+ assignFirstMetric(
29685
+ metrics,
29686
+ "prompt_cache_creation_tokens",
29687
+ inputTokenDetails,
29688
+ ["cache_creation"]
29689
+ );
29690
+ if (metrics.prompt_cache_creation_tokens === void 0) {
29691
+ assignFirstMetric(metrics, "prompt_cache_creation_tokens", usage, [
29692
+ "cache_creation_input_tokens",
29693
+ "prompt_cache_creation_tokens"
29694
+ ]);
29695
+ }
29696
+ if (metrics.tokens === void 0 && (metrics.prompt_tokens !== void 0 || metrics.completion_tokens !== void 0)) {
29697
+ metrics.tokens = (metrics.prompt_tokens ?? 0) + (metrics.completion_tokens ?? 0);
29698
+ }
29699
+ const startTime = timestampSeconds(
29700
+ preferOwnValue(run, previous, "start_time")
29701
+ );
29702
+ const events = preferOwnValue(run, previous, "events");
29703
+ if (startTime !== void 0 && Array.isArray(events)) {
29704
+ for (const event of events) {
29705
+ if (ownValue(event, "name") !== "new_token") {
29706
+ continue;
29707
+ }
29708
+ const eventTime3 = timestampSeconds(ownValue(event, "time"));
29709
+ if (eventTime3 !== void 0 && eventTime3 >= startTime) {
29710
+ metrics.time_to_first_token = eventTime3 - startTime;
29711
+ }
29712
+ break;
29713
+ }
29714
+ }
29715
+ return metrics;
29716
+ }
29717
+ function assignFirstMetric(metrics, target, source, keys) {
29718
+ for (const key of keys) {
29719
+ const value = ownValue(source, key);
29720
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
29721
+ metrics[target] = value;
29722
+ return;
29723
+ }
29724
+ }
29725
+ }
29726
+ function errorMessage(value) {
29727
+ if (typeof value === "string") {
29728
+ return value;
29729
+ }
29730
+ if (value instanceof Error) {
29731
+ return value.message;
29732
+ }
29733
+ return void 0;
29734
+ }
29735
+ function sanitizeLoggedValue(value, seen = /* @__PURE__ */ new WeakSet(), depth = 0) {
29736
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
29737
+ return value;
29738
+ }
29739
+ if (typeof value === "number") {
29740
+ return Number.isFinite(value) ? value : void 0;
29741
+ }
29742
+ if (value instanceof Date) {
29743
+ return Number.isFinite(value.getTime()) ? value.toISOString() : void 0;
29744
+ }
29745
+ if (typeof value !== "object" || depth >= 20) {
29746
+ return void 0;
29747
+ }
29748
+ if (seen.has(value)) {
29749
+ return "[Circular]";
29750
+ }
29751
+ seen.add(value);
29752
+ if (Array.isArray(value)) {
29753
+ return value.map((item) => sanitizeLoggedValue(item, seen, depth + 1));
29754
+ }
29755
+ const entries = [];
29756
+ for (const [key, descriptor] of Object.entries(
29757
+ Object.getOwnPropertyDescriptors(value)
29758
+ )) {
29759
+ if (!descriptor.enumerable || !("value" in descriptor) || BLOCKED_METADATA_KEYS.has(key)) {
29760
+ continue;
29761
+ }
29762
+ entries.push([key, sanitizeLoggedValue(descriptor.value, seen, depth + 1)]);
29763
+ }
29764
+ return Object.fromEntries(entries);
29765
+ }
29766
+
29201
29767
  // src/instrumentation/plugins/pi-coding-agent-channels.ts
29202
29768
  var piCodingAgentChannels = defineChannels(
29203
29769
  "@earendil-works/pi-coding-agent",
@@ -29577,11 +30143,11 @@ function patchAssistantMessageStream(stream, promptState, llmState) {
29577
30143
  function recordPiAssistantMessageEvent(promptState, llmState, event) {
29578
30144
  recordFirstTokenMetric(llmState, event);
29579
30145
  const message = "message" in event ? event.message : void 0;
29580
- const errorMessage = "error" in event ? event.error : void 0;
30146
+ const errorMessage2 = "error" in event ? event.error : void 0;
29581
30147
  if (event.type === "done" && isPiAssistantMessage(message)) {
29582
30148
  finishPiLlmSpan(promptState, llmState, message);
29583
- } else if (event.type === "error" && isPiAssistantMessage(errorMessage)) {
29584
- finishPiLlmSpan(promptState, llmState, errorMessage);
30149
+ } else if (event.type === "error" && isPiAssistantMessage(errorMessage2)) {
30150
+ finishPiLlmSpan(promptState, llmState, errorMessage2);
29585
30151
  }
29586
30152
  }
29587
30153
  function recordFirstTokenMetric(state, event) {
@@ -30099,6 +30665,7 @@ var strandsAgentSDKChannels = defineChannels("@strands-agents/sdk", {
30099
30665
  });
30100
30666
 
30101
30667
  // src/instrumentation/plugins/strands-agent-sdk-plugin.ts
30668
+ var MAX_STRANDS_STRING_ATTACHMENT_CACHE_ENTRIES = 32;
30102
30669
  var StrandsAgentSDKPlugin = class extends BasePlugin {
30103
30670
  activeChildParents = /* @__PURE__ */ new WeakMap();
30104
30671
  onEnable() {
@@ -30243,11 +30810,16 @@ function startAgentStream(event, activeChildParents) {
30243
30810
  ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
30244
30811
  };
30245
30812
  const parentSpan = agent ? getOnlyChildParent(activeChildParents, agent) : void 0;
30813
+ const attachmentCache = createStrandsAttachmentCache();
30814
+ const input = processStrandsInputAttachments(
30815
+ event.arguments[0],
30816
+ attachmentCache
30817
+ );
30246
30818
  const span = parentSpan ? withCurrent(
30247
30819
  parentSpan,
30248
30820
  () => startSpan({
30249
30821
  event: {
30250
- input: event.arguments[0],
30822
+ input,
30251
30823
  metadata
30252
30824
  },
30253
30825
  name: formatAgentSpanName(agent),
@@ -30255,7 +30827,7 @@ function startAgentStream(event, activeChildParents) {
30255
30827
  })
30256
30828
  ) : startSpan({
30257
30829
  event: {
30258
- input: event.arguments[0],
30830
+ input,
30259
30831
  metadata
30260
30832
  },
30261
30833
  name: formatAgentSpanName(agent),
@@ -30263,6 +30835,7 @@ function startAgentStream(event, activeChildParents) {
30263
30835
  });
30264
30836
  return {
30265
30837
  activeTools: /* @__PURE__ */ new Map(),
30838
+ attachmentCache,
30266
30839
  finalized: false,
30267
30840
  metadata,
30268
30841
  span,
@@ -30278,11 +30851,12 @@ function startMultiAgentStream(event, operation, activeChildParents) {
30278
30851
  ...event.moduleVersion ? { "strands_agent_sdk.version": event.moduleVersion } : {}
30279
30852
  };
30280
30853
  const parentSpan = orchestrator ? getOnlyChildParent(activeChildParents, orchestrator) : void 0;
30854
+ const input = processStrandsInputAttachments(event.arguments[0]);
30281
30855
  const span = parentSpan ? withCurrent(
30282
30856
  parentSpan,
30283
30857
  () => startSpan({
30284
30858
  event: {
30285
- input: event.arguments[0],
30859
+ input,
30286
30860
  metadata
30287
30861
  },
30288
30862
  name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
@@ -30290,7 +30864,7 @@ function startMultiAgentStream(event, operation, activeChildParents) {
30290
30864
  })
30291
30865
  ) : startSpan({
30292
30866
  event: {
30293
- input: event.arguments[0],
30867
+ input,
30294
30868
  metadata
30295
30869
  },
30296
30870
  name: operation === "Graph.stream" ? "Strands Graph" : "Strands Swarm",
@@ -30399,7 +30973,10 @@ function startModelSpan(state, event) {
30399
30973
  state.span,
30400
30974
  () => startSpan({
30401
30975
  event: {
30402
- input: Array.isArray(event.agent?.messages) ? event.agent.messages : void 0,
30976
+ input: Array.isArray(event.agent?.messages) ? processStrandsInputAttachments(
30977
+ event.agent.messages,
30978
+ state.attachmentCache
30979
+ ) : void 0,
30403
30980
  metadata
30404
30981
  },
30405
30982
  name: formatModelSpanName(model),
@@ -30613,6 +31190,7 @@ function finalizeAgentStream(state, error, output) {
30613
31190
  ...output !== void 0 ? { output } : {}
30614
31191
  });
30615
31192
  state.span.end();
31193
+ state.attachmentCache.strings.clear();
30616
31194
  }
30617
31195
  function finalizeMultiAgentStream(state, activeChildParents, error, output) {
30618
31196
  if (state.finalized) {
@@ -30759,6 +31337,166 @@ function extractNodeResultOutput(result) {
30759
31337
  }
30760
31338
  return result;
30761
31339
  }
31340
+ var STRANDS_MEDIA_TYPES = {
31341
+ png: "image/png",
31342
+ jpg: "image/jpeg",
31343
+ jpeg: "image/jpeg",
31344
+ gif: "image/gif",
31345
+ webp: "image/webp",
31346
+ mkv: "video/x-matroska",
31347
+ mov: "video/quicktime",
31348
+ mp4: "video/mp4",
31349
+ webm: "video/webm",
31350
+ flv: "video/x-flv",
31351
+ mpeg: "video/mpeg",
31352
+ mpg: "video/mpeg",
31353
+ wmv: "video/x-ms-wmv",
31354
+ "3gp": "video/3gpp",
31355
+ pdf: "application/pdf",
31356
+ csv: "text/csv",
31357
+ doc: "application/msword",
31358
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
31359
+ xls: "application/vnd.ms-excel",
31360
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
31361
+ html: "text/html",
31362
+ txt: "text/plain",
31363
+ md: "text/markdown",
31364
+ json: "application/json",
31365
+ xml: "application/xml"
31366
+ };
31367
+ function createStrandsAttachmentCache() {
31368
+ return {
31369
+ objects: /* @__PURE__ */ new WeakMap(),
31370
+ strings: new LRUCache({
31371
+ max: MAX_STRANDS_STRING_ATTACHMENT_CACHE_ENTRIES
31372
+ })
31373
+ };
31374
+ }
31375
+ function processStrandsInputAttachments(input, cache = createStrandsAttachmentCache()) {
31376
+ try {
31377
+ return processStrandsInputNode(input, cache);
31378
+ } catch (error) {
31379
+ logInstrumentationError5("Strands Agent SDK input attachments", error);
31380
+ return input;
31381
+ }
31382
+ }
31383
+ function processStrandsInputNode(value, cache) {
31384
+ if (value instanceof BaseAttachment) {
31385
+ return value;
31386
+ }
31387
+ if (Array.isArray(value)) {
31388
+ return value.map((child) => processStrandsInputNode(child, cache));
31389
+ }
31390
+ if (!isObject(value)) {
31391
+ return value;
31392
+ }
31393
+ const directMedia = processDirectStrandsMediaBlock(value, cache);
31394
+ if (directMedia !== void 0) {
31395
+ return directMedia;
31396
+ }
31397
+ const wrappedMedia = processWrappedStrandsMediaBlock(value, cache);
31398
+ if (wrappedMedia !== void 0) {
31399
+ return wrappedMedia;
31400
+ }
31401
+ if (value.type === "message" && Array.isArray(value.content)) {
31402
+ return {
31403
+ role: value.role,
31404
+ content: value.content.map(
31405
+ (child) => processStrandsInputNode(child, cache)
31406
+ ),
31407
+ ...value.metadata !== void 0 ? { metadata: value.metadata } : {}
31408
+ };
31409
+ }
31410
+ if (typeof value.toJSON === "function") {
31411
+ return processStrandsInputNode(value.toJSON(), cache);
31412
+ }
31413
+ return Object.fromEntries(
31414
+ Object.entries(value).map(([key, child]) => [
31415
+ key,
31416
+ processStrandsInputNode(child, cache)
31417
+ ])
31418
+ );
31419
+ }
31420
+ function processDirectStrandsMediaBlock(block, cache) {
31421
+ if (!isStrandsMediaBlock(block)) {
31422
+ return void 0;
31423
+ }
31424
+ const mediaKey = block.type === "imageBlock" ? "image" : block.type === "videoBlock" ? "video" : "document";
31425
+ return createStrandsMediaAttachment(mediaKey, block, cache);
31426
+ }
31427
+ function isStrandsMediaBlock(block) {
31428
+ return (block.type === "imageBlock" || block.type === "videoBlock" || block.type === "documentBlock") && typeof block.format === "string" && isObject(block.source);
31429
+ }
31430
+ function processWrappedStrandsMediaBlock(block, cache) {
31431
+ for (const mediaKey of ["image", "video", "document"]) {
31432
+ const media = block[mediaKey];
31433
+ if (!Object.hasOwn(block, mediaKey) || !isObject(media)) {
31434
+ continue;
31435
+ }
31436
+ const processed = createStrandsMediaAttachment(mediaKey, media, cache);
31437
+ if (processed !== void 0) {
31438
+ return processed;
31439
+ }
31440
+ }
31441
+ return void 0;
31442
+ }
31443
+ function createStrandsMediaAttachment(mediaKey, media, cache) {
31444
+ const format = media.format;
31445
+ const source = media.source;
31446
+ if (typeof format !== "string" || !isObject(source) || !Object.hasOwn(source, "bytes")) {
31447
+ return void 0;
31448
+ }
31449
+ const contentType = STRANDS_MEDIA_TYPES[format.toLowerCase()];
31450
+ if (!contentType) {
31451
+ return void 0;
31452
+ }
31453
+ const filename = mediaKey === "document" && typeof media.name === "string" && media.name.length > 0 ? media.name : `${mediaKey}.${format.toLowerCase()}`;
31454
+ const attachment = getOrCreateStrandsAttachment(
31455
+ source.bytes,
31456
+ filename,
31457
+ contentType,
31458
+ cache
31459
+ );
31460
+ if (!attachment) {
31461
+ return void 0;
31462
+ }
31463
+ const { type: _type, ...serializedMedia } = media;
31464
+ const { type: _sourceType, ...serializedSource } = source;
31465
+ return {
31466
+ [mediaKey]: {
31467
+ ...serializedMedia,
31468
+ source: {
31469
+ ...serializedSource,
31470
+ bytes: attachment
31471
+ }
31472
+ }
31473
+ };
31474
+ }
31475
+ function getOrCreateStrandsAttachment(data, filename, contentType, cache) {
31476
+ const key = `${contentType}\0${filename}`;
31477
+ const attachments = typeof data === "string" ? cache.strings.get(data) : isObject(data) ? cache.objects.get(data) : void 0;
31478
+ const cached = attachments?.get(key);
31479
+ if (cached) {
31480
+ return cached;
31481
+ }
31482
+ const blob = convertDataToBlob(data, contentType);
31483
+ if (!blob) {
31484
+ return void 0;
31485
+ }
31486
+ const attachment = new Attachment({
31487
+ data: blob,
31488
+ filename,
31489
+ contentType
31490
+ });
31491
+ const updatedAttachments = attachments ?? /* @__PURE__ */ new Map();
31492
+ updatedAttachments.set(key, attachment);
31493
+ if (typeof data === "string") {
31494
+ cache.strings.set(data, updatedAttachments);
31495
+ } else if (isObject(data)) {
31496
+ cache.objects.set(data, updatedAttachments);
31497
+ }
31498
+ return attachment;
31499
+ }
30762
31500
  function normalizeContentBlocks(blocks) {
30763
31501
  const text = blocks.map((block) => typeof block.text === "string" ? block.text : void 0).filter((part) => Boolean(part)).join("");
30764
31502
  return text.length > 0 ? text : blocks;
@@ -30888,6 +31626,7 @@ var BraintrustPlugin = class extends BasePlugin {
30888
31626
  gitHubCopilotPlugin = null;
30889
31627
  fluePlugin = null;
30890
31628
  langChainPlugin = null;
31629
+ langSmithPlugin = null;
30891
31630
  piCodingAgentPlugin = null;
30892
31631
  strandsAgentSDKPlugin = null;
30893
31632
  constructor(config = {}) {
@@ -30984,6 +31723,12 @@ var BraintrustPlugin = class extends BasePlugin {
30984
31723
  this.langChainPlugin = new LangChainPlugin();
30985
31724
  this.langChainPlugin.enable();
30986
31725
  }
31726
+ if (integrations.langsmith !== false) {
31727
+ this.langSmithPlugin = new LangSmithPlugin({
31728
+ skipLangChainRuns: integrations.langchain !== false
31729
+ });
31730
+ this.langSmithPlugin.enable();
31731
+ }
30987
31732
  }
30988
31733
  onDisable() {
30989
31734
  if (this.openaiPlugin) {
@@ -31074,6 +31819,10 @@ var BraintrustPlugin = class extends BasePlugin {
31074
31819
  this.langChainPlugin.disable();
31075
31820
  this.langChainPlugin = null;
31076
31821
  }
31822
+ if (this.langSmithPlugin) {
31823
+ this.langSmithPlugin.disable();
31824
+ this.langSmithPlugin = null;
31825
+ }
31077
31826
  }
31078
31827
  };
31079
31828
 
@@ -31138,7 +31887,8 @@ var envIntegrationAliases = {
31138
31887
  langchain: "langchain",
31139
31888
  "langchain-js": "langchain",
31140
31889
  "@langchain": "langchain",
31141
- langgraph: "langgraph"
31890
+ langgraph: "langgraph",
31891
+ langsmith: "langsmith"
31142
31892
  };
31143
31893
  function getDefaultInstrumentationIntegrations() {
31144
31894
  return {
@@ -31169,6 +31919,7 @@ function getDefaultInstrumentationIntegrations() {
31169
31919
  gitHubCopilot: true,
31170
31920
  langchain: true,
31171
31921
  langgraph: true,
31922
+ langsmith: true,
31172
31923
  piCodingAgent: true,
31173
31924
  strandsAgentSDK: true
31174
31925
  };
@@ -31389,6 +32140,8 @@ __export(exports_exports, {
31389
32140
  addAzureBlobHeaders: () => addAzureBlobHeaders,
31390
32141
  agentAssertionScorer: () => agentAssertionScorer,
31391
32142
  braintrustAISDKTelemetry: () => braintrustAISDKTelemetry,
32143
+ braintrustEveHook: () => braintrustEveHook,
32144
+ braintrustEveInstrumentation: () => braintrustEveInstrumentation,
31392
32145
  braintrustFlueInstrumentation: () => braintrustFlueInstrumentation,
31393
32146
  braintrustFlueObserver: () => braintrustFlueObserver,
31394
32147
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
@@ -31478,6 +32231,9 @@ __export(exports_exports, {
31478
32231
  wrapGoogleGenAI: () => wrapGoogleGenAI,
31479
32232
  wrapGroq: () => wrapGroq,
31480
32233
  wrapHuggingFace: () => wrapHuggingFace,
32234
+ wrapLangSmithClient: () => wrapLangSmithClient,
32235
+ wrapLangSmithRunTrees: () => wrapLangSmithRunTrees,
32236
+ wrapLangSmithTraceable: () => wrapLangSmithTraceable,
31481
32237
  wrapMastraAgent: () => wrapMastraAgent,
31482
32238
  wrapMistral: () => wrapMistral,
31483
32239
  wrapOpenAI: () => wrapOpenAI,
@@ -32889,6 +33645,1390 @@ function BraintrustMiddleware(config = {}) {
32889
33645
  };
32890
33646
  }
32891
33647
 
33648
+ // src/instrumentation/plugins/eve-plugin.ts
33649
+ var EVE_TRACE_STATE_KEY = "braintrust.eve.tracing";
33650
+ var MAX_EVE_CACHE_ENTRIES = 1e4;
33651
+ var MAX_STORED_LLM_INPUTS = 100;
33652
+ var MAX_STORED_SPAN_REFERENCES = 1e4;
33653
+ var MAX_STORED_STEP_STARTS = 1e4;
33654
+ function braintrustEveHook(options) {
33655
+ const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
33656
+ const bridge = new EveBridge(state);
33657
+ return {
33658
+ events: {
33659
+ "*": async (event, ctx) => {
33660
+ await bridge.handle(event, ctx, options.metadata);
33661
+ }
33662
+ }
33663
+ };
33664
+ }
33665
+ function braintrustEveInstrumentation(options) {
33666
+ const state = options.defineState(EVE_TRACE_STATE_KEY, emptyEveTraceState);
33667
+ return {
33668
+ events: {
33669
+ "step.started": (input) => {
33670
+ try {
33671
+ captureEveModelInput(state, input);
33672
+ } catch (error) {
33673
+ debugLogger.warn("Error in Eve LLM input capture:", error);
33674
+ }
33675
+ }
33676
+ },
33677
+ recordInputs: false,
33678
+ recordOutputs: false,
33679
+ setup: options.setup
33680
+ };
33681
+ }
33682
+ function isEveHandleMessageStreamEvent(event) {
33683
+ return isObject(event) && typeof event["type"] === "string";
33684
+ }
33685
+ var ResumedEveSpan = class {
33686
+ constructor(reference) {
33687
+ this.reference = reference;
33688
+ this.endTime = reference.endTime;
33689
+ }
33690
+ endTime;
33691
+ get rootSpanId() {
33692
+ return this.reference.rootSpanId;
33693
+ }
33694
+ get spanId() {
33695
+ return this.reference.spanId;
33696
+ }
33697
+ log(event) {
33698
+ const metrics = {
33699
+ ...this.reference.startEvent?.metrics,
33700
+ ...this.endTime === void 0 ? {} : { end: this.endTime },
33701
+ ...event.metrics
33702
+ };
33703
+ updateSpan({
33704
+ exported: this.reference.exported,
33705
+ ...this.reference.startEvent,
33706
+ ...event,
33707
+ ...Object.keys(metrics).length > 0 ? { metrics } : {}
33708
+ });
33709
+ }
33710
+ end(args) {
33711
+ if (this.endTime === void 0) {
33712
+ this.endTime = args?.endTime ?? getCurrentUnixTimestamp();
33713
+ this.log({ metrics: { end: this.endTime } });
33714
+ }
33715
+ return this.endTime;
33716
+ }
33717
+ };
33718
+ var EveBridge = class {
33719
+ constructor(state) {
33720
+ this.state = state;
33721
+ }
33722
+ eventQueuesBySession = /* @__PURE__ */ new Map();
33723
+ completedToolKeys = new LRUCache({
33724
+ max: MAX_EVE_CACHE_ENTRIES
33725
+ });
33726
+ toolsByCallKey = new LRUCache({
33727
+ max: MAX_EVE_CACHE_ENTRIES
33728
+ });
33729
+ turnsByKey = new LRUCache({
33730
+ max: MAX_EVE_CACHE_ENTRIES
33731
+ });
33732
+ async startEveSpan(args) {
33733
+ const rowId = args?.event?.id;
33734
+ const reference = typeof rowId === "string" && readEveTraceState(this.state).spanReferences.find(
33735
+ (candidate) => candidate.rowId === rowId
33736
+ );
33737
+ if (reference) {
33738
+ return new ResumedEveSpan(reference);
33739
+ }
33740
+ const startTime = args?.startTime ?? getCurrentUnixTimestamp();
33741
+ const parentSpanIds = args?.parentSpanIds;
33742
+ const startEvent = {
33743
+ created: (/* @__PURE__ */ new Date()).toISOString(),
33744
+ metrics: { start: startTime },
33745
+ span_attributes: {
33746
+ ...args?.name ? { name: args.name } : {},
33747
+ ...args?.type ? { type: args.type } : {},
33748
+ ...args?.spanAttributes
33749
+ },
33750
+ span_parents: parentSpanIds ? "spanId" in parentSpanIds ? [parentSpanIds.spanId] : parentSpanIds.parentSpanIds : []
33751
+ };
33752
+ const span = withCurrent(
33753
+ NOOP_SPAN,
33754
+ () => _internalStartSpanWithInitialMerge({ ...args, startTime })
33755
+ );
33756
+ if (typeof rowId !== "string") {
33757
+ return span;
33758
+ }
33759
+ try {
33760
+ const exported = await span.export();
33761
+ const reference2 = {
33762
+ exported,
33763
+ rootSpanId: span.rootSpanId,
33764
+ rowId,
33765
+ spanId: span.spanId,
33766
+ startEvent
33767
+ };
33768
+ this.state.update((current) => {
33769
+ const normalized = normalizeEveTraceState(current);
33770
+ return normalized.spanReferences.some(
33771
+ (candidate) => candidate.rowId === rowId
33772
+ ) ? normalized : {
33773
+ ...normalized,
33774
+ spanReferences: [...normalized.spanReferences, reference2].slice(
33775
+ -MAX_STORED_SPAN_REFERENCES
33776
+ )
33777
+ };
33778
+ });
33779
+ } catch (error) {
33780
+ debugLogger.warn("Error exporting Eve span for resumption:", error);
33781
+ }
33782
+ return span;
33783
+ }
33784
+ async startEveChildSpan(parent, args) {
33785
+ return await this.startEveSpan({
33786
+ ...args,
33787
+ parentSpanIds: {
33788
+ rootSpanId: parent.rootSpanId,
33789
+ spanId: parent.spanId
33790
+ }
33791
+ });
33792
+ }
33793
+ stepOrdinal(event) {
33794
+ let ordinal = 0;
33795
+ this.state.update((current) => {
33796
+ const state = normalizeEveTraceState(current);
33797
+ const previous = state.stepStarts.filter(
33798
+ (entry) => entry.turnId === event.data.turnId && entry.stepIndex === event.data.stepIndex
33799
+ ).at(-1);
33800
+ if (previous?.open) {
33801
+ ordinal = previous.ordinal;
33802
+ return state;
33803
+ }
33804
+ ordinal = state.stepStarts.filter(
33805
+ (entry) => entry.turnId === event.data.turnId
33806
+ ).length;
33807
+ return {
33808
+ ...state,
33809
+ stepStarts: [
33810
+ ...state.stepStarts,
33811
+ {
33812
+ open: true,
33813
+ ordinal,
33814
+ stepIndex: event.data.stepIndex,
33815
+ turnId: event.data.turnId
33816
+ }
33817
+ ].slice(-MAX_STORED_STEP_STARTS)
33818
+ };
33819
+ });
33820
+ return ordinal;
33821
+ }
33822
+ markStepEnded(turnId, stepIndex) {
33823
+ this.state.update((current) => {
33824
+ const state = normalizeEveTraceState(current);
33825
+ let index = -1;
33826
+ for (let i = state.stepStarts.length - 1; i >= 0; i--) {
33827
+ const entry = state.stepStarts[i];
33828
+ if (entry?.turnId === turnId && entry.stepIndex === stepIndex) {
33829
+ index = i;
33830
+ break;
33831
+ }
33832
+ }
33833
+ if (index < 0 || !state.stepStarts[index]?.open) {
33834
+ return state;
33835
+ }
33836
+ return {
33837
+ ...state,
33838
+ stepStarts: state.stepStarts.map(
33839
+ (entry, entryIndex) => entryIndex === index ? { ...entry, open: false } : entry
33840
+ )
33841
+ };
33842
+ });
33843
+ }
33844
+ async handle(event, ctx, hookMetadata) {
33845
+ if (!isEveHandleMessageStreamEvent(event)) {
33846
+ return;
33847
+ }
33848
+ const run = async () => {
33849
+ try {
33850
+ if (!await this.handleEvent(event, ctx, hookMetadata)) {
33851
+ return;
33852
+ }
33853
+ if (event.type === "session.failed") {
33854
+ const sessionId2 = event.data.sessionId || sessionIdFromContext(ctx);
33855
+ await this.flushInstrumentation();
33856
+ if (sessionId2) {
33857
+ this.cleanupSession(sessionId2);
33858
+ }
33859
+ } else if (event.type === "session.completed") {
33860
+ const sessionId2 = sessionIdFromContext(ctx);
33861
+ await this.flushInstrumentation();
33862
+ if (sessionId2) {
33863
+ this.cleanupSession(sessionId2);
33864
+ }
33865
+ }
33866
+ } catch (error) {
33867
+ debugLogger.warn("Error in Eve hook instrumentation:", error);
33868
+ }
33869
+ };
33870
+ const sessionId = event.type === "session.failed" ? event.data.sessionId || sessionIdFromContext(ctx) : sessionIdFromContext(ctx);
33871
+ if (!sessionId) {
33872
+ await run();
33873
+ return;
33874
+ }
33875
+ const previous = this.eventQueuesBySession.get(sessionId);
33876
+ const queued = previous ? previous.then(run) : run();
33877
+ this.eventQueuesBySession.set(sessionId, queued);
33878
+ try {
33879
+ await queued;
33880
+ } finally {
33881
+ if (this.eventQueuesBySession.get(sessionId) === queued) {
33882
+ this.eventQueuesBySession.delete(sessionId);
33883
+ }
33884
+ }
33885
+ }
33886
+ async handleEvent(event, ctx, hookMetadata) {
33887
+ switch (event.type) {
33888
+ case "session.started":
33889
+ this.handleSessionStarted(event, ctx, hookMetadata);
33890
+ return true;
33891
+ case "turn.started":
33892
+ await this.handleTurnStarted(event, ctx, hookMetadata);
33893
+ return true;
33894
+ case "message.received":
33895
+ await this.handleMessageReceived(event, ctx, hookMetadata);
33896
+ return true;
33897
+ case "step.started":
33898
+ await this.handleStepStarted(event, ctx, hookMetadata);
33899
+ return true;
33900
+ case "message.completed":
33901
+ this.handleMessageCompleted(event, ctx);
33902
+ return true;
33903
+ case "result.completed":
33904
+ this.handleResultCompleted(event, ctx);
33905
+ return true;
33906
+ case "actions.requested":
33907
+ await this.handleActionsRequested(event, ctx, hookMetadata);
33908
+ return true;
33909
+ case "action.result":
33910
+ await this.handleActionResult(event, ctx, hookMetadata);
33911
+ return true;
33912
+ case "subagent.called":
33913
+ await this.handleSubagentCalled(event, ctx, hookMetadata);
33914
+ return true;
33915
+ case "subagent.completed":
33916
+ await this.handleSubagentCompleted(event, ctx, hookMetadata);
33917
+ return true;
33918
+ case "step.completed":
33919
+ this.handleStepCompleted(event, ctx);
33920
+ return true;
33921
+ case "step.failed":
33922
+ this.handleStepFailed(event, ctx);
33923
+ return true;
33924
+ case "turn.completed":
33925
+ this.handleTurnCompleted(event, ctx);
33926
+ return true;
33927
+ case "turn.failed":
33928
+ this.handleTurnFailed(event, ctx);
33929
+ return true;
33930
+ case "session.failed":
33931
+ this.handleSessionFailed(event, ctx);
33932
+ return true;
33933
+ case "session.completed":
33934
+ this.handleSessionCompleted(event, ctx);
33935
+ return true;
33936
+ default:
33937
+ return false;
33938
+ }
33939
+ }
33940
+ handleSessionStarted(event, ctx, hookMetadata) {
33941
+ const sessionId = sessionIdFromContext(ctx);
33942
+ if (!sessionId) {
33943
+ return;
33944
+ }
33945
+ const metadata = {
33946
+ ...hookMetadata ?? {},
33947
+ ...modelMetadataFromRuntime(event.data.runtime)
33948
+ };
33949
+ this.state.update((current) => {
33950
+ const normalized = normalizeEveTraceState(current);
33951
+ return {
33952
+ ...normalized,
33953
+ metadata: { ...normalized.metadata, ...metadata }
33954
+ };
33955
+ });
33956
+ for (const [key, turn] of this.turnsByKey) {
33957
+ if (!key.startsWith(`${sessionId}:`)) {
33958
+ continue;
33959
+ }
33960
+ turn.metadata = { ...turn.metadata, ...metadata };
33961
+ turn.span.log({ metadata: turn.metadata });
33962
+ for (const step of turn.stepsByIndex.values()) {
33963
+ step.metadata = { ...step.metadata, ...metadata };
33964
+ step.span.log({ metadata: step.metadata });
33965
+ }
33966
+ }
33967
+ }
33968
+ async handleTurnStarted(event, ctx, hookMetadata) {
33969
+ const sessionId = sessionIdFromContext(ctx);
33970
+ if (!sessionId) {
33971
+ return;
33972
+ }
33973
+ const key = turnKey2(sessionId, event.data.turnId);
33974
+ const metadata = {
33975
+ ...readEveTraceState(this.state).metadata,
33976
+ ...hookMetadata ?? {},
33977
+ "eve.session_id": sessionId
33978
+ };
33979
+ const existing = this.turnsByKey.get(key);
33980
+ if (existing) {
33981
+ existing.metadata = { ...existing.metadata, ...metadata };
33982
+ existing.span.log({ metadata: existing.metadata });
33983
+ return;
33984
+ }
33985
+ const span = await this.startTurnSpan(sessionId, event, ctx, metadata);
33986
+ span.log({ metadata });
33987
+ this.turnsByKey.set(key, {
33988
+ key,
33989
+ metadata,
33990
+ metrics: {},
33991
+ span,
33992
+ stepsByIndex: /* @__PURE__ */ new Map(),
33993
+ turnId: event.data.turnId
33994
+ });
33995
+ }
33996
+ async handleMessageReceived(event, ctx, hookMetadata) {
33997
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
33998
+ if (!turn) {
33999
+ return;
34000
+ }
34001
+ const input = [{ content: event.data.message, role: "user" }];
34002
+ turn.span.log({ input });
34003
+ }
34004
+ async handleStepStarted(event, ctx, hookMetadata) {
34005
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
34006
+ const sessionId = sessionIdFromContext(ctx);
34007
+ if (!turn || !sessionId) {
34008
+ return;
34009
+ }
34010
+ const existing = turn.stepsByIndex.get(event.data.stepIndex);
34011
+ if (existing) {
34012
+ existing.span.log({
34013
+ ...existing.input !== void 0 ? { input: existing.input } : {},
34014
+ metadata: existing.metadata,
34015
+ metrics: existing.metrics,
34016
+ output: existing.output
34017
+ });
34018
+ const endTime = eventTime2(event);
34019
+ existing.span.end(endTime === void 0 ? void 0 : { endTime });
34020
+ this.markStepEnded(event.data.turnId, event.data.stepIndex);
34021
+ }
34022
+ const stepOrdinal = this.stepOrdinal(event);
34023
+ const metadata = { ...turn.metadata };
34024
+ const input = consumeCapturedEveModelInput(
34025
+ this.state,
34026
+ sessionId,
34027
+ event.data.turnId,
34028
+ event.data.stepIndex
34029
+ );
34030
+ const { rowId: eventId, spanId } = await generateEveIds(
34031
+ "step",
34032
+ sessionId,
34033
+ event.data.turnId,
34034
+ String(stepOrdinal)
34035
+ );
34036
+ const span = await this.startEveChildSpan(turn.span, {
34037
+ event: {
34038
+ id: eventId,
34039
+ ...input !== void 0 ? { input } : {},
34040
+ metadata
34041
+ },
34042
+ name: "eve.step",
34043
+ spanAttributes: { type: "llm" /* LLM */ },
34044
+ spanId,
34045
+ startTime: eventTime2(event)
34046
+ });
34047
+ span.log({ ...input !== void 0 ? { input } : {}, metadata });
34048
+ turn.stepsByIndex.set(event.data.stepIndex, {
34049
+ ...input !== void 0 ? { input } : {},
34050
+ metadata,
34051
+ metrics: {},
34052
+ span
34053
+ });
34054
+ }
34055
+ handleMessageCompleted(event, ctx) {
34056
+ const step = this.stepForEvent(event, ctx);
34057
+ if (!step) {
34058
+ return;
34059
+ }
34060
+ const existingMessage = Array.isArray(step.output) && isObject(step.output[0]) ? step.output[0].message : void 0;
34061
+ const existingToolCalls = isObject(existingMessage) ? existingMessage.tool_calls : void 0;
34062
+ step.output = [
34063
+ {
34064
+ finish_reason: normalizedFinishReason(event.data.finishReason),
34065
+ index: 0,
34066
+ message: {
34067
+ content: event.data.message,
34068
+ role: "assistant",
34069
+ ...Array.isArray(existingToolCalls) ? { tool_calls: existingToolCalls } : {}
34070
+ }
34071
+ }
34072
+ ];
34073
+ const turn = this.turnForEvent(event, ctx);
34074
+ if (turn && event.data.finishReason !== "tool-calls") {
34075
+ turn.output = event.data.message;
34076
+ }
34077
+ }
34078
+ handleResultCompleted(event, ctx) {
34079
+ const step = this.stepForEvent(event, ctx);
34080
+ if (step) {
34081
+ step.output = [
34082
+ {
34083
+ finish_reason: "stop",
34084
+ index: 0,
34085
+ message: {
34086
+ content: event.data.result,
34087
+ role: "assistant"
34088
+ }
34089
+ }
34090
+ ];
34091
+ }
34092
+ const turn = this.turnForEvent(event, ctx);
34093
+ if (turn) {
34094
+ turn.output = event.data.result;
34095
+ }
34096
+ }
34097
+ async handleActionsRequested(event, ctx, hookMetadata) {
34098
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
34099
+ const sessionId = sessionIdFromContext(ctx);
34100
+ if (!turn || !sessionId) {
34101
+ return;
34102
+ }
34103
+ const traceActions = event.data.actions.filter(isTraceableActionRequest);
34104
+ if (traceActions.length === 0) {
34105
+ return;
34106
+ }
34107
+ for (const action of traceActions) {
34108
+ if (isToolCallAction(action)) {
34109
+ await this.startRequestedTool(event, turn, sessionId, action);
34110
+ } else if (isLocalSubagentCallAction(action)) {
34111
+ await this.startRequestedSubagent(event, turn, sessionId, action);
34112
+ }
34113
+ }
34114
+ const step = turn.stepsByIndex.get(event.data.stepIndex);
34115
+ if (!step) {
34116
+ return;
34117
+ }
34118
+ const toolCallsById = /* @__PURE__ */ new Map();
34119
+ if (Array.isArray(step.output) && isObject(step.output[0])) {
34120
+ const message = step.output[0]["message"];
34121
+ if (isObject(message) && Array.isArray(message["tool_calls"])) {
34122
+ for (const toolCall of message["tool_calls"]) {
34123
+ if (isObject(toolCall) && typeof toolCall["id"] === "string") {
34124
+ toolCallsById.set(toolCall["id"], toolCall);
34125
+ }
34126
+ }
34127
+ }
34128
+ }
34129
+ for (const action of traceActions) {
34130
+ const name = action.kind === "tool-call" ? action.toolName : action.subagentName ?? action.name ?? "agent";
34131
+ toolCallsById.set(action.callId, {
34132
+ function: {
34133
+ arguments: JSON.stringify(action.input),
34134
+ name
34135
+ },
34136
+ id: action.callId,
34137
+ type: "function"
34138
+ });
34139
+ }
34140
+ step.output = [
34141
+ {
34142
+ finish_reason: "tool_calls",
34143
+ index: 0,
34144
+ message: {
34145
+ content: null,
34146
+ role: "assistant",
34147
+ tool_calls: [...toolCallsById.values()]
34148
+ }
34149
+ }
34150
+ ];
34151
+ step.span.log({ metadata: step.metadata, output: step.output });
34152
+ }
34153
+ async handleActionResult(event, ctx, hookMetadata) {
34154
+ if (isToolResult(event.data.result)) {
34155
+ await this.handleToolResult(event, ctx, event.data.result, hookMetadata);
34156
+ return;
34157
+ }
34158
+ if (isSubagentResult(event.data.result)) {
34159
+ await this.handleSubagentResult(
34160
+ event,
34161
+ ctx,
34162
+ event.data.result,
34163
+ hookMetadata
34164
+ );
34165
+ }
34166
+ }
34167
+ async handleToolResult(event, ctx, result, hookMetadata) {
34168
+ const sessionId = sessionIdFromContext(ctx);
34169
+ if (!sessionId) {
34170
+ return;
34171
+ }
34172
+ const key = toolKey3(sessionId, result.callId);
34173
+ if (this.completedToolKeys.has(key)) {
34174
+ return;
34175
+ }
34176
+ const tool = this.toolsByCallKey.get(key) ?? await this.startSyntheticTool(event, ctx, result, hookMetadata);
34177
+ if (!tool) {
34178
+ return;
34179
+ }
34180
+ const failed = event.data.status === "failed" || result.isError === true || event.data.error !== void 0;
34181
+ tool.span.log({
34182
+ ...failed ? {
34183
+ error: actionResultError(event.data.error, result.output)
34184
+ } : {},
34185
+ metadata: tool.metadata,
34186
+ output: result.output
34187
+ });
34188
+ const endTime = eventTime2(event);
34189
+ tool.span.end(endTime === void 0 ? void 0 : { endTime });
34190
+ this.toolsByCallKey.delete(key);
34191
+ this.completedToolKeys.set(key, true);
34192
+ }
34193
+ async handleSubagentCalled(event, ctx, hookMetadata) {
34194
+ if (event.data.remote?.url) {
34195
+ return;
34196
+ }
34197
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
34198
+ const sessionId = sessionIdFromContext(ctx);
34199
+ if (!turn || !sessionId) {
34200
+ return;
34201
+ }
34202
+ const key = toolKey3(sessionId, event.data.callId);
34203
+ const metadata = toolMetadataFromTurn(turn);
34204
+ const existing = this.toolsByCallKey.get(key);
34205
+ if (existing) {
34206
+ existing.metadata = { ...existing.metadata, ...metadata };
34207
+ existing.span.log({ metadata: existing.metadata });
34208
+ return;
34209
+ }
34210
+ if (this.completedToolKeys.has(key)) {
34211
+ return;
34212
+ }
34213
+ const { rowId: eventId, spanId } = await generateEveIds(
34214
+ "subagent",
34215
+ sessionId,
34216
+ event.data.callId
34217
+ );
34218
+ const pending = this.toolsByCallKey.get(key);
34219
+ if (pending || this.completedToolKeys.has(key)) {
34220
+ if (pending) {
34221
+ pending.metadata = { ...pending.metadata, ...metadata };
34222
+ pending.span.log({ metadata: pending.metadata });
34223
+ }
34224
+ return;
34225
+ }
34226
+ const span = await this.startEveChildSpan(turn.span, {
34227
+ event: {
34228
+ id: eventId,
34229
+ metadata
34230
+ },
34231
+ name: event.data.toolName ?? event.data.name,
34232
+ spanAttributes: { type: "tool" /* TOOL */ },
34233
+ spanId,
34234
+ startTime: eventTime2(event)
34235
+ });
34236
+ span.log({ metadata });
34237
+ this.toolsByCallKey.set(key, {
34238
+ metadata,
34239
+ span,
34240
+ turnKey: turnKey2(sessionId, event.data.turnId)
34241
+ });
34242
+ }
34243
+ async handleSubagentCompleted(event, ctx, hookMetadata) {
34244
+ const sessionId = sessionIdFromContext(ctx);
34245
+ if (!sessionId) {
34246
+ return;
34247
+ }
34248
+ const key = toolKey3(sessionId, event.data.callId);
34249
+ if (this.completedToolKeys.has(key)) {
34250
+ return;
34251
+ }
34252
+ const subagent = this.toolsByCallKey.get(key) ?? await this.startSyntheticSubagent(event, ctx, hookMetadata);
34253
+ if (!subagent) {
34254
+ return;
34255
+ }
34256
+ subagent.span.log({
34257
+ ...event.data.status === "failed" ? {
34258
+ error: actionResultError(event.data.error, event.data.output)
34259
+ } : {},
34260
+ metadata: subagent.metadata,
34261
+ ...event.data.output !== void 0 ? { output: event.data.output } : {}
34262
+ });
34263
+ const endTime = eventTime2(event);
34264
+ const recordedEndTime = subagent.span.end(
34265
+ endTime === void 0 ? void 0 : { endTime }
34266
+ );
34267
+ this.state.update((current) => {
34268
+ const normalized = normalizeEveTraceState(current);
34269
+ return {
34270
+ ...normalized,
34271
+ spanReferences: normalized.spanReferences.map(
34272
+ (reference) => reference.spanId === subagent.span.spanId ? { ...reference, endTime: recordedEndTime } : reference
34273
+ )
34274
+ };
34275
+ });
34276
+ }
34277
+ async handleSubagentResult(event, ctx, result, hookMetadata) {
34278
+ const sessionId = sessionIdFromContext(ctx);
34279
+ if (!sessionId) {
34280
+ return;
34281
+ }
34282
+ const key = toolKey3(sessionId, result.callId);
34283
+ if (this.completedToolKeys.has(key)) {
34284
+ return;
34285
+ }
34286
+ const subagent = this.toolsByCallKey.get(key) ?? await this.startSyntheticSubagentResult(
34287
+ event,
34288
+ ctx,
34289
+ result,
34290
+ hookMetadata
34291
+ );
34292
+ if (!subagent) {
34293
+ return;
34294
+ }
34295
+ const isError = event.data.status === "failed" || result.isError === true || event.data.error !== void 0;
34296
+ subagent.span.log({
34297
+ ...isError ? {
34298
+ error: actionResultError(event.data.error, result.output)
34299
+ } : {},
34300
+ metadata: subagent.metadata,
34301
+ output: result.output
34302
+ });
34303
+ const endTime = eventTime2(event);
34304
+ subagent.span.end(endTime === void 0 ? void 0 : { endTime });
34305
+ this.toolsByCallKey.delete(key);
34306
+ this.completedToolKeys.set(key, true);
34307
+ }
34308
+ handleStepCompleted(event, ctx) {
34309
+ const step = this.stepForEvent(event, ctx);
34310
+ if (!step) {
34311
+ return;
34312
+ }
34313
+ const usage = event.data.usage;
34314
+ const inputTokens = typeof usage?.inputTokens === "number" && Number.isFinite(usage.inputTokens) && usage.inputTokens >= 0 ? usage.inputTokens : void 0;
34315
+ const outputTokens = typeof usage?.outputTokens === "number" && Number.isFinite(usage.outputTokens) && usage.outputTokens >= 0 ? usage.outputTokens : void 0;
34316
+ const cacheReadTokens = typeof usage?.cacheReadTokens === "number" && Number.isFinite(usage.cacheReadTokens) && usage.cacheReadTokens >= 0 ? usage.cacheReadTokens : void 0;
34317
+ const cacheWriteTokens = typeof usage?.cacheWriteTokens === "number" && Number.isFinite(usage.cacheWriteTokens) && usage.cacheWriteTokens >= 0 ? usage.cacheWriteTokens : void 0;
34318
+ const costUsd = typeof usage?.costUsd === "number" && Number.isFinite(usage.costUsd) && usage.costUsd >= 0 ? usage.costUsd : void 0;
34319
+ const total = inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0;
34320
+ const metrics = {
34321
+ ...inputTokens !== void 0 ? { prompt_tokens: inputTokens } : {},
34322
+ ...outputTokens !== void 0 ? { completion_tokens: outputTokens } : {},
34323
+ ...total !== void 0 ? { tokens: total } : {},
34324
+ ...cacheReadTokens !== void 0 ? { prompt_cached_tokens: cacheReadTokens } : {},
34325
+ ...cacheWriteTokens !== void 0 ? { prompt_cache_creation_tokens: cacheWriteTokens } : {},
34326
+ ...costUsd !== void 0 ? { estimated_cost: costUsd } : {}
34327
+ };
34328
+ step.metrics = { ...step.metrics, ...metrics };
34329
+ if (Array.isArray(step.output) && isObject(step.output[0])) {
34330
+ const finishReason = step.output[0].finish_reason;
34331
+ if (typeof finishReason !== "string") {
34332
+ step.output[0].finish_reason = normalizedFinishReason(
34333
+ event.data.finishReason
34334
+ );
34335
+ }
34336
+ }
34337
+ step.span.log({
34338
+ ...step.input !== void 0 ? { input: step.input } : {},
34339
+ metadata: step.metadata,
34340
+ metrics,
34341
+ output: step.output
34342
+ });
34343
+ const endTime = eventTime2(event);
34344
+ step.span.end(endTime === void 0 ? void 0 : { endTime });
34345
+ const turn = this.turnForEvent(event, ctx);
34346
+ if (turn) {
34347
+ for (const [key, value] of Object.entries(metrics)) {
34348
+ turn.metrics[key] = (turn.metrics[key] ?? 0) + value;
34349
+ }
34350
+ turn.stepsByIndex.delete(event.data.stepIndex);
34351
+ }
34352
+ this.markStepEnded(event.data.turnId, event.data.stepIndex);
34353
+ }
34354
+ handleStepFailed(event, ctx) {
34355
+ const step = this.stepForEvent(event, ctx);
34356
+ if (step) {
34357
+ step.span.log({
34358
+ error: errorFromMessage(
34359
+ event.data.message,
34360
+ event.data.code,
34361
+ event.data.details
34362
+ )
34363
+ });
34364
+ const endTime = eventTime2(event);
34365
+ step.span.end(endTime === void 0 ? void 0 : { endTime });
34366
+ }
34367
+ const turn = this.turnForEvent(event, ctx);
34368
+ turn?.stepsByIndex.delete(event.data.stepIndex);
34369
+ this.markStepEnded(event.data.turnId, event.data.stepIndex);
34370
+ }
34371
+ handleTurnCompleted(event, ctx) {
34372
+ const turn = this.turnForEvent(event, ctx);
34373
+ if (!turn) {
34374
+ return;
34375
+ }
34376
+ this.finalizeTurn(turn, {
34377
+ endTime: eventTime2(event)
34378
+ });
34379
+ }
34380
+ handleTurnFailed(event, ctx) {
34381
+ const turn = this.turnForEvent(event, ctx);
34382
+ if (!turn) {
34383
+ return;
34384
+ }
34385
+ this.finalizeTurn(turn, {
34386
+ endTime: eventTime2(event),
34387
+ error: errorFromMessage(
34388
+ event.data.message,
34389
+ event.data.code,
34390
+ event.data.details
34391
+ )
34392
+ });
34393
+ }
34394
+ handleSessionFailed(event, ctx) {
34395
+ const sessionId = event.data.sessionId || sessionIdFromContext(ctx);
34396
+ if (!sessionId) {
34397
+ return;
34398
+ }
34399
+ const error = errorFromMessage(
34400
+ event.data.message,
34401
+ event.data.code,
34402
+ event.data.details
34403
+ );
34404
+ for (const [key, turn] of this.turnsByKey) {
34405
+ if (!key.startsWith(`${sessionId}:`)) {
34406
+ continue;
34407
+ }
34408
+ this.finalizeTurn(turn, {
34409
+ endTime: eventTime2(event),
34410
+ error
34411
+ });
34412
+ }
34413
+ for (const [key, tool] of this.toolsByCallKey) {
34414
+ if (key.startsWith(`${sessionId}:`)) {
34415
+ const endTime = eventTime2(event);
34416
+ if (!tool.endedByTurn) {
34417
+ tool.span.log({ metadata: tool.metadata });
34418
+ tool.span.end(endTime === void 0 ? void 0 : { endTime });
34419
+ tool.endedByTurn = true;
34420
+ }
34421
+ }
34422
+ }
34423
+ }
34424
+ handleSessionCompleted(event, ctx) {
34425
+ const sessionId = sessionIdFromContext(ctx);
34426
+ if (!sessionId) {
34427
+ return;
34428
+ }
34429
+ for (const [key, turn] of this.turnsByKey) {
34430
+ if (!key.startsWith(`${sessionId}:`)) {
34431
+ continue;
34432
+ }
34433
+ this.finalizeTurn(turn, {
34434
+ endTime: eventTime2(event)
34435
+ });
34436
+ }
34437
+ for (const [key, tool] of this.toolsByCallKey) {
34438
+ if (key.startsWith(`${sessionId}:`) && !tool.endedByTurn) {
34439
+ const endTime = eventTime2(event);
34440
+ tool.span.log({ metadata: tool.metadata });
34441
+ tool.span.end(endTime === void 0 ? void 0 : { endTime });
34442
+ tool.endedByTurn = true;
34443
+ }
34444
+ }
34445
+ }
34446
+ async ensureTurn(event, ctx, hookMetadata) {
34447
+ const sessionId = sessionIdFromContext(ctx);
34448
+ if (!sessionId) {
34449
+ return void 0;
34450
+ }
34451
+ const key = turnKey2(sessionId, event.data.turnId);
34452
+ const existing = this.turnsByKey.get(key);
34453
+ if (existing) {
34454
+ return existing;
34455
+ }
34456
+ const metadata = {
34457
+ ...readEveTraceState(this.state).metadata,
34458
+ ...hookMetadata ?? {},
34459
+ "eve.session_id": sessionId
34460
+ };
34461
+ const span = await this.startTurnSpan(sessionId, event, ctx, metadata);
34462
+ span.log({ metadata });
34463
+ const state = {
34464
+ key,
34465
+ metadata,
34466
+ metrics: {},
34467
+ span,
34468
+ stepsByIndex: /* @__PURE__ */ new Map(),
34469
+ turnId: event.data.turnId
34470
+ };
34471
+ this.turnsByKey.set(key, state);
34472
+ return state;
34473
+ }
34474
+ async startRequestedTool(event, turn, sessionId, action) {
34475
+ const key = toolKey3(sessionId, action.callId);
34476
+ if (this.toolsByCallKey.has(key) || this.completedToolKeys.has(key)) {
34477
+ return;
34478
+ }
34479
+ const metadata = toolMetadataFromTurn(turn);
34480
+ const { rowId: eventId, spanId } = await generateEveIds(
34481
+ "tool",
34482
+ sessionId,
34483
+ event.data.turnId,
34484
+ action.callId
34485
+ );
34486
+ if (this.toolsByCallKey.has(key) || this.completedToolKeys.has(key)) {
34487
+ return;
34488
+ }
34489
+ const span = await this.startEveChildSpan(turn.span, {
34490
+ event: {
34491
+ id: eventId,
34492
+ input: action.input,
34493
+ metadata
34494
+ },
34495
+ name: action.toolName,
34496
+ spanAttributes: { type: "tool" /* TOOL */ },
34497
+ spanId,
34498
+ startTime: eventTime2(event)
34499
+ });
34500
+ span.log({ input: action.input, metadata });
34501
+ this.toolsByCallKey.set(key, {
34502
+ metadata,
34503
+ span,
34504
+ turnKey: turnKey2(sessionId, event.data.turnId)
34505
+ });
34506
+ }
34507
+ async startRequestedSubagent(event, turn, sessionId, action) {
34508
+ const key = toolKey3(sessionId, action.callId);
34509
+ if (this.toolsByCallKey.has(key) || this.completedToolKeys.has(key)) {
34510
+ return;
34511
+ }
34512
+ const name = action.subagentName ?? action.name ?? "agent";
34513
+ const metadata = toolMetadataFromTurn(turn);
34514
+ const { rowId: eventId, spanId } = await generateEveIds(
34515
+ "subagent",
34516
+ sessionId,
34517
+ action.callId
34518
+ );
34519
+ if (this.toolsByCallKey.has(key) || this.completedToolKeys.has(key)) {
34520
+ return;
34521
+ }
34522
+ const span = await this.startEveChildSpan(turn.span, {
34523
+ event: {
34524
+ id: eventId,
34525
+ input: action.input,
34526
+ metadata
34527
+ },
34528
+ name,
34529
+ spanAttributes: { type: "tool" /* TOOL */ },
34530
+ spanId,
34531
+ startTime: eventTime2(event)
34532
+ });
34533
+ span.log({ input: action.input, metadata });
34534
+ this.toolsByCallKey.set(key, {
34535
+ metadata,
34536
+ span,
34537
+ turnKey: turnKey2(sessionId, event.data.turnId)
34538
+ });
34539
+ }
34540
+ async startSyntheticTool(event, ctx, result, hookMetadata) {
34541
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
34542
+ const sessionId = sessionIdFromContext(ctx);
34543
+ if (!turn || !sessionId) {
34544
+ return void 0;
34545
+ }
34546
+ const metadata = toolMetadataFromTurn(turn);
34547
+ const { rowId: eventId, spanId } = await generateEveIds(
34548
+ "tool",
34549
+ sessionId,
34550
+ event.data.turnId,
34551
+ result.callId
34552
+ );
34553
+ const existing = this.toolsByCallKey.get(toolKey3(sessionId, result.callId));
34554
+ if (existing) {
34555
+ return existing;
34556
+ }
34557
+ const span = await this.startEveChildSpan(turn.span, {
34558
+ event: {
34559
+ id: eventId,
34560
+ metadata
34561
+ },
34562
+ name: result.toolName,
34563
+ spanAttributes: { type: "tool" /* TOOL */ },
34564
+ spanId,
34565
+ startTime: eventTime2(event)
34566
+ });
34567
+ span.log({ metadata });
34568
+ const state = {
34569
+ metadata,
34570
+ span,
34571
+ turnKey: turnKey2(sessionId, event.data.turnId)
34572
+ };
34573
+ this.toolsByCallKey.set(toolKey3(sessionId, result.callId), state);
34574
+ return state;
34575
+ }
34576
+ async startSyntheticSubagent(event, ctx, hookMetadata) {
34577
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
34578
+ const sessionId = sessionIdFromContext(ctx);
34579
+ if (!turn || !sessionId) {
34580
+ return void 0;
34581
+ }
34582
+ const metadata = toolMetadataFromTurn(turn);
34583
+ const { rowId: eventId, spanId } = await generateEveIds(
34584
+ "subagent",
34585
+ sessionId,
34586
+ event.data.callId
34587
+ );
34588
+ const existing = this.toolsByCallKey.get(
34589
+ toolKey3(sessionId, event.data.callId)
34590
+ );
34591
+ if (existing) {
34592
+ return existing;
34593
+ }
34594
+ const span = await this.startEveChildSpan(turn.span, {
34595
+ event: {
34596
+ id: eventId,
34597
+ metadata
34598
+ },
34599
+ name: event.data.subagentName,
34600
+ spanAttributes: { type: "tool" /* TOOL */ },
34601
+ spanId,
34602
+ startTime: eventTime2(event)
34603
+ });
34604
+ span.log({ metadata });
34605
+ const state = {
34606
+ metadata,
34607
+ span,
34608
+ turnKey: turnKey2(sessionId, event.data.turnId)
34609
+ };
34610
+ this.toolsByCallKey.set(toolKey3(sessionId, event.data.callId), state);
34611
+ return state;
34612
+ }
34613
+ async startSyntheticSubagentResult(event, ctx, result, hookMetadata) {
34614
+ const turn = await this.ensureTurn(event, ctx, hookMetadata);
34615
+ const sessionId = sessionIdFromContext(ctx);
34616
+ if (!turn || !sessionId) {
34617
+ return void 0;
34618
+ }
34619
+ const metadata = toolMetadataFromTurn(turn);
34620
+ const { rowId: eventId, spanId } = await generateEveIds(
34621
+ "subagent",
34622
+ sessionId,
34623
+ result.callId
34624
+ );
34625
+ const existing = this.toolsByCallKey.get(toolKey3(sessionId, result.callId));
34626
+ if (existing) {
34627
+ return existing;
34628
+ }
34629
+ const span = await this.startEveChildSpan(turn.span, {
34630
+ event: {
34631
+ id: eventId,
34632
+ metadata
34633
+ },
34634
+ name: result.subagentName,
34635
+ spanAttributes: { type: "tool" /* TOOL */ },
34636
+ spanId,
34637
+ startTime: eventTime2(event)
34638
+ });
34639
+ span.log({ metadata });
34640
+ const state = {
34641
+ metadata,
34642
+ span,
34643
+ turnKey: turnKey2(sessionId, event.data.turnId)
34644
+ };
34645
+ this.toolsByCallKey.set(toolKey3(sessionId, result.callId), state);
34646
+ return state;
34647
+ }
34648
+ async startTurnSpan(sessionId, event, ctx, metadata) {
34649
+ const session = isObject(ctx) ? ctx["session"] : void 0;
34650
+ const parent = isObject(session) ? session["parent"] : void 0;
34651
+ const parentTurn = isObject(parent) ? parent["turn"] : void 0;
34652
+ const parentLineage = isObject(parent) && typeof parent["callId"] === "string" && typeof parent["sessionId"] === "string" && isObject(parentTurn) && typeof parentTurn["id"] === "string" ? {
34653
+ callId: parent["callId"],
34654
+ sessionId: parent["sessionId"],
34655
+ turnId: parentTurn["id"]
34656
+ } : void 0;
34657
+ const [{ rowId: eventId, spanId }, rootSpanId, parentSpanId] = await Promise.all([
34658
+ generateEveIds("turn", sessionId, event.data.turnId),
34659
+ deterministicEveId(
34660
+ "eve:root",
34661
+ parentLineage?.sessionId ?? sessionId,
34662
+ parentLineage?.turnId ?? event.data.turnId
34663
+ ),
34664
+ parentLineage ? deterministicEveId(
34665
+ "eve:subagent",
34666
+ parentLineage.sessionId,
34667
+ parentLineage.callId
34668
+ ) : Promise.resolve(void 0)
34669
+ ]);
34670
+ return await this.startEveSpan({
34671
+ event: {
34672
+ id: eventId,
34673
+ metadata
34674
+ },
34675
+ name: "eve.turn",
34676
+ parentSpanIds: parentSpanId ? { rootSpanId, spanId: parentSpanId } : { parentSpanIds: [], rootSpanId },
34677
+ spanAttributes: { type: "task" /* TASK */ },
34678
+ spanId,
34679
+ startTime: eventTime2(event)
34680
+ });
34681
+ }
34682
+ turnForEvent(event, ctx) {
34683
+ const sessionId = sessionIdFromContext(ctx);
34684
+ return sessionId ? this.turnsByKey.get(turnKey2(sessionId, event.data.turnId)) : void 0;
34685
+ }
34686
+ stepForEvent(event, ctx) {
34687
+ return this.turnForEvent(event, ctx)?.stepsByIndex.get(
34688
+ event.data.stepIndex
34689
+ );
34690
+ }
34691
+ finalizeTurn(turn, args) {
34692
+ const { endTime } = args;
34693
+ for (const step of turn.stepsByIndex.values()) {
34694
+ step.span.log({
34695
+ ...step.input !== void 0 ? { input: step.input } : {},
34696
+ metadata: step.metadata,
34697
+ metrics: step.metrics,
34698
+ output: step.output
34699
+ });
34700
+ step.span.end(endTime === void 0 ? void 0 : { endTime });
34701
+ }
34702
+ turn.stepsByIndex.clear();
34703
+ for (const tool of this.toolsByCallKey.values()) {
34704
+ if (tool.turnKey !== turn.key) {
34705
+ continue;
34706
+ }
34707
+ if (tool.endedByTurn) {
34708
+ continue;
34709
+ }
34710
+ tool.span.log({ metadata: tool.metadata });
34711
+ tool.span.end(endTime === void 0 ? void 0 : { endTime });
34712
+ tool.endedByTurn = true;
34713
+ }
34714
+ if (args.error) {
34715
+ turn.span.log({ error: args.error });
34716
+ } else {
34717
+ turn.span.log({
34718
+ metadata: turn.metadata,
34719
+ metrics: turn.metrics,
34720
+ output: turn.output
34721
+ });
34722
+ }
34723
+ turn.span.end(endTime === void 0 ? void 0 : { endTime });
34724
+ this.turnsByKey.delete(turn.key);
34725
+ this.state.update((current) => {
34726
+ const normalized = normalizeEveTraceState(current);
34727
+ return {
34728
+ ...normalized,
34729
+ stepStarts: normalized.stepStarts.filter(
34730
+ (entry) => entry.turnId !== turn.turnId
34731
+ )
34732
+ };
34733
+ });
34734
+ }
34735
+ cleanupSession(sessionId) {
34736
+ const keyPrefix = `${sessionId}:`;
34737
+ for (const key of this.turnsByKey.keys()) {
34738
+ if (key.startsWith(keyPrefix)) {
34739
+ this.turnsByKey.delete(key);
34740
+ }
34741
+ }
34742
+ for (const key of this.toolsByCallKey.keys()) {
34743
+ if (key.startsWith(keyPrefix)) {
34744
+ this.toolsByCallKey.delete(key);
34745
+ }
34746
+ }
34747
+ for (const key of this.completedToolKeys.keys()) {
34748
+ if (key.startsWith(keyPrefix)) {
34749
+ this.completedToolKeys.delete(key);
34750
+ }
34751
+ }
34752
+ this.state.update(() => emptyEveTraceState());
34753
+ }
34754
+ async flushInstrumentation() {
34755
+ try {
34756
+ await flush();
34757
+ return true;
34758
+ } catch (error) {
34759
+ debugLogger.warn("Error in Eve flush instrumentation:", error);
34760
+ return false;
34761
+ }
34762
+ }
34763
+ };
34764
+ function emptyEveTraceState() {
34765
+ return {
34766
+ llmInputs: [],
34767
+ metadata: {},
34768
+ spanReferences: [],
34769
+ stepStarts: []
34770
+ };
34771
+ }
34772
+ function normalizeEveTraceState(state) {
34773
+ if (!isObject(state)) {
34774
+ return emptyEveTraceState();
34775
+ }
34776
+ const metadata = isObject(state["metadata"]) ? state["metadata"] : {};
34777
+ const spanReferences = Array.isArray(state["spanReferences"]) ? state["spanReferences"].flatMap((entry) => {
34778
+ if (!isObject(entry)) {
34779
+ return [];
34780
+ }
34781
+ const exported = entry["exported"];
34782
+ const endTime = entry["endTime"];
34783
+ const rootSpanId = entry["rootSpanId"];
34784
+ const rowId = entry["rowId"];
34785
+ const spanId = entry["spanId"];
34786
+ const startEvent = entry["startEvent"];
34787
+ const startEventCreated = isObject(startEvent) ? startEvent["created"] : void 0;
34788
+ const startEventMetrics = isObject(startEvent) ? startEvent["metrics"] : void 0;
34789
+ const startEventSpanAttributes = isObject(startEvent) ? startEvent["span_attributes"] : void 0;
34790
+ const startEventSpanParents = isObject(startEvent) ? startEvent["span_parents"] : void 0;
34791
+ const normalizedStartEvent = typeof startEventCreated === "string" && isObject(startEventMetrics) && typeof startEventMetrics["start"] === "number" && Number.isFinite(startEventMetrics["start"]) && isObject(startEventSpanAttributes) && Array.isArray(startEventSpanParents) && startEventSpanParents.every(
34792
+ (parent) => typeof parent === "string"
34793
+ ) ? {
34794
+ created: startEventCreated,
34795
+ metrics: { start: startEventMetrics["start"] },
34796
+ span_attributes: { ...startEventSpanAttributes },
34797
+ span_parents: [...startEventSpanParents]
34798
+ } : void 0;
34799
+ return typeof exported === "string" && typeof rootSpanId === "string" && typeof rowId === "string" && typeof spanId === "string" ? [
34800
+ {
34801
+ ...typeof endTime === "number" && Number.isFinite(endTime) ? { endTime } : {},
34802
+ exported,
34803
+ rootSpanId,
34804
+ rowId,
34805
+ spanId,
34806
+ ...normalizedStartEvent ? { startEvent: normalizedStartEvent } : {}
34807
+ }
34808
+ ] : [];
34809
+ }).slice(-MAX_STORED_SPAN_REFERENCES) : [];
34810
+ const llmInputs = Array.isArray(state["llmInputs"]) ? state["llmInputs"].flatMap((entry) => {
34811
+ if (!isObject(entry)) {
34812
+ return [];
34813
+ }
34814
+ const key = entry["key"];
34815
+ const input = entry["input"];
34816
+ return typeof key === "string" && isCapturedModelInput(input) ? [{ input, key }] : [];
34817
+ }).slice(-MAX_STORED_LLM_INPUTS) : [];
34818
+ const stepStarts = Array.isArray(state["stepStarts"]) ? state["stepStarts"].flatMap((entry) => {
34819
+ if (!isObject(entry)) {
34820
+ return [];
34821
+ }
34822
+ const ordinal = entry["ordinal"];
34823
+ const open = entry["open"];
34824
+ const stepIndex = entry["stepIndex"];
34825
+ const turnId = entry["turnId"];
34826
+ return typeof ordinal === "number" && Number.isInteger(ordinal) && ordinal >= 0 && typeof open === "boolean" && typeof stepIndex === "number" && Number.isInteger(stepIndex) && typeof turnId === "string" ? [{ open, ordinal, stepIndex, turnId }] : [];
34827
+ }).slice(-MAX_STORED_STEP_STARTS) : [];
34828
+ return { llmInputs, metadata: { ...metadata }, spanReferences, stepStarts };
34829
+ }
34830
+ function readEveTraceState(state) {
34831
+ try {
34832
+ return normalizeEveTraceState(state.get());
34833
+ } catch {
34834
+ return emptyEveTraceState();
34835
+ }
34836
+ }
34837
+ function captureEveModelInput(state, input) {
34838
+ if (!isObject(input)) {
34839
+ return;
34840
+ }
34841
+ const session = input["session"];
34842
+ const turn = input["turn"];
34843
+ const step = input["step"];
34844
+ if (!isObject(session) || !isObject(turn) || !isObject(step)) {
34845
+ return;
34846
+ }
34847
+ const sessionId = session["id"];
34848
+ const turnId = turn["id"];
34849
+ const stepIndex = step["index"];
34850
+ if (typeof sessionId !== "string" || typeof turnId !== "string" || typeof stepIndex !== "number" || !Number.isInteger(stepIndex)) {
34851
+ return;
34852
+ }
34853
+ const captured = capturedModelInput(input["modelInput"]);
34854
+ if (!captured) {
34855
+ return;
34856
+ }
34857
+ const key = llmInputKey(sessionId, turnId, stepIndex);
34858
+ state.update((current) => {
34859
+ const normalized = normalizeEveTraceState(current);
34860
+ const llmInputs = [...normalized.llmInputs, { input: captured, key }];
34861
+ return {
34862
+ ...normalized,
34863
+ llmInputs: llmInputs.slice(-MAX_STORED_LLM_INPUTS)
34864
+ };
34865
+ });
34866
+ }
34867
+ function consumeCapturedEveModelInput(state, sessionId, turnId, stepIndex) {
34868
+ try {
34869
+ const key = llmInputKey(sessionId, turnId, stepIndex);
34870
+ let input;
34871
+ state.update((current) => {
34872
+ const normalized = normalizeEveTraceState(current);
34873
+ const index = normalized.llmInputs.findIndex(
34874
+ (candidate) => candidate.key === key
34875
+ );
34876
+ if (index < 0) {
34877
+ return normalized;
34878
+ }
34879
+ input = normalized.llmInputs[index]?.input;
34880
+ return {
34881
+ ...normalized,
34882
+ llmInputs: normalized.llmInputs.filter(
34883
+ (_, candidateIndex) => candidateIndex !== index
34884
+ )
34885
+ };
34886
+ });
34887
+ return input;
34888
+ } catch (error) {
34889
+ debugLogger.warn("Error in Eve LLM input consumption:", error);
34890
+ return void 0;
34891
+ }
34892
+ }
34893
+ function capturedModelInput(modelInput) {
34894
+ if (!isObject(modelInput)) {
34895
+ return void 0;
34896
+ }
34897
+ const messages = modelInput["messages"];
34898
+ if (!Array.isArray(messages)) {
34899
+ return void 0;
34900
+ }
34901
+ const instructions = modelInput["instructions"];
34902
+ const value = [
34903
+ ...instructions !== void 0 ? [{ content: instructions, role: "system" }] : [],
34904
+ ...messages
34905
+ ];
34906
+ try {
34907
+ const cloned = JSON.parse(JSON.stringify(value));
34908
+ if (!Array.isArray(cloned)) {
34909
+ return void 0;
34910
+ }
34911
+ return cloned;
34912
+ } catch {
34913
+ return void 0;
34914
+ }
34915
+ }
34916
+ function isCapturedModelInput(input) {
34917
+ return Array.isArray(input);
34918
+ }
34919
+ function llmInputKey(sessionId, turnId, stepIndex) {
34920
+ return `${sessionId}\0${turnId}\0${stepIndex}`;
34921
+ }
34922
+ function modelMetadataFromRuntime(runtime) {
34923
+ if (!isObject(runtime)) {
34924
+ return {};
34925
+ }
34926
+ const modelId = runtime["modelId"];
34927
+ return typeof modelId === "string" && !modelId.trim().startsWith("dynamic:") ? modelMetadataFromModelId(modelId) : {};
34928
+ }
34929
+ function modelMetadataFromModelId(modelId) {
34930
+ const normalized = modelId.trim();
34931
+ if (!normalized) {
34932
+ return {};
34933
+ }
34934
+ const slashIndex = normalized.indexOf("/");
34935
+ if (slashIndex > 0 && slashIndex < normalized.length - 1) {
34936
+ return {
34937
+ model: normalized.slice(slashIndex + 1),
34938
+ provider: normalized.slice(0, slashIndex)
34939
+ };
34940
+ }
34941
+ return {
34942
+ model: normalized
34943
+ };
34944
+ }
34945
+ function sessionIdFromContext(ctx) {
34946
+ if (!isObject(ctx)) {
34947
+ return void 0;
34948
+ }
34949
+ const session = ctx["session"];
34950
+ if (!isObject(session)) {
34951
+ return void 0;
34952
+ }
34953
+ const id = session["id"];
34954
+ return typeof id === "string" ? id : void 0;
34955
+ }
34956
+ function toolMetadataFromTurn(turn) {
34957
+ const { model: _model, provider: _provider, ...metadata } = turn.metadata;
34958
+ return metadata;
34959
+ }
34960
+ function isToolCallAction(action) {
34961
+ return isObject(action) && action["kind"] === "tool-call" && typeof action["callId"] === "string" && typeof action["toolName"] === "string" && isObject(action["input"]);
34962
+ }
34963
+ function isLocalSubagentCallAction(action) {
34964
+ return isObject(action) && action["kind"] === "subagent-call" && typeof action["callId"] === "string" && isObject(action["input"]);
34965
+ }
34966
+ function isTraceableActionRequest(action) {
34967
+ return isToolCallAction(action) || isLocalSubagentCallAction(action);
34968
+ }
34969
+ function isToolResult(result) {
34970
+ return isObject(result) && result["kind"] === "tool-result" && typeof result["callId"] === "string" && typeof result["toolName"] === "string";
34971
+ }
34972
+ function isSubagentResult(result) {
34973
+ return isObject(result) && result["kind"] === "subagent-result" && typeof result["callId"] === "string" && typeof result["subagentName"] === "string";
34974
+ }
34975
+ function normalizedFinishReason(finishReason) {
34976
+ switch (finishReason) {
34977
+ case "content-filter":
34978
+ return "content_filter";
34979
+ case "tool-calls":
34980
+ return "tool_calls";
34981
+ default:
34982
+ return finishReason;
34983
+ }
34984
+ }
34985
+ function errorFromMessage(message, code, details) {
34986
+ const error = new Error(`${code}: ${message}`);
34987
+ if (details !== void 0) {
34988
+ error.cause = details;
34989
+ }
34990
+ return error;
34991
+ }
34992
+ function actionResultError(error, output) {
34993
+ if (error) {
34994
+ return errorFromMessage(error.message, error.code);
34995
+ }
34996
+ const result = new Error("Eve action failed");
34997
+ if (output !== void 0) {
34998
+ result.cause = output;
34999
+ }
35000
+ return result;
35001
+ }
35002
+ function eventTime2(event) {
35003
+ if (!event.meta?.at) {
35004
+ return void 0;
35005
+ }
35006
+ const timestamp = Date.parse(event.meta.at);
35007
+ return Number.isFinite(timestamp) ? timestamp / 1e3 : void 0;
35008
+ }
35009
+ function turnKey2(sessionId, turnId) {
35010
+ return `${sessionId}:${turnId}`;
35011
+ }
35012
+ function toolKey3(sessionId, callId) {
35013
+ return `${sessionId}:${callId}`;
35014
+ }
35015
+ async function generateEveIds(kind, ...parts) {
35016
+ const [rowId, spanId] = await Promise.all([
35017
+ deterministicEveId(`eve:row:${kind}`, ...parts),
35018
+ deterministicEveId(`eve:${kind}`, ...parts)
35019
+ ]);
35020
+ return { rowId, spanId };
35021
+ }
35022
+ async function deterministicEveId(...parts) {
35023
+ const data = new TextEncoder().encode(
35024
+ parts.map((part) => `${part.length}:${part}`).join("\0")
35025
+ );
35026
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", data);
35027
+ const bytes = Array.from(new Uint8Array(digest, 0, 16));
35028
+ const hex = bytes.map((byte) => byte.toString(16).padStart(2, "0")).join("");
35029
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
35030
+ }
35031
+
32892
35032
  // src/typed-instrumentation-helpers.ts
32893
35033
  var TypedApplyProxy = Proxy;
32894
35034
 
@@ -33051,6 +35191,15 @@ function modelMetrics(attributes) {
33051
35191
  }
33052
35192
  return Object.keys(out).length > 0 ? out : void 0;
33053
35193
  }
35194
+ function timeToFirstTokenSeconds(attributes, spanStartSeconds) {
35195
+ if (!isObject(attributes)) return void 0;
35196
+ if (spanStartSeconds === void 0) return void 0;
35197
+ const raw = attributes.completionStartTime;
35198
+ const completionStart = raw instanceof Date || typeof raw === "string" || typeof raw === "number" ? epochSeconds(raw) : void 0;
35199
+ if (completionStart === void 0) return void 0;
35200
+ const ttft = completionStart - spanStartSeconds;
35201
+ return Number.isFinite(ttft) && ttft >= 0 ? ttft : void 0;
35202
+ }
33054
35203
  function buildMetadata(exported) {
33055
35204
  const out = {};
33056
35205
  if (exported.entityId !== void 0) out.entity_id = exported.entityId;
@@ -33120,7 +35269,13 @@ var BraintrustObservabilityExporter = class {
33120
35269
  const args = {
33121
35270
  name: exported.name,
33122
35271
  spanAttributes: { type: spanTypeFor(exported.type) },
33123
- startTime: epochSeconds(exported.startTime)
35272
+ startTime: epochSeconds(exported.startTime),
35273
+ // Use the Mastra span id as the Braintrust row id so that
35274
+ // `logFeedback({ id: <mastra span id> })` (and Mastra's score events)
35275
+ // attach to the right row. Without this, `SpanImpl` auto-generates a
35276
+ // row id (`this._id = eventId ?? idGenerator.getSpanId()`) that no
35277
+ // external caller could know.
35278
+ event: { id: exported.id }
33124
35279
  };
33125
35280
  const parentRecord = exported.parentSpanId ? this.spans.get(exported.parentSpanId) : void 0;
33126
35281
  if (!this.capturedParent) {
@@ -33169,8 +35324,15 @@ var BraintrustObservabilityExporter = class {
33169
35324
  event.metadata = metadata;
33170
35325
  }
33171
35326
  const metrics = modelMetrics(exported.attributes);
33172
- if (metrics) {
33173
- event.metrics = metrics;
35327
+ const ttft = timeToFirstTokenSeconds(
35328
+ exported.attributes,
35329
+ epochSeconds(exported.startTime)
35330
+ );
35331
+ if (metrics || ttft !== void 0) {
35332
+ event.metrics = {
35333
+ ...metrics ?? {},
35334
+ ...ttft !== void 0 ? { time_to_first_token: ttft } : {}
35335
+ };
33174
35336
  }
33175
35337
  if (Object.keys(event).length > 0) {
33176
35338
  record.span.log(event);
@@ -34049,17 +36211,17 @@ function wrapGenkit(genkit) {
34049
36211
  console.warn("Unsupported Genkit object. Not wrapping.");
34050
36212
  return genkit;
34051
36213
  }
34052
- function isRecord2(value) {
36214
+ function isRecord3(value) {
34053
36215
  return typeof value === "object" && value !== null;
34054
36216
  }
34055
36217
  function isPropertyBag(value) {
34056
- return isRecord2(value) || typeof value === "function";
36218
+ return isRecord3(value) || typeof value === "function";
34057
36219
  }
34058
36220
  function hasFunction(value, methodName) {
34059
36221
  return isPropertyBag(value) && methodName in value && typeof value[methodName] === "function";
34060
36222
  }
34061
36223
  function isGenkitInstance(value) {
34062
- return isRecord2(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
36224
+ return isRecord3(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
34063
36225
  }
34064
36226
  function isGenkitModule(value) {
34065
36227
  return hasFunction(value, "genkit");
@@ -34113,7 +36275,7 @@ function patchGenkitRegistry(instance) {
34113
36275
  patchGenkitRegistryConstructor(registry2);
34114
36276
  }
34115
36277
  function patchGenkitRegistryLookup(registry2) {
34116
- if (!isRecord2(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
36278
+ if (!isRecord3(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
34117
36279
  return;
34118
36280
  }
34119
36281
  const originalLookupAction = registry2.lookupAction;
@@ -34139,7 +36301,7 @@ function patchGenkitRegistryLookup(registry2) {
34139
36301
  }
34140
36302
  }
34141
36303
  function patchGenkitRegistryConstructor(registry2) {
34142
- if (!isRecord2(registry2)) {
36304
+ if (!isRecord3(registry2)) {
34143
36305
  return;
34144
36306
  }
34145
36307
  const constructor = registry2.constructor;
@@ -34155,7 +36317,7 @@ function patchGenkitRegistryConstructor(registry2) {
34155
36317
  configurable: true,
34156
36318
  value: (...args) => {
34157
36319
  const childRegistry = originalWithParent.apply(constructor, args);
34158
- if (args.some((arg) => isRecord2(arg) && hasRegistryPatchedFlag(arg))) {
36320
+ if (args.some((arg) => isRecord3(arg) && hasRegistryPatchedFlag(arg))) {
34159
36321
  patchGenkitRegistryLookup(childRegistry);
34160
36322
  patchGenkitRegistryConstructor(childRegistry);
34161
36323
  }
@@ -34254,7 +36416,7 @@ function hasRegistryConstructorPatchedFlag(value) {
34254
36416
  );
34255
36417
  }
34256
36418
  function isPromiseLike2(value) {
34257
- return isRecord2(value) && "then" in value && typeof value.then === "function";
36419
+ return isRecord3(value) && "then" in value && typeof value.then === "function";
34258
36420
  }
34259
36421
 
34260
36422
  // src/wrappers/huggingface.ts
@@ -34617,14 +36779,14 @@ function wrapMistral(mistral) {
34617
36779
  console.warn("Unsupported Mistral library. Not wrapping.");
34618
36780
  return mistral;
34619
36781
  }
34620
- function isRecord3(value) {
36782
+ function isRecord4(value) {
34621
36783
  return typeof value === "object" && value !== null;
34622
36784
  }
34623
36785
  function hasFunction3(value, methodName) {
34624
- return isRecord3(value) && methodName in value && typeof value[methodName] === "function";
36786
+ return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
34625
36787
  }
34626
36788
  function isSupportedMistralClient(value) {
34627
- if (!isRecord3(value)) {
36789
+ if (!isRecord4(value)) {
34628
36790
  return false;
34629
36791
  }
34630
36792
  return value.chat !== void 0 && hasChat(value.chat) || value.embeddings !== void 0 && hasEmbeddings(value.embeddings) || value.fim !== void 0 && hasFim(value.fim) || value.agents !== void 0 && hasAgents(value.agents) || value.classifiers !== void 0 && hasClassifiers(value.classifiers);
@@ -34808,14 +36970,14 @@ function wrapCohere(cohere) {
34808
36970
  return cohere;
34809
36971
  }
34810
36972
  var cohereProxyCache = /* @__PURE__ */ new WeakMap();
34811
- function isRecord4(value) {
36973
+ function isRecord5(value) {
34812
36974
  return typeof value === "object" && value !== null;
34813
36975
  }
34814
36976
  function hasFunction4(value, methodName) {
34815
- return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
36977
+ return isRecord5(value) && methodName in value && typeof value[methodName] === "function";
34816
36978
  }
34817
36979
  function isSupportedCohereClient(value) {
34818
- if (!isRecord4(value)) {
36980
+ if (!isRecord5(value)) {
34819
36981
  return false;
34820
36982
  }
34821
36983
  return hasFunction4(value, "chat") || hasFunction4(value, "chatStream") || hasFunction4(value, "embed") || hasFunction4(value, "rerank");
@@ -34875,20 +37037,20 @@ function wrapGroq(groq) {
34875
37037
  console.warn("Unsupported Groq library. Not wrapping.");
34876
37038
  return groq;
34877
37039
  }
34878
- function isRecord5(value) {
37040
+ function isRecord6(value) {
34879
37041
  return typeof value === "object" && value !== null;
34880
37042
  }
34881
37043
  function hasFunction5(value, methodName) {
34882
- return isRecord5(value) && methodName in value && typeof value[methodName] === "function";
37044
+ return isRecord6(value) && methodName in value && typeof value[methodName] === "function";
34883
37045
  }
34884
37046
  function hasChat2(value) {
34885
- return isRecord5(value) && isRecord5(value.completions) && hasFunction5(value.completions, "create");
37047
+ return isRecord6(value) && isRecord6(value.completions) && hasFunction5(value.completions, "create");
34886
37048
  }
34887
37049
  function hasEmbeddings2(value) {
34888
37050
  return hasFunction5(value, "create");
34889
37051
  }
34890
37052
  function isSupportedGroqClient(value) {
34891
- return isRecord5(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
37053
+ return isRecord6(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
34892
37054
  }
34893
37055
  function groqProxy(groq) {
34894
37056
  const privateMethodWorkaroundCache = /* @__PURE__ */ new WeakMap();
@@ -34971,11 +37133,11 @@ var BEDROCK_RUNTIME_OPERATION_METHODS = /* @__PURE__ */ new Set([
34971
37133
  "invokeModelWithBidirectionalStream",
34972
37134
  "invokeModelWithResponseStream"
34973
37135
  ]);
34974
- function isRecord6(value) {
37136
+ function isRecord7(value) {
34975
37137
  return typeof value === "object" && value !== null;
34976
37138
  }
34977
37139
  function isSupportedBedrockRuntimeClient(value) {
34978
- return isRecord6(value) && typeof value.send === "function";
37140
+ return isRecord7(value) && typeof value.send === "function";
34979
37141
  }
34980
37142
  function bedrockRuntimeProxy(client) {
34981
37143
  const cached = bedrockRuntimeProxyCache.get(client);
@@ -35094,6 +37256,271 @@ function wrappedResumeSession(client) {
35094
37256
  );
35095
37257
  }
35096
37258
 
37259
+ // src/wrappers/langsmith.ts
37260
+ var WRAPPED_CLIENT_CLASS = /* @__PURE__ */ Symbol.for(
37261
+ "braintrust.langsmith.wrapped-client-class"
37262
+ );
37263
+ var WRAPPED_CLIENT_INSTANCE = /* @__PURE__ */ Symbol.for(
37264
+ "braintrust.langsmith.wrapped-client-instance"
37265
+ );
37266
+ var WRAPPED_CLIENT_NAMESPACE = /* @__PURE__ */ Symbol.for(
37267
+ "braintrust.langsmith.wrapped-client-namespace"
37268
+ );
37269
+ var WRAPPED_RUN_TREE_CLASS = /* @__PURE__ */ Symbol.for(
37270
+ "braintrust.langsmith.wrapped-run-tree-class"
37271
+ );
37272
+ var WRAPPED_RUN_TREE_INSTANCE = /* @__PURE__ */ Symbol.for(
37273
+ "braintrust.langsmith.wrapped-run-tree-instance"
37274
+ );
37275
+ var WRAPPED_RUN_TREES_NAMESPACE = /* @__PURE__ */ Symbol.for(
37276
+ "braintrust.langsmith.wrapped-run-trees-namespace"
37277
+ );
37278
+ var WRAPPED_TRACEABLE = /* @__PURE__ */ Symbol.for("braintrust.langsmith.wrapped-traceable");
37279
+ var WRAPPED_TRACEABLE_NAMESPACE = /* @__PURE__ */ Symbol.for(
37280
+ "braintrust.langsmith.wrapped-traceable-namespace"
37281
+ );
37282
+ function wrapLangSmithTraceable(namespace) {
37283
+ return wrapNamespaceExport(
37284
+ namespace,
37285
+ "traceable",
37286
+ WRAPPED_TRACEABLE_NAMESPACE,
37287
+ (value) => wrapTraceable(value)
37288
+ );
37289
+ }
37290
+ function wrapLangSmithRunTrees(namespace) {
37291
+ return wrapNamespaceExport(
37292
+ namespace,
37293
+ "RunTree",
37294
+ WRAPPED_RUN_TREES_NAMESPACE,
37295
+ (value) => wrapRunTreeClass(value)
37296
+ );
37297
+ }
37298
+ function wrapLangSmithClient(namespace) {
37299
+ return wrapNamespaceExport(
37300
+ namespace,
37301
+ "Client",
37302
+ WRAPPED_CLIENT_NAMESPACE,
37303
+ (value) => wrapClientClass(value)
37304
+ );
37305
+ }
37306
+ function wrapNamespaceExport(namespace, exportName, marker, wrap2) {
37307
+ if (!namespace || typeof namespace !== "object") {
37308
+ return namespace;
37309
+ }
37310
+ const candidate = namespace;
37311
+ if (candidate[marker] === true) {
37312
+ return namespace;
37313
+ }
37314
+ if (typeof candidate[exportName] !== "function") {
37315
+ console.warn(
37316
+ `Unsupported LangSmith ${exportName} namespace. Not wrapping.`
37317
+ );
37318
+ return namespace;
37319
+ }
37320
+ const target = isModuleNamespace5(namespace) ? Object.setPrototypeOf({}, namespace) : candidate;
37321
+ const moduleNamespace = target !== candidate;
37322
+ let wrappedExport;
37323
+ return new Proxy(target, {
37324
+ get(target2, prop, receiver) {
37325
+ if (prop === marker) {
37326
+ return true;
37327
+ }
37328
+ const value = Reflect.get(target2, prop, receiver);
37329
+ if (prop !== exportName || typeof value !== "function") {
37330
+ return value;
37331
+ }
37332
+ wrappedExport ??= wrap2(value);
37333
+ return wrappedExport;
37334
+ },
37335
+ getOwnPropertyDescriptor(target2, prop) {
37336
+ const descriptor = Reflect.getOwnPropertyDescriptor(target2, prop);
37337
+ if (descriptor || !moduleNamespace) {
37338
+ return descriptor;
37339
+ }
37340
+ const namespaceDescriptor = Reflect.getOwnPropertyDescriptor(
37341
+ candidate,
37342
+ prop
37343
+ );
37344
+ return namespaceDescriptor ? { ...namespaceDescriptor, configurable: true } : void 0;
37345
+ },
37346
+ has(target2, prop) {
37347
+ return Reflect.has(target2, prop) || moduleNamespace && prop in candidate;
37348
+ },
37349
+ ownKeys(target2) {
37350
+ return moduleNamespace ? Reflect.ownKeys(candidate) : Reflect.ownKeys(target2);
37351
+ }
37352
+ });
37353
+ }
37354
+ function isModuleNamespace5(value) {
37355
+ if (!value || typeof value !== "object") {
37356
+ return false;
37357
+ }
37358
+ if (value.constructor?.name === "Module") {
37359
+ return true;
37360
+ }
37361
+ const firstKey = Object.keys(value)[0];
37362
+ if (!firstKey) {
37363
+ return false;
37364
+ }
37365
+ const descriptor = Object.getOwnPropertyDescriptor(value, firstKey);
37366
+ return descriptor ? !descriptor.configurable && !descriptor.writable : false;
37367
+ }
37368
+ function wrapTraceable(traceable2) {
37369
+ if (traceable2[WRAPPED_TRACEABLE]) {
37370
+ return traceable2;
37371
+ }
37372
+ return new Proxy(traceable2, {
37373
+ get(target, prop, receiver) {
37374
+ if (prop === WRAPPED_TRACEABLE) {
37375
+ return true;
37376
+ }
37377
+ return Reflect.get(target, prop, receiver);
37378
+ },
37379
+ apply(target, thisArg, argArray) {
37380
+ const [fn, rawConfig] = argArray;
37381
+ const config = rawConfig && typeof rawConfig === "object" ? rawConfig : void 0;
37382
+ const originalOnEnd = config?.on_end;
37383
+ const wrappedConfig = {
37384
+ ...config,
37385
+ on_end(runTree) {
37386
+ publishRunUpdate(runTree);
37387
+ if (originalOnEnd) {
37388
+ Reflect.apply(originalOnEnd, config, [runTree]);
37389
+ }
37390
+ }
37391
+ };
37392
+ return Reflect.apply(target, thisArg, [fn, wrappedConfig]);
37393
+ }
37394
+ });
37395
+ }
37396
+ function wrapRunTreeClass(RunTree) {
37397
+ if (RunTree[WRAPPED_RUN_TREE_CLASS]) {
37398
+ return RunTree;
37399
+ }
37400
+ return new Proxy(RunTree, {
37401
+ get(target, prop, receiver) {
37402
+ if (prop === WRAPPED_RUN_TREE_CLASS) {
37403
+ return true;
37404
+ }
37405
+ const value = Reflect.get(target, prop, receiver);
37406
+ return typeof value === "function" ? value.bind(target) : value;
37407
+ },
37408
+ construct(target, args, newTarget) {
37409
+ return wrapRunTreeInstance(Reflect.construct(target, args, newTarget));
37410
+ }
37411
+ });
37412
+ }
37413
+ function wrapRunTreeInstance(runTree) {
37414
+ if (runTree[WRAPPED_RUN_TREE_INSTANCE]) {
37415
+ return runTree;
37416
+ }
37417
+ return new Proxy(runTree, {
37418
+ get(target, prop, receiver) {
37419
+ if (prop === WRAPPED_RUN_TREE_INSTANCE) {
37420
+ return true;
37421
+ }
37422
+ const value = Reflect.get(target, prop, receiver);
37423
+ if (typeof value !== "function") {
37424
+ return value;
37425
+ }
37426
+ let wrapped;
37427
+ if (prop === "createChild") {
37428
+ wrapped = (...args) => wrapRunTreeInstance(Reflect.apply(value, target, args));
37429
+ } else if (prop === "postRun") {
37430
+ const method = value;
37431
+ wrapped = (...args) => langSmithChannels.createRun.tracePromise(
37432
+ () => Reflect.apply(method, target, args),
37433
+ { arguments: [target] }
37434
+ );
37435
+ } else if (prop === "patchRun") {
37436
+ const method = value;
37437
+ wrapped = (...args) => langSmithChannels.updateRun.tracePromise(
37438
+ () => Reflect.apply(method, target, args),
37439
+ {
37440
+ arguments: [
37441
+ typeof target.id === "string" ? target.id : "",
37442
+ target
37443
+ ]
37444
+ }
37445
+ );
37446
+ } else {
37447
+ wrapped = value.bind(target);
37448
+ }
37449
+ return wrapped;
37450
+ }
37451
+ });
37452
+ }
37453
+ function wrapClientClass(Client) {
37454
+ if (Client[WRAPPED_CLIENT_CLASS]) {
37455
+ return Client;
37456
+ }
37457
+ return new Proxy(Client, {
37458
+ get(target, prop, receiver) {
37459
+ if (prop === WRAPPED_CLIENT_CLASS) {
37460
+ return true;
37461
+ }
37462
+ const value = Reflect.get(target, prop, receiver);
37463
+ return typeof value === "function" ? value.bind(target) : value;
37464
+ },
37465
+ construct(target, args, newTarget) {
37466
+ return wrapClientInstance(Reflect.construct(target, args, newTarget));
37467
+ }
37468
+ });
37469
+ }
37470
+ function wrapClientInstance(client) {
37471
+ if (client[WRAPPED_CLIENT_INSTANCE]) {
37472
+ return client;
37473
+ }
37474
+ return new Proxy(client, {
37475
+ get(target, prop, receiver) {
37476
+ if (prop === WRAPPED_CLIENT_INSTANCE) {
37477
+ return true;
37478
+ }
37479
+ const value = Reflect.get(target, prop, receiver);
37480
+ if (typeof value !== "function") {
37481
+ return value;
37482
+ }
37483
+ let wrapped;
37484
+ if (prop === "createRun") {
37485
+ const method = value;
37486
+ wrapped = (...args) => langSmithChannels.createRun.tracePromise(
37487
+ () => Reflect.apply(method, target, args),
37488
+ { arguments: args }
37489
+ );
37490
+ } else if (prop === "updateRun") {
37491
+ const method = value;
37492
+ wrapped = (...args) => langSmithChannels.updateRun.tracePromise(
37493
+ () => Reflect.apply(method, target, args),
37494
+ { arguments: args }
37495
+ );
37496
+ } else if (prop === "batchIngestRuns") {
37497
+ const method = value;
37498
+ wrapped = (...args) => langSmithChannels.batchIngestRuns.tracePromise(
37499
+ () => Reflect.apply(method, target, args),
37500
+ { arguments: args }
37501
+ );
37502
+ } else {
37503
+ wrapped = value.bind(target);
37504
+ }
37505
+ return wrapped;
37506
+ }
37507
+ });
37508
+ }
37509
+ function publishRunUpdate(runTree) {
37510
+ if (!runTree || typeof runTree.id !== "string" || !runTree.id) {
37511
+ return;
37512
+ }
37513
+ try {
37514
+ void langSmithChannels.updateRun.tracePromise(() => Promise.resolve(void 0), {
37515
+ arguments: [runTree.id, runTree]
37516
+ }).catch((error) => {
37517
+ debugLogger.error("LangSmith traceable instrumentation failed:", error);
37518
+ });
37519
+ } catch (error) {
37520
+ debugLogger.error("LangSmith traceable instrumentation failed:", error);
37521
+ }
37522
+ }
37523
+
35097
37524
  // src/wrappers/vitest/context-manager.ts
35098
37525
  var VitestContextManager = class {
35099
37526
  /**
@@ -39455,6 +41882,8 @@ export {
39455
41882
  addAzureBlobHeaders,
39456
41883
  agentAssertionScorer,
39457
41884
  braintrustAISDKTelemetry,
41885
+ braintrustEveHook,
41886
+ braintrustEveInstrumentation,
39458
41887
  braintrustFlueInstrumentation,
39459
41888
  braintrustFlueObserver,
39460
41889
  braintrustStreamChunkSchema,
@@ -39545,6 +41974,9 @@ export {
39545
41974
  wrapGoogleGenAI,
39546
41975
  wrapGroq,
39547
41976
  wrapHuggingFace,
41977
+ wrapLangSmithClient,
41978
+ wrapLangSmithRunTrees,
41979
+ wrapLangSmithTraceable,
39548
41980
  wrapMastraAgent,
39549
41981
  wrapMistral,
39550
41982
  wrapOpenAI,