bitfab 0.54.14 → 0.57.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,9 +17,10 @@ import {
17
17
  serializeValue,
18
18
  toJsonSafe,
19
19
  toJsonSafeReport
20
- } from "./chunk-X6JOFMNV.js";
20
+ } from "./chunk-6C2SC7HK.js";
21
21
  import {
22
22
  BitfabError,
23
+ CONTENT_OFF_KEY,
23
24
  DEFAULT_SERVICE_URL,
24
25
  HttpClient,
25
26
  MixedTracingError,
@@ -28,12 +29,15 @@ import {
28
29
  callerTraceMetadata,
29
30
  getReplayContext,
30
31
  gitRunner,
32
+ isFrameworkInstrumentation,
31
33
  makeSpanOrigin,
32
34
  readEnv,
33
35
  recordCallerTraceMetadata,
36
+ recordedByFramework,
34
37
  retireTraceMetadata,
38
+ traceIdOf,
35
39
  warnOnce
36
- } from "./chunk-NIGVK5V7.js";
40
+ } from "./chunk-OBZQSMPQ.js";
37
41
  import {
38
42
  __privateAdd,
39
43
  __privateGet,
@@ -3707,6 +3711,25 @@ var BitfabVercelAiHandler = class {
3707
3711
 
3708
3712
  // src/client.ts
3709
3713
  var activeTraceStates = /* @__PURE__ */ new Map();
3714
+ function fitsTraceSpanBudget(payload) {
3715
+ if (!recordedByFramework(payload)) {
3716
+ return true;
3717
+ }
3718
+ const traceId = traceIdOf(payload);
3719
+ const spanBudget = traceId === void 0 ? void 0 : activeTraceStates.get(traceId)?.spanBudget;
3720
+ if (spanBudget === void 0) {
3721
+ return true;
3722
+ }
3723
+ if (spanBudget.spansUsed >= spanBudget.maxSpans) {
3724
+ spanBudget.truncate();
3725
+ return false;
3726
+ }
3727
+ spanBudget.spansUsed += 1;
3728
+ return true;
3729
+ }
3730
+ function rootTraceFunctionKeyOfTrace(traceId, fallback) {
3731
+ return activeTraceStates.get(traceId)?.traceFunctionKey ?? fallback;
3732
+ }
3710
3733
  function rootTraceFunctionKeyOf(payload) {
3711
3734
  const captured = payload[ROOT_TRACE_FUNCTION_KEY_FIELD];
3712
3735
  if (typeof captured === "string") {
@@ -4082,7 +4105,8 @@ function readBooleanEnv(name) {
4082
4105
  return void 0;
4083
4106
  }
4084
4107
  var DEFAULT_AUTO_TRACE_MAX_DEPTH = 30;
4085
- var DEFAULT_AUTO_TRACE_MAX_SPANS = 500;
4108
+ var DEFAULT_AUTO_TRACE_MAX_SPANS = 2048;
4109
+ var DEFAULT_AUTO_TRACE_MAX_CAPTURED_SUBTREE_SPANS = 512;
4086
4110
  var AUTO_TRACE_PROTOCOL = "ts-auto-v1";
4087
4111
  function spanOwnerName(receiver) {
4088
4112
  if (typeof receiver === "function") {
@@ -4153,6 +4177,9 @@ var Bitfab = class {
4153
4177
  this.httpClient.externalTraceTransform = (payload, submit) => this.simulationPlan.sendTrace(payload, submit);
4154
4178
  this.httpClient.releaseHeldExternalSpans = (timeoutMs) => this.simulationPlan.release(timeoutMs);
4155
4179
  this.httpClient.stopSimulationPlan = () => this.simulationPlan.stop();
4180
+ if (this.findApiKey(false) !== void 0) {
4181
+ this.simulationPlan.refresh();
4182
+ }
4156
4183
  this.datasets = new DatasetsClient(this.httpClient);
4157
4184
  this.assertionCategories = new AssertionCategoriesClient(this.httpClient);
4158
4185
  this.traces = new TracesClient(this.httpClient);
@@ -4309,10 +4336,23 @@ var Bitfab = class {
4309
4336
  options.maxDepth,
4310
4337
  DEFAULT_AUTO_TRACE_MAX_DEPTH
4311
4338
  );
4339
+ if (options.maxSpans !== void 0 && options.maxSpans < 1) {
4340
+ throw new BitfabError(
4341
+ `maxSpans must be at least 1 because the root span counts toward it (got ${options.maxSpans})`
4342
+ );
4343
+ }
4312
4344
  const maxSpans = autoTraceLimit(
4313
4345
  options.maxSpans,
4314
4346
  DEFAULT_AUTO_TRACE_MAX_SPANS
4315
4347
  );
4348
+ const maxCapturedSubtreeSpans = Math.min(
4349
+ autoTraceLimit(
4350
+ options.maxCapturedSubtreeSpans,
4351
+ DEFAULT_AUTO_TRACE_MAX_CAPTURED_SUBTREE_SPANS
4352
+ ),
4353
+ maxSpans
4354
+ );
4355
+ const rootIsAsync = fn.constructor.name === "AsyncFunction";
4316
4356
  const excluded = new Set(options.exclude ?? []);
4317
4357
  const includeWrappers = options.includeWrappers ?? false;
4318
4358
  const rootNameFor = (receiver) => options.name ?? (fn.name !== "" ? qualifiedSpanName(receiver, name) ?? name : name);
@@ -4328,7 +4368,7 @@ var Bitfab = class {
4328
4368
  spanOptions,
4329
4369
  function(...args) {
4330
4370
  self.simulationPlan.refresh();
4331
- let spansUsed = 0;
4371
+ let capturedSubtreeCount = 0;
4332
4372
  let truncated = false;
4333
4373
  const warnTruncated = () => {
4334
4374
  if (!truncated) {
@@ -4338,15 +4378,27 @@ var Bitfab = class {
4338
4378
  protocol: AUTO_TRACE_PROTOCOL,
4339
4379
  truncated: true,
4340
4380
  maxDepth,
4341
- maxSpans
4381
+ maxSpans,
4382
+ maxCapturedSubtreeSpans
4342
4383
  }
4343
4384
  });
4344
4385
  }
4345
4386
  warnOnce(
4346
4387
  `auto-trace-truncated:${traceFunctionKey}`,
4347
- `"${traceFunctionKey}" hit an automatic subtree capture limit (maxDepth=${maxDepth}, maxSpans=${maxSpans}); its trace is incomplete. Raise the limits or narrow the subtree with exclude.`
4388
+ `"${traceFunctionKey}" hit an automatic subtree capture limit (maxDepth=${maxDepth}, maxCapturedSubtreeSpans=${maxCapturedSubtreeSpans}, maxSpans=${maxSpans}); its trace is incomplete. Raise the limits, declare the calls you need with node(), or narrow the subtree with exclude.`
4348
4389
  );
4349
4390
  };
4391
+ const rootSpanStack = getSpanStack();
4392
+ const spanBudget = {
4393
+ spansUsed: 1,
4394
+ maxSpans,
4395
+ truncate: () => runWithSpanStack(rootSpanStack, warnTruncated)
4396
+ };
4397
+ const rootSpan = rootSpanStack[rootSpanStack.length - 1];
4398
+ const rootTraceState = rootSpan === void 0 ? void 0 : activeTraceStates.get(rootSpan.traceId);
4399
+ if (rootTraceState !== void 0 && rootTraceState.spanBudget === void 0) {
4400
+ rootTraceState.spanBudget = spanBudget;
4401
+ }
4350
4402
  const spanStackOf = (entry) => entry.spanStack;
4351
4403
  const openChild = (entry, childOptions, inputs, isAsync, invokeFn) => {
4352
4404
  const runInside = () => runWithAutoTraceEntry(
@@ -4375,12 +4427,25 @@ var Bitfab = class {
4375
4427
  return tracedChild(...inputs);
4376
4428
  });
4377
4429
  };
4378
- const overBudget = (entry) => {
4379
- if (entry.depth < maxDepth && spansUsed < maxSpans) {
4380
- return false;
4430
+ const rootTraceFunctionKeyOfEntry = (entry) => {
4431
+ const stack = spanStackOf(entry);
4432
+ const innermost = stack[stack.length - 1];
4433
+ return innermost === void 0 ? traceFunctionKey : rootTraceFunctionKeyOfTrace(innermost.traceId, traceFunctionKey);
4434
+ };
4435
+ const recordsSpan = (entry, spanName, declared) => {
4436
+ const countsTowardCapturedSubtree = !declared && !self.simulationPlan.contentOffNow(
4437
+ rootTraceFunctionKeyOfEntry(entry),
4438
+ spanName
4439
+ );
4440
+ if (entry.depth < maxDepth && spanBudget.spansUsed < maxSpans && (!countsTowardCapturedSubtree || capturedSubtreeCount < maxCapturedSubtreeSpans)) {
4441
+ spanBudget.spansUsed += 1;
4442
+ if (countsTowardCapturedSubtree) {
4443
+ capturedSubtreeCount += 1;
4444
+ }
4445
+ return true;
4381
4446
  }
4382
4447
  runWithSpanStack(spanStackOf(entry), warnTruncated);
4383
- return true;
4448
+ return false;
4384
4449
  };
4385
4450
  const autoTraceContext = {
4386
4451
  traceFunctionKey,
@@ -4394,13 +4459,13 @@ var Bitfab = class {
4394
4459
  if (nodeConfiguration?.capture === false) {
4395
4460
  return clearAutoTraceNodeConfiguration(invokeFn);
4396
4461
  }
4397
- if (overBudget(entry)) {
4462
+ const spanName = nodeConfiguration?.name ?? definition.name;
4463
+ if (!recordsSpan(entry, spanName, nodeConfiguration !== void 0)) {
4398
4464
  return invokeWithoutNode();
4399
4465
  }
4400
- spansUsed += 1;
4401
4466
  const mockOnReplay = nodeConfiguration?.mockOnReplay ?? options.mockOnReplayDefault;
4402
4467
  const childOptions = {
4403
- name: nodeConfiguration?.name ?? definition.name,
4468
+ name: spanName,
4404
4469
  type: nodeConfiguration?.type ?? "function",
4405
4470
  captureWhen: "nested",
4406
4471
  surface: "opt-out",
@@ -4427,10 +4492,9 @@ var Bitfab = class {
4427
4492
  );
4428
4493
  },
4429
4494
  invokeNestedRoot(nestedName, nestedFunctionName, inputs, invokeFn, entry, link) {
4430
- if (excluded.has(nestedName) || excluded.has(nestedFunctionName) || overBudget(entry)) {
4495
+ if (excluded.has(nestedName) || excluded.has(nestedFunctionName) || !recordsSpan(entry, nestedName, true)) {
4431
4496
  return invokeFn();
4432
4497
  }
4433
- spansUsed += 1;
4434
4498
  const childOptions = {
4435
4499
  name: nestedName,
4436
4500
  type: "function",
@@ -4457,6 +4521,12 @@ var Bitfab = class {
4457
4521
  }
4458
4522
  const enclosing = currentAutoTraceEntries();
4459
4523
  if (enclosing.length === 0) {
4524
+ const firstPlanRead = rootIsAsync ? self.simulationPlan.waitForFirstRead() : void 0;
4525
+ if (firstPlanRead !== void 0) {
4526
+ return firstPlanRead.then(
4527
+ () => tracedRoot.apply(this, args)
4528
+ );
4529
+ }
4460
4530
  return tracedRoot.apply(this, args);
4461
4531
  }
4462
4532
  const link = getReplayContext() || inSeedScope() ? void 0 : { traceFunctionKey };
@@ -4503,6 +4573,9 @@ var Bitfab = class {
4503
4573
  return autoTraceRoot;
4504
4574
  }
4505
4575
  applySimulationPlan(payload, submit) {
4576
+ if (!fitsTraceSpanBudget(payload)) {
4577
+ return;
4578
+ }
4506
4579
  this.simulationPlan.send(payload, rootTraceFunctionKeyOf(payload), submit);
4507
4580
  }
4508
4581
  /**
@@ -4537,15 +4610,24 @@ var Bitfab = class {
4537
4610
  * from the environment. Once a non-empty key is found it is cached, so an
4538
4611
  * early resolve that found nothing never poisons a later one.
4539
4612
  */
4540
- resolveApiKey() {
4613
+ findApiKey(callsKeyFunction) {
4541
4614
  if (this.resolvedApiKey !== void 0) {
4542
4615
  return this.resolvedApiKey;
4543
4616
  }
4617
+ if (typeof this.apiKeyConfig === "function" && !callsKeyFunction) {
4618
+ return void 0;
4619
+ }
4544
4620
  const fromConfig = typeof this.apiKeyConfig === "function" ? this.apiKeyConfig() : this.apiKeyConfig;
4545
4621
  const candidate = fromConfig && fromConfig.trim() !== "" ? fromConfig : readEnv2("BITFAB_API_KEY");
4546
4622
  const key = candidate && candidate.trim() !== "" ? candidate : void 0;
4547
4623
  if (key) {
4548
4624
  this.resolvedApiKey = key;
4625
+ }
4626
+ return key;
4627
+ }
4628
+ resolveApiKey() {
4629
+ const key = this.findApiKey(true);
4630
+ if (key) {
4549
4631
  return key;
4550
4632
  }
4551
4633
  if (this.strict) {
@@ -5165,7 +5247,10 @@ var Bitfab = class {
5165
5247
  self.httpClient.traceCompletion.start(traceId, spanId);
5166
5248
  startedSpan = { traceId, spanId };
5167
5249
  const functionName = fn.name !== "" ? fn.name : void 0;
5168
- const rootTraceFunctionKey = activeTraceStates.get(traceId)?.traceFunctionKey ?? traceFunctionKey;
5250
+ const rootTraceFunctionKey = rootTraceFunctionKeyOfTrace(
5251
+ traceId,
5252
+ traceFunctionKey
5253
+ );
5169
5254
  const baseSpanParams = {
5170
5255
  traceFunctionKey,
5171
5256
  rootTraceFunctionKey,
@@ -5687,14 +5772,25 @@ var Bitfab = class {
5687
5772
  ...params.testRunId && { testRunId: params.testRunId }
5688
5773
  });
5689
5774
  }
5775
+ contentOffBySimulationPlan(params) {
5776
+ if (params.rootTraceFunctionKey === void 0 || isFrameworkInstrumentation(params.instrumentation)) {
5777
+ return false;
5778
+ }
5779
+ return this.simulationPlan.contentOffNow(
5780
+ params.rootTraceFunctionKey,
5781
+ params.spanName
5782
+ ) || params.parentSpanId !== null && this.simulationPlan.unavailableNow();
5783
+ }
5690
5784
  /**
5691
5785
  * Send a wrapper span from function execution.
5692
5786
  * Internal method to record spans when using withSpan.
5693
5787
  * Queued on the client's span transport; delivery is the transport's job.
5694
5788
  */
5695
5789
  sendWrapperSpan(params) {
5696
- const serializedInputs = params.captureContent ? serializeValue(params.inputs) : void 0;
5697
- const serializedResult = params.captureContent ? serializeValue(params.result) : void 0;
5790
+ const contentOff = this.contentOffBySimulationPlan(params);
5791
+ const buildsContent = params.captureContent && !contentOff;
5792
+ const serializedInputs = buildsContent ? serializeValue(params.inputs) : void 0;
5793
+ const serializedResult = buildsContent ? serializeValue(params.result) : void 0;
5698
5794
  const externalSpan = {
5699
5795
  id: params.spanId,
5700
5796
  trace_id: params.traceId,
@@ -5745,7 +5841,8 @@ var Bitfab = class {
5745
5841
  ...params.captureContent && params.contexts && params.contexts.length > 0 && {
5746
5842
  contexts: params.contexts
5747
5843
  },
5748
- ...params.captureContent && params.prompt !== void 0 && { prompt: params.prompt }
5844
+ ...params.captureContent && params.prompt !== void 0 && { prompt: params.prompt },
5845
+ ...contentOff && { [CONTENT_OFF_KEY]: true }
5749
5846
  }
5750
5847
  };
5751
5848
  if (params.parentSpanId) {
@@ -5911,7 +6008,7 @@ var Bitfab = class {
5911
6008
  await runWithSeedContext({ traceId }, async () => target(...args));
5912
6009
  } finally {
5913
6010
  try {
5914
- const { flushTraces: flushTraces2 } = await import("./http-HM2SNB6L.js");
6011
+ const { flushTraces: flushTraces2 } = await import("./http-HPTD7HW6.js");
5915
6012
  await flushTraces2(3e4);
5916
6013
  } finally {
5917
6014
  unrecorded = activeTraceStates.delete(traceId);
@@ -5970,7 +6067,7 @@ var Bitfab = class {
5970
6067
  `Function is wrapped with trace function key '${wrappedKey}' but replay was called with '${traceFunctionKey}'. Pass matching keys, or pass the unwrapped function to replay it under the explicit key.`
5971
6068
  );
5972
6069
  }
5973
- const { replay: doReplay } = await import("./replay-XCXNPWMC.js");
6070
+ const { replay: doReplay } = await import("./replay-FESLQSMD.js");
5974
6071
  return doReplay(
5975
6072
  this.httpClient,
5976
6073
  this.serviceUrl,
@@ -6290,7 +6387,7 @@ async function seedFromRegistry(registry, pipeline, cases, options = {}) {
6290
6387
  sessionId: seedCase.sessionId
6291
6388
  })
6292
6389
  );
6293
- const { flushTraces: flushTraces2 } = await import("./http-HM2SNB6L.js");
6390
+ const { flushTraces: flushTraces2 } = await import("./http-HPTD7HW6.js");
6294
6391
  await flushTraces2(3e4);
6295
6392
  return { pipeline, traceFunctionKey, traceIds };
6296
6393
  }
@@ -6329,4 +6426,4 @@ export {
6329
6426
  reseedFromRegistry,
6330
6427
  seedFromRegistry
6331
6428
  };
6332
- //# sourceMappingURL=chunk-SV5FYJQ4.js.map
6429
+ //# sourceMappingURL=chunk-AEF2SRQC.js.map