@bitfab/sdk 0.23.1 → 0.23.2

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
@@ -171,6 +171,122 @@ declare class BitfabClaudeAgentHandler {
171
171
  private resetState;
172
172
  }
173
173
 
174
+ /**
175
+ * Vercel AI SDK integration for Bitfab tracing.
176
+ *
177
+ * The Vercel AI SDK (`ai`) routes every `generateText` / `streamText` /
178
+ * `generateObject` / `streamObject` call through a language model. Bitfab hooks
179
+ * that model with a *language-model middleware* (`wrapLanguageModel`), so each
180
+ * model call is captured as a keyed `llm` span with no hand-written `withSpan`:
181
+ *
182
+ * ```typescript
183
+ * import { Bitfab } from "@bitfab/sdk";
184
+ * import { wrapLanguageModel, streamText } from "ai";
185
+ * import { openai } from "@ai-sdk/openai";
186
+ *
187
+ * const bitfab = new Bitfab({ apiKey: "..." });
188
+ *
189
+ * const model = wrapLanguageModel({
190
+ * model: openai("gpt-4o"),
191
+ * middleware: bitfab.getVercelAiMiddleware("chat-turn"),
192
+ * });
193
+ *
194
+ * const result = streamText({ model, messages });
195
+ * return result.toUIMessageStreamResponse(); // live stream untouched
196
+ * ```
197
+ *
198
+ * The span records the call parameters (the prompt/messages) as its input and a
199
+ * serializable summary (`{ text, toolCalls, usage, finishReason }`) as its
200
+ * output. Streaming is handled by passing the model's stream through a
201
+ * transform that accumulates the assembled text/usage as the caller consumes
202
+ * it: the live stream is handed back unchanged (first-byte latency untouched)
203
+ * and the span is finalized once the stream completes.
204
+ *
205
+ * The middleware is fully duck-typed (no static or dynamic `ai` import), so it
206
+ * adds no dependency and is browser-safe. It works with `ai` v5 and v6.
207
+ */
208
+ type LlmSpanOptions = {
209
+ type: "llm";
210
+ finalize: (result: unknown) => unknown | Promise<unknown>;
211
+ };
212
+ type WithSpanFn$1 = <TArgs extends unknown[], TReturn>(traceFunctionKey: string, options: LlmSpanOptions, fn: (...args: TArgs) => TReturn) => (...args: TArgs) => TReturn;
213
+ /**
214
+ * Duck-typed subset of the Vercel AI SDK language-model call parameters. The
215
+ * only field we read for the span input is `prompt` (the messages), but the
216
+ * whole object is recorded so the call is reconstructable on replay.
217
+ */
218
+ interface VercelCallParams {
219
+ prompt?: unknown;
220
+ [key: string]: unknown;
221
+ }
222
+ /** A content part of a non-streaming `doGenerate` result. */
223
+ interface VercelContentPart {
224
+ type: string;
225
+ text?: string;
226
+ toolCallId?: string;
227
+ toolName?: string;
228
+ input?: unknown;
229
+ args?: unknown;
230
+ }
231
+ /** Duck-typed subset of a non-streaming `doGenerate` result. */
232
+ interface VercelGenerateResult {
233
+ content?: VercelContentPart[];
234
+ text?: string;
235
+ usage?: unknown;
236
+ finishReason?: unknown;
237
+ [key: string]: unknown;
238
+ }
239
+ /** Duck-typed subset of a single streaming part from `doStream`. */
240
+ interface VercelStreamPart {
241
+ type: string;
242
+ delta?: string;
243
+ textDelta?: string;
244
+ toolCallId?: string;
245
+ toolName?: string;
246
+ input?: unknown;
247
+ args?: unknown;
248
+ usage?: unknown;
249
+ finishReason?: unknown;
250
+ }
251
+ /** Duck-typed subset of a streaming `doStream` result. */
252
+ interface VercelStreamResult {
253
+ stream: ReadableStream<VercelStreamPart>;
254
+ [key: string]: unknown;
255
+ }
256
+ interface MiddlewareCall<TResult> {
257
+ doGenerate: () => PromiseLike<VercelGenerateResult>;
258
+ doStream: () => PromiseLike<VercelStreamResult>;
259
+ params: VercelCallParams;
260
+ model: unknown;
261
+ __result?: TResult;
262
+ }
263
+ /**
264
+ * The structural shape of a Vercel AI SDK language-model middleware. Matches
265
+ * `LanguageModelV3Middleware` from `@ai-sdk/provider` without importing it, so
266
+ * the SDK stays dependency-free. `wrapLanguageModel` only reads the method
267
+ * fields (it ignores `specificationVersion`), so this object drops straight in.
268
+ */
269
+ interface BitfabLanguageModelMiddleware {
270
+ specificationVersion: "v3";
271
+ wrapGenerate: (options: MiddlewareCall<VercelGenerateResult>) => Promise<any>;
272
+ wrapStream: (options: MiddlewareCall<VercelStreamResult>) => Promise<any>;
273
+ }
274
+ /**
275
+ * Vercel AI SDK middleware that records each language-model call as a keyed
276
+ * `llm` span. Obtain it from {@link BitfabClient.getVercelAiMiddleware} rather
277
+ * than constructing it directly.
278
+ */
279
+ declare class BitfabVercelAiHandler {
280
+ private readonly traceFunctionKey;
281
+ private readonly withSpanFn;
282
+ constructor(config: {
283
+ traceFunctionKey: string;
284
+ withSpan: WithSpanFn$1;
285
+ });
286
+ /** The `wrapLanguageModel` middleware object for this trace function key. */
287
+ get middleware(): BitfabLanguageModelMiddleware;
288
+ }
289
+
174
290
  /**
175
291
  * Per-trace database snapshot ref capture.
176
292
  *
@@ -705,10 +821,6 @@ declare class BitfabOpenAITracingProcessor implements TracingProcessor {
705
821
  private sendSpan;
706
822
  }
707
823
 
708
- /**
709
- * Bitfab client for provider-based API calls.
710
- */
711
-
712
824
  /**
713
825
  * Options for wrapBAML.
714
826
  */
@@ -1025,6 +1137,31 @@ declare class Bitfab {
1025
1137
  * @returns A BitfabClaudeAgentHandler configured for this client
1026
1138
  */
1027
1139
  getClaudeAgentHandler(traceFunctionKey: string): BitfabClaudeAgentHandler;
1140
+ /**
1141
+ * Get a Vercel AI SDK language-model middleware for tracing.
1142
+ *
1143
+ * Pass it to the AI SDK's `wrapLanguageModel` and use the wrapped model with
1144
+ * `generateText` / `streamText` / `generateObject` / `streamObject`. Every
1145
+ * call through that model is captured as a keyed `llm` span carrying the call
1146
+ * parameters (the prompt) as input and a serializable summary
1147
+ * (`{ text, toolCalls, usage, finishReason }`) as output. Streaming is
1148
+ * captured without disturbing the caller's live stream.
1149
+ *
1150
+ * ```typescript
1151
+ * import { wrapLanguageModel, streamText } from "ai";
1152
+ * import { openai } from "@ai-sdk/openai";
1153
+ *
1154
+ * const model = wrapLanguageModel({
1155
+ * model: openai("gpt-4o"),
1156
+ * middleware: client.getVercelAiMiddleware("chat-turn"),
1157
+ * });
1158
+ * const result = streamText({ model, messages });
1159
+ * ```
1160
+ *
1161
+ * @param traceFunctionKey - Groups traces under this key in Bitfab
1162
+ * @returns A Vercel AI SDK middleware configured for this client
1163
+ */
1164
+ getVercelAiMiddleware(traceFunctionKey: string): BitfabLanguageModelMiddleware;
1028
1165
  /**
1029
1166
  * Wrap a BAML client method to automatically capture prompt and LLM metadata.
1030
1167
  *
@@ -1221,7 +1358,7 @@ declare class BitfabFunction {
1221
1358
  /**
1222
1359
  * SDK version from package.json (injected at build time)
1223
1360
  */
1224
- declare const __version__ = "0.23.1";
1361
+ declare const __version__ = "0.23.2";
1225
1362
 
1226
1363
  /**
1227
1364
  * Constants for the Bitfab SDK.
@@ -1289,4 +1426,4 @@ declare const finalizers: {
1289
1426
  readableStream: typeof readableStream;
1290
1427
  };
1291
1428
 
1292
- export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, BitfabOpenAIAgentHandler, 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__, finalizers, flushTraces, getCurrentSpan, getCurrentTrace };
1429
+ export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, type BitfabLanguageModelMiddleware, BitfabOpenAIAgentHandler, BitfabOpenAITracingProcessor, BitfabVercelAiHandler, 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 VercelCallParams, type VercelGenerateResult, type VercelStreamResult, type WrapBAMLOptions, type WrappedBamlFn, __version__, finalizers, flushTraces, getCurrentSpan, getCurrentTrace };
package/dist/index.d.ts CHANGED
@@ -171,6 +171,122 @@ declare class BitfabClaudeAgentHandler {
171
171
  private resetState;
172
172
  }
173
173
 
174
+ /**
175
+ * Vercel AI SDK integration for Bitfab tracing.
176
+ *
177
+ * The Vercel AI SDK (`ai`) routes every `generateText` / `streamText` /
178
+ * `generateObject` / `streamObject` call through a language model. Bitfab hooks
179
+ * that model with a *language-model middleware* (`wrapLanguageModel`), so each
180
+ * model call is captured as a keyed `llm` span with no hand-written `withSpan`:
181
+ *
182
+ * ```typescript
183
+ * import { Bitfab } from "@bitfab/sdk";
184
+ * import { wrapLanguageModel, streamText } from "ai";
185
+ * import { openai } from "@ai-sdk/openai";
186
+ *
187
+ * const bitfab = new Bitfab({ apiKey: "..." });
188
+ *
189
+ * const model = wrapLanguageModel({
190
+ * model: openai("gpt-4o"),
191
+ * middleware: bitfab.getVercelAiMiddleware("chat-turn"),
192
+ * });
193
+ *
194
+ * const result = streamText({ model, messages });
195
+ * return result.toUIMessageStreamResponse(); // live stream untouched
196
+ * ```
197
+ *
198
+ * The span records the call parameters (the prompt/messages) as its input and a
199
+ * serializable summary (`{ text, toolCalls, usage, finishReason }`) as its
200
+ * output. Streaming is handled by passing the model's stream through a
201
+ * transform that accumulates the assembled text/usage as the caller consumes
202
+ * it: the live stream is handed back unchanged (first-byte latency untouched)
203
+ * and the span is finalized once the stream completes.
204
+ *
205
+ * The middleware is fully duck-typed (no static or dynamic `ai` import), so it
206
+ * adds no dependency and is browser-safe. It works with `ai` v5 and v6.
207
+ */
208
+ type LlmSpanOptions = {
209
+ type: "llm";
210
+ finalize: (result: unknown) => unknown | Promise<unknown>;
211
+ };
212
+ type WithSpanFn$1 = <TArgs extends unknown[], TReturn>(traceFunctionKey: string, options: LlmSpanOptions, fn: (...args: TArgs) => TReturn) => (...args: TArgs) => TReturn;
213
+ /**
214
+ * Duck-typed subset of the Vercel AI SDK language-model call parameters. The
215
+ * only field we read for the span input is `prompt` (the messages), but the
216
+ * whole object is recorded so the call is reconstructable on replay.
217
+ */
218
+ interface VercelCallParams {
219
+ prompt?: unknown;
220
+ [key: string]: unknown;
221
+ }
222
+ /** A content part of a non-streaming `doGenerate` result. */
223
+ interface VercelContentPart {
224
+ type: string;
225
+ text?: string;
226
+ toolCallId?: string;
227
+ toolName?: string;
228
+ input?: unknown;
229
+ args?: unknown;
230
+ }
231
+ /** Duck-typed subset of a non-streaming `doGenerate` result. */
232
+ interface VercelGenerateResult {
233
+ content?: VercelContentPart[];
234
+ text?: string;
235
+ usage?: unknown;
236
+ finishReason?: unknown;
237
+ [key: string]: unknown;
238
+ }
239
+ /** Duck-typed subset of a single streaming part from `doStream`. */
240
+ interface VercelStreamPart {
241
+ type: string;
242
+ delta?: string;
243
+ textDelta?: string;
244
+ toolCallId?: string;
245
+ toolName?: string;
246
+ input?: unknown;
247
+ args?: unknown;
248
+ usage?: unknown;
249
+ finishReason?: unknown;
250
+ }
251
+ /** Duck-typed subset of a streaming `doStream` result. */
252
+ interface VercelStreamResult {
253
+ stream: ReadableStream<VercelStreamPart>;
254
+ [key: string]: unknown;
255
+ }
256
+ interface MiddlewareCall<TResult> {
257
+ doGenerate: () => PromiseLike<VercelGenerateResult>;
258
+ doStream: () => PromiseLike<VercelStreamResult>;
259
+ params: VercelCallParams;
260
+ model: unknown;
261
+ __result?: TResult;
262
+ }
263
+ /**
264
+ * The structural shape of a Vercel AI SDK language-model middleware. Matches
265
+ * `LanguageModelV3Middleware` from `@ai-sdk/provider` without importing it, so
266
+ * the SDK stays dependency-free. `wrapLanguageModel` only reads the method
267
+ * fields (it ignores `specificationVersion`), so this object drops straight in.
268
+ */
269
+ interface BitfabLanguageModelMiddleware {
270
+ specificationVersion: "v3";
271
+ wrapGenerate: (options: MiddlewareCall<VercelGenerateResult>) => Promise<any>;
272
+ wrapStream: (options: MiddlewareCall<VercelStreamResult>) => Promise<any>;
273
+ }
274
+ /**
275
+ * Vercel AI SDK middleware that records each language-model call as a keyed
276
+ * `llm` span. Obtain it from {@link BitfabClient.getVercelAiMiddleware} rather
277
+ * than constructing it directly.
278
+ */
279
+ declare class BitfabVercelAiHandler {
280
+ private readonly traceFunctionKey;
281
+ private readonly withSpanFn;
282
+ constructor(config: {
283
+ traceFunctionKey: string;
284
+ withSpan: WithSpanFn$1;
285
+ });
286
+ /** The `wrapLanguageModel` middleware object for this trace function key. */
287
+ get middleware(): BitfabLanguageModelMiddleware;
288
+ }
289
+
174
290
  /**
175
291
  * Per-trace database snapshot ref capture.
176
292
  *
@@ -705,10 +821,6 @@ declare class BitfabOpenAITracingProcessor implements TracingProcessor {
705
821
  private sendSpan;
706
822
  }
707
823
 
708
- /**
709
- * Bitfab client for provider-based API calls.
710
- */
711
-
712
824
  /**
713
825
  * Options for wrapBAML.
714
826
  */
@@ -1025,6 +1137,31 @@ declare class Bitfab {
1025
1137
  * @returns A BitfabClaudeAgentHandler configured for this client
1026
1138
  */
1027
1139
  getClaudeAgentHandler(traceFunctionKey: string): BitfabClaudeAgentHandler;
1140
+ /**
1141
+ * Get a Vercel AI SDK language-model middleware for tracing.
1142
+ *
1143
+ * Pass it to the AI SDK's `wrapLanguageModel` and use the wrapped model with
1144
+ * `generateText` / `streamText` / `generateObject` / `streamObject`. Every
1145
+ * call through that model is captured as a keyed `llm` span carrying the call
1146
+ * parameters (the prompt) as input and a serializable summary
1147
+ * (`{ text, toolCalls, usage, finishReason }`) as output. Streaming is
1148
+ * captured without disturbing the caller's live stream.
1149
+ *
1150
+ * ```typescript
1151
+ * import { wrapLanguageModel, streamText } from "ai";
1152
+ * import { openai } from "@ai-sdk/openai";
1153
+ *
1154
+ * const model = wrapLanguageModel({
1155
+ * model: openai("gpt-4o"),
1156
+ * middleware: client.getVercelAiMiddleware("chat-turn"),
1157
+ * });
1158
+ * const result = streamText({ model, messages });
1159
+ * ```
1160
+ *
1161
+ * @param traceFunctionKey - Groups traces under this key in Bitfab
1162
+ * @returns A Vercel AI SDK middleware configured for this client
1163
+ */
1164
+ getVercelAiMiddleware(traceFunctionKey: string): BitfabLanguageModelMiddleware;
1028
1165
  /**
1029
1166
  * Wrap a BAML client method to automatically capture prompt and LLM metadata.
1030
1167
  *
@@ -1221,7 +1358,7 @@ declare class BitfabFunction {
1221
1358
  /**
1222
1359
  * SDK version from package.json (injected at build time)
1223
1360
  */
1224
- declare const __version__ = "0.23.1";
1361
+ declare const __version__ = "0.23.2";
1225
1362
 
1226
1363
  /**
1227
1364
  * Constants for the Bitfab SDK.
@@ -1289,4 +1426,4 @@ declare const finalizers: {
1289
1426
  readableStream: typeof readableStream;
1290
1427
  };
1291
1428
 
1292
- export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, BitfabOpenAIAgentHandler, 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__, finalizers, flushTraces, getCurrentSpan, getCurrentTrace };
1429
+ export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, type BitfabLanguageModelMiddleware, BitfabOpenAIAgentHandler, BitfabOpenAITracingProcessor, BitfabVercelAiHandler, 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 VercelCallParams, type VercelGenerateResult, type VercelStreamResult, type WrapBAMLOptions, type WrappedBamlFn, __version__, finalizers, flushTraces, getCurrentSpan, getCurrentTrace };
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  BitfabLangGraphCallbackHandler,
6
6
  BitfabOpenAIAgentHandler,
7
7
  BitfabOpenAITracingProcessor,
8
+ BitfabVercelAiHandler,
8
9
  DEFAULT_SERVICE_URL,
9
10
  ReplayEnvironment,
10
11
  SUPPORTED_PROVIDERS,
@@ -13,7 +14,7 @@ import {
13
14
  flushTraces,
14
15
  getCurrentSpan,
15
16
  getCurrentTrace
16
- } from "./chunk-2EDITKO2.js";
17
+ } from "./chunk-PP5K6RIU.js";
17
18
  import {
18
19
  BitfabError
19
20
  } from "./chunk-EQI6ZJC3.js";
@@ -26,6 +27,7 @@ export {
26
27
  BitfabLangGraphCallbackHandler,
27
28
  BitfabOpenAIAgentHandler,
28
29
  BitfabOpenAITracingProcessor,
30
+ BitfabVercelAiHandler,
29
31
  DEFAULT_SERVICE_URL,
30
32
  ReplayEnvironment,
31
33
  SUPPORTED_PROVIDERS,
package/dist/node.cjs CHANGED
@@ -486,6 +486,7 @@ __export(node_exports, {
486
486
  BitfabLangGraphCallbackHandler: () => BitfabLangGraphCallbackHandler,
487
487
  BitfabOpenAIAgentHandler: () => BitfabOpenAIAgentHandler,
488
488
  BitfabOpenAITracingProcessor: () => BitfabOpenAITracingProcessor,
489
+ BitfabVercelAiHandler: () => BitfabVercelAiHandler,
489
490
  DEFAULT_SERVICE_URL: () => DEFAULT_SERVICE_URL,
490
491
  ReplayEnvironment: () => ReplayEnvironment,
491
492
  SUPPORTED_PROVIDERS: () => SUPPORTED_PROVIDERS,
@@ -505,7 +506,7 @@ registerAsyncLocalStorageClass(
505
506
  );
506
507
 
507
508
  // src/version.generated.ts
508
- var __version__ = "0.23.1";
509
+ var __version__ = "0.23.2";
509
510
 
510
511
  // src/constants.ts
511
512
  var DEFAULT_SERVICE_URL = "https://bitfab.ai";
@@ -2619,6 +2620,135 @@ var BitfabOpenAITracingProcessor = class {
2619
2620
  }
2620
2621
  };
2621
2622
 
2623
+ // src/vercelAiSdk.ts
2624
+ function modelLabel(model) {
2625
+ if (!model || typeof model !== "object") {
2626
+ return void 0;
2627
+ }
2628
+ const m = model;
2629
+ const provider = typeof m.provider === "string" ? m.provider : void 0;
2630
+ const modelId = typeof m.modelId === "string" ? m.modelId : void 0;
2631
+ if (provider == null && modelId == null) {
2632
+ return void 0;
2633
+ }
2634
+ return { provider, modelId };
2635
+ }
2636
+ function summarizeGenerate(result, model) {
2637
+ const content = Array.isArray(result.content) ? result.content : [];
2638
+ const text = typeof result.text === "string" ? result.text : content.filter((p) => p.type === "text" && typeof p.text === "string").map((p) => p.text).join("");
2639
+ const toolCalls = content.filter((p) => p.type === "tool-call").map((p) => ({
2640
+ toolCallId: p.toolCallId,
2641
+ toolName: p.toolName,
2642
+ input: p.input ?? p.args
2643
+ }));
2644
+ const summary = {
2645
+ text,
2646
+ toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
2647
+ usage: result.usage,
2648
+ finishReason: result.finishReason
2649
+ };
2650
+ if (model) {
2651
+ summary.model = model;
2652
+ }
2653
+ return summary;
2654
+ }
2655
+ function accumulateStream(onComplete, model) {
2656
+ let text = "";
2657
+ const toolCalls = [];
2658
+ let usage;
2659
+ let finishReason;
2660
+ let completed = false;
2661
+ const complete = () => {
2662
+ if (completed) {
2663
+ return;
2664
+ }
2665
+ completed = true;
2666
+ const summary = {
2667
+ text,
2668
+ toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
2669
+ usage,
2670
+ finishReason
2671
+ };
2672
+ if (model) {
2673
+ summary.model = model;
2674
+ }
2675
+ onComplete(summary);
2676
+ };
2677
+ return new TransformStream({
2678
+ transform(part, controller) {
2679
+ try {
2680
+ if (part?.type === "text-delta") {
2681
+ text += part.delta ?? part.textDelta ?? "";
2682
+ } else if (part?.type === "tool-call") {
2683
+ toolCalls.push({
2684
+ toolCallId: part.toolCallId,
2685
+ toolName: part.toolName,
2686
+ input: part.input ?? part.args
2687
+ });
2688
+ } else if (part?.type === "finish") {
2689
+ usage = part.usage;
2690
+ finishReason = part.finishReason;
2691
+ complete();
2692
+ }
2693
+ } catch {
2694
+ }
2695
+ controller.enqueue(part);
2696
+ },
2697
+ flush() {
2698
+ complete();
2699
+ }
2700
+ });
2701
+ }
2702
+ var BitfabVercelAiHandler = class {
2703
+ constructor(config) {
2704
+ this.traceFunctionKey = config.traceFunctionKey;
2705
+ this.withSpanFn = config.withSpan;
2706
+ }
2707
+ /** The `wrapLanguageModel` middleware object for this trace function key. */
2708
+ get middleware() {
2709
+ const key = this.traceFunctionKey;
2710
+ const withSpan = this.withSpanFn;
2711
+ return {
2712
+ specificationVersion: "v3",
2713
+ wrapGenerate: async ({ doGenerate, params, model }) => {
2714
+ const label = modelLabel(model);
2715
+ const traced = withSpan(
2716
+ key,
2717
+ {
2718
+ type: "llm",
2719
+ finalize: (result) => summarizeGenerate(result ?? {}, label)
2720
+ },
2721
+ () => doGenerate()
2722
+ );
2723
+ return traced(params);
2724
+ },
2725
+ wrapStream: async ({ doStream, params, model }) => {
2726
+ const label = modelLabel(model);
2727
+ let resolveSummary = () => {
2728
+ };
2729
+ const summary = new Promise((resolve) => {
2730
+ resolveSummary = resolve;
2731
+ });
2732
+ const traced = withSpan(
2733
+ key,
2734
+ // The wrapped fn returns immediately with the live stream, so the span
2735
+ // output cannot be read from the return value. `finalize` instead
2736
+ // awaits the summary the accumulator resolves once the stream drains.
2737
+ { type: "llm", finalize: () => summary },
2738
+ async () => {
2739
+ const result = await doStream();
2740
+ const stream = result.stream.pipeThrough(
2741
+ accumulateStream(resolveSummary, label)
2742
+ );
2743
+ return { ...result, stream };
2744
+ }
2745
+ );
2746
+ return traced(params);
2747
+ }
2748
+ };
2749
+ }
2750
+ };
2751
+
2622
2752
  // src/client.ts
2623
2753
  var activeTraceStates = /* @__PURE__ */ new Map();
2624
2754
  var pendingSpanPromises = /* @__PURE__ */ new Map();
@@ -3134,6 +3264,36 @@ var Bitfab = class {
3134
3264
  }
3135
3265
  });
3136
3266
  }
3267
+ /**
3268
+ * Get a Vercel AI SDK language-model middleware for tracing.
3269
+ *
3270
+ * Pass it to the AI SDK's `wrapLanguageModel` and use the wrapped model with
3271
+ * `generateText` / `streamText` / `generateObject` / `streamObject`. Every
3272
+ * call through that model is captured as a keyed `llm` span carrying the call
3273
+ * parameters (the prompt) as input and a serializable summary
3274
+ * (`{ text, toolCalls, usage, finishReason }`) as output. Streaming is
3275
+ * captured without disturbing the caller's live stream.
3276
+ *
3277
+ * ```typescript
3278
+ * import { wrapLanguageModel, streamText } from "ai";
3279
+ * import { openai } from "@ai-sdk/openai";
3280
+ *
3281
+ * const model = wrapLanguageModel({
3282
+ * model: openai("gpt-4o"),
3283
+ * middleware: client.getVercelAiMiddleware("chat-turn"),
3284
+ * });
3285
+ * const result = streamText({ model, messages });
3286
+ * ```
3287
+ *
3288
+ * @param traceFunctionKey - Groups traces under this key in Bitfab
3289
+ * @returns A Vercel AI SDK middleware configured for this client
3290
+ */
3291
+ getVercelAiMiddleware(traceFunctionKey) {
3292
+ return new BitfabVercelAiHandler({
3293
+ traceFunctionKey,
3294
+ withSpan: this.withSpan.bind(this)
3295
+ }).middleware;
3296
+ }
3137
3297
  /**
3138
3298
  * Wrap a BAML client method to automatically capture prompt and LLM metadata.
3139
3299
  *
@@ -3810,6 +3970,7 @@ assertAsyncStorageRegistered();
3810
3970
  BitfabLangGraphCallbackHandler,
3811
3971
  BitfabOpenAIAgentHandler,
3812
3972
  BitfabOpenAITracingProcessor,
3973
+ BitfabVercelAiHandler,
3813
3974
  DEFAULT_SERVICE_URL,
3814
3975
  ReplayEnvironment,
3815
3976
  SUPPORTED_PROVIDERS,