bitfab 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.cjs CHANGED
@@ -488,6 +488,7 @@ __export(index_exports, {
488
488
  BitfabLangGraphCallbackHandler: () => BitfabLangGraphCallbackHandler,
489
489
  BitfabOpenAIAgentHandler: () => BitfabOpenAIAgentHandler,
490
490
  BitfabOpenAITracingProcessor: () => BitfabOpenAITracingProcessor,
491
+ BitfabVercelAiHandler: () => BitfabVercelAiHandler,
491
492
  DEFAULT_SERVICE_URL: () => DEFAULT_SERVICE_URL,
492
493
  ReplayEnvironment: () => ReplayEnvironment,
493
494
  SUPPORTED_PROVIDERS: () => SUPPORTED_PROVIDERS,
@@ -500,7 +501,7 @@ __export(index_exports, {
500
501
  module.exports = __toCommonJS(index_exports);
501
502
 
502
503
  // src/version.generated.ts
503
- var __version__ = "0.23.1";
504
+ var __version__ = "0.23.2";
504
505
 
505
506
  // src/constants.ts
506
507
  var DEFAULT_SERVICE_URL = "https://bitfab.ai";
@@ -2614,6 +2615,135 @@ var BitfabOpenAITracingProcessor = class {
2614
2615
  }
2615
2616
  };
2616
2617
 
2618
+ // src/vercelAiSdk.ts
2619
+ function modelLabel(model) {
2620
+ if (!model || typeof model !== "object") {
2621
+ return void 0;
2622
+ }
2623
+ const m = model;
2624
+ const provider = typeof m.provider === "string" ? m.provider : void 0;
2625
+ const modelId = typeof m.modelId === "string" ? m.modelId : void 0;
2626
+ if (provider == null && modelId == null) {
2627
+ return void 0;
2628
+ }
2629
+ return { provider, modelId };
2630
+ }
2631
+ function summarizeGenerate(result, model) {
2632
+ const content = Array.isArray(result.content) ? result.content : [];
2633
+ const text = typeof result.text === "string" ? result.text : content.filter((p) => p.type === "text" && typeof p.text === "string").map((p) => p.text).join("");
2634
+ const toolCalls = content.filter((p) => p.type === "tool-call").map((p) => ({
2635
+ toolCallId: p.toolCallId,
2636
+ toolName: p.toolName,
2637
+ input: p.input ?? p.args
2638
+ }));
2639
+ const summary = {
2640
+ text,
2641
+ toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
2642
+ usage: result.usage,
2643
+ finishReason: result.finishReason
2644
+ };
2645
+ if (model) {
2646
+ summary.model = model;
2647
+ }
2648
+ return summary;
2649
+ }
2650
+ function accumulateStream(onComplete, model) {
2651
+ let text = "";
2652
+ const toolCalls = [];
2653
+ let usage;
2654
+ let finishReason;
2655
+ let completed = false;
2656
+ const complete = () => {
2657
+ if (completed) {
2658
+ return;
2659
+ }
2660
+ completed = true;
2661
+ const summary = {
2662
+ text,
2663
+ toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
2664
+ usage,
2665
+ finishReason
2666
+ };
2667
+ if (model) {
2668
+ summary.model = model;
2669
+ }
2670
+ onComplete(summary);
2671
+ };
2672
+ return new TransformStream({
2673
+ transform(part, controller) {
2674
+ try {
2675
+ if (part?.type === "text-delta") {
2676
+ text += part.delta ?? part.textDelta ?? "";
2677
+ } else if (part?.type === "tool-call") {
2678
+ toolCalls.push({
2679
+ toolCallId: part.toolCallId,
2680
+ toolName: part.toolName,
2681
+ input: part.input ?? part.args
2682
+ });
2683
+ } else if (part?.type === "finish") {
2684
+ usage = part.usage;
2685
+ finishReason = part.finishReason;
2686
+ complete();
2687
+ }
2688
+ } catch {
2689
+ }
2690
+ controller.enqueue(part);
2691
+ },
2692
+ flush() {
2693
+ complete();
2694
+ }
2695
+ });
2696
+ }
2697
+ var BitfabVercelAiHandler = class {
2698
+ constructor(config) {
2699
+ this.traceFunctionKey = config.traceFunctionKey;
2700
+ this.withSpanFn = config.withSpan;
2701
+ }
2702
+ /** The `wrapLanguageModel` middleware object for this trace function key. */
2703
+ get middleware() {
2704
+ const key = this.traceFunctionKey;
2705
+ const withSpan = this.withSpanFn;
2706
+ return {
2707
+ specificationVersion: "v3",
2708
+ wrapGenerate: async ({ doGenerate, params, model }) => {
2709
+ const label = modelLabel(model);
2710
+ const traced = withSpan(
2711
+ key,
2712
+ {
2713
+ type: "llm",
2714
+ finalize: (result) => summarizeGenerate(result ?? {}, label)
2715
+ },
2716
+ () => doGenerate()
2717
+ );
2718
+ return traced(params);
2719
+ },
2720
+ wrapStream: async ({ doStream, params, model }) => {
2721
+ const label = modelLabel(model);
2722
+ let resolveSummary = () => {
2723
+ };
2724
+ const summary = new Promise((resolve) => {
2725
+ resolveSummary = resolve;
2726
+ });
2727
+ const traced = withSpan(
2728
+ key,
2729
+ // The wrapped fn returns immediately with the live stream, so the span
2730
+ // output cannot be read from the return value. `finalize` instead
2731
+ // awaits the summary the accumulator resolves once the stream drains.
2732
+ { type: "llm", finalize: () => summary },
2733
+ async () => {
2734
+ const result = await doStream();
2735
+ const stream = result.stream.pipeThrough(
2736
+ accumulateStream(resolveSummary, label)
2737
+ );
2738
+ return { ...result, stream };
2739
+ }
2740
+ );
2741
+ return traced(params);
2742
+ }
2743
+ };
2744
+ }
2745
+ };
2746
+
2617
2747
  // src/client.ts
2618
2748
  var activeTraceStates = /* @__PURE__ */ new Map();
2619
2749
  var pendingSpanPromises = /* @__PURE__ */ new Map();
@@ -3129,6 +3259,36 @@ var Bitfab = class {
3129
3259
  }
3130
3260
  });
3131
3261
  }
3262
+ /**
3263
+ * Get a Vercel AI SDK language-model middleware for tracing.
3264
+ *
3265
+ * Pass it to the AI SDK's `wrapLanguageModel` and use the wrapped model with
3266
+ * `generateText` / `streamText` / `generateObject` / `streamObject`. Every
3267
+ * call through that model is captured as a keyed `llm` span carrying the call
3268
+ * parameters (the prompt) as input and a serializable summary
3269
+ * (`{ text, toolCalls, usage, finishReason }`) as output. Streaming is
3270
+ * captured without disturbing the caller's live stream.
3271
+ *
3272
+ * ```typescript
3273
+ * import { wrapLanguageModel, streamText } from "ai";
3274
+ * import { openai } from "@ai-sdk/openai";
3275
+ *
3276
+ * const model = wrapLanguageModel({
3277
+ * model: openai("gpt-4o"),
3278
+ * middleware: client.getVercelAiMiddleware("chat-turn"),
3279
+ * });
3280
+ * const result = streamText({ model, messages });
3281
+ * ```
3282
+ *
3283
+ * @param traceFunctionKey - Groups traces under this key in Bitfab
3284
+ * @returns A Vercel AI SDK middleware configured for this client
3285
+ */
3286
+ getVercelAiMiddleware(traceFunctionKey) {
3287
+ return new BitfabVercelAiHandler({
3288
+ traceFunctionKey,
3289
+ withSpan: this.withSpan.bind(this)
3290
+ }).middleware;
3291
+ }
3132
3292
  /**
3133
3293
  * Wrap a BAML client method to automatically capture prompt and LLM metadata.
3134
3294
  *
@@ -3801,6 +3961,7 @@ var finalizers = {
3801
3961
  BitfabLangGraphCallbackHandler,
3802
3962
  BitfabOpenAIAgentHandler,
3803
3963
  BitfabOpenAITracingProcessor,
3964
+ BitfabVercelAiHandler,
3804
3965
  DEFAULT_SERVICE_URL,
3805
3966
  ReplayEnvironment,
3806
3967
  SUPPORTED_PROVIDERS,