Skip to main content
Package: @bitfab/sdk. Dual ESM/CJS. Node.js ≥ 18 and modern browsers.

Module Exports

Constants

class Bitfab

new Bitfab(config: BitfabConfig)

withSpan

Wraps a function so that each invocation produces a span. Returns: a function with the same signature as the input. Semantics:
  • If enabled === false, returns the original function unchanged
  • Span name defaults to fn.name || traceFunctionKey
  • Span type defaults to "custom"
  • Input arguments are serialized via superjson (type-preserving)
  • Return value (sync or the resolved Promise value) is serialized as output
  • SpanOptions.finalize?: (result) => unknown | Promise<unknown> records a serializable view of a non-serializable result (a live stream). The raw result is returned to the caller unchanged; await finalize(result) is recorded as the span output. Runs in the background; a throwing finalize records an error instead of crashing. Ignored for async-generator results. Pair with the exported finalizers.aiSdk (Vercel AI SDK) or finalizers.readableStream
  • Async-generator spans remain open until iteration completes, returns early, or throws. Nested spans created inside the generator body inherit that span. To include spans created by the consumer in the same trace, wrap the controller that owns the iteration in an outer root span.
  • Thrown errors are recorded (error and error_source: "code" fields) and re-thrown
  • Spans nest automatically via AsyncLocalStorage (Node) or a module-level stack (browser fallback)
  • Browser fallback does not isolate concurrent async chains (Promise.all with independent withSpan calls may see the wrong parent)

getFunction

Returns a BitfabFunction bound to traceFunctionKey.

wrapBAML

Framework integration → see BAML framework guide for examples.
Returns: a WrappedBamlFn — an async function with a .collector property set after each call. Throws:
  • BitfabError if form 1 is used without bamlClient in constructor
  • BitfabError if the method has no .name
Semantics:
  • If @boundaryml/baml is not installed, the method is called directly; .collector is null
  • Otherwise: creates a BAML Collector, calls the method through a tracked client, then:
    • Calls getCurrentSpan().setPrompt(...) with the rendered messages as JSON
    • Calls getCurrentSpan().addContext({ model, provider, inputTokens, outputTokens, durationMs })
  • onCollector callback fires after each invocation; errors in the callback are swallowed

getTrace

Returns a DetachedTrace handle for annotating a trace after its root span has closed, from any process or thread. Throws: BitfabError if traceId is not a canonical Bitfab trace ID. Semantics:
  • All methods on the returned handle are fire-and-forget (return Promise<unknown>)
  • When enabled === false, methods return Promise.resolve() immediately
  • Pending requests are tracked so flushTraces() waits for them
  • Server returns 404 if no trace exists with that ID; failure is logged as a warning

getTraceSpan

Fetches one persisted span without loading its trace. traceId is the canonical Bitfab trace ID, and lookup is { id } using the span’s Bitfab ID or { name, occurrence? }; occurrence is "first" | "last" | number and defaults to "last". Numeric occurrences are zero-based in start-time order. Returns null when no trace or span matches.

replay

Returns: { items, testRunId, testRunUrl }. See ReplayResult. Notes:
  • A trace replays only when its root span has serializable inputs, or it was instrumented through a framework handler (whose recorded root input is serializable). If the original inputs were stubbed as non-serializable at capture time, the trace cannot be replayed.
  • fn may be an already-withSpan-wrapped function (carries its trace function key, used as-is) or a plain callable (replay() wraps it under the key automatically); either way new spans link to the test run via async context. Don’t wrap an already-wrapped function in a fresh closure: the closure has no trace function key, so replay() wraps the closure as the root and the inner wrapped function records a second span, nesting a duplicate.
  • Inputs are deserialized from historical spans and passed positionally

call

Executes a server-configured BAML function locally using envVars. Throws: BitfabError on lookup failure or execution error.

Framework Integrations

Handlers returned by these methods are framework-native adapters — they plug into each framework’s own callback/processor/hook surface and emit Bitfab spans automatically. For usage examples and semantics, see the per-framework guides; signatures here are canonical.

getLangGraphCallbackHandler

Returns a duck-typed LangChain/LangGraph callback handler. Pass in config.callbacks when invoking a graph/chain. Root framework invocations are registered immediately as pending external traces and completed when the root callback ends. The handler-created root is replayable from the framework input, so a separate withSpan root is only needed for meaningful surrounding application work. See LangGraph framework guide. Aliased as getLangChainCallbackHandler(traceFunctionKey) for plain LangChain projects; the returned handler and behavior are identical. The handler class is also exported as BitfabLangChainCallbackHandler.

getOpenAiTracingProcessor

Returns a processor to register with @openai/agentsaddTraceProcessor (which keeps the SDK’s default OpenAI exporter; setTraceProcessors replaces it). Captures agent internals; pair it with getOpenAiAgentHandler for a replayable root. See OpenAI Agents framework guide.

getOpenAiAgentHandler

Returns a handler whose wrapRun(agent, input, options?) is a drop-in for @openai/agentsrun() that records a keyed, replayable root span carrying the run input (the tracing processor’s spans nest underneath). See OpenAI Agents framework guide.

getClaudeAgentHandler

Returns a handler exposing instrumentOptions(options), wrapResponse(stream, opts?), and wrapQuery(stream, opts?) for the Claude Agent SDK. Pass { input: prompt } to the wrap call to record a replayable root span. See Claude Agent SDK framework guide.

getVercelAiMiddleware

Returns a Vercel AI SDK language model middleware. Pass it to the AI SDK’s wrapLanguageModel, then use the wrapped model with generateText / streamText / generateObject / streamObject. Every call is captured as a keyed llm span carrying the call parameters as input; streaming is captured without disturbing the live stream. See Vercel AI SDK framework guide.

wrapBAML

See the BAML framework guide for examples; full signature under wrapBAML above.

class BitfabFunction

Fluent wrapper binding a traceFunctionKey. Obtained via client.getFunction(key).

withSpan

Delegates to client.withSpan(boundKey, optionsOrFn, maybeFn).

getVercelAiMiddleware

Delegates to client.getVercelAiMiddleware(boundKey), reusing the bound key so a withSpan root and the middleware share it. See Nesting with core tracing.

getClaudeAgentHandler

Delegates to client.getClaudeAgentHandler(boundKey), reusing the bound key so a withSpan root and the handler share it. See Nesting with core tracing.

getLangGraphCallbackHandler

Delegates to client.getLangGraphCallbackHandler(boundKey), reusing the bound key so a withSpan root and the handler share it. See Nesting with core tracing.

getLangChainCallbackHandler

Alias of getLangGraphCallbackHandler: LangChain and LangGraph share one callback system.

wrapBAML

Identical signature and semantics to Bitfab#wrapBAML. Unlike the getXHandler() methods above, it does not use the bound key; it opens no span and enriches the current span, so call it inside a function wrapped by this handle’s withSpan.

class BitfabError

Extends Error.
Thrown for SDK-originated failures (missing function, missing prompt, misconfiguration). Never thrown for transport errors on withSpan paths — those are swallowed.

class BitfabLangGraphCallbackHandler

Duck-types LangChain’s callback handler interface without importing @langchain/core. Obtained via client.getLangGraphCallbackHandler(key). No direct instantiation needed for normal use. It records chain, LLM, tool, and retriever roots as pending traces on start, then completes them on root end. Full callback surface documented in LangGraph framework guide.

class BitfabOpenAITracingProcessor

Implements the OpenAI Agents SDK TracingProcessor interface. Obtained via client.getOpenAiTracingProcessor(). No direct instantiation needed for normal use. See OpenAI Agents framework guide.

class BitfabOpenAIAgentHandler

Run wrapper for the OpenAI Agents SDK. Obtained via client.getOpenAiAgentHandler(key). Exposes wrapRun(agent, input, options?), a drop-in for run() that records a keyed, replayable root span. See OpenAI Agents framework guide.

class BitfabClaudeAgentHandler

Handler for the Claude Agent SDK. Obtained via client.getClaudeAgentHandler(key). Exposes instrumentOptions, wrapResponse, and wrapQuery. See Claude Agent SDK framework guide for method signatures and usage.

Functions

getCurrentSpan()

Returns the innermost active span. Outside a span context, returns a no-op whose traceId is "".

getCurrentTrace()

Returns a handle to the active trace. Outside a span context, returns a no-op.

flushTraces(timeoutMs?: number)

Waits for pending trace dispatches to complete. Default timeoutMs: 5000. Use before process.exit() in short-lived scripts. Resolves after timeoutMs or when all pending sends finish, whichever comes first.

Interfaces

BitfabConfig

See constructor table.

SpanOptions

SpanType

CurrentSpan

CurrentTrace

DetachedTrace

Returned by client.getTrace(traceId), where traceId is the canonical Bitfab trace ID. Methods have the same semantics as CurrentTrace but send to the server immediately (fire-and-forget). When enabled === false, all methods return Promise.resolve().

WrapBAMLOptions

WrappedBamlFn<TArgs, TReturn>

collector is null before the first call or when @boundaryml/baml is unavailable. After each successful call, it holds the BAML Collector instance from that invocation.

ReplayOptions

onProgress fires once per item as it settles (completion order, not input order), so you can render live progress and consume the settled item’s input/output before the whole replay finishes. Replay doesn’t know pass/fail yet (verdicts are assigned later), so the totals only split ran-ok vs errored. A throwing callback never crashes the run. The SDK exports a ready-made reporter, reportReplayProgress, that you can pass straight in (onProgress: reportReplayProgress): it writes the running totals plus settled item payload to stderr, which the Bitfab plugin polls to report live progress and write per-item result files while the replay runs in the background, so scripts never hand-format the protocol. ReplayEnvironment is read inside the replayed function: environment.databaseUrl, environment.expiresAt, environment.providerConsoleUrl, environment.readOnly, environment.traceId, and environment.active (false when no per-trace branch was resolved). Reading databaseUrl outside a replay item throws.

ReplayResult<T>

AllowedEnvVars

Only OPENAI_API_KEY is currently whitelisted.

ActiveSpanContext

Passed to the OpenAI tracing processor’s span-linking hook.

Error Behavior Summary

Module Resolution

  • Node.js ESM: dist/index.js
  • Node.js CJS: dist/index.cjs
  • Browser: works, but AsyncLocalStorage-dependent features degrade (see withSpan semantics)