bitfab 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
@@ -422,13 +422,15 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
422
422
  dbSnapshotRef: serverItem.dbSnapshotRef ?? null
423
423
  };
424
424
  }
425
- async function mapWithConcurrency(tasks, maxConcurrency) {
425
+ async function mapWithConcurrency(tasks, maxConcurrency, onSettled) {
426
426
  const results = new Array(tasks.length);
427
427
  let nextIndex = 0;
428
428
  async function worker() {
429
429
  while (nextIndex < tasks.length) {
430
430
  const index = nextIndex++;
431
- results[index] = await tasks[index]();
431
+ const result = await tasks[index]();
432
+ results[index] = result;
433
+ onSettled?.(result, index);
432
434
  }
433
435
  }
434
436
  const workers = Array.from(
@@ -488,7 +490,26 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
488
490
  options?.adaptInputs
489
491
  )
490
492
  );
491
- const resultItems = await mapWithConcurrency(tasks, maxConcurrency);
493
+ const total = tasks.length;
494
+ let completed = 0;
495
+ let succeeded = 0;
496
+ let errored = 0;
497
+ const resultItems = await mapWithConcurrency(
498
+ tasks,
499
+ maxConcurrency,
500
+ options?.onProgress ? (item) => {
501
+ completed += 1;
502
+ if (item.error === null) {
503
+ succeeded += 1;
504
+ } else {
505
+ errored += 1;
506
+ }
507
+ try {
508
+ options?.onProgress?.({ completed, total, succeeded, errored });
509
+ } catch {
510
+ }
511
+ } : void 0
512
+ );
492
513
  const completeResult = await httpClient.completeReplay(testRunId);
493
514
  const serverTraceIds = completeResult.traceIds;
494
515
  const replayTokens = completeResult.tokens;
@@ -575,7 +596,7 @@ __export(index_exports, {
575
596
  module.exports = __toCommonJS(index_exports);
576
597
 
577
598
  // src/version.generated.ts
578
- var __version__ = "0.24.1";
599
+ var __version__ = "0.26.0";
579
600
 
580
601
  // src/constants.ts
581
602
  var DEFAULT_SERVICE_URL = "https://bitfab.ai";
@@ -4081,10 +4102,105 @@ var BitfabFunction = class {
4081
4102
  const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
4082
4103
  return this.client.withSpan(this.traceFunctionKey, options, fn);
4083
4104
  }
4105
+ /**
4106
+ * Get a Vercel AI SDK language-model middleware bound to this function's key.
4107
+ *
4108
+ * Equivalent to `client.getVercelAiMiddleware(key)` but reuses the key bound
4109
+ * on this handle, so an outer `withSpan` root and the middleware-traced model
4110
+ * calls share one key without repeating the string. With a matching key, the
4111
+ * outer span is the replayable root and the model-call spans nest beneath it.
4112
+ *
4113
+ * Nesting is captured when the model is called, so keep the
4114
+ * `generateText` / `streamText` call inside this handle's `withSpan`; the
4115
+ * middleware object itself can be created anywhere.
4116
+ *
4117
+ * ```typescript
4118
+ * const chatTurn = client.getFunction("chat-turn");
4119
+ * const runChatTurn = chatTurn.withSpan(
4120
+ * { type: "agent", finalize: finalizers.aiSdk },
4121
+ * (messages) => streamText({ model, messages }),
4122
+ * );
4123
+ * const model = wrapLanguageModel({
4124
+ * model: openai("gpt-4o"),
4125
+ * middleware: chatTurn.getVercelAiMiddleware(),
4126
+ * });
4127
+ * ```
4128
+ *
4129
+ * @returns A Vercel AI SDK middleware configured for this client and key
4130
+ */
4131
+ getVercelAiMiddleware() {
4132
+ return this.client.getVercelAiMiddleware(this.traceFunctionKey);
4133
+ }
4134
+ /**
4135
+ * Get a Claude Agent SDK handler bound to this function's key.
4136
+ *
4137
+ * Equivalent to `client.getClaudeAgentHandler(key)` but reuses the key bound
4138
+ * on this handle, so an outer `withSpan` root and the handler share one key
4139
+ * without repeating the string. With a matching key, the outer span is the
4140
+ * replayable root and every handler span nests beneath it.
4141
+ *
4142
+ * Use the handler inside this handle's `withSpan` body so its spans capture
4143
+ * the enclosing root; framework calls made with no active span record their
4144
+ * own root instead.
4145
+ *
4146
+ * ```typescript
4147
+ * const pipeline = client.getFunction("my-agent");
4148
+ * const tracedRun = pipeline.withSpan({ type: "agent" }, async (prompt) => {
4149
+ * const handler = pipeline.getClaudeAgentHandler();
4150
+ * const options = handler.instrumentOptions({ model: "claude-sonnet-4-6" });
4151
+ * for await (const msg of handler.wrapQuery(query({ prompt, options }))) { ... }
4152
+ * });
4153
+ * ```
4154
+ *
4155
+ * @returns A Claude Agent SDK handler configured for this client and key
4156
+ */
4157
+ getClaudeAgentHandler() {
4158
+ return this.client.getClaudeAgentHandler(this.traceFunctionKey);
4159
+ }
4160
+ /**
4161
+ * Get a LangGraph/LangChain callback handler bound to this function's key.
4162
+ *
4163
+ * Equivalent to `client.getLangGraphCallbackHandler(key)` but reuses the key
4164
+ * bound on this handle, so an outer `withSpan` root and the handler share one
4165
+ * key without repeating the string. With a matching key, the outer span is
4166
+ * the replayable root and the LangGraph spans nest beneath it.
4167
+ *
4168
+ * Use the handler inside this handle's `withSpan` body so its spans capture
4169
+ * the enclosing root; framework calls made with no active span record their
4170
+ * own root instead.
4171
+ *
4172
+ * ```typescript
4173
+ * const pipeline = client.getFunction("my-pipeline");
4174
+ * const tracedRun = pipeline.withSpan({ type: "agent" }, async (query) => {
4175
+ * const handler = pipeline.getLangGraphCallbackHandler();
4176
+ * return agent.invoke({ messages: [...] }, { callbacks: [handler] });
4177
+ * });
4178
+ * ```
4179
+ *
4180
+ * @returns A LangGraph/LangChain callback handler for this client and key
4181
+ */
4182
+ getLangGraphCallbackHandler() {
4183
+ return this.client.getLangGraphCallbackHandler(this.traceFunctionKey);
4184
+ }
4185
+ /**
4186
+ * Alias of {@link getLangGraphCallbackHandler} — LangChain and LangGraph
4187
+ * share one callback system, so the same bound handler serves both.
4188
+ *
4189
+ * @returns A LangChain callback handler for this client and key
4190
+ */
4191
+ getLangChainCallbackHandler() {
4192
+ return this.client.getLangChainCallbackHandler(this.traceFunctionKey);
4193
+ }
4084
4194
  /**
4085
4195
  * Wrap a BAML client method to automatically capture prompt and LLM metadata.
4086
4196
  * Delegates to the parent client's wrapBAML method.
4087
4197
  *
4198
+ * Unlike the other methods on this handle, `wrapBAML` does NOT use the bound
4199
+ * key: it opens no span of its own. It enriches the *current* span (via
4200
+ * `getCurrentSpan().setPrompt()` / `addContext()`), so call it inside a
4201
+ * function wrapped by this handle's `withSpan` — the bound key keys that
4202
+ * wrapper, and the BAML prompt/metadata attach to it.
4203
+ *
4088
4204
  * @param methodOrClient - Either a BAML method (uses constructor bamlClient) or the BAML client instance
4089
4205
  * @param maybeMethodOrOptions - The BAML method when the first argument is a client, or WrapBAMLOptions when the first argument is the method
4090
4206
  * @param maybeOptions - WrapBAMLOptions when using the two-argument (client, method) form