@bitfab/sdk 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
|
@@ -14,12 +14,12 @@ import {
|
|
|
14
14
|
flushTraces,
|
|
15
15
|
getCurrentSpan,
|
|
16
16
|
getCurrentTrace
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-2M5AWVVQ.js";
|
|
18
18
|
import {
|
|
19
19
|
BITFAB_PROGRESS_PREFIX,
|
|
20
20
|
BitfabError,
|
|
21
21
|
reportReplayProgress
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-V3XORTWI.js";
|
|
23
23
|
export {
|
|
24
24
|
BITFAB_PROGRESS_PREFIX,
|
|
25
25
|
Bitfab,
|
package/dist/node.cjs
CHANGED
|
@@ -289,6 +289,22 @@ var init_randomUuid = __esm({
|
|
|
289
289
|
}
|
|
290
290
|
});
|
|
291
291
|
|
|
292
|
+
// src/mockOverride.ts
|
|
293
|
+
function resolveMockValue(value, ctx) {
|
|
294
|
+
return typeof value === "function" ? value(ctx) : value;
|
|
295
|
+
}
|
|
296
|
+
function normalizeMockOverrides(mockOverride) {
|
|
297
|
+
if (mockOverride === void 0) {
|
|
298
|
+
return [];
|
|
299
|
+
}
|
|
300
|
+
return Array.isArray(mockOverride) ? mockOverride : [mockOverride];
|
|
301
|
+
}
|
|
302
|
+
var init_mockOverride = __esm({
|
|
303
|
+
"src/mockOverride.ts"() {
|
|
304
|
+
"use strict";
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
|
|
292
308
|
// src/replayContext.ts
|
|
293
309
|
function getReplayContext() {
|
|
294
310
|
return replayContextStorage?.getStore() ?? null;
|
|
@@ -364,6 +380,7 @@ function buildMockTree(rootNode) {
|
|
|
364
380
|
counters.set(counterKey, index + 1);
|
|
365
381
|
spans.set(`${counterKey}:${index}`, {
|
|
366
382
|
sourceSpanId: node.sourceSpanId,
|
|
383
|
+
externalSpanId: node.externalSpanId,
|
|
367
384
|
output: node.output,
|
|
368
385
|
outputMeta: node.outputMeta
|
|
369
386
|
});
|
|
@@ -377,7 +394,7 @@ function buildMockTree(rootNode) {
|
|
|
377
394
|
}
|
|
378
395
|
return { spans };
|
|
379
396
|
}
|
|
380
|
-
async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, environment, adaptInputs) {
|
|
397
|
+
async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, resolvedOverrides, environment, adaptInputs) {
|
|
381
398
|
const lease = environment ? serverItem.dbBranchLease : void 0;
|
|
382
399
|
let inputs = [];
|
|
383
400
|
let originalOutput;
|
|
@@ -396,28 +413,45 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
|
|
|
396
413
|
sourceSpanId: serverItem.externalSpanId
|
|
397
414
|
});
|
|
398
415
|
}
|
|
416
|
+
const hasOverrides = resolvedOverrides.length > 0;
|
|
417
|
+
const needTree = mockStrategy === "all" || mockStrategy === "marked" || hasOverrides;
|
|
418
|
+
const includeOutputs = mockStrategy === "all";
|
|
399
419
|
let mockTree;
|
|
400
|
-
if (
|
|
420
|
+
if (needTree) {
|
|
401
421
|
try {
|
|
402
422
|
const treeResponse = await httpClient.getSpanTree(
|
|
403
|
-
serverItem.externalSpanId
|
|
423
|
+
serverItem.externalSpanId,
|
|
424
|
+
{ includeOutputs }
|
|
404
425
|
);
|
|
405
426
|
if (treeResponse.root) {
|
|
406
427
|
mockTree = buildMockTree(treeResponse.root);
|
|
407
|
-
} else if (mockStrategy === "all") {
|
|
428
|
+
} else if (mockStrategy === "all" || hasOverrides) {
|
|
408
429
|
throw new BitfabError(
|
|
409
|
-
`Replay mock strategy "
|
|
430
|
+
`Replay mock strategy "${mockStrategy}"${hasOverrides ? " with overrides" : ""} requires a span tree root for source span ${serverItem.externalSpanId}.`
|
|
410
431
|
);
|
|
411
432
|
} else {
|
|
412
433
|
mockTree = void 0;
|
|
413
434
|
}
|
|
414
435
|
} catch (e) {
|
|
415
|
-
if (mockStrategy === "all") {
|
|
436
|
+
if (mockStrategy === "all" || hasOverrides) {
|
|
416
437
|
throw e;
|
|
417
438
|
}
|
|
418
439
|
mockTree = void 0;
|
|
419
440
|
}
|
|
420
441
|
}
|
|
442
|
+
const outputCache = /* @__PURE__ */ new Map();
|
|
443
|
+
const fetchSpanOutput = mockTree && !includeOutputs ? (externalSpanId) => {
|
|
444
|
+
let pending = outputCache.get(externalSpanId);
|
|
445
|
+
if (!pending) {
|
|
446
|
+
pending = httpClient.getExternalSpan(externalSpanId).then(
|
|
447
|
+
(s) => deserializeOutput(
|
|
448
|
+
s.rawData?.span_data ?? {}
|
|
449
|
+
)
|
|
450
|
+
);
|
|
451
|
+
outputCache.set(externalSpanId, pending);
|
|
452
|
+
}
|
|
453
|
+
return pending;
|
|
454
|
+
} : void 0;
|
|
421
455
|
const maybePromise = runWithReplayContext(
|
|
422
456
|
{
|
|
423
457
|
testRunId,
|
|
@@ -428,6 +462,8 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
|
|
|
428
462
|
mockTree,
|
|
429
463
|
callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
|
|
430
464
|
mockStrategy,
|
|
465
|
+
mockOverrides: hasOverrides ? resolvedOverrides : void 0,
|
|
466
|
+
fetchSpanOutput,
|
|
431
467
|
dbBranchLease: lease,
|
|
432
468
|
pendingPersistence
|
|
433
469
|
},
|
|
@@ -484,7 +520,7 @@ async function mapWithConcurrency(tasks, maxConcurrency, onSettled) {
|
|
|
484
520
|
await Promise.all(workers);
|
|
485
521
|
return results;
|
|
486
522
|
}
|
|
487
|
-
async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
|
|
523
|
+
async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, registeredOverrides = []) {
|
|
488
524
|
if (options?.traceIds !== void 0) {
|
|
489
525
|
if (options.traceIds.length === 0) {
|
|
490
526
|
throw new BitfabError("traceIds must contain at least one trace ID.");
|
|
@@ -524,6 +560,10 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
|
|
|
524
560
|
);
|
|
525
561
|
const mockStrategy = options?.mock ?? "marked";
|
|
526
562
|
const maxConcurrency = options?.maxConcurrency ?? 10;
|
|
563
|
+
const resolvedOverrides = [
|
|
564
|
+
...normalizeMockOverrides(options?.mockOverride),
|
|
565
|
+
...registeredOverrides
|
|
566
|
+
];
|
|
527
567
|
const tasks = serverItems.map(
|
|
528
568
|
(serverItem) => () => processItem(
|
|
529
569
|
httpClient,
|
|
@@ -531,6 +571,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
|
|
|
531
571
|
fn,
|
|
532
572
|
testRunId,
|
|
533
573
|
mockStrategy,
|
|
574
|
+
resolvedOverrides,
|
|
534
575
|
options?.environment,
|
|
535
576
|
options?.adaptInputs
|
|
536
577
|
)
|
|
@@ -657,6 +698,7 @@ var init_replay = __esm({
|
|
|
657
698
|
"src/replay.ts"() {
|
|
658
699
|
"use strict";
|
|
659
700
|
init_errors();
|
|
701
|
+
init_mockOverride();
|
|
660
702
|
init_randomUuid();
|
|
661
703
|
init_replayContext();
|
|
662
704
|
init_serialize();
|
|
@@ -697,7 +739,7 @@ registerAsyncLocalStorageClass(
|
|
|
697
739
|
);
|
|
698
740
|
|
|
699
741
|
// src/version.generated.ts
|
|
700
|
-
var __version__ = "0.
|
|
742
|
+
var __version__ = "0.29.0";
|
|
701
743
|
|
|
702
744
|
// src/constants.ts
|
|
703
745
|
var DEFAULT_SERVICE_URL = "https://bitfab.ai";
|
|
@@ -1126,9 +1168,14 @@ var HttpClient = class {
|
|
|
1126
1168
|
/**
|
|
1127
1169
|
* Fetch the span tree for a root span.
|
|
1128
1170
|
* Blocking GET request.
|
|
1171
|
+
*
|
|
1172
|
+
* Pass `includeOutputs: false` for a payload-free tree (structure +
|
|
1173
|
+
* `externalSpanId` only), so recorded outputs are fetched lazily per mocked
|
|
1174
|
+
* span instead of all up front. Omit it (default eager) for `mock: "all"`.
|
|
1129
1175
|
*/
|
|
1130
|
-
async getSpanTree(externalSpanId) {
|
|
1131
|
-
const
|
|
1176
|
+
async getSpanTree(externalSpanId, options) {
|
|
1177
|
+
const query = options?.includeOutputs === false ? "?includeOutputs=false" : "";
|
|
1178
|
+
const url = `${this.serviceUrl}/api/sdk/replay/spanTree/${externalSpanId}${query}`;
|
|
1132
1179
|
const controller = new AbortController();
|
|
1133
1180
|
const timeoutId = setTimeout(() => controller.abort(), 3e4);
|
|
1134
1181
|
try {
|
|
@@ -2714,6 +2761,9 @@ var BitfabLangGraphCallbackHandler = class {
|
|
|
2714
2761
|
}
|
|
2715
2762
|
};
|
|
2716
2763
|
|
|
2764
|
+
// src/client.ts
|
|
2765
|
+
init_mockOverride();
|
|
2766
|
+
|
|
2717
2767
|
// src/openaiAgentSdk.ts
|
|
2718
2768
|
var BitfabOpenAIAgentHandler = class {
|
|
2719
2769
|
constructor(config) {
|
|
@@ -3529,6 +3579,12 @@ var Bitfab = class {
|
|
|
3529
3579
|
constructor(config) {
|
|
3530
3580
|
/** Gate the empty-key warning to fire at most once. */
|
|
3531
3581
|
this.apiKeyWarned = false;
|
|
3582
|
+
/**
|
|
3583
|
+
* Mock overrides registered via {@link Bitfab.registerMockOverride}, applied
|
|
3584
|
+
* to every `replay` on this client (after any per-call `mockOverride`). In
|
|
3585
|
+
* registration order; first matcher wins within this list.
|
|
3586
|
+
*/
|
|
3587
|
+
this.mockOverrides = [];
|
|
3532
3588
|
this.apiKeyConfig = config.apiKey;
|
|
3533
3589
|
this.serviceUrl = config.serviceUrl ?? DEFAULT_SERVICE_URL;
|
|
3534
3590
|
this.timeout = config.timeout ?? 12e4;
|
|
@@ -4141,24 +4197,77 @@ var Bitfab = class {
|
|
|
4141
4197
|
const counterKey = `${traceFunctionKey}:${baseSpanParams.spanName}`;
|
|
4142
4198
|
const callIndex = counters.get(counterKey) ?? 0;
|
|
4143
4199
|
counters.set(counterKey, callIndex + 1);
|
|
4144
|
-
const
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
if (
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4200
|
+
const mockKey = `${counterKey}:${callIndex}`;
|
|
4201
|
+
const mockSpan = replayCtxForMock.mockTree.spans.get(mockKey);
|
|
4202
|
+
const emitMock = (output) => {
|
|
4203
|
+
void sendSpan({ result: output, mocked: true });
|
|
4204
|
+
if (fnReturnsPromise) {
|
|
4205
|
+
return Promise.resolve(output);
|
|
4206
|
+
}
|
|
4207
|
+
return output;
|
|
4208
|
+
};
|
|
4209
|
+
const emitMockAsync = (pending) => {
|
|
4210
|
+
if (!fnReturnsPromise) {
|
|
4211
|
+
throw new BitfabError(
|
|
4212
|
+
`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.`
|
|
4213
|
+
);
|
|
4214
|
+
}
|
|
4215
|
+
return (async () => {
|
|
4216
|
+
const output = await pending;
|
|
4156
4217
|
void sendSpan({ result: output, mocked: true });
|
|
4157
|
-
if (fnReturnsPromise) {
|
|
4158
|
-
return Promise.resolve(output);
|
|
4159
|
-
}
|
|
4160
4218
|
return output;
|
|
4219
|
+
})();
|
|
4220
|
+
};
|
|
4221
|
+
const resolveRecordedOutput = () => {
|
|
4222
|
+
const hasInlineOutput = mockSpan?.output !== void 0 || mockSpan?.outputMeta !== void 0;
|
|
4223
|
+
if (!hasInlineOutput && replayCtxForMock.fetchSpanOutput && mockSpan?.externalSpanId) {
|
|
4224
|
+
return replayCtxForMock.fetchSpanOutput(mockSpan.externalSpanId);
|
|
4161
4225
|
}
|
|
4226
|
+
if (!mockSpan) {
|
|
4227
|
+
return Promise.reject(
|
|
4228
|
+
new BitfabError(
|
|
4229
|
+
`No recorded span to source output for "${traceFunctionKey}".`
|
|
4230
|
+
)
|
|
4231
|
+
);
|
|
4232
|
+
}
|
|
4233
|
+
let output = mockSpan.output;
|
|
4234
|
+
if (mockSpan.outputMeta !== void 0 && mockSpan.outputMeta !== null) {
|
|
4235
|
+
output = deserializeValue({
|
|
4236
|
+
json: mockSpan.output,
|
|
4237
|
+
meta: mockSpan.outputMeta
|
|
4238
|
+
});
|
|
4239
|
+
}
|
|
4240
|
+
return output;
|
|
4241
|
+
};
|
|
4242
|
+
if (replayCtxForMock.mockOverrides?.length) {
|
|
4243
|
+
const nodeMeta = {
|
|
4244
|
+
traceFunctionKey,
|
|
4245
|
+
spanName: baseSpanParams.spanName,
|
|
4246
|
+
type: options.type ?? "custom",
|
|
4247
|
+
originalSpanId: mockSpan?.sourceSpanId
|
|
4248
|
+
};
|
|
4249
|
+
const override = replayCtxForMock.mockOverrides.find(
|
|
4250
|
+
(o) => o.match(nodeMeta)
|
|
4251
|
+
);
|
|
4252
|
+
if (override) {
|
|
4253
|
+
const injected = resolveMockValue(override.value, {
|
|
4254
|
+
node: nodeMeta,
|
|
4255
|
+
inputs: args,
|
|
4256
|
+
getOriginalOutput: () => Promise.resolve(resolveRecordedOutput())
|
|
4257
|
+
});
|
|
4258
|
+
if (injected instanceof Promise) {
|
|
4259
|
+
return emitMockAsync(injected);
|
|
4260
|
+
}
|
|
4261
|
+
return emitMock(injected);
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4264
|
+
const shouldMock = replayCtxForMock.mockStrategy === "all" || replayCtxForMock.mockStrategy === "marked" && options.mockOnReplay === true;
|
|
4265
|
+
if (shouldMock && mockSpan) {
|
|
4266
|
+
const recorded = resolveRecordedOutput();
|
|
4267
|
+
if (recorded instanceof Promise) {
|
|
4268
|
+
return emitMockAsync(recorded);
|
|
4269
|
+
}
|
|
4270
|
+
return emitMock(recorded);
|
|
4162
4271
|
}
|
|
4163
4272
|
}
|
|
4164
4273
|
const recordSpan = (result) => {
|
|
@@ -4438,26 +4547,14 @@ var Bitfab = class {
|
|
|
4438
4547
|
...params.mocked && { mocked: true }
|
|
4439
4548
|
});
|
|
4440
4549
|
}
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
* invocation records a trace tied to the test run. The plain-callable form
|
|
4450
|
-
* is how handler-instrumented workflows (LangGraph/LangChain, Claude Agent
|
|
4451
|
-
* SDK) replay - those record traces under a key with no `withSpan`-wrapped
|
|
4452
|
-
* root in the app.
|
|
4453
|
-
*
|
|
4454
|
-
* @param traceFunctionKey - The trace function key to replay
|
|
4455
|
-
* @param fn - The function to run recorded inputs through
|
|
4456
|
-
* @param options - Optional replay options. When `traceIds` is passed,
|
|
4457
|
-
* `limit` is ignored (with a warning): an explicit ID list already
|
|
4458
|
-
* determines how many traces replay.
|
|
4459
|
-
* @returns ReplayResult with items, testRunId, and testRunUrl
|
|
4460
|
-
*/
|
|
4550
|
+
registerMockOverride(overrideOrMatch, value) {
|
|
4551
|
+
const override = typeof overrideOrMatch === "function" ? { match: overrideOrMatch, value } : overrideOrMatch;
|
|
4552
|
+
this.mockOverrides.push(override);
|
|
4553
|
+
}
|
|
4554
|
+
/** Remove all overrides registered via {@link registerMockOverride}. */
|
|
4555
|
+
clearMockOverrides() {
|
|
4556
|
+
this.mockOverrides.length = 0;
|
|
4557
|
+
}
|
|
4461
4558
|
async replay(traceFunctionKey, fn, options) {
|
|
4462
4559
|
const wrappedKey = fn._bitfabTraceFunctionKey;
|
|
4463
4560
|
let replayFn = fn;
|
|
@@ -4478,7 +4575,8 @@ var Bitfab = class {
|
|
|
4478
4575
|
this.serviceUrl,
|
|
4479
4576
|
traceFunctionKey,
|
|
4480
4577
|
replayFn,
|
|
4481
|
-
options
|
|
4578
|
+
options,
|
|
4579
|
+
this.mockOverrides
|
|
4482
4580
|
);
|
|
4483
4581
|
}
|
|
4484
4582
|
};
|