@bitfab/sdk 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
@@ -387,23 +387,27 @@ function buildMockTree(rootNode) {
387
387
  }
388
388
  return { spans };
389
389
  }
390
- async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, resolvedOverrides, environment, adaptInputs) {
390
+ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, resolvedOverrides, replayedTraceId, environment, adaptInputs) {
391
391
  const lease = environment ? serverItem.dbBranchLease : void 0;
392
392
  let inputs = [];
393
393
  let originalOutput;
394
394
  let result;
395
395
  let error = null;
396
- const replayedTraceId = randomUuid();
397
396
  const pendingPersistence = [];
397
+ const originalTraceId = serverItem.originalTraceId ?? serverItem.sourceTraceId;
398
+ const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
398
399
  try {
399
- const span = await httpClient.getExternalSpan(serverItem.externalSpanId);
400
+ const span = await httpClient.getExternalSpan(originalSpanId);
400
401
  const spanData = span.rawData?.span_data ?? {};
401
402
  inputs = deserializeInputs(spanData);
402
403
  originalOutput = deserializeOutput(spanData);
403
404
  if (adaptInputs) {
404
405
  inputs = adaptInputs(inputs, {
405
- traceId: serverItem.traceId,
406
- sourceSpanId: serverItem.externalSpanId
406
+ originalTraceId,
407
+ originalSpanId,
408
+ // Deprecated aliases for originalTraceId/originalSpanId.
409
+ sourceTraceId: originalTraceId,
410
+ sourceSpanId: originalSpanId
407
411
  });
408
412
  }
409
413
  const hasOverrides = resolvedOverrides.length > 0;
@@ -412,15 +416,14 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
412
416
  let mockTree;
413
417
  if (needTree) {
414
418
  try {
415
- const treeResponse = await httpClient.getSpanTree(
416
- serverItem.externalSpanId,
417
- { includeOutputs }
418
- );
419
+ const treeResponse = await httpClient.getSpanTree(originalSpanId, {
420
+ includeOutputs
421
+ });
419
422
  if (treeResponse.root) {
420
423
  mockTree = buildMockTree(treeResponse.root);
421
424
  } else if (mockStrategy === "all" || hasOverrides) {
422
425
  throw new BitfabError(
423
- `Replay mock strategy "${mockStrategy}"${hasOverrides ? " with overrides" : ""} requires a span tree root for source span ${serverItem.externalSpanId}.`
426
+ `Replay mock strategy "${mockStrategy}"${hasOverrides ? " with overrides" : ""} requires a span tree root for original span ${originalSpanId}.`
424
427
  );
425
428
  } else {
426
429
  mockTree = void 0;
@@ -451,7 +454,7 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
451
454
  traceId: replayedTraceId,
452
455
  inputSourceSpanId: span.id,
453
456
  inputSourceTraceId: span.externalTraceId,
454
- sourceBitfabTraceId: serverItem.traceId,
457
+ sourceBitfabTraceId: originalTraceId,
455
458
  mockTree,
456
459
  callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
457
460
  mockStrategy,
@@ -481,7 +484,15 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
481
484
  }
482
485
  }
483
486
  return {
484
- traceId: replayedTraceId,
487
+ // Written in by replay() from the complete-replay response once the server
488
+ // has minted this replay trace's row. Null until then: the client-side
489
+ // correlation id (replayedTraceId) is never surfaced as the item's traceId.
490
+ traceId: null,
491
+ originalTraceId,
492
+ originalSpanId,
493
+ // Deprecated aliases for originalTraceId/originalSpanId.
494
+ sourceTraceId: originalTraceId,
495
+ sourceSpanId: originalSpanId,
485
496
  input: inputs,
486
497
  result,
487
498
  originalOutput,
@@ -549,7 +560,8 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
549
560
  options?.environment !== void 0,
550
561
  // includeDbBranchLease
551
562
  options?.experimentGroupId,
552
- options?.datasetId
563
+ options?.datasetId,
564
+ options?.graderIds
553
565
  );
554
566
  const mockStrategy = options?.mock ?? "marked";
555
567
  const maxConcurrency = options?.maxConcurrency ?? 10;
@@ -557,14 +569,16 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
557
569
  ...normalizeMockOverrides(options?.mockOverride),
558
570
  ...registeredOverrides
559
571
  ];
572
+ const replayedTraceIds = serverItems.map(() => randomUuid());
560
573
  const tasks = serverItems.map(
561
- (serverItem) => () => processItem(
574
+ (serverItem, index) => () => processItem(
562
575
  httpClient,
563
576
  serverItem,
564
577
  fn,
565
578
  testRunId,
566
579
  mockStrategy,
567
580
  resolvedOverrides,
581
+ replayedTraceIds[index],
568
582
  options?.environment,
569
583
  options?.adaptInputs
570
584
  )
@@ -591,11 +605,17 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
591
605
  succeeded,
592
606
  errored,
593
607
  item: {
594
- // Source (historical) trace id, so a UI can identify the trace
595
- // that just settled. The item's own traceId is the new replay
596
- // trace and is assigned later (below), so use the server item.
597
- traceId: serverItems[index]?.traceId ?? null,
598
- replayTraceId: item.traceId,
608
+ // The server replay trace id isn't known until completeReplay
609
+ // runs (below), so it can't be reported mid-run and we never
610
+ // emit the client-side placeholder. originalTraceId (the
611
+ // historical trace) is known now and is what a UI keys on to
612
+ // identify what just settled.
613
+ traceId: null,
614
+ originalTraceId: item.originalTraceId ?? null,
615
+ originalSpanId: item.originalSpanId ?? null,
616
+ // Deprecated aliases for originalTraceId/originalSpanId.
617
+ sourceTraceId: item.originalTraceId ?? null,
618
+ sourceSpanId: item.originalSpanId ?? null,
599
619
  input: item.input,
600
620
  result: item.result,
601
621
  originalOutput: item.originalOutput,
@@ -613,56 +633,58 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
613
633
  const completeResult = await httpClient.completeReplay(testRunId);
614
634
  const serverTraceIds = completeResult.traceIds;
615
635
  const replayTokens = completeResult.tokens;
616
- if (serverTraceIds === void 0) {
617
- try {
618
- console.warn(
619
- "Bitfab: server did not return replay trace IDs; item.traceId will be null (server upgrade required for verdict persistence)"
620
- );
621
- } catch {
622
- }
623
- for (const item of resultItems) {
624
- item.traceId = null;
625
- }
626
- } else {
636
+ if (serverTraceIds !== void 0) {
627
637
  const missing = [];
628
638
  let completedCount = 0;
629
- for (const item of resultItems) {
630
- if (item.traceId) {
631
- const mapped = serverTraceIds[item.traceId];
632
- if (item.error === null) {
633
- completedCount += 1;
634
- if (mapped === void 0) {
635
- missing.push(item.traceId);
636
- }
637
- }
638
- if (mapped !== void 0) {
639
- item.tokens = replayTokens?.[mapped] ?? null;
639
+ for (let index = 0; index < resultItems.length; index += 1) {
640
+ const item = resultItems[index];
641
+ const localId = replayedTraceIds[index];
642
+ const mapped = localId ? serverTraceIds[localId] : void 0;
643
+ item.traceId = mapped ?? null;
644
+ if (item.error === null) {
645
+ completedCount += 1;
646
+ if (mapped === void 0) {
647
+ missing.push(localId ?? item.originalTraceId);
640
648
  }
641
- item.traceId = mapped ?? null;
649
+ }
650
+ if (mapped !== void 0) {
651
+ item.tokens = replayTokens?.[mapped] ?? null;
642
652
  }
643
653
  }
644
- if (missing.length > 0) {
654
+ if (completedCount > 0 && missing.length === completedCount) {
645
655
  const serverCount = completeResult.traceCount !== void 0 ? ` The server persisted ${completeResult.traceCount} trace(s) for this run.` : "";
646
- if (missing.length === completedCount) {
647
- throw new BitfabError(
648
- `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.`
649
- );
650
- }
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
+ }
660
+ if (missing.length > 0) {
651
661
  try {
652
662
  console.error(
653
- `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(", ")}`
663
+ `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.`
654
664
  );
655
665
  } catch {
656
666
  }
657
667
  }
658
668
  }
659
- const replayResult = {
669
+ const result = {
660
670
  items: resultItems,
661
671
  testRunId,
662
672
  testRunUrl: `${serviceUrl}${testRunUrl}`
663
673
  };
664
- await writeReplayResultFile(replayResult);
665
- return replayResult;
674
+ await writeReplayResultFile(result);
675
+ try {
676
+ options?.onProgress?.({
677
+ type: "complete",
678
+ testRunId,
679
+ completed: total,
680
+ total,
681
+ succeeded,
682
+ errored,
683
+ result
684
+ });
685
+ } catch {
686
+ }
687
+ return result;
666
688
  }
667
689
  async function writeReplayResultFile(result) {
668
690
  const resultPath = typeof process !== "undefined" ? process.env?.BITFAB_REPLAY_RESULT_PATH : void 0;
@@ -725,7 +747,7 @@ __export(index_exports, {
725
747
  module.exports = __toCommonJS(index_exports);
726
748
 
727
749
  // src/version.generated.ts
728
- var __version__ = "0.29.0";
750
+ var __version__ = "0.30.0";
729
751
 
730
752
  // src/constants.ts
731
753
  var DEFAULT_SERVICE_URL = "https://bitfab.ai";
@@ -1084,7 +1106,7 @@ var HttpClient = class {
1084
1106
  * Start a replay session by fetching historical traces.
1085
1107
  * Blocking call - creates a test run and returns lightweight item references.
1086
1108
  */
1087
- async startReplay(traceFunctionKey, limit, traceIds, name, codeChangeDescription, codeChangeFiles, includeDbBranchLease, experimentGroupId, datasetId) {
1109
+ async startReplay(traceFunctionKey, limit, traceIds, name, codeChangeDescription, codeChangeFiles, includeDbBranchLease, experimentGroupId, datasetId, graderIds) {
1088
1110
  const payload = { traceFunctionKey };
1089
1111
  if (limit !== void 0) {
1090
1112
  payload.limit = limit;
@@ -1110,6 +1132,9 @@ var HttpClient = class {
1110
1132
  if (datasetId !== void 0) {
1111
1133
  payload.datasetId = datasetId;
1112
1134
  }
1135
+ if (graderIds !== void 0) {
1136
+ payload.graderIds = graderIds;
1137
+ }
1113
1138
  const timeout = includeDbBranchLease ? 18e4 : 3e4;
1114
1139
  return this.request("/api/sdk/replay/start", payload, {
1115
1140
  timeout
@@ -4155,7 +4180,7 @@ var Bitfab = class {
4155
4180
  dbSnapshotUsage: {
4156
4181
  neonBranchId: replayCtx.dbBranchLease.neonBranchId,
4157
4182
  snapshotTimestamp: replayCtx.dbBranchLease.snapshotTimestamp,
4158
- sourceTraceId: replayCtx.sourceBitfabTraceId,
4183
+ originalTraceId: replayCtx.sourceBitfabTraceId,
4159
4184
  accessed: replayCtx.dbSnapshotAccessed === true
4160
4185
  }
4161
4186
  }
@@ -4459,8 +4484,11 @@ var Bitfab = class {
4459
4484
  ...params.dbSnapshotUsage.snapshotTimestamp && {
4460
4485
  snapshot_timestamp: params.dbSnapshotUsage.snapshotTimestamp
4461
4486
  },
4462
- ...params.dbSnapshotUsage.sourceTraceId && {
4463
- source_trace_id: params.dbSnapshotUsage.sourceTraceId
4487
+ ...params.dbSnapshotUsage.originalTraceId && {
4488
+ original_trace_id: params.dbSnapshotUsage.originalTraceId,
4489
+ // Deprecated wire alias, kept so this SDK still reports usage
4490
+ // against servers that predate the rename.
4491
+ source_trace_id: params.dbSnapshotUsage.originalTraceId
4464
4492
  },
4465
4493
  accessed: params.dbSnapshotUsage.accessed
4466
4494
  };