bitfab 0.29.0 → 0.30.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.
package/dist/index.cjs CHANGED
@@ -396,23 +396,27 @@ function buildMockTree(rootNode) {
396
396
  }
397
397
  return { spans };
398
398
  }
399
- async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, resolvedOverrides, environment, adaptInputs) {
399
+ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, resolvedOverrides, replayedTraceId, environment, adaptInputs) {
400
400
  const lease = environment ? serverItem.dbBranchLease : void 0;
401
401
  let inputs = [];
402
402
  let originalOutput;
403
403
  let result;
404
404
  let error = null;
405
- const replayedTraceId = randomUuid();
406
405
  const pendingPersistence = [];
406
+ const originalTraceId = serverItem.originalTraceId ?? serverItem.sourceTraceId;
407
+ const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
407
408
  try {
408
- const span = await httpClient.getExternalSpan(serverItem.externalSpanId);
409
+ const span = await httpClient.getExternalSpan(originalSpanId);
409
410
  const spanData = span.rawData?.span_data ?? {};
410
411
  inputs = deserializeInputs(spanData);
411
412
  originalOutput = deserializeOutput(spanData);
412
413
  if (adaptInputs) {
413
414
  inputs = adaptInputs(inputs, {
414
- traceId: serverItem.traceId,
415
- sourceSpanId: serverItem.externalSpanId
415
+ originalTraceId,
416
+ originalSpanId,
417
+ // Deprecated aliases for originalTraceId/originalSpanId.
418
+ sourceTraceId: originalTraceId,
419
+ sourceSpanId: originalSpanId
416
420
  });
417
421
  }
418
422
  const hasOverrides = resolvedOverrides.length > 0;
@@ -421,15 +425,14 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
421
425
  let mockTree;
422
426
  if (needTree) {
423
427
  try {
424
- const treeResponse = await httpClient.getSpanTree(
425
- serverItem.externalSpanId,
426
- { includeOutputs }
427
- );
428
+ const treeResponse = await httpClient.getSpanTree(originalSpanId, {
429
+ includeOutputs
430
+ });
428
431
  if (treeResponse.root) {
429
432
  mockTree = buildMockTree(treeResponse.root);
430
433
  } else if (mockStrategy === "all" || hasOverrides) {
431
434
  throw new BitfabError(
432
- `Replay mock strategy "${mockStrategy}"${hasOverrides ? " with overrides" : ""} requires a span tree root for source span ${serverItem.externalSpanId}.`
435
+ `Replay mock strategy "${mockStrategy}"${hasOverrides ? " with overrides" : ""} requires a span tree root for original span ${originalSpanId}.`
433
436
  );
434
437
  } else {
435
438
  mockTree = void 0;
@@ -460,7 +463,7 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
460
463
  traceId: replayedTraceId,
461
464
  inputSourceSpanId: span.id,
462
465
  inputSourceTraceId: span.externalTraceId,
463
- sourceBitfabTraceId: serverItem.traceId,
466
+ sourceBitfabTraceId: originalTraceId,
464
467
  mockTree,
465
468
  callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
466
469
  mockStrategy,
@@ -490,7 +493,15 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
490
493
  }
491
494
  }
492
495
  return {
493
- traceId: replayedTraceId,
496
+ // Written in by replay() from the complete-replay response once the server
497
+ // has minted this replay trace's row. Null until then: the client-side
498
+ // correlation id (replayedTraceId) is never surfaced as the item's traceId.
499
+ traceId: null,
500
+ originalTraceId,
501
+ originalSpanId,
502
+ // Deprecated aliases for originalTraceId/originalSpanId.
503
+ sourceTraceId: originalTraceId,
504
+ sourceSpanId: originalSpanId,
494
505
  input: inputs,
495
506
  result,
496
507
  originalOutput,
@@ -558,7 +569,8 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
558
569
  options?.environment !== void 0,
559
570
  // includeDbBranchLease
560
571
  options?.experimentGroupId,
561
- options?.datasetId
572
+ options?.datasetId,
573
+ options?.graderIds
562
574
  );
563
575
  const mockStrategy = options?.mock ?? "marked";
564
576
  const maxConcurrency = options?.maxConcurrency ?? 10;
@@ -566,14 +578,16 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
566
578
  ...normalizeMockOverrides(options?.mockOverride),
567
579
  ...registeredOverrides
568
580
  ];
581
+ const replayedTraceIds = serverItems.map(() => randomUuid());
569
582
  const tasks = serverItems.map(
570
- (serverItem) => () => processItem(
583
+ (serverItem, index) => () => processItem(
571
584
  httpClient,
572
585
  serverItem,
573
586
  fn,
574
587
  testRunId,
575
588
  mockStrategy,
576
589
  resolvedOverrides,
590
+ replayedTraceIds[index],
577
591
  options?.environment,
578
592
  options?.adaptInputs
579
593
  )
@@ -600,11 +614,17 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
600
614
  succeeded,
601
615
  errored,
602
616
  item: {
603
- // Source (historical) trace id, so a UI can identify the trace
604
- // that just settled. The item's own traceId is the new replay
605
- // trace and is assigned later (below), so use the server item.
606
- traceId: serverItems[index]?.traceId ?? null,
607
- replayTraceId: item.traceId,
617
+ // The server replay trace id isn't known until completeReplay
618
+ // runs (below), so it can't be reported mid-run and we never
619
+ // emit the client-side placeholder. originalTraceId (the
620
+ // historical trace) is known now and is what a UI keys on to
621
+ // identify what just settled.
622
+ traceId: null,
623
+ originalTraceId: item.originalTraceId ?? null,
624
+ originalSpanId: item.originalSpanId ?? null,
625
+ // Deprecated aliases for originalTraceId/originalSpanId.
626
+ sourceTraceId: item.originalTraceId ?? null,
627
+ sourceSpanId: item.originalSpanId ?? null,
608
628
  input: item.input,
609
629
  result: item.result,
610
630
  originalOutput: item.originalOutput,
@@ -622,56 +642,58 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
622
642
  const completeResult = await httpClient.completeReplay(testRunId);
623
643
  const serverTraceIds = completeResult.traceIds;
624
644
  const replayTokens = completeResult.tokens;
625
- if (serverTraceIds === void 0) {
626
- try {
627
- console.warn(
628
- "Bitfab: server did not return replay trace IDs; item.traceId will be null (server upgrade required for verdict persistence)"
629
- );
630
- } catch {
631
- }
632
- for (const item of resultItems) {
633
- item.traceId = null;
634
- }
635
- } else {
645
+ if (serverTraceIds !== void 0) {
636
646
  const missing = [];
637
647
  let completedCount = 0;
638
- for (const item of resultItems) {
639
- if (item.traceId) {
640
- const mapped = serverTraceIds[item.traceId];
641
- if (item.error === null) {
642
- completedCount += 1;
643
- if (mapped === void 0) {
644
- missing.push(item.traceId);
645
- }
646
- }
647
- if (mapped !== void 0) {
648
- item.tokens = replayTokens?.[mapped] ?? null;
648
+ for (let index = 0; index < resultItems.length; index += 1) {
649
+ const item = resultItems[index];
650
+ const localId = replayedTraceIds[index];
651
+ const mapped = localId ? serverTraceIds[localId] : void 0;
652
+ item.traceId = mapped ?? null;
653
+ if (item.error === null) {
654
+ completedCount += 1;
655
+ if (mapped === void 0) {
656
+ missing.push(localId ?? item.originalTraceId);
649
657
  }
650
- item.traceId = mapped ?? null;
658
+ }
659
+ if (mapped !== void 0) {
660
+ item.tokens = replayTokens?.[mapped] ?? null;
651
661
  }
652
662
  }
653
- if (missing.length > 0) {
663
+ if (completedCount > 0 && missing.length === completedCount) {
654
664
  const serverCount = completeResult.traceCount !== void 0 ? ` The server persisted ${completeResult.traceCount} trace(s) for this run.` : "";
655
- if (missing.length === completedCount) {
656
- throw new BitfabError(
657
- `Replay completed but the server has no persisted trace for any of the ${completedCount} completed item(s) (testRunId ${testRunId}).${serverCount} Trace uploads were awaited, so either the uploads failed (check for "Bitfab: Failed to create" errors above) or the replayed function is not wrapped with withSpan.`
658
- );
659
- }
665
+ throw new BitfabError(
666
+ `Replay completed but the server has no persisted trace for any of the ${completedCount} completed item(s) (testRunId ${testRunId}).${serverCount} Trace uploads were awaited, so either the uploads failed (check for "Bitfab: Failed to create" errors above) or the replayed function is not wrapped with withSpan.`
667
+ );
668
+ }
669
+ if (missing.length > 0) {
660
670
  try {
661
671
  console.error(
662
- `Bitfab: server has no persisted trace for ${missing.length} of ${completedCount} completed replay item(s) (testRunId ${testRunId}).${serverCount} Their traceId is null and verdicts cannot be persisted for them. Missing: ${missing.join(", ")}`
672
+ `Bitfab: server has no persisted trace for ${missing.length} of ${completedCount} completed replay item(s) (testRunId ${testRunId}). Their replay token usage is unavailable and they cannot be labeled.`
663
673
  );
664
674
  } catch {
665
675
  }
666
676
  }
667
677
  }
668
- const replayResult = {
678
+ const result = {
669
679
  items: resultItems,
670
680
  testRunId,
671
681
  testRunUrl: `${serviceUrl}${testRunUrl}`
672
682
  };
673
- await writeReplayResultFile(replayResult);
674
- return replayResult;
683
+ await writeReplayResultFile(result);
684
+ try {
685
+ options?.onProgress?.({
686
+ type: "complete",
687
+ testRunId,
688
+ completed: total,
689
+ total,
690
+ succeeded,
691
+ errored,
692
+ result
693
+ });
694
+ } catch {
695
+ }
696
+ return result;
675
697
  }
676
698
  async function writeReplayResultFile(result) {
677
699
  const resultPath = typeof process !== "undefined" ? process.env?.BITFAB_REPLAY_RESULT_PATH : void 0;
@@ -734,7 +756,7 @@ __export(index_exports, {
734
756
  module.exports = __toCommonJS(index_exports);
735
757
 
736
758
  // src/version.generated.ts
737
- var __version__ = "0.29.0";
759
+ var __version__ = "0.30.0";
738
760
 
739
761
  // src/constants.ts
740
762
  var DEFAULT_SERVICE_URL = "https://bitfab.ai";
@@ -1093,7 +1115,7 @@ var HttpClient = class {
1093
1115
  * Start a replay session by fetching historical traces.
1094
1116
  * Blocking call - creates a test run and returns lightweight item references.
1095
1117
  */
1096
- async startReplay(traceFunctionKey, limit, traceIds, name, codeChangeDescription, codeChangeFiles, includeDbBranchLease, experimentGroupId, datasetId) {
1118
+ async startReplay(traceFunctionKey, limit, traceIds, name, codeChangeDescription, codeChangeFiles, includeDbBranchLease, experimentGroupId, datasetId, graderIds) {
1097
1119
  const payload = { traceFunctionKey };
1098
1120
  if (limit !== void 0) {
1099
1121
  payload.limit = limit;
@@ -1119,6 +1141,9 @@ var HttpClient = class {
1119
1141
  if (datasetId !== void 0) {
1120
1142
  payload.datasetId = datasetId;
1121
1143
  }
1144
+ if (graderIds !== void 0) {
1145
+ payload.graderIds = graderIds;
1146
+ }
1122
1147
  const timeout = includeDbBranchLease ? 18e4 : 3e4;
1123
1148
  return this.request("/api/sdk/replay/start", payload, {
1124
1149
  timeout
@@ -4164,7 +4189,7 @@ var Bitfab = class {
4164
4189
  dbSnapshotUsage: {
4165
4190
  neonBranchId: replayCtx.dbBranchLease.neonBranchId,
4166
4191
  snapshotTimestamp: replayCtx.dbBranchLease.snapshotTimestamp,
4167
- sourceTraceId: replayCtx.sourceBitfabTraceId,
4192
+ originalTraceId: replayCtx.sourceBitfabTraceId,
4168
4193
  accessed: replayCtx.dbSnapshotAccessed === true
4169
4194
  }
4170
4195
  }
@@ -4468,8 +4493,11 @@ var Bitfab = class {
4468
4493
  ...params.dbSnapshotUsage.snapshotTimestamp && {
4469
4494
  snapshot_timestamp: params.dbSnapshotUsage.snapshotTimestamp
4470
4495
  },
4471
- ...params.dbSnapshotUsage.sourceTraceId && {
4472
- source_trace_id: params.dbSnapshotUsage.sourceTraceId
4496
+ ...params.dbSnapshotUsage.originalTraceId && {
4497
+ original_trace_id: params.dbSnapshotUsage.originalTraceId,
4498
+ // Deprecated wire alias, kept so this SDK still reports usage
4499
+ // against servers that predate the rename.
4500
+ source_trace_id: params.dbSnapshotUsage.originalTraceId
4473
4501
  },
4474
4502
  accessed: params.dbSnapshotUsage.accessed
4475
4503
  };