bitfab 0.28.11 → 0.29.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/{chunk-ZBWTCBVQ.js → chunk-2M5AWVVQ.js} +96 -42
- package/dist/chunk-2M5AWVVQ.js.map +1 -0
- package/dist/{chunk-5E4BUIYA.js → chunk-V3XORTWI.js} +45 -8
- package/dist/chunk-V3XORTWI.js.map +1 -0
- package/dist/index.cjs +144 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +111 -2
- package/dist/index.d.ts +111 -2
- package/dist/index.js +2 -2
- package/dist/node.cjs +144 -46
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +2 -2
- package/dist/{replay-IEE4RY57.js → replay-HEGU3YU2.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-5E4BUIYA.js.map +0 -1
- package/dist/chunk-ZBWTCBVQ.js.map +0 -1
- /package/dist/{replay-IEE4RY57.js.map → replay-HEGU3YU2.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -73,6 +73,76 @@ declare class BitfabError extends Error {
|
|
|
73
73
|
constructor(message: string, url?: string | undefined);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Selective mock overrides for replay.
|
|
78
|
+
*
|
|
79
|
+
* A mock override injects a custom value into a specific span (node) during
|
|
80
|
+
* replay: the matched span short-circuits its real execution and returns the
|
|
81
|
+
* value you supply, so downstream real code runs against the substituted
|
|
82
|
+
* output. This is a third mock mode alongside "run real code" and "replay
|
|
83
|
+
* recorded output" (see {@link MockStrategy}).
|
|
84
|
+
*
|
|
85
|
+
* The matcher and value are deliberately separate so matching stays cheap
|
|
86
|
+
* (structural metadata only, no output fetch) and the recorded output is
|
|
87
|
+
* fetched lazily - and only if the value function actually asks for it via
|
|
88
|
+
* {@link MockOverrideCtx.getOriginalOutput}.
|
|
89
|
+
*/
|
|
90
|
+
/**
|
|
91
|
+
* Structural identity of a span during replay, passed to a {@link NodeMatcher}.
|
|
92
|
+
* Carries no output payload - matching must not depend on the recorded output,
|
|
93
|
+
* so the output fetch stays lazy and gated.
|
|
94
|
+
*/
|
|
95
|
+
interface SpanNodeMeta {
|
|
96
|
+
/** The `withSpan` key of the executing span (its code-side identity). */
|
|
97
|
+
traceFunctionKey: string;
|
|
98
|
+
/** Resolved span name: `options.name ?? fn.name ?? traceFunctionKey`. */
|
|
99
|
+
spanName: string;
|
|
100
|
+
/** Span type, e.g. "llm", "agent", "tool", "custom". */
|
|
101
|
+
type: string;
|
|
102
|
+
/**
|
|
103
|
+
* The id of this span in the original (replayed) trace, when it exists in
|
|
104
|
+
* that trace's tree. Undefined when the live span has no recorded
|
|
105
|
+
* counterpart (e.g. a span the changed code newly introduced).
|
|
106
|
+
*/
|
|
107
|
+
originalSpanId?: string;
|
|
108
|
+
}
|
|
109
|
+
/** Context passed to a {@link MockValue} function for a matched span. */
|
|
110
|
+
interface MockOverrideCtx {
|
|
111
|
+
/** The matched span's structural metadata. */
|
|
112
|
+
node: SpanNodeMeta;
|
|
113
|
+
/** The live replay args passed to the wrapped function this run. */
|
|
114
|
+
inputs: unknown[];
|
|
115
|
+
/**
|
|
116
|
+
* Lazily fetch this span's ORIGINAL recorded output (deserialized). The fetch
|
|
117
|
+
* happens only when called and is memoized per replay item, so a purely flat
|
|
118
|
+
* override that never calls it triggers zero output round trips. Rejects if
|
|
119
|
+
* the span has no recorded counterpart. Being async, it is only usable for
|
|
120
|
+
* spans wrapping async functions.
|
|
121
|
+
*/
|
|
122
|
+
getOriginalOutput: () => Promise<unknown>;
|
|
123
|
+
}
|
|
124
|
+
/** Selects which spans an override applies to. Runs on structural metadata. */
|
|
125
|
+
type NodeMatcher = (node: SpanNodeMeta) => boolean;
|
|
126
|
+
/** The function form of {@link MockValue}, receiving the override context. */
|
|
127
|
+
type MockValueFn = (ctx: MockOverrideCtx) => unknown | Promise<unknown>;
|
|
128
|
+
/**
|
|
129
|
+
* The value injected for a matched span: either a flat value used as-is, or a
|
|
130
|
+
* function of the {@link MockOverrideCtx} that returns one (or a Promise of
|
|
131
|
+
* one). Full replacement - the value IS the span's output, no merge with the
|
|
132
|
+
* recorded output.
|
|
133
|
+
*
|
|
134
|
+
* The flat side is spelled out (rather than `unknown`) so an inline function
|
|
135
|
+
* still gets a typed `ctx`: `unknown | Fn` would collapse to `unknown` and drop
|
|
136
|
+
* the contextual type. To inject a value that is itself a function, wrap it:
|
|
137
|
+
* `value: () => theFunction`.
|
|
138
|
+
*/
|
|
139
|
+
type MockValue = MockValueFn | string | number | boolean | bigint | symbol | object | null | undefined;
|
|
140
|
+
/** One (match, value) pair. */
|
|
141
|
+
interface MockOverride {
|
|
142
|
+
match: NodeMatcher;
|
|
143
|
+
value: MockValue;
|
|
144
|
+
}
|
|
145
|
+
|
|
76
146
|
/**
|
|
77
147
|
* HTTP client utilities for Bitfab API requests.
|
|
78
148
|
*
|
|
@@ -654,6 +724,15 @@ interface ReplayOptions {
|
|
|
654
724
|
* - "all": every child withSpan returns historical output
|
|
655
725
|
*/
|
|
656
726
|
mock?: MockStrategy;
|
|
727
|
+
/**
|
|
728
|
+
* Selective mock overrides: inject custom values into specific spans during
|
|
729
|
+
* replay, so downstream real code runs against the substituted output. Each
|
|
730
|
+
* override is a `{ match, value }` pair; the first matcher that
|
|
731
|
+
* matches a span wins. These take precedence over any overrides registered on
|
|
732
|
+
* the client via `registerMockOverride`, and over the base `mock` strategy - a
|
|
733
|
+
* span no override matches falls back to that strategy. See {@link MockOverride}.
|
|
734
|
+
*/
|
|
735
|
+
mockOverride?: MockOverride | MockOverride[];
|
|
657
736
|
/**
|
|
658
737
|
* Per-trace environment. When the source trace carries a DB branching
|
|
659
738
|
* snapshot, the SDK populates `environment.databaseUrl` before invoking
|
|
@@ -1192,6 +1271,12 @@ declare class Bitfab {
|
|
|
1192
1271
|
private readonly httpClient;
|
|
1193
1272
|
private readonly bamlClient;
|
|
1194
1273
|
private readonly dbSnapshot;
|
|
1274
|
+
/**
|
|
1275
|
+
* Mock overrides registered via {@link Bitfab.registerMockOverride}, applied
|
|
1276
|
+
* to every `replay` on this client (after any per-call `mockOverride`). In
|
|
1277
|
+
* registration order; first matcher wins within this list.
|
|
1278
|
+
*/
|
|
1279
|
+
private readonly mockOverrides;
|
|
1195
1280
|
/**
|
|
1196
1281
|
* Initialize the Bitfab client.
|
|
1197
1282
|
*
|
|
@@ -1499,6 +1584,30 @@ declare class Bitfab {
|
|
|
1499
1584
|
* determines how many traces replay.
|
|
1500
1585
|
* @returns ReplayResult with items, testRunId, and testRunUrl
|
|
1501
1586
|
*/
|
|
1587
|
+
/**
|
|
1588
|
+
* Register a mock override applied to every subsequent `replay` on this
|
|
1589
|
+
* client, so downstream real code runs against a value you supply for the
|
|
1590
|
+
* matched span. Instance-scoped (no global state); call {@link clearMockOverrides}
|
|
1591
|
+
* to reset. Per-call `replay({ mockOverride })` overrides take precedence, and
|
|
1592
|
+
* both take precedence over the base `mock` strategy.
|
|
1593
|
+
*
|
|
1594
|
+
* ```ts
|
|
1595
|
+
* // Object form (value is a flat value here)
|
|
1596
|
+
* bitfab.registerMockOverride({
|
|
1597
|
+
* match: (node) => node.traceFunctionKey === "classify-intent",
|
|
1598
|
+
* value: { label: "refund" },
|
|
1599
|
+
* })
|
|
1600
|
+
* // Ordered form (equivalent); value may also be a function of the context
|
|
1601
|
+
* bitfab.registerMockOverride(
|
|
1602
|
+
* (node) => node.traceFunctionKey === "classify-intent",
|
|
1603
|
+
* ({ inputs }) => ({ label: "refund" }),
|
|
1604
|
+
* )
|
|
1605
|
+
* ```
|
|
1606
|
+
*/
|
|
1607
|
+
registerMockOverride(override: MockOverride): void;
|
|
1608
|
+
registerMockOverride(match: NodeMatcher, value: MockValue): void;
|
|
1609
|
+
/** Remove all overrides registered via {@link registerMockOverride}. */
|
|
1610
|
+
clearMockOverrides(): void;
|
|
1502
1611
|
replay<TReturn>(traceFunctionKey: string, fn: (...args: any[]) => TReturn | Promise<TReturn>, options?: ReplayOptions): Promise<ReplayResult<TReturn>>;
|
|
1503
1612
|
}
|
|
1504
1613
|
/**
|
|
@@ -1649,7 +1758,7 @@ declare class BitfabFunction {
|
|
|
1649
1758
|
/**
|
|
1650
1759
|
* SDK version from package.json (injected at build time)
|
|
1651
1760
|
*/
|
|
1652
|
-
declare const __version__ = "0.
|
|
1761
|
+
declare const __version__ = "0.29.0";
|
|
1653
1762
|
|
|
1654
1763
|
/**
|
|
1655
1764
|
* Constants for the Bitfab SDK.
|
|
@@ -1717,4 +1826,4 @@ declare const finalizers: {
|
|
|
1717
1826
|
readableStream: typeof readableStream;
|
|
1718
1827
|
};
|
|
1719
1828
|
|
|
1720
|
-
export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, BITFAB_PROGRESS_PREFIX, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, type BitfabLanguageModelMiddleware, BitfabOpenAIAgentHandler, BitfabOpenAITracingProcessor, BitfabVercelAiHandler, type CapturedSpan, 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 ReplayProgress, type ReplayResult, SUPPORTED_PROVIDERS, type SpanLookup, type SpanOccurrence, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type VercelCallParams, type VercelGenerateResult, type VercelStreamResult, type WrapBAMLOptions, type WrappedBamlFn, __version__, finalizers, flushTraces, getCurrentSpan, getCurrentTrace, reportReplayProgress };
|
|
1829
|
+
export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, BITFAB_PROGRESS_PREFIX, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, type BitfabLanguageModelMiddleware, BitfabOpenAIAgentHandler, BitfabOpenAITracingProcessor, BitfabVercelAiHandler, type CapturedSpan, type CodeChangeFile, type CurrentSpan, type CurrentTrace, DEFAULT_SERVICE_URL, type DbSnapshotConfig, type DbSnapshotProvider, type DbSnapshotRef, type DetachedTrace, type MockOverride, type MockOverrideCtx, type MockStrategy, type MockValue, type NodeMatcher, type ProviderDefinition, ReplayEnvironment, type ReplayEnvironmentSnapshot, type ReplayItem, type ReplayOptions, type ReplayProgress, type ReplayResult, SUPPORTED_PROVIDERS, type SpanLookup, type SpanNodeMeta, type SpanOccurrence, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type VercelCallParams, type VercelGenerateResult, type VercelStreamResult, type WrapBAMLOptions, type WrappedBamlFn, __version__, finalizers, flushTraces, getCurrentSpan, getCurrentTrace, reportReplayProgress };
|
package/dist/index.d.ts
CHANGED
|
@@ -73,6 +73,76 @@ declare class BitfabError extends Error {
|
|
|
73
73
|
constructor(message: string, url?: string | undefined);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Selective mock overrides for replay.
|
|
78
|
+
*
|
|
79
|
+
* A mock override injects a custom value into a specific span (node) during
|
|
80
|
+
* replay: the matched span short-circuits its real execution and returns the
|
|
81
|
+
* value you supply, so downstream real code runs against the substituted
|
|
82
|
+
* output. This is a third mock mode alongside "run real code" and "replay
|
|
83
|
+
* recorded output" (see {@link MockStrategy}).
|
|
84
|
+
*
|
|
85
|
+
* The matcher and value are deliberately separate so matching stays cheap
|
|
86
|
+
* (structural metadata only, no output fetch) and the recorded output is
|
|
87
|
+
* fetched lazily - and only if the value function actually asks for it via
|
|
88
|
+
* {@link MockOverrideCtx.getOriginalOutput}.
|
|
89
|
+
*/
|
|
90
|
+
/**
|
|
91
|
+
* Structural identity of a span during replay, passed to a {@link NodeMatcher}.
|
|
92
|
+
* Carries no output payload - matching must not depend on the recorded output,
|
|
93
|
+
* so the output fetch stays lazy and gated.
|
|
94
|
+
*/
|
|
95
|
+
interface SpanNodeMeta {
|
|
96
|
+
/** The `withSpan` key of the executing span (its code-side identity). */
|
|
97
|
+
traceFunctionKey: string;
|
|
98
|
+
/** Resolved span name: `options.name ?? fn.name ?? traceFunctionKey`. */
|
|
99
|
+
spanName: string;
|
|
100
|
+
/** Span type, e.g. "llm", "agent", "tool", "custom". */
|
|
101
|
+
type: string;
|
|
102
|
+
/**
|
|
103
|
+
* The id of this span in the original (replayed) trace, when it exists in
|
|
104
|
+
* that trace's tree. Undefined when the live span has no recorded
|
|
105
|
+
* counterpart (e.g. a span the changed code newly introduced).
|
|
106
|
+
*/
|
|
107
|
+
originalSpanId?: string;
|
|
108
|
+
}
|
|
109
|
+
/** Context passed to a {@link MockValue} function for a matched span. */
|
|
110
|
+
interface MockOverrideCtx {
|
|
111
|
+
/** The matched span's structural metadata. */
|
|
112
|
+
node: SpanNodeMeta;
|
|
113
|
+
/** The live replay args passed to the wrapped function this run. */
|
|
114
|
+
inputs: unknown[];
|
|
115
|
+
/**
|
|
116
|
+
* Lazily fetch this span's ORIGINAL recorded output (deserialized). The fetch
|
|
117
|
+
* happens only when called and is memoized per replay item, so a purely flat
|
|
118
|
+
* override that never calls it triggers zero output round trips. Rejects if
|
|
119
|
+
* the span has no recorded counterpart. Being async, it is only usable for
|
|
120
|
+
* spans wrapping async functions.
|
|
121
|
+
*/
|
|
122
|
+
getOriginalOutput: () => Promise<unknown>;
|
|
123
|
+
}
|
|
124
|
+
/** Selects which spans an override applies to. Runs on structural metadata. */
|
|
125
|
+
type NodeMatcher = (node: SpanNodeMeta) => boolean;
|
|
126
|
+
/** The function form of {@link MockValue}, receiving the override context. */
|
|
127
|
+
type MockValueFn = (ctx: MockOverrideCtx) => unknown | Promise<unknown>;
|
|
128
|
+
/**
|
|
129
|
+
* The value injected for a matched span: either a flat value used as-is, or a
|
|
130
|
+
* function of the {@link MockOverrideCtx} that returns one (or a Promise of
|
|
131
|
+
* one). Full replacement - the value IS the span's output, no merge with the
|
|
132
|
+
* recorded output.
|
|
133
|
+
*
|
|
134
|
+
* The flat side is spelled out (rather than `unknown`) so an inline function
|
|
135
|
+
* still gets a typed `ctx`: `unknown | Fn` would collapse to `unknown` and drop
|
|
136
|
+
* the contextual type. To inject a value that is itself a function, wrap it:
|
|
137
|
+
* `value: () => theFunction`.
|
|
138
|
+
*/
|
|
139
|
+
type MockValue = MockValueFn | string | number | boolean | bigint | symbol | object | null | undefined;
|
|
140
|
+
/** One (match, value) pair. */
|
|
141
|
+
interface MockOverride {
|
|
142
|
+
match: NodeMatcher;
|
|
143
|
+
value: MockValue;
|
|
144
|
+
}
|
|
145
|
+
|
|
76
146
|
/**
|
|
77
147
|
* HTTP client utilities for Bitfab API requests.
|
|
78
148
|
*
|
|
@@ -654,6 +724,15 @@ interface ReplayOptions {
|
|
|
654
724
|
* - "all": every child withSpan returns historical output
|
|
655
725
|
*/
|
|
656
726
|
mock?: MockStrategy;
|
|
727
|
+
/**
|
|
728
|
+
* Selective mock overrides: inject custom values into specific spans during
|
|
729
|
+
* replay, so downstream real code runs against the substituted output. Each
|
|
730
|
+
* override is a `{ match, value }` pair; the first matcher that
|
|
731
|
+
* matches a span wins. These take precedence over any overrides registered on
|
|
732
|
+
* the client via `registerMockOverride`, and over the base `mock` strategy - a
|
|
733
|
+
* span no override matches falls back to that strategy. See {@link MockOverride}.
|
|
734
|
+
*/
|
|
735
|
+
mockOverride?: MockOverride | MockOverride[];
|
|
657
736
|
/**
|
|
658
737
|
* Per-trace environment. When the source trace carries a DB branching
|
|
659
738
|
* snapshot, the SDK populates `environment.databaseUrl` before invoking
|
|
@@ -1192,6 +1271,12 @@ declare class Bitfab {
|
|
|
1192
1271
|
private readonly httpClient;
|
|
1193
1272
|
private readonly bamlClient;
|
|
1194
1273
|
private readonly dbSnapshot;
|
|
1274
|
+
/**
|
|
1275
|
+
* Mock overrides registered via {@link Bitfab.registerMockOverride}, applied
|
|
1276
|
+
* to every `replay` on this client (after any per-call `mockOverride`). In
|
|
1277
|
+
* registration order; first matcher wins within this list.
|
|
1278
|
+
*/
|
|
1279
|
+
private readonly mockOverrides;
|
|
1195
1280
|
/**
|
|
1196
1281
|
* Initialize the Bitfab client.
|
|
1197
1282
|
*
|
|
@@ -1499,6 +1584,30 @@ declare class Bitfab {
|
|
|
1499
1584
|
* determines how many traces replay.
|
|
1500
1585
|
* @returns ReplayResult with items, testRunId, and testRunUrl
|
|
1501
1586
|
*/
|
|
1587
|
+
/**
|
|
1588
|
+
* Register a mock override applied to every subsequent `replay` on this
|
|
1589
|
+
* client, so downstream real code runs against a value you supply for the
|
|
1590
|
+
* matched span. Instance-scoped (no global state); call {@link clearMockOverrides}
|
|
1591
|
+
* to reset. Per-call `replay({ mockOverride })` overrides take precedence, and
|
|
1592
|
+
* both take precedence over the base `mock` strategy.
|
|
1593
|
+
*
|
|
1594
|
+
* ```ts
|
|
1595
|
+
* // Object form (value is a flat value here)
|
|
1596
|
+
* bitfab.registerMockOverride({
|
|
1597
|
+
* match: (node) => node.traceFunctionKey === "classify-intent",
|
|
1598
|
+
* value: { label: "refund" },
|
|
1599
|
+
* })
|
|
1600
|
+
* // Ordered form (equivalent); value may also be a function of the context
|
|
1601
|
+
* bitfab.registerMockOverride(
|
|
1602
|
+
* (node) => node.traceFunctionKey === "classify-intent",
|
|
1603
|
+
* ({ inputs }) => ({ label: "refund" }),
|
|
1604
|
+
* )
|
|
1605
|
+
* ```
|
|
1606
|
+
*/
|
|
1607
|
+
registerMockOverride(override: MockOverride): void;
|
|
1608
|
+
registerMockOverride(match: NodeMatcher, value: MockValue): void;
|
|
1609
|
+
/** Remove all overrides registered via {@link registerMockOverride}. */
|
|
1610
|
+
clearMockOverrides(): void;
|
|
1502
1611
|
replay<TReturn>(traceFunctionKey: string, fn: (...args: any[]) => TReturn | Promise<TReturn>, options?: ReplayOptions): Promise<ReplayResult<TReturn>>;
|
|
1503
1612
|
}
|
|
1504
1613
|
/**
|
|
@@ -1649,7 +1758,7 @@ declare class BitfabFunction {
|
|
|
1649
1758
|
/**
|
|
1650
1759
|
* SDK version from package.json (injected at build time)
|
|
1651
1760
|
*/
|
|
1652
|
-
declare const __version__ = "0.
|
|
1761
|
+
declare const __version__ = "0.29.0";
|
|
1653
1762
|
|
|
1654
1763
|
/**
|
|
1655
1764
|
* Constants for the Bitfab SDK.
|
|
@@ -1717,4 +1826,4 @@ declare const finalizers: {
|
|
|
1717
1826
|
readableStream: typeof readableStream;
|
|
1718
1827
|
};
|
|
1719
1828
|
|
|
1720
|
-
export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, BITFAB_PROGRESS_PREFIX, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, type BitfabLanguageModelMiddleware, BitfabOpenAIAgentHandler, BitfabOpenAITracingProcessor, BitfabVercelAiHandler, type CapturedSpan, 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 ReplayProgress, type ReplayResult, SUPPORTED_PROVIDERS, type SpanLookup, type SpanOccurrence, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type VercelCallParams, type VercelGenerateResult, type VercelStreamResult, type WrapBAMLOptions, type WrappedBamlFn, __version__, finalizers, flushTraces, getCurrentSpan, getCurrentTrace, reportReplayProgress };
|
|
1829
|
+
export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, BITFAB_PROGRESS_PREFIX, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, type BitfabLanguageModelMiddleware, BitfabOpenAIAgentHandler, BitfabOpenAITracingProcessor, BitfabVercelAiHandler, type CapturedSpan, type CodeChangeFile, type CurrentSpan, type CurrentTrace, DEFAULT_SERVICE_URL, type DbSnapshotConfig, type DbSnapshotProvider, type DbSnapshotRef, type DetachedTrace, type MockOverride, type MockOverrideCtx, type MockStrategy, type MockValue, type NodeMatcher, type ProviderDefinition, ReplayEnvironment, type ReplayEnvironmentSnapshot, type ReplayItem, type ReplayOptions, type ReplayProgress, type ReplayResult, SUPPORTED_PROVIDERS, type SpanLookup, type SpanNodeMeta, type SpanOccurrence, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type VercelCallParams, type VercelGenerateResult, type VercelStreamResult, type WrapBAMLOptions, type WrappedBamlFn, __version__, finalizers, flushTraces, getCurrentSpan, getCurrentTrace, reportReplayProgress };
|
package/dist/index.js
CHANGED
|
@@ -23,12 +23,12 @@ import {
|
|
|
23
23
|
flushTraces,
|
|
24
24
|
getCurrentSpan,
|
|
25
25
|
getCurrentTrace
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-2M5AWVVQ.js";
|
|
27
27
|
import {
|
|
28
28
|
BITFAB_PROGRESS_PREFIX,
|
|
29
29
|
BitfabError,
|
|
30
30
|
reportReplayProgress
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-V3XORTWI.js";
|
|
32
32
|
export {
|
|
33
33
|
BITFAB_PROGRESS_PREFIX,
|
|
34
34
|
Bitfab,
|
package/dist/node.cjs
CHANGED
|
@@ -298,6 +298,22 @@ var init_randomUuid = __esm({
|
|
|
298
298
|
}
|
|
299
299
|
});
|
|
300
300
|
|
|
301
|
+
// src/mockOverride.ts
|
|
302
|
+
function resolveMockValue(value, ctx) {
|
|
303
|
+
return typeof value === "function" ? value(ctx) : value;
|
|
304
|
+
}
|
|
305
|
+
function normalizeMockOverrides(mockOverride) {
|
|
306
|
+
if (mockOverride === void 0) {
|
|
307
|
+
return [];
|
|
308
|
+
}
|
|
309
|
+
return Array.isArray(mockOverride) ? mockOverride : [mockOverride];
|
|
310
|
+
}
|
|
311
|
+
var init_mockOverride = __esm({
|
|
312
|
+
"src/mockOverride.ts"() {
|
|
313
|
+
"use strict";
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
301
317
|
// src/replayContext.ts
|
|
302
318
|
function getReplayContext() {
|
|
303
319
|
return replayContextStorage?.getStore() ?? null;
|
|
@@ -373,6 +389,7 @@ function buildMockTree(rootNode) {
|
|
|
373
389
|
counters.set(counterKey, index + 1);
|
|
374
390
|
spans.set(`${counterKey}:${index}`, {
|
|
375
391
|
sourceSpanId: node.sourceSpanId,
|
|
392
|
+
externalSpanId: node.externalSpanId,
|
|
376
393
|
output: node.output,
|
|
377
394
|
outputMeta: node.outputMeta
|
|
378
395
|
});
|
|
@@ -386,7 +403,7 @@ function buildMockTree(rootNode) {
|
|
|
386
403
|
}
|
|
387
404
|
return { spans };
|
|
388
405
|
}
|
|
389
|
-
async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, environment, adaptInputs) {
|
|
406
|
+
async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, resolvedOverrides, environment, adaptInputs) {
|
|
390
407
|
const lease = environment ? serverItem.dbBranchLease : void 0;
|
|
391
408
|
let inputs = [];
|
|
392
409
|
let originalOutput;
|
|
@@ -405,28 +422,45 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
|
|
|
405
422
|
sourceSpanId: serverItem.externalSpanId
|
|
406
423
|
});
|
|
407
424
|
}
|
|
425
|
+
const hasOverrides = resolvedOverrides.length > 0;
|
|
426
|
+
const needTree = mockStrategy === "all" || mockStrategy === "marked" || hasOverrides;
|
|
427
|
+
const includeOutputs = mockStrategy === "all";
|
|
408
428
|
let mockTree;
|
|
409
|
-
if (
|
|
429
|
+
if (needTree) {
|
|
410
430
|
try {
|
|
411
431
|
const treeResponse = await httpClient.getSpanTree(
|
|
412
|
-
serverItem.externalSpanId
|
|
432
|
+
serverItem.externalSpanId,
|
|
433
|
+
{ includeOutputs }
|
|
413
434
|
);
|
|
414
435
|
if (treeResponse.root) {
|
|
415
436
|
mockTree = buildMockTree(treeResponse.root);
|
|
416
|
-
} else if (mockStrategy === "all") {
|
|
437
|
+
} else if (mockStrategy === "all" || hasOverrides) {
|
|
417
438
|
throw new BitfabError(
|
|
418
|
-
`Replay mock strategy "
|
|
439
|
+
`Replay mock strategy "${mockStrategy}"${hasOverrides ? " with overrides" : ""} requires a span tree root for source span ${serverItem.externalSpanId}.`
|
|
419
440
|
);
|
|
420
441
|
} else {
|
|
421
442
|
mockTree = void 0;
|
|
422
443
|
}
|
|
423
444
|
} catch (e) {
|
|
424
|
-
if (mockStrategy === "all") {
|
|
445
|
+
if (mockStrategy === "all" || hasOverrides) {
|
|
425
446
|
throw e;
|
|
426
447
|
}
|
|
427
448
|
mockTree = void 0;
|
|
428
449
|
}
|
|
429
450
|
}
|
|
451
|
+
const outputCache = /* @__PURE__ */ new Map();
|
|
452
|
+
const fetchSpanOutput = mockTree && !includeOutputs ? (externalSpanId) => {
|
|
453
|
+
let pending = outputCache.get(externalSpanId);
|
|
454
|
+
if (!pending) {
|
|
455
|
+
pending = httpClient.getExternalSpan(externalSpanId).then(
|
|
456
|
+
(s) => deserializeOutput(
|
|
457
|
+
s.rawData?.span_data ?? {}
|
|
458
|
+
)
|
|
459
|
+
);
|
|
460
|
+
outputCache.set(externalSpanId, pending);
|
|
461
|
+
}
|
|
462
|
+
return pending;
|
|
463
|
+
} : void 0;
|
|
430
464
|
const maybePromise = runWithReplayContext(
|
|
431
465
|
{
|
|
432
466
|
testRunId,
|
|
@@ -437,6 +471,8 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
|
|
|
437
471
|
mockTree,
|
|
438
472
|
callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
|
|
439
473
|
mockStrategy,
|
|
474
|
+
mockOverrides: hasOverrides ? resolvedOverrides : void 0,
|
|
475
|
+
fetchSpanOutput,
|
|
440
476
|
dbBranchLease: lease,
|
|
441
477
|
pendingPersistence
|
|
442
478
|
},
|
|
@@ -493,7 +529,7 @@ async function mapWithConcurrency(tasks, maxConcurrency, onSettled) {
|
|
|
493
529
|
await Promise.all(workers);
|
|
494
530
|
return results;
|
|
495
531
|
}
|
|
496
|
-
async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
|
|
532
|
+
async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, registeredOverrides = []) {
|
|
497
533
|
if (options?.traceIds !== void 0) {
|
|
498
534
|
if (options.traceIds.length === 0) {
|
|
499
535
|
throw new BitfabError("traceIds must contain at least one trace ID.");
|
|
@@ -533,6 +569,10 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
|
|
|
533
569
|
);
|
|
534
570
|
const mockStrategy = options?.mock ?? "marked";
|
|
535
571
|
const maxConcurrency = options?.maxConcurrency ?? 10;
|
|
572
|
+
const resolvedOverrides = [
|
|
573
|
+
...normalizeMockOverrides(options?.mockOverride),
|
|
574
|
+
...registeredOverrides
|
|
575
|
+
];
|
|
536
576
|
const tasks = serverItems.map(
|
|
537
577
|
(serverItem) => () => processItem(
|
|
538
578
|
httpClient,
|
|
@@ -540,6 +580,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
|
|
|
540
580
|
fn,
|
|
541
581
|
testRunId,
|
|
542
582
|
mockStrategy,
|
|
583
|
+
resolvedOverrides,
|
|
543
584
|
options?.environment,
|
|
544
585
|
options?.adaptInputs
|
|
545
586
|
)
|
|
@@ -666,6 +707,7 @@ var init_replay = __esm({
|
|
|
666
707
|
"src/replay.ts"() {
|
|
667
708
|
"use strict";
|
|
668
709
|
init_errors();
|
|
710
|
+
init_mockOverride();
|
|
669
711
|
init_randomUuid();
|
|
670
712
|
init_replayContext();
|
|
671
713
|
init_serialize();
|
|
@@ -706,7 +748,7 @@ registerAsyncLocalStorageClass(
|
|
|
706
748
|
);
|
|
707
749
|
|
|
708
750
|
// src/version.generated.ts
|
|
709
|
-
var __version__ = "0.
|
|
751
|
+
var __version__ = "0.29.0";
|
|
710
752
|
|
|
711
753
|
// src/constants.ts
|
|
712
754
|
var DEFAULT_SERVICE_URL = "https://bitfab.ai";
|
|
@@ -1135,9 +1177,14 @@ var HttpClient = class {
|
|
|
1135
1177
|
/**
|
|
1136
1178
|
* Fetch the span tree for a root span.
|
|
1137
1179
|
* Blocking GET request.
|
|
1180
|
+
*
|
|
1181
|
+
* Pass `includeOutputs: false` for a payload-free tree (structure +
|
|
1182
|
+
* `externalSpanId` only), so recorded outputs are fetched lazily per mocked
|
|
1183
|
+
* span instead of all up front. Omit it (default eager) for `mock: "all"`.
|
|
1138
1184
|
*/
|
|
1139
|
-
async getSpanTree(externalSpanId) {
|
|
1140
|
-
const
|
|
1185
|
+
async getSpanTree(externalSpanId, options) {
|
|
1186
|
+
const query = options?.includeOutputs === false ? "?includeOutputs=false" : "";
|
|
1187
|
+
const url = `${this.serviceUrl}/api/sdk/replay/spanTree/${externalSpanId}${query}`;
|
|
1141
1188
|
const controller = new AbortController();
|
|
1142
1189
|
const timeoutId = setTimeout(() => controller.abort(), 3e4);
|
|
1143
1190
|
try {
|
|
@@ -2723,6 +2770,9 @@ var BitfabLangGraphCallbackHandler = class {
|
|
|
2723
2770
|
}
|
|
2724
2771
|
};
|
|
2725
2772
|
|
|
2773
|
+
// src/client.ts
|
|
2774
|
+
init_mockOverride();
|
|
2775
|
+
|
|
2726
2776
|
// src/openaiAgentSdk.ts
|
|
2727
2777
|
var BitfabOpenAIAgentHandler = class {
|
|
2728
2778
|
constructor(config) {
|
|
@@ -3538,6 +3588,12 @@ var Bitfab = class {
|
|
|
3538
3588
|
constructor(config) {
|
|
3539
3589
|
/** Gate the empty-key warning to fire at most once. */
|
|
3540
3590
|
this.apiKeyWarned = false;
|
|
3591
|
+
/**
|
|
3592
|
+
* Mock overrides registered via {@link Bitfab.registerMockOverride}, applied
|
|
3593
|
+
* to every `replay` on this client (after any per-call `mockOverride`). In
|
|
3594
|
+
* registration order; first matcher wins within this list.
|
|
3595
|
+
*/
|
|
3596
|
+
this.mockOverrides = [];
|
|
3541
3597
|
this.apiKeyConfig = config.apiKey;
|
|
3542
3598
|
this.serviceUrl = config.serviceUrl ?? DEFAULT_SERVICE_URL;
|
|
3543
3599
|
this.timeout = config.timeout ?? 12e4;
|
|
@@ -4150,24 +4206,77 @@ var Bitfab = class {
|
|
|
4150
4206
|
const counterKey = `${traceFunctionKey}:${baseSpanParams.spanName}`;
|
|
4151
4207
|
const callIndex = counters.get(counterKey) ?? 0;
|
|
4152
4208
|
counters.set(counterKey, callIndex + 1);
|
|
4153
|
-
const
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
if (
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4209
|
+
const mockKey = `${counterKey}:${callIndex}`;
|
|
4210
|
+
const mockSpan = replayCtxForMock.mockTree.spans.get(mockKey);
|
|
4211
|
+
const emitMock = (output) => {
|
|
4212
|
+
void sendSpan({ result: output, mocked: true });
|
|
4213
|
+
if (fnReturnsPromise) {
|
|
4214
|
+
return Promise.resolve(output);
|
|
4215
|
+
}
|
|
4216
|
+
return output;
|
|
4217
|
+
};
|
|
4218
|
+
const emitMockAsync = (pending) => {
|
|
4219
|
+
if (!fnReturnsPromise) {
|
|
4220
|
+
throw new BitfabError(
|
|
4221
|
+
`Cannot mock synchronous span "${traceFunctionKey}" with an asynchronously-resolved value (lazy recorded-output fetch or an async value function). Make the wrapped function async, or use mock: "all" so recorded outputs are fetched eagerly.`
|
|
4222
|
+
);
|
|
4223
|
+
}
|
|
4224
|
+
return (async () => {
|
|
4225
|
+
const output = await pending;
|
|
4165
4226
|
void sendSpan({ result: output, mocked: true });
|
|
4166
|
-
if (fnReturnsPromise) {
|
|
4167
|
-
return Promise.resolve(output);
|
|
4168
|
-
}
|
|
4169
4227
|
return output;
|
|
4228
|
+
})();
|
|
4229
|
+
};
|
|
4230
|
+
const resolveRecordedOutput = () => {
|
|
4231
|
+
const hasInlineOutput = mockSpan?.output !== void 0 || mockSpan?.outputMeta !== void 0;
|
|
4232
|
+
if (!hasInlineOutput && replayCtxForMock.fetchSpanOutput && mockSpan?.externalSpanId) {
|
|
4233
|
+
return replayCtxForMock.fetchSpanOutput(mockSpan.externalSpanId);
|
|
4170
4234
|
}
|
|
4235
|
+
if (!mockSpan) {
|
|
4236
|
+
return Promise.reject(
|
|
4237
|
+
new BitfabError(
|
|
4238
|
+
`No recorded span to source output for "${traceFunctionKey}".`
|
|
4239
|
+
)
|
|
4240
|
+
);
|
|
4241
|
+
}
|
|
4242
|
+
let output = mockSpan.output;
|
|
4243
|
+
if (mockSpan.outputMeta !== void 0 && mockSpan.outputMeta !== null) {
|
|
4244
|
+
output = deserializeValue({
|
|
4245
|
+
json: mockSpan.output,
|
|
4246
|
+
meta: mockSpan.outputMeta
|
|
4247
|
+
});
|
|
4248
|
+
}
|
|
4249
|
+
return output;
|
|
4250
|
+
};
|
|
4251
|
+
if (replayCtxForMock.mockOverrides?.length) {
|
|
4252
|
+
const nodeMeta = {
|
|
4253
|
+
traceFunctionKey,
|
|
4254
|
+
spanName: baseSpanParams.spanName,
|
|
4255
|
+
type: options.type ?? "custom",
|
|
4256
|
+
originalSpanId: mockSpan?.sourceSpanId
|
|
4257
|
+
};
|
|
4258
|
+
const override = replayCtxForMock.mockOverrides.find(
|
|
4259
|
+
(o) => o.match(nodeMeta)
|
|
4260
|
+
);
|
|
4261
|
+
if (override) {
|
|
4262
|
+
const injected = resolveMockValue(override.value, {
|
|
4263
|
+
node: nodeMeta,
|
|
4264
|
+
inputs: args,
|
|
4265
|
+
getOriginalOutput: () => Promise.resolve(resolveRecordedOutput())
|
|
4266
|
+
});
|
|
4267
|
+
if (injected instanceof Promise) {
|
|
4268
|
+
return emitMockAsync(injected);
|
|
4269
|
+
}
|
|
4270
|
+
return emitMock(injected);
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
const shouldMock = replayCtxForMock.mockStrategy === "all" || replayCtxForMock.mockStrategy === "marked" && options.mockOnReplay === true;
|
|
4274
|
+
if (shouldMock && mockSpan) {
|
|
4275
|
+
const recorded = resolveRecordedOutput();
|
|
4276
|
+
if (recorded instanceof Promise) {
|
|
4277
|
+
return emitMockAsync(recorded);
|
|
4278
|
+
}
|
|
4279
|
+
return emitMock(recorded);
|
|
4171
4280
|
}
|
|
4172
4281
|
}
|
|
4173
4282
|
const recordSpan = (result) => {
|
|
@@ -4447,26 +4556,14 @@ var Bitfab = class {
|
|
|
4447
4556
|
...params.mocked && { mocked: true }
|
|
4448
4557
|
});
|
|
4449
4558
|
}
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
* invocation records a trace tied to the test run. The plain-callable form
|
|
4459
|
-
* is how handler-instrumented workflows (LangGraph/LangChain, Claude Agent
|
|
4460
|
-
* SDK) replay - those record traces under a key with no `withSpan`-wrapped
|
|
4461
|
-
* root in the app.
|
|
4462
|
-
*
|
|
4463
|
-
* @param traceFunctionKey - The trace function key to replay
|
|
4464
|
-
* @param fn - The function to run recorded inputs through
|
|
4465
|
-
* @param options - Optional replay options. When `traceIds` is passed,
|
|
4466
|
-
* `limit` is ignored (with a warning): an explicit ID list already
|
|
4467
|
-
* determines how many traces replay.
|
|
4468
|
-
* @returns ReplayResult with items, testRunId, and testRunUrl
|
|
4469
|
-
*/
|
|
4559
|
+
registerMockOverride(overrideOrMatch, value) {
|
|
4560
|
+
const override = typeof overrideOrMatch === "function" ? { match: overrideOrMatch, value } : overrideOrMatch;
|
|
4561
|
+
this.mockOverrides.push(override);
|
|
4562
|
+
}
|
|
4563
|
+
/** Remove all overrides registered via {@link registerMockOverride}. */
|
|
4564
|
+
clearMockOverrides() {
|
|
4565
|
+
this.mockOverrides.length = 0;
|
|
4566
|
+
}
|
|
4470
4567
|
async replay(traceFunctionKey, fn, options) {
|
|
4471
4568
|
const wrappedKey = fn._bitfabTraceFunctionKey;
|
|
4472
4569
|
let replayFn = fn;
|
|
@@ -4487,7 +4584,8 @@ var Bitfab = class {
|
|
|
4487
4584
|
this.serviceUrl,
|
|
4488
4585
|
traceFunctionKey,
|
|
4489
4586
|
replayFn,
|
|
4490
|
-
options
|
|
4587
|
+
options,
|
|
4588
|
+
this.mockOverrides
|
|
4491
4589
|
);
|
|
4492
4590
|
}
|
|
4493
4591
|
};
|