@bitfab/sdk 0.38.9 → 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.9";
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);
@@ -6162,6 +6223,7 @@ var Bitfab = class {
6162
6223
  return invokeWithoutNode();
6163
6224
  }
6164
6225
  spansUsed += 1;
6226
+ const mockOnReplay = nodeConfiguration?.mockOnReplay ?? options.mockOnReplayDefault;
6165
6227
  const childOptions = {
6166
6228
  name: nodeConfiguration?.name ?? definition.name,
6167
6229
  type: nodeConfiguration?.type ?? "function",
@@ -6172,8 +6234,8 @@ var Bitfab = class {
6172
6234
  ...nodeConfiguration?.testRunId !== void 0 && {
6173
6235
  testRunId: nodeConfiguration.testRunId
6174
6236
  },
6175
- ...nodeConfiguration?.mockOnReplay !== void 0 && {
6176
- mockOnReplay: nodeConfiguration.mockOnReplay
6237
+ ...mockOnReplay !== void 0 && {
6238
+ mockOnReplay
6177
6239
  },
6178
6240
  ...nodeConfiguration?.finalize !== void 0 && {
6179
6241
  finalize: nodeConfiguration.finalize
@@ -6859,6 +6921,7 @@ var Bitfab = class {
6859
6921
  inputSourceTraceId: traceState?.inputSourceTraceId,
6860
6922
  dbSnapshotRef: traceState?.dbSnapshotRef,
6861
6923
  dropped: traceState?.dropped,
6924
+ ingestionType: traceState?.ingestionType,
6862
6925
  // Built AFTER the wrapped fn finished, so `accessed` reflects
6863
6926
  // whether customer code obtained the branch URL during this
6864
6927
  // item. Omitted entirely when no lease was attached, so the
@@ -7082,6 +7145,7 @@ var Bitfab = class {
7082
7145
  Object.defineProperty(wrappedFn, "_bitfabTraceFunctionKey", {
7083
7146
  value: traceFunctionKey
7084
7147
  });
7148
+ Object.defineProperty(wrappedFn, "_bitfabWrappedFn", { value: fn });
7085
7149
  return wrappedFn;
7086
7150
  }
7087
7151
  /**
@@ -7244,6 +7308,9 @@ var Bitfab = class {
7244
7308
  if (params.dbSnapshotRef) {
7245
7309
  rawTrace.db_snapshot_ref = params.dbSnapshotRef;
7246
7310
  }
7311
+ if (params.ingestionType) {
7312
+ rawTrace.ingestion_type = params.ingestionType;
7313
+ }
7247
7314
  if (params.dbSnapshotUsage) {
7248
7315
  rawTrace.db_snapshot_usage = {
7249
7316
  neon_branch_id: params.dbSnapshotUsage.neonBranchId,
@@ -7390,6 +7457,68 @@ var Bitfab = class {
7390
7457
  clearMockOverrides() {
7391
7458
  this.mockOverrides.length = 0;
7392
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
+ }
7393
7522
  async replay(traceFunctionKey, fn, options) {
7394
7523
  const wrappedKey = fn._bitfabTraceFunctionKey;
7395
7524
  let replayFn = fn;
@@ -7650,6 +7779,37 @@ init_replay();
7650
7779
  function defineReplayRegistry(registry) {
7651
7780
  return registry;
7652
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
+ }
7653
7813
  // Annotate the CommonJS export names for ESM import in node:
7654
7814
  0 && (module.exports = {
7655
7815
  BITFAB_PROGRESS_PREFIX,
@@ -7677,6 +7837,7 @@ function defineReplayRegistry(registry) {
7677
7837
  getCurrentSpan,
7678
7838
  getCurrentTrace,
7679
7839
  reportReplayProgress,
7840
+ seedFromRegistry,
7680
7841
  serializeReplayResult
7681
7842
  });
7682
7843
  //# sourceMappingURL=index.cjs.map