@bitfab/sdk 0.24.1 → 0.26.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/index.cjs CHANGED
@@ -413,13 +413,15 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
413
413
  dbSnapshotRef: serverItem.dbSnapshotRef ?? null
414
414
  };
415
415
  }
416
- async function mapWithConcurrency(tasks, maxConcurrency) {
416
+ async function mapWithConcurrency(tasks, maxConcurrency, onSettled) {
417
417
  const results = new Array(tasks.length);
418
418
  let nextIndex = 0;
419
419
  async function worker() {
420
420
  while (nextIndex < tasks.length) {
421
421
  const index = nextIndex++;
422
- results[index] = await tasks[index]();
422
+ const result = await tasks[index]();
423
+ results[index] = result;
424
+ onSettled?.(result, index);
423
425
  }
424
426
  }
425
427
  const workers = Array.from(
@@ -479,7 +481,26 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
479
481
  options?.adaptInputs
480
482
  )
481
483
  );
482
- const resultItems = await mapWithConcurrency(tasks, maxConcurrency);
484
+ const total = tasks.length;
485
+ let completed = 0;
486
+ let succeeded = 0;
487
+ let errored = 0;
488
+ const resultItems = await mapWithConcurrency(
489
+ tasks,
490
+ maxConcurrency,
491
+ options?.onProgress ? (item) => {
492
+ completed += 1;
493
+ if (item.error === null) {
494
+ succeeded += 1;
495
+ } else {
496
+ errored += 1;
497
+ }
498
+ try {
499
+ options?.onProgress?.({ completed, total, succeeded, errored });
500
+ } catch {
501
+ }
502
+ } : void 0
503
+ );
483
504
  const completeResult = await httpClient.completeReplay(testRunId);
484
505
  const serverTraceIds = completeResult.traceIds;
485
506
  const replayTokens = completeResult.tokens;
@@ -566,7 +587,7 @@ __export(index_exports, {
566
587
  module.exports = __toCommonJS(index_exports);
567
588
 
568
589
  // src/version.generated.ts
569
- var __version__ = "0.24.1";
590
+ var __version__ = "0.26.0";
570
591
 
571
592
  // src/constants.ts
572
593
  var DEFAULT_SERVICE_URL = "https://bitfab.ai";
@@ -4072,10 +4093,105 @@ var BitfabFunction = class {
4072
4093
  const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
4073
4094
  return this.client.withSpan(this.traceFunctionKey, options, fn);
4074
4095
  }
4096
+ /**
4097
+ * Get a Vercel AI SDK language-model middleware bound to this function's key.
4098
+ *
4099
+ * Equivalent to `client.getVercelAiMiddleware(key)` but reuses the key bound
4100
+ * on this handle, so an outer `withSpan` root and the middleware-traced model
4101
+ * calls share one key without repeating the string. With a matching key, the
4102
+ * outer span is the replayable root and the model-call spans nest beneath it.
4103
+ *
4104
+ * Nesting is captured when the model is called, so keep the
4105
+ * `generateText` / `streamText` call inside this handle's `withSpan`; the
4106
+ * middleware object itself can be created anywhere.
4107
+ *
4108
+ * ```typescript
4109
+ * const chatTurn = client.getFunction("chat-turn");
4110
+ * const runChatTurn = chatTurn.withSpan(
4111
+ * { type: "agent", finalize: finalizers.aiSdk },
4112
+ * (messages) => streamText({ model, messages }),
4113
+ * );
4114
+ * const model = wrapLanguageModel({
4115
+ * model: openai("gpt-4o"),
4116
+ * middleware: chatTurn.getVercelAiMiddleware(),
4117
+ * });
4118
+ * ```
4119
+ *
4120
+ * @returns A Vercel AI SDK middleware configured for this client and key
4121
+ */
4122
+ getVercelAiMiddleware() {
4123
+ return this.client.getVercelAiMiddleware(this.traceFunctionKey);
4124
+ }
4125
+ /**
4126
+ * Get a Claude Agent SDK handler bound to this function's key.
4127
+ *
4128
+ * Equivalent to `client.getClaudeAgentHandler(key)` but reuses the key bound
4129
+ * on this handle, so an outer `withSpan` root and the handler share one key
4130
+ * without repeating the string. With a matching key, the outer span is the
4131
+ * replayable root and every handler span nests beneath it.
4132
+ *
4133
+ * Use the handler inside this handle's `withSpan` body so its spans capture
4134
+ * the enclosing root; framework calls made with no active span record their
4135
+ * own root instead.
4136
+ *
4137
+ * ```typescript
4138
+ * const pipeline = client.getFunction("my-agent");
4139
+ * const tracedRun = pipeline.withSpan({ type: "agent" }, async (prompt) => {
4140
+ * const handler = pipeline.getClaudeAgentHandler();
4141
+ * const options = handler.instrumentOptions({ model: "claude-sonnet-4-6" });
4142
+ * for await (const msg of handler.wrapQuery(query({ prompt, options }))) { ... }
4143
+ * });
4144
+ * ```
4145
+ *
4146
+ * @returns A Claude Agent SDK handler configured for this client and key
4147
+ */
4148
+ getClaudeAgentHandler() {
4149
+ return this.client.getClaudeAgentHandler(this.traceFunctionKey);
4150
+ }
4151
+ /**
4152
+ * Get a LangGraph/LangChain callback handler bound to this function's key.
4153
+ *
4154
+ * Equivalent to `client.getLangGraphCallbackHandler(key)` but reuses the key
4155
+ * bound on this handle, so an outer `withSpan` root and the handler share one
4156
+ * key without repeating the string. With a matching key, the outer span is
4157
+ * the replayable root and the LangGraph spans nest beneath it.
4158
+ *
4159
+ * Use the handler inside this handle's `withSpan` body so its spans capture
4160
+ * the enclosing root; framework calls made with no active span record their
4161
+ * own root instead.
4162
+ *
4163
+ * ```typescript
4164
+ * const pipeline = client.getFunction("my-pipeline");
4165
+ * const tracedRun = pipeline.withSpan({ type: "agent" }, async (query) => {
4166
+ * const handler = pipeline.getLangGraphCallbackHandler();
4167
+ * return agent.invoke({ messages: [...] }, { callbacks: [handler] });
4168
+ * });
4169
+ * ```
4170
+ *
4171
+ * @returns A LangGraph/LangChain callback handler for this client and key
4172
+ */
4173
+ getLangGraphCallbackHandler() {
4174
+ return this.client.getLangGraphCallbackHandler(this.traceFunctionKey);
4175
+ }
4176
+ /**
4177
+ * Alias of {@link getLangGraphCallbackHandler} — LangChain and LangGraph
4178
+ * share one callback system, so the same bound handler serves both.
4179
+ *
4180
+ * @returns A LangChain callback handler for this client and key
4181
+ */
4182
+ getLangChainCallbackHandler() {
4183
+ return this.client.getLangChainCallbackHandler(this.traceFunctionKey);
4184
+ }
4075
4185
  /**
4076
4186
  * Wrap a BAML client method to automatically capture prompt and LLM metadata.
4077
4187
  * Delegates to the parent client's wrapBAML method.
4078
4188
  *
4189
+ * Unlike the other methods on this handle, `wrapBAML` does NOT use the bound
4190
+ * key: it opens no span of its own. It enriches the *current* span (via
4191
+ * `getCurrentSpan().setPrompt()` / `addContext()`), so call it inside a
4192
+ * function wrapped by this handle's `withSpan` — the bound key keys that
4193
+ * wrapper, and the BAML prompt/metadata attach to it.
4194
+ *
4079
4195
  * @param methodOrClient - Either a BAML method (uses constructor bamlClient) or the BAML client instance
4080
4196
  * @param maybeMethodOrOptions - The BAML method when the first argument is a client, or WrapBAMLOptions when the first argument is the method
4081
4197
  * @param maybeOptions - WrapBAMLOptions when using the two-argument (client, method) form