@bitfab/sdk 0.17.0 → 0.18.1
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/{chunk-M6N633CX.js → chunk-ILIUTS5D.js} +147 -17
- package/dist/chunk-ILIUTS5D.js.map +1 -0
- package/dist/index.cjs +146 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -7
- package/dist/index.d.ts +11 -7
- package/dist/index.js +1 -1
- package/dist/node.cjs +146 -16
- package/dist/node.cjs.map +1 -1
- package/dist/node.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-M6N633CX.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -225,7 +225,7 @@ interface CodeChangeFile {
|
|
|
225
225
|
* LangGraph/LangChain callback handler for Bitfab tracing.
|
|
226
226
|
*
|
|
227
227
|
* Hooks into LangGraph's callback system to capture graph node execution,
|
|
228
|
-
* LLM calls, and tool invocations as Bitfab spans
|
|
228
|
+
* LLM calls, and tool invocations as Bitfab spans, without requiring users
|
|
229
229
|
* to wrap their functions with withSpan (which fails on non-serializable args).
|
|
230
230
|
*
|
|
231
231
|
* Duck-typed to match LangChain.js's BaseCallbackHandler interface.
|
|
@@ -238,8 +238,8 @@ interface ActiveSpanContext$1 {
|
|
|
238
238
|
/**
|
|
239
239
|
* LangChain/LangGraph callback handler that sends traces to Bitfab.
|
|
240
240
|
*
|
|
241
|
-
* Duck-typed to match LangChain.js's BaseCallbackHandler
|
|
242
|
-
* `@langchain/core` dependency required. Pass as a callback:
|
|
241
|
+
* Duck-typed to match LangChain.js's BaseCallbackHandler, so no
|
|
242
|
+
* `@langchain/core` dependency is required. Pass as a callback:
|
|
243
243
|
*
|
|
244
244
|
* ```typescript
|
|
245
245
|
* const handler = bitfab.getLangGraphCallbackHandler("my-agent");
|
|
@@ -978,11 +978,15 @@ declare class Bitfab {
|
|
|
978
978
|
* Fetches the last N traces for the given trace function key, re-runs each
|
|
979
979
|
* through the provided function, and returns comparison data.
|
|
980
980
|
*
|
|
981
|
-
*
|
|
982
|
-
*
|
|
981
|
+
* Accepts either a `withSpan`-wrapped function (under the same key) or any
|
|
982
|
+
* plain callable: plain callables are wrapped internally so each replayed
|
|
983
|
+
* invocation records a trace tied to the test run. The plain-callable form
|
|
984
|
+
* is how handler-instrumented workflows (LangGraph/LangChain, Claude Agent
|
|
985
|
+
* SDK) replay — those record traces under a key with no `withSpan`-wrapped
|
|
986
|
+
* root in the app.
|
|
983
987
|
*
|
|
984
988
|
* @param traceFunctionKey - The trace function key to replay
|
|
985
|
-
* @param fn - The function to
|
|
989
|
+
* @param fn - The function to run recorded inputs through
|
|
986
990
|
* @param options - Optional replay options. When `traceIds` is passed,
|
|
987
991
|
* `limit` is ignored (with a warning): an explicit ID list already
|
|
988
992
|
* determines how many traces replay.
|
|
@@ -1051,7 +1055,7 @@ declare class BitfabFunction {
|
|
|
1051
1055
|
/**
|
|
1052
1056
|
* SDK version from package.json (injected at build time)
|
|
1053
1057
|
*/
|
|
1054
|
-
declare const __version__ = "0.
|
|
1058
|
+
declare const __version__ = "0.18.1";
|
|
1055
1059
|
|
|
1056
1060
|
/**
|
|
1057
1061
|
* Constants for the Bitfab SDK.
|
package/dist/index.d.ts
CHANGED
|
@@ -225,7 +225,7 @@ interface CodeChangeFile {
|
|
|
225
225
|
* LangGraph/LangChain callback handler for Bitfab tracing.
|
|
226
226
|
*
|
|
227
227
|
* Hooks into LangGraph's callback system to capture graph node execution,
|
|
228
|
-
* LLM calls, and tool invocations as Bitfab spans
|
|
228
|
+
* LLM calls, and tool invocations as Bitfab spans, without requiring users
|
|
229
229
|
* to wrap their functions with withSpan (which fails on non-serializable args).
|
|
230
230
|
*
|
|
231
231
|
* Duck-typed to match LangChain.js's BaseCallbackHandler interface.
|
|
@@ -238,8 +238,8 @@ interface ActiveSpanContext$1 {
|
|
|
238
238
|
/**
|
|
239
239
|
* LangChain/LangGraph callback handler that sends traces to Bitfab.
|
|
240
240
|
*
|
|
241
|
-
* Duck-typed to match LangChain.js's BaseCallbackHandler
|
|
242
|
-
* `@langchain/core` dependency required. Pass as a callback:
|
|
241
|
+
* Duck-typed to match LangChain.js's BaseCallbackHandler, so no
|
|
242
|
+
* `@langchain/core` dependency is required. Pass as a callback:
|
|
243
243
|
*
|
|
244
244
|
* ```typescript
|
|
245
245
|
* const handler = bitfab.getLangGraphCallbackHandler("my-agent");
|
|
@@ -978,11 +978,15 @@ declare class Bitfab {
|
|
|
978
978
|
* Fetches the last N traces for the given trace function key, re-runs each
|
|
979
979
|
* through the provided function, and returns comparison data.
|
|
980
980
|
*
|
|
981
|
-
*
|
|
982
|
-
*
|
|
981
|
+
* Accepts either a `withSpan`-wrapped function (under the same key) or any
|
|
982
|
+
* plain callable: plain callables are wrapped internally so each replayed
|
|
983
|
+
* invocation records a trace tied to the test run. The plain-callable form
|
|
984
|
+
* is how handler-instrumented workflows (LangGraph/LangChain, Claude Agent
|
|
985
|
+
* SDK) replay — those record traces under a key with no `withSpan`-wrapped
|
|
986
|
+
* root in the app.
|
|
983
987
|
*
|
|
984
988
|
* @param traceFunctionKey - The trace function key to replay
|
|
985
|
-
* @param fn - The function to
|
|
989
|
+
* @param fn - The function to run recorded inputs through
|
|
986
990
|
* @param options - Optional replay options. When `traceIds` is passed,
|
|
987
991
|
* `limit` is ignored (with a warning): an explicit ID list already
|
|
988
992
|
* determines how many traces replay.
|
|
@@ -1051,7 +1055,7 @@ declare class BitfabFunction {
|
|
|
1051
1055
|
/**
|
|
1052
1056
|
* SDK version from package.json (injected at build time)
|
|
1053
1057
|
*/
|
|
1054
|
-
declare const __version__ = "0.
|
|
1058
|
+
declare const __version__ = "0.18.1";
|
|
1055
1059
|
|
|
1056
1060
|
/**
|
|
1057
1061
|
* Constants for the Bitfab SDK.
|
package/dist/index.js
CHANGED
package/dist/node.cjs
CHANGED
|
@@ -447,7 +447,7 @@ registerAsyncLocalStorageClass(
|
|
|
447
447
|
);
|
|
448
448
|
|
|
449
449
|
// src/version.generated.ts
|
|
450
|
-
var __version__ = "0.
|
|
450
|
+
var __version__ = "0.18.1";
|
|
451
451
|
|
|
452
452
|
// src/constants.ts
|
|
453
453
|
var DEFAULT_SERVICE_URL = "https://bitfab.ai";
|
|
@@ -1677,21 +1677,131 @@ function extractModelName(serialized, metadata) {
|
|
|
1677
1677
|
}
|
|
1678
1678
|
return void 0;
|
|
1679
1679
|
}
|
|
1680
|
+
function asTokenCount(value) {
|
|
1681
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
1682
|
+
}
|
|
1683
|
+
function normalizeTokenUsage(raw) {
|
|
1684
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
1685
|
+
return null;
|
|
1686
|
+
}
|
|
1687
|
+
const u = raw;
|
|
1688
|
+
if ("cache_read_input_tokens" in u || "cache_creation_input_tokens" in u) {
|
|
1689
|
+
const cacheRead = asTokenCount(u.cache_read_input_tokens);
|
|
1690
|
+
const cacheCreation = asTokenCount(u.cache_creation_input_tokens);
|
|
1691
|
+
const baseInput = asTokenCount(u.input_tokens);
|
|
1692
|
+
const outputTokens = asTokenCount(u.output_tokens);
|
|
1693
|
+
if (cacheRead === null && cacheCreation === null && baseInput === null && outputTokens === null) {
|
|
1694
|
+
return null;
|
|
1695
|
+
}
|
|
1696
|
+
const inputTokens = (baseInput ?? 0) + (cacheRead ?? 0) + (cacheCreation ?? 0);
|
|
1697
|
+
return {
|
|
1698
|
+
inputTokens,
|
|
1699
|
+
outputTokens,
|
|
1700
|
+
totalTokens: inputTokens + (outputTokens ?? 0),
|
|
1701
|
+
cachedInputTokens: cacheRead
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
if ("prompt_tokens" in u || "completion_tokens" in u || "promptTokens" in u || "completionTokens" in u) {
|
|
1705
|
+
const promptDetails = u.prompt_tokens_details ?? {};
|
|
1706
|
+
return withAnyTokenCount({
|
|
1707
|
+
inputTokens: asTokenCount(u.prompt_tokens) ?? asTokenCount(u.promptTokens),
|
|
1708
|
+
outputTokens: asTokenCount(u.completion_tokens) ?? asTokenCount(u.completionTokens),
|
|
1709
|
+
totalTokens: asTokenCount(u.total_tokens) ?? asTokenCount(u.totalTokens),
|
|
1710
|
+
cachedInputTokens: asTokenCount(promptDetails.cached_tokens)
|
|
1711
|
+
});
|
|
1712
|
+
}
|
|
1713
|
+
if ("prompt_token_count" in u || "candidates_token_count" in u) {
|
|
1714
|
+
return withAnyTokenCount({
|
|
1715
|
+
inputTokens: asTokenCount(u.prompt_token_count),
|
|
1716
|
+
outputTokens: asTokenCount(u.candidates_token_count),
|
|
1717
|
+
totalTokens: asTokenCount(u.total_token_count),
|
|
1718
|
+
cachedInputTokens: asTokenCount(u.cached_content_token_count)
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
if ("input_tokens" in u || "output_tokens" in u) {
|
|
1722
|
+
const inputDetails = u.input_token_details ?? {};
|
|
1723
|
+
const inputTokens = asTokenCount(u.input_tokens);
|
|
1724
|
+
const outputTokens = asTokenCount(u.output_tokens);
|
|
1725
|
+
let totalTokens = asTokenCount(u.total_tokens);
|
|
1726
|
+
if (totalTokens === null && inputTokens !== null && outputTokens !== null) {
|
|
1727
|
+
totalTokens = inputTokens + outputTokens;
|
|
1728
|
+
}
|
|
1729
|
+
return withAnyTokenCount({
|
|
1730
|
+
inputTokens,
|
|
1731
|
+
outputTokens,
|
|
1732
|
+
totalTokens,
|
|
1733
|
+
cachedInputTokens: asTokenCount(inputDetails.cache_read)
|
|
1734
|
+
});
|
|
1735
|
+
}
|
|
1736
|
+
return null;
|
|
1737
|
+
}
|
|
1738
|
+
function withAnyTokenCount(usage) {
|
|
1739
|
+
const hasCount = usage.inputTokens !== null || usage.outputTokens !== null || usage.totalTokens !== null || usage.cachedInputTokens !== null;
|
|
1740
|
+
return hasCount ? usage : null;
|
|
1741
|
+
}
|
|
1742
|
+
function addUsage(totals, usage) {
|
|
1743
|
+
for (const key of [
|
|
1744
|
+
"inputTokens",
|
|
1745
|
+
"outputTokens",
|
|
1746
|
+
"totalTokens",
|
|
1747
|
+
"cachedInputTokens"
|
|
1748
|
+
]) {
|
|
1749
|
+
const value = usage[key];
|
|
1750
|
+
if (value !== null) {
|
|
1751
|
+
totals[key] = (totals[key] ?? 0) + value;
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
function usageFromGenerations(generations) {
|
|
1756
|
+
if (!generations?.length) {
|
|
1757
|
+
return null;
|
|
1758
|
+
}
|
|
1759
|
+
const totals = {
|
|
1760
|
+
inputTokens: null,
|
|
1761
|
+
outputTokens: null,
|
|
1762
|
+
totalTokens: null,
|
|
1763
|
+
cachedInputTokens: null
|
|
1764
|
+
};
|
|
1765
|
+
let found = false;
|
|
1766
|
+
for (const batch of generations) {
|
|
1767
|
+
if (!Array.isArray(batch)) {
|
|
1768
|
+
continue;
|
|
1769
|
+
}
|
|
1770
|
+
for (const gen of batch) {
|
|
1771
|
+
const msg = gen?.message;
|
|
1772
|
+
if (!msg || typeof msg !== "object") {
|
|
1773
|
+
continue;
|
|
1774
|
+
}
|
|
1775
|
+
const responseMetadata = msg.response_metadata;
|
|
1776
|
+
const usage = normalizeTokenUsage(msg.usage_metadata) ?? normalizeTokenUsage(responseMetadata?.token_usage) ?? normalizeTokenUsage(responseMetadata?.usage) ?? normalizeTokenUsage(responseMetadata?.tokenUsage);
|
|
1777
|
+
if (!usage) {
|
|
1778
|
+
continue;
|
|
1779
|
+
}
|
|
1780
|
+
found = true;
|
|
1781
|
+
addUsage(totals, usage);
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
return found ? totals : null;
|
|
1785
|
+
}
|
|
1680
1786
|
function extractUsage2(output) {
|
|
1787
|
+
const generations = output.generations;
|
|
1788
|
+
const llmOutput = output.llmOutput ?? output.llm_output;
|
|
1789
|
+
const normalized = usageFromGenerations(generations) ?? normalizeTokenUsage(llmOutput?.tokenUsage) ?? normalizeTokenUsage(llmOutput?.token_usage) ?? normalizeTokenUsage(llmOutput?.usage);
|
|
1681
1790
|
const usage = {};
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1791
|
+
if (!normalized) {
|
|
1792
|
+
return usage;
|
|
1793
|
+
}
|
|
1794
|
+
if (normalized.inputTokens !== null) {
|
|
1795
|
+
usage.inputTokens = normalized.inputTokens;
|
|
1796
|
+
}
|
|
1797
|
+
if (normalized.outputTokens !== null) {
|
|
1798
|
+
usage.outputTokens = normalized.outputTokens;
|
|
1689
1799
|
}
|
|
1690
|
-
if (
|
|
1691
|
-
usage.
|
|
1800
|
+
if (normalized.totalTokens !== null) {
|
|
1801
|
+
usage.totalTokens = normalized.totalTokens;
|
|
1692
1802
|
}
|
|
1693
|
-
if (
|
|
1694
|
-
usage.
|
|
1803
|
+
if (normalized.cachedInputTokens !== null) {
|
|
1804
|
+
usage.cachedInputTokens = normalized.cachedInputTokens;
|
|
1695
1805
|
}
|
|
1696
1806
|
return usage;
|
|
1697
1807
|
}
|
|
@@ -3079,6 +3189,9 @@ var Bitfab = class {
|
|
|
3079
3189
|
};
|
|
3080
3190
|
return runWithSpanStack(newStack, executeWithContext);
|
|
3081
3191
|
};
|
|
3192
|
+
Object.defineProperty(wrappedFn, "_bitfabTraceFunctionKey", {
|
|
3193
|
+
value: traceFunctionKey
|
|
3194
|
+
});
|
|
3082
3195
|
return wrappedFn;
|
|
3083
3196
|
}
|
|
3084
3197
|
/**
|
|
@@ -3250,23 +3363,40 @@ var Bitfab = class {
|
|
|
3250
3363
|
* Fetches the last N traces for the given trace function key, re-runs each
|
|
3251
3364
|
* through the provided function, and returns comparison data.
|
|
3252
3365
|
*
|
|
3253
|
-
*
|
|
3254
|
-
*
|
|
3366
|
+
* Accepts either a `withSpan`-wrapped function (under the same key) or any
|
|
3367
|
+
* plain callable: plain callables are wrapped internally so each replayed
|
|
3368
|
+
* invocation records a trace tied to the test run. The plain-callable form
|
|
3369
|
+
* is how handler-instrumented workflows (LangGraph/LangChain, Claude Agent
|
|
3370
|
+
* SDK) replay — those record traces under a key with no `withSpan`-wrapped
|
|
3371
|
+
* root in the app.
|
|
3255
3372
|
*
|
|
3256
3373
|
* @param traceFunctionKey - The trace function key to replay
|
|
3257
|
-
* @param fn - The function to
|
|
3374
|
+
* @param fn - The function to run recorded inputs through
|
|
3258
3375
|
* @param options - Optional replay options. When `traceIds` is passed,
|
|
3259
3376
|
* `limit` is ignored (with a warning): an explicit ID list already
|
|
3260
3377
|
* determines how many traces replay.
|
|
3261
3378
|
* @returns ReplayResult with items, testRunId, and testRunUrl
|
|
3262
3379
|
*/
|
|
3263
3380
|
async replay(traceFunctionKey, fn, options) {
|
|
3381
|
+
const wrappedKey = fn._bitfabTraceFunctionKey;
|
|
3382
|
+
let replayFn = fn;
|
|
3383
|
+
if (wrappedKey === void 0) {
|
|
3384
|
+
replayFn = this.withSpan(
|
|
3385
|
+
traceFunctionKey,
|
|
3386
|
+
{ name: fn.name || "Replay", type: "agent" },
|
|
3387
|
+
fn
|
|
3388
|
+
);
|
|
3389
|
+
} else if (wrappedKey !== traceFunctionKey) {
|
|
3390
|
+
throw new BitfabError(
|
|
3391
|
+
`Function is wrapped with trace function key '${wrappedKey}' but replay was called with '${traceFunctionKey}'. Pass matching keys, or pass the unwrapped function to replay it under the explicit key.`
|
|
3392
|
+
);
|
|
3393
|
+
}
|
|
3264
3394
|
const { replay: doReplay } = await Promise.resolve().then(() => (init_replay(), replay_exports));
|
|
3265
3395
|
return doReplay(
|
|
3266
3396
|
this.httpClient,
|
|
3267
3397
|
this.serviceUrl,
|
|
3268
3398
|
traceFunctionKey,
|
|
3269
|
-
|
|
3399
|
+
replayFn,
|
|
3270
3400
|
options
|
|
3271
3401
|
);
|
|
3272
3402
|
}
|