@bitfab/sdk 0.15.0 → 0.16.1

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.d.cts CHANGED
@@ -343,9 +343,9 @@ declare class ReplayEnvironment {
343
343
  type MockStrategy = "none" | "all" | "marked";
344
344
  interface ReplayOptions {
345
345
  /**
346
- * Maximum number of traces to replay (1100, default 5). Mutually
347
- * exclusive with `traceIds` an explicit ID list already determines how
348
- * many traces replay, so passing both throws.
346
+ * Maximum number of traces to replay (1-100, default 5). Ignored when
347
+ * `traceIds` is passed (with a warning): an explicit ID list already
348
+ * determines how many traces replay.
349
349
  */
350
350
  limit?: number;
351
351
  /** Optional list of specific trace IDs to replay (max 100). */
@@ -380,7 +380,46 @@ interface ReplayOptions {
380
380
  environment?: ReplayEnvironment;
381
381
  /** Group ID to associate this replay with an experiment group for live streaming in Studio. */
382
382
  experimentGroupId?: string;
383
+ /**
384
+ * Reshape recorded inputs before they are spread into `fn`.
385
+ *
386
+ * Replay pulls each trace's inputs exactly as they were captured against the
387
+ * function's signature AT TRACE TIME. When the function's shape has since
388
+ * changed (params renamed, reordered, collapsed into an options object, etc.),
389
+ * the recorded inputs no longer line up and `fn(...inputs)` throws. This hook
390
+ * lets a caller map the recorded inputs onto the current signature so replay
391
+ * can still run.
392
+ *
393
+ * Receives the deserialized recorded inputs and a per-trace {@link AdaptContext}
394
+ * (so a table-driven adapter can look up the adapted inputs by `traceId`), and
395
+ * returns the array actually spread into `fn`. The returned array is also what
396
+ * `ReplayItem.input` reports, so the experiment shows what was really run.
397
+ *
398
+ * Runs per item, inside the same try/catch as `fn`: if the adapter throws, the
399
+ * failure is surfaced on that item's `error` rather than crashing the run.
400
+ * Omit it to spread the recorded inputs unchanged.
401
+ */
402
+ adaptInputs?: (inputs: unknown[], ctx: AdaptContext) => unknown[];
403
+ }
404
+ /** Per-trace context passed to {@link ReplayOptions.adaptInputs}. */
405
+ interface AdaptContext {
406
+ /** Bitfab trace ID of the historical trace being replayed. */
407
+ traceId: string;
408
+ /** External span ID the recorded inputs were read from. */
409
+ sourceSpanId: string;
383
410
  }
411
+ /**
412
+ * The shape an adapter module must export as `adaptInputs`.
413
+ *
414
+ * Author an adapter in its own file (e.g. `scripts/replay-adapters/<name>.ts`),
415
+ * import it in your replay script, and pass it to `replay({ adaptInputs })`:
416
+ *
417
+ * ```ts
418
+ * import type { AdaptInputsFn } from "@bitfab/sdk"
419
+ * export const adaptInputs: AdaptInputsFn = (inputs, ctx) => [reshape(inputs)]
420
+ * ```
421
+ */
422
+ type AdaptInputsFn = (inputs: unknown[], ctx: AdaptContext) => unknown[];
384
423
  interface ReplayItem<T> {
385
424
  /** Trace ID of the new trace created during replay. */
386
425
  traceId: string | null;
@@ -920,9 +959,9 @@ declare class Bitfab {
920
959
  *
921
960
  * @param traceFunctionKey - The trace function key to replay
922
961
  * @param fn - The function to replay (must be the return value of `withSpan`)
923
- * @param options - Optional replay options. `limit` and `traceIds` are
924
- * mutually exclusive an explicit ID list already determines how many
925
- * traces replay, so passing both throws a BitfabError.
962
+ * @param options - Optional replay options. When `traceIds` is passed,
963
+ * `limit` is ignored (with a warning): an explicit ID list already
964
+ * determines how many traces replay.
926
965
  * @returns ReplayResult with items, testRunId, and testRunUrl
927
966
  */
928
967
  replay<TReturn>(traceFunctionKey: string, fn: (...args: any[]) => TReturn | Promise<TReturn>, options?: ReplayOptions): Promise<ReplayResult<TReturn>>;
@@ -988,7 +1027,7 @@ declare class BitfabFunction {
988
1027
  /**
989
1028
  * SDK version from package.json (injected at build time)
990
1029
  */
991
- declare const __version__ = "0.15.0";
1030
+ declare const __version__ = "0.16.1";
992
1031
 
993
1032
  /**
994
1033
  * Constants for the Bitfab SDK.
@@ -998,4 +1037,4 @@ declare const __version__ = "0.15.0";
998
1037
  */
999
1038
  declare const DEFAULT_SERVICE_URL = "https://bitfab.ai";
1000
1039
 
1001
- export { type ActiveSpanContext, type AllowedEnvVars, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler, BitfabOpenAITracingProcessor, type CodeChangeFile, type CurrentSpan, type CurrentTrace, DEFAULT_SERVICE_URL, type DbSnapshotConfig, type DbSnapshotProvider, type DbSnapshotRef, type DetachedTrace, type MockStrategy, type ProviderDefinition, ReplayEnvironment, type ReplayEnvironmentSnapshot, type ReplayItem, type ReplayOptions, type ReplayResult, SUPPORTED_PROVIDERS, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type WrapBAMLOptions, type WrappedBamlFn, __version__, flushTraces, getCurrentSpan, getCurrentTrace };
1040
+ export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler, BitfabOpenAITracingProcessor, type CodeChangeFile, type CurrentSpan, type CurrentTrace, DEFAULT_SERVICE_URL, type DbSnapshotConfig, type DbSnapshotProvider, type DbSnapshotRef, type DetachedTrace, type MockStrategy, type ProviderDefinition, ReplayEnvironment, type ReplayEnvironmentSnapshot, type ReplayItem, type ReplayOptions, type ReplayResult, SUPPORTED_PROVIDERS, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type WrapBAMLOptions, type WrappedBamlFn, __version__, flushTraces, getCurrentSpan, getCurrentTrace };
package/dist/index.d.ts CHANGED
@@ -343,9 +343,9 @@ declare class ReplayEnvironment {
343
343
  type MockStrategy = "none" | "all" | "marked";
344
344
  interface ReplayOptions {
345
345
  /**
346
- * Maximum number of traces to replay (1100, default 5). Mutually
347
- * exclusive with `traceIds` an explicit ID list already determines how
348
- * many traces replay, so passing both throws.
346
+ * Maximum number of traces to replay (1-100, default 5). Ignored when
347
+ * `traceIds` is passed (with a warning): an explicit ID list already
348
+ * determines how many traces replay.
349
349
  */
350
350
  limit?: number;
351
351
  /** Optional list of specific trace IDs to replay (max 100). */
@@ -380,7 +380,46 @@ interface ReplayOptions {
380
380
  environment?: ReplayEnvironment;
381
381
  /** Group ID to associate this replay with an experiment group for live streaming in Studio. */
382
382
  experimentGroupId?: string;
383
+ /**
384
+ * Reshape recorded inputs before they are spread into `fn`.
385
+ *
386
+ * Replay pulls each trace's inputs exactly as they were captured against the
387
+ * function's signature AT TRACE TIME. When the function's shape has since
388
+ * changed (params renamed, reordered, collapsed into an options object, etc.),
389
+ * the recorded inputs no longer line up and `fn(...inputs)` throws. This hook
390
+ * lets a caller map the recorded inputs onto the current signature so replay
391
+ * can still run.
392
+ *
393
+ * Receives the deserialized recorded inputs and a per-trace {@link AdaptContext}
394
+ * (so a table-driven adapter can look up the adapted inputs by `traceId`), and
395
+ * returns the array actually spread into `fn`. The returned array is also what
396
+ * `ReplayItem.input` reports, so the experiment shows what was really run.
397
+ *
398
+ * Runs per item, inside the same try/catch as `fn`: if the adapter throws, the
399
+ * failure is surfaced on that item's `error` rather than crashing the run.
400
+ * Omit it to spread the recorded inputs unchanged.
401
+ */
402
+ adaptInputs?: (inputs: unknown[], ctx: AdaptContext) => unknown[];
403
+ }
404
+ /** Per-trace context passed to {@link ReplayOptions.adaptInputs}. */
405
+ interface AdaptContext {
406
+ /** Bitfab trace ID of the historical trace being replayed. */
407
+ traceId: string;
408
+ /** External span ID the recorded inputs were read from. */
409
+ sourceSpanId: string;
383
410
  }
411
+ /**
412
+ * The shape an adapter module must export as `adaptInputs`.
413
+ *
414
+ * Author an adapter in its own file (e.g. `scripts/replay-adapters/<name>.ts`),
415
+ * import it in your replay script, and pass it to `replay({ adaptInputs })`:
416
+ *
417
+ * ```ts
418
+ * import type { AdaptInputsFn } from "@bitfab/sdk"
419
+ * export const adaptInputs: AdaptInputsFn = (inputs, ctx) => [reshape(inputs)]
420
+ * ```
421
+ */
422
+ type AdaptInputsFn = (inputs: unknown[], ctx: AdaptContext) => unknown[];
384
423
  interface ReplayItem<T> {
385
424
  /** Trace ID of the new trace created during replay. */
386
425
  traceId: string | null;
@@ -920,9 +959,9 @@ declare class Bitfab {
920
959
  *
921
960
  * @param traceFunctionKey - The trace function key to replay
922
961
  * @param fn - The function to replay (must be the return value of `withSpan`)
923
- * @param options - Optional replay options. `limit` and `traceIds` are
924
- * mutually exclusive an explicit ID list already determines how many
925
- * traces replay, so passing both throws a BitfabError.
962
+ * @param options - Optional replay options. When `traceIds` is passed,
963
+ * `limit` is ignored (with a warning): an explicit ID list already
964
+ * determines how many traces replay.
926
965
  * @returns ReplayResult with items, testRunId, and testRunUrl
927
966
  */
928
967
  replay<TReturn>(traceFunctionKey: string, fn: (...args: any[]) => TReturn | Promise<TReturn>, options?: ReplayOptions): Promise<ReplayResult<TReturn>>;
@@ -988,7 +1027,7 @@ declare class BitfabFunction {
988
1027
  /**
989
1028
  * SDK version from package.json (injected at build time)
990
1029
  */
991
- declare const __version__ = "0.15.0";
1030
+ declare const __version__ = "0.16.1";
992
1031
 
993
1032
  /**
994
1033
  * Constants for the Bitfab SDK.
@@ -998,4 +1037,4 @@ declare const __version__ = "0.15.0";
998
1037
  */
999
1038
  declare const DEFAULT_SERVICE_URL = "https://bitfab.ai";
1000
1039
 
1001
- export { type ActiveSpanContext, type AllowedEnvVars, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler, BitfabOpenAITracingProcessor, type CodeChangeFile, type CurrentSpan, type CurrentTrace, DEFAULT_SERVICE_URL, type DbSnapshotConfig, type DbSnapshotProvider, type DbSnapshotRef, type DetachedTrace, type MockStrategy, type ProviderDefinition, ReplayEnvironment, type ReplayEnvironmentSnapshot, type ReplayItem, type ReplayOptions, type ReplayResult, SUPPORTED_PROVIDERS, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type WrapBAMLOptions, type WrappedBamlFn, __version__, flushTraces, getCurrentSpan, getCurrentTrace };
1040
+ export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler, BitfabOpenAITracingProcessor, type CodeChangeFile, type CurrentSpan, type CurrentTrace, DEFAULT_SERVICE_URL, type DbSnapshotConfig, type DbSnapshotProvider, type DbSnapshotRef, type DetachedTrace, type MockStrategy, type ProviderDefinition, ReplayEnvironment, type ReplayEnvironmentSnapshot, type ReplayItem, type ReplayOptions, type ReplayResult, SUPPORTED_PROVIDERS, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type WrapBAMLOptions, type WrappedBamlFn, __version__, flushTraces, getCurrentSpan, getCurrentTrace };
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  flushTraces,
12
12
  getCurrentSpan,
13
13
  getCurrentTrace
14
- } from "./chunk-YPG3XIG4.js";
14
+ } from "./chunk-P4WFJ5O3.js";
15
15
  import {
16
16
  BitfabError
17
17
  } from "./chunk-QT7HWOKU.js";
package/dist/node.cjs CHANGED
@@ -225,7 +225,7 @@ function buildMockTree(rootNode) {
225
225
  }
226
226
  return { spans };
227
227
  }
228
- async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, environment) {
228
+ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, environment, adaptInputs) {
229
229
  const lease = environment ? serverItem.dbBranchLease : void 0;
230
230
  let inputs = [];
231
231
  let originalOutput;
@@ -238,6 +238,12 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
238
238
  const spanData = span.rawData?.span_data ?? {};
239
239
  inputs = deserializeInputs(spanData);
240
240
  originalOutput = deserializeOutput(spanData);
241
+ if (adaptInputs) {
242
+ inputs = adaptInputs(inputs, {
243
+ traceId: serverItem.traceId,
244
+ sourceSpanId: serverItem.externalSpanId
245
+ });
246
+ }
241
247
  let mockTree;
242
248
  if (mockStrategy === "all" || mockStrategy === "marked") {
243
249
  const treeResponse = await httpClient.getSpanTree(
@@ -318,9 +324,12 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
318
324
  }
319
325
  }
320
326
  if (options?.limit !== void 0 && options?.traceIds !== void 0) {
321
- throw new BitfabError(
322
- "Pass either limit or traceIds, not both: an explicit trace ID list already determines how many traces replay."
323
- );
327
+ try {
328
+ console.warn(
329
+ "Bitfab: limit is ignored when traceIds is passed: the explicit trace ID list already determines how many traces replay."
330
+ );
331
+ } catch {
332
+ }
324
333
  }
325
334
  await replayContextReady;
326
335
  const {
@@ -348,7 +357,8 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
348
357
  fn,
349
358
  testRunId,
350
359
  mockStrategy,
351
- options?.environment
360
+ options?.environment,
361
+ options?.adaptInputs
352
362
  )
353
363
  );
354
364
  const resultItems = await mapWithConcurrency(tasks, maxConcurrency);
@@ -436,7 +446,7 @@ registerAsyncLocalStorageClass(
436
446
  );
437
447
 
438
448
  // src/version.generated.ts
439
- var __version__ = "0.15.0";
449
+ var __version__ = "0.16.1";
440
450
 
441
451
  // src/constants.ts
442
452
  var DEFAULT_SERVICE_URL = "https://bitfab.ai";
@@ -3226,9 +3236,9 @@ var Bitfab = class {
3226
3236
  *
3227
3237
  * @param traceFunctionKey - The trace function key to replay
3228
3238
  * @param fn - The function to replay (must be the return value of `withSpan`)
3229
- * @param options - Optional replay options. `limit` and `traceIds` are
3230
- * mutually exclusive an explicit ID list already determines how many
3231
- * traces replay, so passing both throws a BitfabError.
3239
+ * @param options - Optional replay options. When `traceIds` is passed,
3240
+ * `limit` is ignored (with a warning): an explicit ID list already
3241
+ * determines how many traces replay.
3232
3242
  * @returns ReplayResult with items, testRunId, and testRunUrl
3233
3243
  */
3234
3244
  async replay(traceFunctionKey, fn, options) {