@bitfab/sdk 0.38.10 → 0.39.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.
@@ -0,0 +1,19 @@
1
+ import {
2
+ BitfabError,
3
+ HttpClient,
4
+ awaitOnExit,
5
+ awaitPendingRequests,
6
+ flushTraces,
7
+ parseRetryAfterMs,
8
+ serializePayloadBody
9
+ } from "./chunk-RH4K4RSS.js";
10
+ export {
11
+ BitfabError,
12
+ HttpClient,
13
+ awaitOnExit,
14
+ awaitPendingRequests,
15
+ flushTraces,
16
+ parseRetryAfterMs,
17
+ serializePayloadBody
18
+ };
19
+ //# sourceMappingURL=http-GJZJKNZZ.js.map
@@ -0,0 +1,20 @@
1
+ import {
2
+ BitfabError,
3
+ HttpClient,
4
+ awaitOnExit,
5
+ awaitPendingRequests,
6
+ flushTraces,
7
+ parseRetryAfterMs,
8
+ serializePayloadBody
9
+ } from "./chunk-2JQSYJJR.js";
10
+ import "./chunk-H6LZRFMN.js";
11
+ export {
12
+ BitfabError,
13
+ HttpClient,
14
+ awaitOnExit,
15
+ awaitPendingRequests,
16
+ flushTraces,
17
+ parseRetryAfterMs,
18
+ serializePayloadBody
19
+ };
20
+ //# sourceMappingURL=http-PRCLI43J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/index.cjs CHANGED
@@ -42,7 +42,7 @@ var __version__, __packageName__;
42
42
  var init_version_generated = __esm({
43
43
  "src/version.generated.ts"() {
44
44
  "use strict";
45
- __version__ = "0.38.10";
45
+ __version__ = "0.39.0";
46
46
  __packageName__ = "@bitfab/sdk";
47
47
  }
48
48
  });
@@ -1198,6 +1198,16 @@ var init_transport = __esm({
1198
1198
  });
1199
1199
 
1200
1200
  // src/http.ts
1201
+ var http_exports = {};
1202
+ __export(http_exports, {
1203
+ BitfabError: () => BitfabError,
1204
+ HttpClient: () => HttpClient,
1205
+ awaitOnExit: () => awaitOnExit,
1206
+ awaitPendingRequests: () => awaitPendingRequests,
1207
+ flushTraces: () => flushTraces,
1208
+ parseRetryAfterMs: () => parseRetryAfterMs,
1209
+ serializePayloadBody: () => serializePayloadBody
1210
+ });
1201
1211
  function awaitOnExit(promise) {
1202
1212
  pendingTracePromises.add(promise);
1203
1213
  void promise.finally(() => {
@@ -2542,7 +2552,7 @@ function buildMockTree(rootNode) {
2542
2552
  }
2543
2553
  return { spans };
2544
2554
  }
2545
- async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, resolvedOverrides, replayedTraceId, includeDbBranchLease, dbBranchSettings, adaptInputs) {
2555
+ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, resolvedOverrides, replayedTraceId, includeDbBranchLease, dbBranchSettings, adaptInputs, dryRun) {
2546
2556
  let lease = includeDbBranchLease ? serverItem.dbBranchLease : void 0;
2547
2557
  let leaseError = includeDbBranchLease ? serverItem.dbBranchLeaseError : void 0;
2548
2558
  let dbSnapshotRef = serverItem.dbSnapshotRef;
@@ -2637,6 +2647,32 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2637
2647
  }
2638
2648
  return pending;
2639
2649
  } : void 0;
2650
+ if (dryRun) {
2651
+ return {
2652
+ traceId: null,
2653
+ originalTraceId,
2654
+ originalSpanId,
2655
+ sourceTraceId: originalTraceId,
2656
+ sourceSpanId: originalSpanId,
2657
+ input: inputs,
2658
+ result: void 0,
2659
+ originalOutput,
2660
+ ...serverItem.ingestionType && {
2661
+ ingestionType: serverItem.ingestionType
2662
+ },
2663
+ error: null,
2664
+ traceError: null,
2665
+ replayError: null,
2666
+ durationMs: null,
2667
+ originalDurationMs: serverItem.originalDurationMs ?? serverItem.durationMs ?? null,
2668
+ originalTokens: serverItem.originalTokens ?? serverItem.tokens ?? null,
2669
+ originalModel: serverItem.originalModel ?? serverItem.model ?? null,
2670
+ tokens: null,
2671
+ model: serverItem.originalModel ?? serverItem.model ?? null,
2672
+ dbSnapshotRef: dbSnapshotRef ?? null,
2673
+ dbBranchTimings: dbBranchTimings ?? null
2674
+ };
2675
+ }
2640
2676
  try {
2641
2677
  replayStarted = performance.now();
2642
2678
  const maybePromise = runWithReplayContext(
@@ -2700,6 +2736,9 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2700
2736
  input: inputs,
2701
2737
  result,
2702
2738
  originalOutput,
2739
+ ...serverItem.ingestionType && {
2740
+ ingestionType: serverItem.ingestionType
2741
+ },
2703
2742
  error,
2704
2743
  traceError,
2705
2744
  replayError,
@@ -2847,13 +2886,23 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2847
2886
  options?.name,
2848
2887
  codeChangeDescription,
2849
2888
  codeChangeFiles,
2850
- dbBranchEnabled(options?.dbBranch),
2851
- // includeDbBranchLease
2889
+ // A dry run executes nothing, so a branch would be provisioned (and billed)
2890
+ // for code that never runs, and a seeded source's refusal would fail the item
2891
+ // before it could report its resolved inputs.
2892
+ dbBranchEnabled(options?.dbBranch) && options?.dryRun !== true,
2852
2893
  options?.experimentGroupId,
2853
2894
  options?.datasetId,
2854
2895
  options?.graderIds,
2855
2896
  resolveDbBranchSettings(options?.dbBranch)
2856
2897
  );
2898
+ if (serverItems.length === 0) {
2899
+ try {
2900
+ console.warn(
2901
+ `Bitfab: no traces matched "${traceFunctionKey}", so this replay ran nothing. Capture a trace, or seed one with seedTrace, before replaying.`
2902
+ );
2903
+ } catch {
2904
+ }
2905
+ }
2857
2906
  const mockStrategy = options?.mock ?? "marked";
2858
2907
  const maxConcurrency = options?.maxConcurrency ?? 10;
2859
2908
  const fullTestRunUrl = `${serviceUrl}${testRunUrl}`;
@@ -2872,9 +2921,10 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2872
2921
  mockStrategy,
2873
2922
  resolvedOverrides,
2874
2923
  replayedTraceIds[index],
2875
- dbBranchEnabled(options?.dbBranch),
2924
+ dbBranchEnabled(options?.dbBranch) && options?.dryRun !== true,
2876
2925
  resolveDbBranchSettings(options?.dbBranch),
2877
- options?.adaptInputs
2926
+ options?.adaptInputs,
2927
+ options?.dryRun === true
2878
2928
  )
2879
2929
  );
2880
2930
  const total = tasks.length;
@@ -2982,6 +3032,16 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2982
3032
  }
2983
3033
  } : void 0
2984
3034
  );
3035
+ if (options?.dryRun === true) {
3036
+ await httpClient.completeReplay(testRunId).catch(() => void 0);
3037
+ const dryResult = {
3038
+ items: resultItems,
3039
+ testRunId,
3040
+ testRunUrl: fullTestRunUrl
3041
+ };
3042
+ await writeReplayResultFile(dryResult);
3043
+ return dryResult;
3044
+ }
2985
3045
  const deliveredTraceIds = await preserveReplayFailure(
2986
3046
  () => waitForReplayPersistence(httpClient, testRunId, replayedTraceIds),
2987
3047
  resultItems,
@@ -3150,6 +3210,7 @@ __export(index_exports, {
3150
3210
  getCurrentSpan: () => getCurrentSpan,
3151
3211
  getCurrentTrace: () => getCurrentTrace,
3152
3212
  reportReplayProgress: () => reportReplayProgress,
3213
+ seedFromRegistry: () => seedFromRegistry,
3153
3214
  serializeReplayResult: () => serializeReplayResult
3154
3215
  });
3155
3216
  module.exports = __toCommonJS(index_exports);
@@ -6860,6 +6921,7 @@ var Bitfab = class {
6860
6921
  inputSourceTraceId: traceState?.inputSourceTraceId,
6861
6922
  dbSnapshotRef: traceState?.dbSnapshotRef,
6862
6923
  dropped: traceState?.dropped,
6924
+ ingestionType: traceState?.ingestionType,
6863
6925
  // Built AFTER the wrapped fn finished, so `accessed` reflects
6864
6926
  // whether customer code obtained the branch URL during this
6865
6927
  // item. Omitted entirely when no lease was attached, so the
@@ -7083,6 +7145,7 @@ var Bitfab = class {
7083
7145
  Object.defineProperty(wrappedFn, "_bitfabTraceFunctionKey", {
7084
7146
  value: traceFunctionKey
7085
7147
  });
7148
+ Object.defineProperty(wrappedFn, "_bitfabWrappedFn", { value: fn });
7086
7149
  return wrappedFn;
7087
7150
  }
7088
7151
  /**
@@ -7245,6 +7308,9 @@ var Bitfab = class {
7245
7308
  if (params.dbSnapshotRef) {
7246
7309
  rawTrace.db_snapshot_ref = params.dbSnapshotRef;
7247
7310
  }
7311
+ if (params.ingestionType) {
7312
+ rawTrace.ingestion_type = params.ingestionType;
7313
+ }
7248
7314
  if (params.dbSnapshotUsage) {
7249
7315
  rawTrace.db_snapshot_usage = {
7250
7316
  neon_branch_id: params.dbSnapshotUsage.neonBranchId,
@@ -7391,6 +7457,68 @@ var Bitfab = class {
7391
7457
  clearMockOverrides() {
7392
7458
  this.mockOverrides.length = 0;
7393
7459
  }
7460
+ /**
7461
+ * Write a replayable trace from a case, without running anything.
7462
+ *
7463
+ * Use this to turn a corpus you already hold (a Braintrust dataset, a
7464
+ * spreadsheet, hand-written cases) into traces that {@link replay} can
7465
+ * select. The recorded root span carries `input` as its input and `expected`
7466
+ * as its output, so replay reports each item against the value you expected
7467
+ * rather than against a previous run.
7468
+ *
7469
+ * A seeded trace has no child spans and no database pin, so replay mocking
7470
+ * has nothing recorded to substitute and `dbBranch` refuses it. Pass
7471
+ * `mockOverride` at replay time for calls that must not run.
7472
+ *
7473
+ * @returns The trace ID, usable with `replay({ traceIds: [...] })`.
7474
+ */
7475
+ seedTrace(traceFunctionKey, options) {
7476
+ const { input } = options;
7477
+ const fn = options.fn?._bitfabWrappedFn ?? options.fn;
7478
+ if (fn && input.length < fn.length) {
7479
+ throw new BitfabError(
7480
+ `Seeded case supplies ${input.length} argument(s) but ${fn.name === "" ? "the function" : fn.name} requires ${fn.length}. Fix the case, or omit fn to seed it anyway.`
7481
+ );
7482
+ }
7483
+ const traceId = randomUuid();
7484
+ const startedAt = nowIsoTimestamp();
7485
+ activeTraceStates.set(traceId, {
7486
+ traceId,
7487
+ startedAt,
7488
+ contexts: [],
7489
+ ingestionType: "seeded",
7490
+ ...options.sessionId !== void 0 && { sessionId: options.sessionId },
7491
+ ...options.metadata !== void 0 && { metadata: options.metadata }
7492
+ });
7493
+ try {
7494
+ this.sendWrapperSpan({
7495
+ traceFunctionKey,
7496
+ spanName: options.spanName ?? traceFunctionKey,
7497
+ traceId,
7498
+ spanId: randomUuid(),
7499
+ parentSpanId: null,
7500
+ inputs: input,
7501
+ result: options.expected,
7502
+ startedAt,
7503
+ endedAt: startedAt,
7504
+ spanType: options.spanType ?? "agent",
7505
+ captureContent: true
7506
+ });
7507
+ this.sendTraceCompletion({
7508
+ traceFunctionKey,
7509
+ traceId,
7510
+ startedAt,
7511
+ endedAt: startedAt,
7512
+ sessionId: options.sessionId,
7513
+ metadata: options.metadata,
7514
+ contexts: [],
7515
+ ingestionType: "seeded"
7516
+ });
7517
+ } finally {
7518
+ activeTraceStates.delete(traceId);
7519
+ }
7520
+ return traceId;
7521
+ }
7394
7522
  async replay(traceFunctionKey, fn, options) {
7395
7523
  const wrappedKey = fn._bitfabTraceFunctionKey;
7396
7524
  let replayFn = fn;
@@ -7651,6 +7779,37 @@ init_replay();
7651
7779
  function defineReplayRegistry(registry) {
7652
7780
  return registry;
7653
7781
  }
7782
+ async function seedFromRegistry(registry, pipeline, cases) {
7783
+ const registration = registry[pipeline];
7784
+ if (registration === void 0) {
7785
+ throw new BitfabError(
7786
+ `Unknown pipeline '${pipeline}'. Registered: ${Object.keys(registry).join(", ")}`
7787
+ );
7788
+ }
7789
+ const traceFunctionKey = resolveTraceFunctionKey(registration);
7790
+ const traceIds = cases.map(
7791
+ (seedCase) => registration.client.seedTrace(traceFunctionKey, {
7792
+ input: seedCase.input,
7793
+ expected: seedCase.expected,
7794
+ fn: registration.fn,
7795
+ metadata: seedCase.metadata,
7796
+ sessionId: seedCase.sessionId
7797
+ })
7798
+ );
7799
+ const { flushTraces: flushTraces2 } = await Promise.resolve().then(() => (init_http(), http_exports));
7800
+ await flushTraces2(3e4);
7801
+ return { pipeline, traceFunctionKey, traceIds };
7802
+ }
7803
+ function resolveTraceFunctionKey(registration) {
7804
+ const wrappedKey = registration.fn._bitfabTraceFunctionKey;
7805
+ const key = registration.traceFunctionKey ?? wrappedKey;
7806
+ if (key === void 0) {
7807
+ throw new BitfabError(
7808
+ "Replay registry entry uses a plain function. Set traceFunctionKey to the key its production handler records."
7809
+ );
7810
+ }
7811
+ return key;
7812
+ }
7654
7813
  // Annotate the CommonJS export names for ESM import in node:
7655
7814
  0 && (module.exports = {
7656
7815
  BITFAB_PROGRESS_PREFIX,
@@ -7678,6 +7837,7 @@ function defineReplayRegistry(registry) {
7678
7837
  getCurrentSpan,
7679
7838
  getCurrentTrace,
7680
7839
  reportReplayProgress,
7840
+ seedFromRegistry,
7681
7841
  serializeReplayResult
7682
7842
  });
7683
7843
  //# sourceMappingURL=index.cjs.map