bitfab 0.54.13 → 0.57.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 (34) hide show
  1. package/dist/{chunk-VW7MA7DS.js → chunk-3KWRBX56.js} +29 -17
  2. package/dist/chunk-3KWRBX56.js.map +1 -0
  3. package/dist/{chunk-Q7HDNYYY.js → chunk-56USYDIX.js} +143 -34
  4. package/dist/chunk-56USYDIX.js.map +1 -0
  5. package/dist/{chunk-KPALXSAF.js → chunk-FZNBGX2R.js} +37 -7
  6. package/dist/chunk-FZNBGX2R.js.map +1 -0
  7. package/dist/{chunk-FZNRSEMN.js → chunk-JEN5MX7A.js} +9 -3
  8. package/dist/chunk-JEN5MX7A.js.map +1 -0
  9. package/dist/{chunk-YKOD4GWI.js → chunk-YE75OWXI.js} +136 -110
  10. package/dist/chunk-YE75OWXI.js.map +1 -0
  11. package/dist/{http-7PF6XCJR.js → http-33ALYZUK.js} +2 -2
  12. package/dist/{http-42KAFBUN.js → http-HKMIFNAR.js} +2 -2
  13. package/dist/index.cjs +276 -146
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +12 -5
  16. package/dist/index.d.ts +12 -5
  17. package/dist/index.js +3 -3
  18. package/dist/node.cjs +276 -146
  19. package/dist/node.cjs.map +1 -1
  20. package/dist/node.d.cts +1 -1
  21. package/dist/node.d.ts +1 -1
  22. package/dist/node.js +3 -3
  23. package/dist/{replay-5RHBDIEK.js → replay-JCY64EHP.js} +3 -3
  24. package/dist/replayCli.js +2 -2
  25. package/dist/seedCli.js +2 -2
  26. package/package.json +1 -1
  27. package/dist/chunk-FZNRSEMN.js.map +0 -1
  28. package/dist/chunk-KPALXSAF.js.map +0 -1
  29. package/dist/chunk-Q7HDNYYY.js.map +0 -1
  30. package/dist/chunk-VW7MA7DS.js.map +0 -1
  31. package/dist/chunk-YKOD4GWI.js.map +0 -1
  32. /package/dist/{http-42KAFBUN.js.map → http-33ALYZUK.js.map} +0 -0
  33. /package/dist/{http-7PF6XCJR.js.map → http-HKMIFNAR.js.map} +0 -0
  34. /package/dist/{replay-5RHBDIEK.js.map → replay-JCY64EHP.js.map} +0 -0
@@ -17,9 +17,10 @@ import {
17
17
  serializeValue,
18
18
  toJsonSafe,
19
19
  toJsonSafeReport
20
- } from "./chunk-FZNRSEMN.js";
20
+ } from "./chunk-JEN5MX7A.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-YKOD4GWI.js";
40
+ } from "./chunk-YE75OWXI.js";
37
41
  import {
38
42
  __privateAdd,
39
43
  __privateGet,
@@ -1467,6 +1471,14 @@ var LabelsClient = class {
1467
1471
  );
1468
1472
  return response.labels;
1469
1473
  }
1474
+ /** Withhold a verdict for a trace or replay attempt whose check did not run. */
1475
+ async skip(target, testRunId) {
1476
+ return this.save({ ...target, skip: true }, testRunId);
1477
+ }
1478
+ /** Clear a previous verdict for a trace, replay attempt, or assertion. */
1479
+ async archive(target, testRunId) {
1480
+ return this.save({ ...target, archive: true }, testRunId);
1481
+ }
1470
1482
  async saveHuman(update) {
1471
1483
  const [outcome] = await this.saveHumanAll([update]);
1472
1484
  return outcome;
@@ -2375,6 +2387,15 @@ var BitfabLangGraphIntegration = class {
2375
2387
  }
2376
2388
  };
2377
2389
 
2390
+ // src/streamFinalizationError.ts
2391
+ var StreamFinalizationError = class extends Error {
2392
+ constructor(message, output) {
2393
+ super(message);
2394
+ this.output = output;
2395
+ this.name = "StreamFinalizationError";
2396
+ }
2397
+ };
2398
+
2378
2399
  // src/openaiAgentSdk.ts
2379
2400
  var BitfabOpenAIAgentHandler = class {
2380
2401
  constructor(config) {
@@ -2414,7 +2435,11 @@ var BitfabOpenAIAgentHandler = class {
2414
2435
  if (isStreaming && res?.completed) {
2415
2436
  try {
2416
2437
  await res.completed;
2417
- } catch {
2438
+ } catch (error) {
2439
+ throw new StreamFinalizationError(
2440
+ error instanceof Error ? error.message : String(error),
2441
+ res.finalOutput
2442
+ );
2418
2443
  }
2419
2444
  }
2420
2445
  return res?.finalOutput;
@@ -3154,15 +3179,6 @@ function runWithSeedContext(ctx, fn) {
3154
3179
  return fn();
3155
3180
  }
3156
3181
 
3157
- // src/streamFinalizationError.ts
3158
- var StreamFinalizationError = class extends Error {
3159
- constructor(message, output) {
3160
- super(message);
3161
- this.output = output;
3162
- this.name = "StreamFinalizationError";
3163
- }
3164
- };
3165
-
3166
3182
  // src/traces.ts
3167
3183
  var ASSERTIONS_PATH = "/api/sdk/traces/assertions";
3168
3184
  var SEARCH_PATH = "/api/sdk/traces/search";
@@ -3695,6 +3711,25 @@ var BitfabVercelAiHandler = class {
3695
3711
 
3696
3712
  // src/client.ts
3697
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
+ }
3698
3733
  function rootTraceFunctionKeyOf(payload) {
3699
3734
  const captured = payload[ROOT_TRACE_FUNCTION_KEY_FIELD];
3700
3735
  if (typeof captured === "string") {
@@ -4070,7 +4105,8 @@ function readBooleanEnv(name) {
4070
4105
  return void 0;
4071
4106
  }
4072
4107
  var DEFAULT_AUTO_TRACE_MAX_DEPTH = 30;
4073
- 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;
4074
4110
  var AUTO_TRACE_PROTOCOL = "ts-auto-v1";
4075
4111
  function spanOwnerName(receiver) {
4076
4112
  if (typeof receiver === "function") {
@@ -4141,6 +4177,9 @@ var Bitfab = class {
4141
4177
  this.httpClient.externalTraceTransform = (payload, submit) => this.simulationPlan.sendTrace(payload, submit);
4142
4178
  this.httpClient.releaseHeldExternalSpans = (timeoutMs) => this.simulationPlan.release(timeoutMs);
4143
4179
  this.httpClient.stopSimulationPlan = () => this.simulationPlan.stop();
4180
+ if (this.findApiKey(false) !== void 0) {
4181
+ this.simulationPlan.refresh();
4182
+ }
4144
4183
  this.datasets = new DatasetsClient(this.httpClient);
4145
4184
  this.assertionCategories = new AssertionCategoriesClient(this.httpClient);
4146
4185
  this.traces = new TracesClient(this.httpClient);
@@ -4297,10 +4336,23 @@ var Bitfab = class {
4297
4336
  options.maxDepth,
4298
4337
  DEFAULT_AUTO_TRACE_MAX_DEPTH
4299
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
+ }
4300
4344
  const maxSpans = autoTraceLimit(
4301
4345
  options.maxSpans,
4302
4346
  DEFAULT_AUTO_TRACE_MAX_SPANS
4303
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";
4304
4356
  const excluded = new Set(options.exclude ?? []);
4305
4357
  const includeWrappers = options.includeWrappers ?? false;
4306
4358
  const rootNameFor = (receiver) => options.name ?? (fn.name !== "" ? qualifiedSpanName(receiver, name) ?? name : name);
@@ -4316,7 +4368,7 @@ var Bitfab = class {
4316
4368
  spanOptions,
4317
4369
  function(...args) {
4318
4370
  self.simulationPlan.refresh();
4319
- let spansUsed = 0;
4371
+ let capturedSubtreeCount = 0;
4320
4372
  let truncated = false;
4321
4373
  const warnTruncated = () => {
4322
4374
  if (!truncated) {
@@ -4326,15 +4378,27 @@ var Bitfab = class {
4326
4378
  protocol: AUTO_TRACE_PROTOCOL,
4327
4379
  truncated: true,
4328
4380
  maxDepth,
4329
- maxSpans
4381
+ maxSpans,
4382
+ maxCapturedSubtreeSpans
4330
4383
  }
4331
4384
  });
4332
4385
  }
4333
4386
  warnOnce(
4334
4387
  `auto-trace-truncated:${traceFunctionKey}`,
4335
- `"${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.`
4336
4389
  );
4337
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
+ }
4338
4402
  const spanStackOf = (entry) => entry.spanStack;
4339
4403
  const openChild = (entry, childOptions, inputs, isAsync, invokeFn) => {
4340
4404
  const runInside = () => runWithAutoTraceEntry(
@@ -4363,12 +4427,25 @@ var Bitfab = class {
4363
4427
  return tracedChild(...inputs);
4364
4428
  });
4365
4429
  };
4366
- const overBudget = (entry) => {
4367
- if (entry.depth < maxDepth && spansUsed < maxSpans) {
4368
- 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;
4369
4446
  }
4370
4447
  runWithSpanStack(spanStackOf(entry), warnTruncated);
4371
- return true;
4448
+ return false;
4372
4449
  };
4373
4450
  const autoTraceContext = {
4374
4451
  traceFunctionKey,
@@ -4382,13 +4459,13 @@ var Bitfab = class {
4382
4459
  if (nodeConfiguration?.capture === false) {
4383
4460
  return clearAutoTraceNodeConfiguration(invokeFn);
4384
4461
  }
4385
- if (overBudget(entry)) {
4462
+ const spanName = nodeConfiguration?.name ?? definition.name;
4463
+ if (!recordsSpan(entry, spanName, nodeConfiguration !== void 0)) {
4386
4464
  return invokeWithoutNode();
4387
4465
  }
4388
- spansUsed += 1;
4389
4466
  const mockOnReplay = nodeConfiguration?.mockOnReplay ?? options.mockOnReplayDefault;
4390
4467
  const childOptions = {
4391
- name: nodeConfiguration?.name ?? definition.name,
4468
+ name: spanName,
4392
4469
  type: nodeConfiguration?.type ?? "function",
4393
4470
  captureWhen: "nested",
4394
4471
  surface: "opt-out",
@@ -4415,10 +4492,9 @@ var Bitfab = class {
4415
4492
  );
4416
4493
  },
4417
4494
  invokeNestedRoot(nestedName, nestedFunctionName, inputs, invokeFn, entry, link) {
4418
- if (excluded.has(nestedName) || excluded.has(nestedFunctionName) || overBudget(entry)) {
4495
+ if (excluded.has(nestedName) || excluded.has(nestedFunctionName) || !recordsSpan(entry, nestedName, true)) {
4419
4496
  return invokeFn();
4420
4497
  }
4421
- spansUsed += 1;
4422
4498
  const childOptions = {
4423
4499
  name: nestedName,
4424
4500
  type: "function",
@@ -4445,6 +4521,12 @@ var Bitfab = class {
4445
4521
  }
4446
4522
  const enclosing = currentAutoTraceEntries();
4447
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
+ }
4448
4530
  return tracedRoot.apply(this, args);
4449
4531
  }
4450
4532
  const link = getReplayContext() || inSeedScope() ? void 0 : { traceFunctionKey };
@@ -4491,6 +4573,9 @@ var Bitfab = class {
4491
4573
  return autoTraceRoot;
4492
4574
  }
4493
4575
  applySimulationPlan(payload, submit) {
4576
+ if (!fitsTraceSpanBudget(payload)) {
4577
+ return;
4578
+ }
4494
4579
  this.simulationPlan.send(payload, rootTraceFunctionKeyOf(payload), submit);
4495
4580
  }
4496
4581
  /**
@@ -4525,15 +4610,24 @@ var Bitfab = class {
4525
4610
  * from the environment. Once a non-empty key is found it is cached, so an
4526
4611
  * early resolve that found nothing never poisons a later one.
4527
4612
  */
4528
- resolveApiKey() {
4613
+ findApiKey(callsKeyFunction) {
4529
4614
  if (this.resolvedApiKey !== void 0) {
4530
4615
  return this.resolvedApiKey;
4531
4616
  }
4617
+ if (typeof this.apiKeyConfig === "function" && !callsKeyFunction) {
4618
+ return void 0;
4619
+ }
4532
4620
  const fromConfig = typeof this.apiKeyConfig === "function" ? this.apiKeyConfig() : this.apiKeyConfig;
4533
4621
  const candidate = fromConfig && fromConfig.trim() !== "" ? fromConfig : readEnv2("BITFAB_API_KEY");
4534
4622
  const key = candidate && candidate.trim() !== "" ? candidate : void 0;
4535
4623
  if (key) {
4536
4624
  this.resolvedApiKey = key;
4625
+ }
4626
+ return key;
4627
+ }
4628
+ resolveApiKey() {
4629
+ const key = this.findApiKey(true);
4630
+ if (key) {
4537
4631
  return key;
4538
4632
  }
4539
4633
  if (this.strict) {
@@ -5153,7 +5247,10 @@ var Bitfab = class {
5153
5247
  self.httpClient.traceCompletion.start(traceId, spanId);
5154
5248
  startedSpan = { traceId, spanId };
5155
5249
  const functionName = fn.name !== "" ? fn.name : void 0;
5156
- const rootTraceFunctionKey = activeTraceStates.get(traceId)?.traceFunctionKey ?? traceFunctionKey;
5250
+ const rootTraceFunctionKey = rootTraceFunctionKeyOfTrace(
5251
+ traceId,
5252
+ traceFunctionKey
5253
+ );
5157
5254
  const baseSpanParams = {
5158
5255
  traceFunctionKey,
5159
5256
  rootTraceFunctionKey,
@@ -5675,14 +5772,25 @@ var Bitfab = class {
5675
5772
  ...params.testRunId && { testRunId: params.testRunId }
5676
5773
  });
5677
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
+ }
5678
5784
  /**
5679
5785
  * Send a wrapper span from function execution.
5680
5786
  * Internal method to record spans when using withSpan.
5681
5787
  * Queued on the client's span transport; delivery is the transport's job.
5682
5788
  */
5683
5789
  sendWrapperSpan(params) {
5684
- const serializedInputs = params.captureContent ? serializeValue(params.inputs) : void 0;
5685
- 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;
5686
5794
  const externalSpan = {
5687
5795
  id: params.spanId,
5688
5796
  trace_id: params.traceId,
@@ -5733,7 +5841,8 @@ var Bitfab = class {
5733
5841
  ...params.captureContent && params.contexts && params.contexts.length > 0 && {
5734
5842
  contexts: params.contexts
5735
5843
  },
5736
- ...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 }
5737
5846
  }
5738
5847
  };
5739
5848
  if (params.parentSpanId) {
@@ -5899,7 +6008,7 @@ var Bitfab = class {
5899
6008
  await runWithSeedContext({ traceId }, async () => target(...args));
5900
6009
  } finally {
5901
6010
  try {
5902
- const { flushTraces: flushTraces2 } = await import("./http-42KAFBUN.js");
6011
+ const { flushTraces: flushTraces2 } = await import("./http-HKMIFNAR.js");
5903
6012
  await flushTraces2(3e4);
5904
6013
  } finally {
5905
6014
  unrecorded = activeTraceStates.delete(traceId);
@@ -5958,7 +6067,7 @@ var Bitfab = class {
5958
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.`
5959
6068
  );
5960
6069
  }
5961
- const { replay: doReplay } = await import("./replay-5RHBDIEK.js");
6070
+ const { replay: doReplay } = await import("./replay-JCY64EHP.js");
5962
6071
  return doReplay(
5963
6072
  this.httpClient,
5964
6073
  this.serviceUrl,
@@ -6278,7 +6387,7 @@ async function seedFromRegistry(registry, pipeline, cases, options = {}) {
6278
6387
  sessionId: seedCase.sessionId
6279
6388
  })
6280
6389
  );
6281
- const { flushTraces: flushTraces2 } = await import("./http-42KAFBUN.js");
6390
+ const { flushTraces: flushTraces2 } = await import("./http-HKMIFNAR.js");
6282
6391
  await flushTraces2(3e4);
6283
6392
  return { pipeline, traceFunctionKey, traceIds };
6284
6393
  }
@@ -6317,4 +6426,4 @@ export {
6317
6426
  reseedFromRegistry,
6318
6427
  seedFromRegistry
6319
6428
  };
6320
- //# sourceMappingURL=chunk-Q7HDNYYY.js.map
6429
+ //# sourceMappingURL=chunk-56USYDIX.js.map