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