@bitfab/sdk 0.38.5 → 0.38.7

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.
@@ -155,11 +155,18 @@ function currentAutoTraceScope() {
155
155
  }
156
156
  function __setBitfabAutoTraceCapturePolicy(client, traceFunctionKey, functionIds) {
157
157
  const policies = autoTraceState.capturePolicies.get(client) ?? /* @__PURE__ */ new Map();
158
+ if (functionIds === void 0) {
159
+ policies.delete(traceFunctionKey);
160
+ if (policies.size === 0) {
161
+ autoTraceState.capturePolicies.delete(client);
162
+ }
163
+ return;
164
+ }
158
165
  policies.set(traceFunctionKey, new Set(functionIds));
159
166
  autoTraceState.capturePolicies.set(client, policies);
160
167
  }
161
168
  function getAutoTraceCapturePolicy(client, traceFunctionKey) {
162
- return autoTraceState.capturePolicies.get(client)?.get(traceFunctionKey) ?? /* @__PURE__ */ new Set();
169
+ return autoTraceState.capturePolicies.get(client)?.get(traceFunctionKey);
163
170
  }
164
171
 
165
172
  export {
@@ -172,4 +179,4 @@ export {
172
179
  __setBitfabAutoTraceCapturePolicy,
173
180
  getAutoTraceCapturePolicy
174
181
  };
175
- //# sourceMappingURL=chunk-J47KPS77.js.map
182
+ //# sourceMappingURL=chunk-ZUD7OFYB.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/autoTrace.ts"],"sourcesContent":["import {\n type AsyncLocalStorageLike,\n createAsyncLocalStorage,\n} from \"./asyncStorage.js\"\n\nexport interface AutoTraceFunctionDefinition {\n id: string\n name: string\n file: string\n line: number\n column: number\n async?: boolean\n wrapper?: boolean\n}\n\nexport interface AutoTraceNodeConfiguration {\n functionName: string\n name?: string\n type?: \"llm\" | \"agent\" | \"function\" | \"guardrail\" | \"handoff\" | \"custom\"\n capture: boolean\n testRunId?: string\n mockOnReplay?: boolean\n // biome-ignore lint/suspicious/noExplicitAny: node finalizers receive the configured function's result, whose type is owned by the caller\n finalize?: (result: any) => unknown | Promise<unknown>\n}\n\nexport interface AutoTraceContext {\n invoke<T>(\n definition: AutoTraceFunctionDefinition,\n inputs: unknown[],\n fn: () => T,\n depth: number,\n nodeConfiguration?: AutoTraceNodeConfiguration,\n ): T\n}\n\ninterface AutoTraceScope {\n context: AutoTraceContext\n depth: number\n nodeConfiguration?: AutoTraceNodeConfiguration\n}\n\ninterface AutoTraceState {\n storage: AsyncLocalStorageLike<AutoTraceScope> | null\n browserScope: AutoTraceScope | undefined\n capturePolicies: WeakMap<object, Map<string, ReadonlySet<string>>>\n activeRoots: number\n}\n\ninterface AutoTraceGlobal {\n __bitfabAutoTraceStateV3?: AutoTraceState\n}\n\ninterface AutoTraceAsyncGenerator {\n next(value?: unknown): Promise<IteratorResult<unknown, unknown>>\n return(value?: unknown): Promise<IteratorResult<unknown, unknown>>\n throw(error?: unknown): Promise<IteratorResult<unknown, unknown>>\n [Symbol.asyncIterator](): AutoTraceAsyncGenerator\n}\n\nconst autoTraceGlobal = globalThis as unknown as AutoTraceGlobal\nconst autoTraceState: AutoTraceState =\n autoTraceGlobal.__bitfabAutoTraceStateV3 ?? {\n storage: null,\n browserScope: undefined,\n capturePolicies: new WeakMap(),\n activeRoots: 0,\n }\nautoTraceGlobal.__bitfabAutoTraceStateV3 = autoTraceState\n\nfunction initializeAutoTraceStorage(): void {\n autoTraceState.storage ??= createAsyncLocalStorage<AutoTraceScope>()\n}\n\nexport function runWithAutoTraceContext<T>(\n context: AutoTraceContext,\n fn: () => T,\n depth = 0,\n): T {\n initializeAutoTraceStorage()\n const scope = { context, depth }\n if (autoTraceState.storage) {\n return autoTraceState.storage.run(scope, fn)\n }\n\n const previous = autoTraceState.browserScope\n autoTraceState.browserScope = scope\n try {\n return fn()\n } finally {\n autoTraceState.browserScope = previous\n }\n}\n\nexport function runWithAutoTraceNodeConfiguration<T>(\n nodeConfiguration: AutoTraceNodeConfiguration,\n fn: () => T,\n): T {\n const scope = currentAutoTraceScope()\n if (!scope) {\n return fn()\n }\n\n const configuredScope = { ...scope, nodeConfiguration }\n let result: T\n if (autoTraceState.storage) {\n result = autoTraceState.storage.run(configuredScope, fn)\n } else {\n const previous = autoTraceState.browserScope\n autoTraceState.browserScope = configuredScope\n try {\n result = fn()\n } finally {\n autoTraceState.browserScope = previous\n }\n }\n\n if (isAutoTraceAsyncGenerator(result)) {\n return wrapAutoTraceNodeAsyncGenerator(nodeConfiguration, result) as T\n }\n return result\n}\n\nexport function runWithAutoTraceRootContext<T>(\n context: AutoTraceContext,\n fn: () => T,\n): T {\n autoTraceState.activeRoots += 1\n let result: T\n try {\n result = runWithAutoTraceContext(context, fn)\n } catch (error) {\n autoTraceState.activeRoots -= 1\n throw error\n }\n\n if (isAutoTraceAsyncGenerator(result)) {\n autoTraceState.activeRoots -= 1\n return wrapAutoTraceAsyncGenerator(context, result) as T\n }\n\n if (result instanceof Promise) {\n return result.finally(() => {\n autoTraceState.activeRoots -= 1\n }) as T\n }\n\n autoTraceState.activeRoots -= 1\n return result\n}\n\nfunction isAutoTraceAsyncGenerator(\n value: unknown,\n): value is AutoTraceAsyncGenerator {\n if (value === null || typeof value !== \"object\") {\n return false\n }\n const candidate = value as Record<PropertyKey, unknown>\n return (\n typeof candidate.next === \"function\" &&\n typeof candidate.return === \"function\" &&\n typeof candidate.throw === \"function\" &&\n typeof candidate[Symbol.asyncIterator] === \"function\"\n )\n}\n\nfunction wrapAutoTraceAsyncGenerator(\n context: AutoTraceContext,\n source: AutoTraceAsyncGenerator,\n): AutoTraceAsyncGenerator {\n const step = (\n method: \"next\" | \"return\" | \"throw\",\n value?: unknown,\n ): Promise<IteratorResult<unknown, unknown>> =>\n runWithAutoTraceRootContext(context, () => source[method](value))\n const wrapped: AutoTraceAsyncGenerator = {\n next: (value) => step(\"next\", value),\n return: (value) => step(\"return\", value),\n throw: (error) => step(\"throw\", error),\n [Symbol.asyncIterator]: () => wrapped,\n }\n return wrapped\n}\n\nfunction wrapAutoTraceNodeAsyncGenerator(\n nodeConfiguration: AutoTraceNodeConfiguration,\n source: AutoTraceAsyncGenerator,\n): AutoTraceAsyncGenerator {\n const step = (\n method: \"next\" | \"return\" | \"throw\",\n value?: unknown,\n ): Promise<IteratorResult<unknown, unknown>> =>\n runWithAutoTraceNodeConfiguration(nodeConfiguration, () =>\n source[method](value),\n )\n const wrapped: AutoTraceAsyncGenerator = {\n next: (value) => step(\"next\", value),\n return: (value) => step(\"return\", value),\n throw: (error) => step(\"throw\", error),\n [Symbol.asyncIterator]: () => wrapped,\n }\n return wrapped\n}\n\nexport function __bitfabAutoSpan<T>(\n definition: AutoTraceFunctionDefinition,\n inputs: unknown[],\n fn: () => T,\n): T {\n const scope = currentAutoTraceScope()\n if (!scope) {\n return fn()\n }\n const nameParts = definition.name.split(\".\")\n const simpleName = nameParts[nameParts.length - 1]\n const nodeConfiguration =\n simpleName === scope.nodeConfiguration?.functionName\n ? scope.nodeConfiguration\n : undefined\n return scope.context.invoke(\n definition,\n inputs,\n fn,\n scope.depth,\n nodeConfiguration,\n )\n}\n\n/**\n * Preserve a function's original call arguments for transform cases where\n * parameter bindings discard them, such as destructured arrow parameters.\n *\n * This helper is internal transform/runtime protocol. The proxy preserves the\n * target's callability, arity, async identity, and non-constructibility while\n * only allocating a trace closure beneath an active automatic trace root.\n *\n * @experimental The automatic tracing protocol may change.\n */\nexport function __bitfabAutoWrap<T extends (...args: never[]) => unknown>(\n definition: AutoTraceFunctionDefinition,\n fn: T,\n): T {\n if (fn.name === \"\") {\n const nameParts = definition.name.split(\".\")\n const inferredName = nameParts[nameParts.length - 1]\n if (inferredName !== undefined) {\n Object.defineProperty(fn, \"name\", {\n configurable: true,\n value: inferredName,\n })\n }\n }\n\n const target = fn as unknown as (...args: unknown[]) => unknown\n return new Proxy(target, {\n apply(callTarget, thisArg, args) {\n if (!__bitfabAutoTraceActive()) {\n return Reflect.apply(callTarget, thisArg, args)\n }\n return __bitfabAutoSpan(definition, args, () =>\n Reflect.apply(callTarget, thisArg, args),\n )\n },\n }) as unknown as T\n}\n\n/**\n * Return whether the current call is inside an automatic trace root.\n *\n * Build transforms use this before allocating function metadata, captured\n * inputs, or an invocation closure. It is internal transform/runtime protocol,\n * not a supported application API.\n *\n * @experimental The automatic tracing protocol may change.\n */\nexport function __bitfabAutoTraceActive(): boolean {\n if (autoTraceState.activeRoots === 0) {\n return false\n }\n return currentAutoTraceScope() !== undefined\n}\n\nfunction currentAutoTraceScope(): AutoTraceScope | undefined {\n initializeAutoTraceStorage()\n return autoTraceState.storage?.getStore() ?? autoTraceState.browserScope\n}\n\nexport function __setBitfabAutoTraceCapturePolicy(\n client: object,\n traceFunctionKey: string,\n functionIds: Iterable<string>,\n): void {\n const policies = autoTraceState.capturePolicies.get(client) ?? new Map()\n policies.set(traceFunctionKey, new Set(functionIds))\n autoTraceState.capturePolicies.set(client, policies)\n}\n\nexport function getAutoTraceCapturePolicy(\n client: object,\n traceFunctionKey: string,\n): ReadonlySet<string> {\n return (\n autoTraceState.capturePolicies.get(client)?.get(traceFunctionKey) ??\n new Set()\n )\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/autoTrace.ts"],"sourcesContent":["import {\n type AsyncLocalStorageLike,\n createAsyncLocalStorage,\n} from \"./asyncStorage.js\"\n\nexport interface AutoTraceFunctionDefinition {\n id: string\n name: string\n file: string\n line: number\n column: number\n async?: boolean\n wrapper?: boolean\n}\n\nexport interface AutoTraceNodeConfiguration {\n functionName: string\n name?: string\n type?: \"llm\" | \"agent\" | \"function\" | \"guardrail\" | \"handoff\" | \"custom\"\n capture: boolean\n testRunId?: string\n mockOnReplay?: boolean\n // biome-ignore lint/suspicious/noExplicitAny: node finalizers receive the configured function's result, whose type is owned by the caller\n finalize?: (result: any) => unknown | Promise<unknown>\n}\n\nexport interface AutoTraceContext {\n invoke<T>(\n definition: AutoTraceFunctionDefinition,\n inputs: unknown[],\n fn: () => T,\n depth: number,\n nodeConfiguration?: AutoTraceNodeConfiguration,\n ): T\n}\n\ninterface AutoTraceScope {\n context: AutoTraceContext\n depth: number\n nodeConfiguration?: AutoTraceNodeConfiguration\n}\n\ninterface AutoTraceState {\n storage: AsyncLocalStorageLike<AutoTraceScope> | null\n browserScope: AutoTraceScope | undefined\n capturePolicies: WeakMap<object, Map<string, ReadonlySet<string>>>\n activeRoots: number\n}\n\ninterface AutoTraceGlobal {\n __bitfabAutoTraceStateV3?: AutoTraceState\n}\n\ninterface AutoTraceAsyncGenerator {\n next(value?: unknown): Promise<IteratorResult<unknown, unknown>>\n return(value?: unknown): Promise<IteratorResult<unknown, unknown>>\n throw(error?: unknown): Promise<IteratorResult<unknown, unknown>>\n [Symbol.asyncIterator](): AutoTraceAsyncGenerator\n}\n\nconst autoTraceGlobal = globalThis as unknown as AutoTraceGlobal\nconst autoTraceState: AutoTraceState =\n autoTraceGlobal.__bitfabAutoTraceStateV3 ?? {\n storage: null,\n browserScope: undefined,\n capturePolicies: new WeakMap(),\n activeRoots: 0,\n }\nautoTraceGlobal.__bitfabAutoTraceStateV3 = autoTraceState\n\nfunction initializeAutoTraceStorage(): void {\n autoTraceState.storage ??= createAsyncLocalStorage<AutoTraceScope>()\n}\n\nexport function runWithAutoTraceContext<T>(\n context: AutoTraceContext,\n fn: () => T,\n depth = 0,\n): T {\n initializeAutoTraceStorage()\n const scope = { context, depth }\n if (autoTraceState.storage) {\n return autoTraceState.storage.run(scope, fn)\n }\n\n const previous = autoTraceState.browserScope\n autoTraceState.browserScope = scope\n try {\n return fn()\n } finally {\n autoTraceState.browserScope = previous\n }\n}\n\nexport function runWithAutoTraceNodeConfiguration<T>(\n nodeConfiguration: AutoTraceNodeConfiguration,\n fn: () => T,\n): T {\n const scope = currentAutoTraceScope()\n if (!scope) {\n return fn()\n }\n\n const configuredScope = { ...scope, nodeConfiguration }\n let result: T\n if (autoTraceState.storage) {\n result = autoTraceState.storage.run(configuredScope, fn)\n } else {\n const previous = autoTraceState.browserScope\n autoTraceState.browserScope = configuredScope\n try {\n result = fn()\n } finally {\n autoTraceState.browserScope = previous\n }\n }\n\n if (isAutoTraceAsyncGenerator(result)) {\n return wrapAutoTraceNodeAsyncGenerator(nodeConfiguration, result) as T\n }\n return result\n}\n\nexport function runWithAutoTraceRootContext<T>(\n context: AutoTraceContext,\n fn: () => T,\n): T {\n autoTraceState.activeRoots += 1\n let result: T\n try {\n result = runWithAutoTraceContext(context, fn)\n } catch (error) {\n autoTraceState.activeRoots -= 1\n throw error\n }\n\n if (isAutoTraceAsyncGenerator(result)) {\n autoTraceState.activeRoots -= 1\n return wrapAutoTraceAsyncGenerator(context, result) as T\n }\n\n if (result instanceof Promise) {\n return result.finally(() => {\n autoTraceState.activeRoots -= 1\n }) as T\n }\n\n autoTraceState.activeRoots -= 1\n return result\n}\n\nfunction isAutoTraceAsyncGenerator(\n value: unknown,\n): value is AutoTraceAsyncGenerator {\n if (value === null || typeof value !== \"object\") {\n return false\n }\n const candidate = value as Record<PropertyKey, unknown>\n return (\n typeof candidate.next === \"function\" &&\n typeof candidate.return === \"function\" &&\n typeof candidate.throw === \"function\" &&\n typeof candidate[Symbol.asyncIterator] === \"function\"\n )\n}\n\nfunction wrapAutoTraceAsyncGenerator(\n context: AutoTraceContext,\n source: AutoTraceAsyncGenerator,\n): AutoTraceAsyncGenerator {\n const step = (\n method: \"next\" | \"return\" | \"throw\",\n value?: unknown,\n ): Promise<IteratorResult<unknown, unknown>> =>\n runWithAutoTraceRootContext(context, () => source[method](value))\n const wrapped: AutoTraceAsyncGenerator = {\n next: (value) => step(\"next\", value),\n return: (value) => step(\"return\", value),\n throw: (error) => step(\"throw\", error),\n [Symbol.asyncIterator]: () => wrapped,\n }\n return wrapped\n}\n\nfunction wrapAutoTraceNodeAsyncGenerator(\n nodeConfiguration: AutoTraceNodeConfiguration,\n source: AutoTraceAsyncGenerator,\n): AutoTraceAsyncGenerator {\n const step = (\n method: \"next\" | \"return\" | \"throw\",\n value?: unknown,\n ): Promise<IteratorResult<unknown, unknown>> =>\n runWithAutoTraceNodeConfiguration(nodeConfiguration, () =>\n source[method](value),\n )\n const wrapped: AutoTraceAsyncGenerator = {\n next: (value) => step(\"next\", value),\n return: (value) => step(\"return\", value),\n throw: (error) => step(\"throw\", error),\n [Symbol.asyncIterator]: () => wrapped,\n }\n return wrapped\n}\n\nexport function __bitfabAutoSpan<T>(\n definition: AutoTraceFunctionDefinition,\n inputs: unknown[],\n fn: () => T,\n): T {\n const scope = currentAutoTraceScope()\n if (!scope) {\n return fn()\n }\n const nameParts = definition.name.split(\".\")\n const simpleName = nameParts[nameParts.length - 1]\n const nodeConfiguration =\n simpleName === scope.nodeConfiguration?.functionName\n ? scope.nodeConfiguration\n : undefined\n return scope.context.invoke(\n definition,\n inputs,\n fn,\n scope.depth,\n nodeConfiguration,\n )\n}\n\n/**\n * Preserve a function's original call arguments for transform cases where\n * parameter bindings discard them, such as destructured arrow parameters.\n *\n * This helper is internal transform/runtime protocol. The proxy preserves the\n * target's callability, arity, async identity, and non-constructibility while\n * only allocating a trace closure beneath an active automatic trace root.\n *\n * @experimental The automatic tracing protocol may change.\n */\nexport function __bitfabAutoWrap<T extends (...args: never[]) => unknown>(\n definition: AutoTraceFunctionDefinition,\n fn: T,\n): T {\n if (fn.name === \"\") {\n const nameParts = definition.name.split(\".\")\n const inferredName = nameParts[nameParts.length - 1]\n if (inferredName !== undefined) {\n Object.defineProperty(fn, \"name\", {\n configurable: true,\n value: inferredName,\n })\n }\n }\n\n const target = fn as unknown as (...args: unknown[]) => unknown\n return new Proxy(target, {\n apply(callTarget, thisArg, args) {\n if (!__bitfabAutoTraceActive()) {\n return Reflect.apply(callTarget, thisArg, args)\n }\n return __bitfabAutoSpan(definition, args, () =>\n Reflect.apply(callTarget, thisArg, args),\n )\n },\n }) as unknown as T\n}\n\n/**\n * Return whether the current call is inside an automatic trace root.\n *\n * Build transforms use this before allocating function metadata, captured\n * inputs, or an invocation closure. It is internal transform/runtime protocol,\n * not a supported application API.\n *\n * @experimental The automatic tracing protocol may change.\n */\nexport function __bitfabAutoTraceActive(): boolean {\n if (autoTraceState.activeRoots === 0) {\n return false\n }\n return currentAutoTraceScope() !== undefined\n}\n\nfunction currentAutoTraceScope(): AutoTraceScope | undefined {\n initializeAutoTraceStorage()\n return autoTraceState.storage?.getStore() ?? autoTraceState.browserScope\n}\n\nexport function __setBitfabAutoTraceCapturePolicy(\n client: object,\n traceFunctionKey: string,\n functionIds: Iterable<string> | undefined,\n): void {\n const policies = autoTraceState.capturePolicies.get(client) ?? new Map()\n if (functionIds === undefined) {\n policies.delete(traceFunctionKey)\n if (policies.size === 0) {\n autoTraceState.capturePolicies.delete(client)\n }\n return\n }\n policies.set(traceFunctionKey, new Set(functionIds))\n autoTraceState.capturePolicies.set(client, policies)\n}\n\nexport function getAutoTraceCapturePolicy(\n client: object,\n traceFunctionKey: string,\n): ReadonlySet<string> | undefined {\n return autoTraceState.capturePolicies.get(client)?.get(traceFunctionKey)\n}\n"],"mappings":"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","names":[]}
package/dist/index.cjs CHANGED
@@ -42,7 +42,7 @@ var __version__, __packageName__;
42
42
  var init_version_generated = __esm({
43
43
  "src/version.generated.ts"() {
44
44
  "use strict";
45
- __version__ = "0.38.5";
45
+ __version__ = "0.38.7";
46
46
  __packageName__ = "@bitfab/sdk";
47
47
  }
48
48
  });
@@ -498,8 +498,8 @@ function encodePayloadBody(payload) {
498
498
  const marker = { error: `payload_serialize_failed: ${message}` };
499
499
  return { body: JSON.stringify(marker), dropped, value: marker };
500
500
  }
501
- const isRecord = typeof sanitized === "object" && sanitized !== null && !Array.isArray(sanitized);
502
- if (dropped.length > 0 && isRecord) {
501
+ const isRecord2 = typeof sanitized === "object" && sanitized !== null && !Array.isArray(sanitized);
502
+ if (dropped.length > 0 && isRecord2) {
503
503
  const obj = sanitized;
504
504
  const existing = Array.isArray(obj.errors) ? obj.errors : [];
505
505
  obj.errors = [
@@ -516,7 +516,7 @@ function encodePayloadBody(payload) {
516
516
  return {
517
517
  body: JSON.stringify(sanitized),
518
518
  dropped,
519
- value: isRecord ? sanitized : void 0
519
+ value: isRecord2 ? sanitized : void 0
520
520
  };
521
521
  }
522
522
  }
@@ -3132,6 +3132,7 @@ __export(index_exports, {
3132
3132
  BitfabFunction: () => BitfabFunction,
3133
3133
  BitfabLangChainCallbackHandler: () => BitfabLangGraphCallbackHandler,
3134
3134
  BitfabLangGraphCallbackHandler: () => BitfabLangGraphCallbackHandler,
3135
+ BitfabLangGraphIntegration: () => BitfabLangGraphIntegration,
3135
3136
  BitfabOpenAIAgentHandler: () => BitfabOpenAIAgentHandler,
3136
3137
  BitfabOpenAITracingProcessor: () => BitfabOpenAITracingProcessor,
3137
3138
  BitfabVercelAiHandler: () => BitfabVercelAiHandler,
@@ -3880,11 +3881,18 @@ function currentAutoTraceScope() {
3880
3881
  }
3881
3882
  function __setBitfabAutoTraceCapturePolicy(client, traceFunctionKey, functionIds) {
3882
3883
  const policies = autoTraceState.capturePolicies.get(client) ?? /* @__PURE__ */ new Map();
3884
+ if (functionIds === void 0) {
3885
+ policies.delete(traceFunctionKey);
3886
+ if (policies.size === 0) {
3887
+ autoTraceState.capturePolicies.delete(client);
3888
+ }
3889
+ return;
3890
+ }
3883
3891
  policies.set(traceFunctionKey, new Set(functionIds));
3884
3892
  autoTraceState.capturePolicies.set(client, policies);
3885
3893
  }
3886
3894
  function getAutoTraceCapturePolicy(client, traceFunctionKey) {
3887
- return autoTraceState.capturePolicies.get(client)?.get(traceFunctionKey) ?? /* @__PURE__ */ new Set();
3895
+ return autoTraceState.capturePolicies.get(client)?.get(traceFunctionKey);
3888
3896
  }
3889
3897
 
3890
3898
  // src/optionalPeer.ts
@@ -4449,6 +4457,7 @@ var BitfabLangGraphCallbackHandler = class {
4449
4457
  });
4450
4458
  this.traceFunctionKey = config.traceFunctionKey;
4451
4459
  this.getActiveSpanContext = config.getActiveSpanContext ?? null;
4460
+ this.captureTools = config.captureTools ?? true;
4452
4461
  }
4453
4462
  /**
4454
4463
  * Flush and release the span transport this handler started. A no-op when
@@ -4757,6 +4766,9 @@ var BitfabLangGraphCallbackHandler = class {
4757
4766
  }
4758
4767
  // ── tool callbacks ────────────────────────────────────────────
4759
4768
  async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName) {
4769
+ if (!this.captureTools) {
4770
+ return;
4771
+ }
4760
4772
  try {
4761
4773
  const serialized = tool ?? {};
4762
4774
  const name = runName ?? serialized.name ?? "tool";
@@ -4773,12 +4785,18 @@ var BitfabLangGraphCallbackHandler = class {
4773
4785
  }
4774
4786
  }
4775
4787
  async handleToolEnd(output, runId) {
4788
+ if (!this.captureTools) {
4789
+ return;
4790
+ }
4776
4791
  try {
4777
4792
  this.completeSpan(runId, output);
4778
4793
  } catch {
4779
4794
  }
4780
4795
  }
4781
4796
  async handleToolError(error, runId) {
4797
+ if (!this.captureTools) {
4798
+ return;
4799
+ }
4782
4800
  try {
4783
4801
  this.completeSpan(
4784
4802
  runId,
@@ -4823,6 +4841,258 @@ var BitfabLangGraphCallbackHandler = class {
4823
4841
  }
4824
4842
  };
4825
4843
 
4844
+ // src/langgraphIntegration.ts
4845
+ init_http();
4846
+ init_replayContext();
4847
+ var TOOL_RESULT_TAG = "__bitfabLangGraphToolResult";
4848
+ function isRecord(value) {
4849
+ return typeof value === "object" && value !== null;
4850
+ }
4851
+ function isToolMessage(value) {
4852
+ return isRecord(value) && value.lc_direct_tool_output === true && value.type === "tool" && (typeof value.content === "string" || Array.isArray(value.content));
4853
+ }
4854
+ function isCommand(value) {
4855
+ return isRecord(value) && value.lg_name === "Command";
4856
+ }
4857
+ function encodeNested(value) {
4858
+ if (isToolMessage(value) || isCommand(value)) {
4859
+ return encodeNativeToolResult(value);
4860
+ }
4861
+ if (Array.isArray(value)) {
4862
+ return value.map(encodeNested);
4863
+ }
4864
+ if (isRecord(value)) {
4865
+ return Object.fromEntries(
4866
+ Object.entries(value).map(([key, entry]) => [key, encodeNested(entry)])
4867
+ );
4868
+ }
4869
+ return value;
4870
+ }
4871
+ function encodeNativeToolResult(value) {
4872
+ if (isToolMessage(value)) {
4873
+ return {
4874
+ [TOOL_RESULT_TAG]: "tool-message",
4875
+ content: value.content,
4876
+ name: typeof value.name === "string" ? value.name : void 0,
4877
+ id: typeof value.id === "string" ? value.id : void 0,
4878
+ status: value.status === "success" || value.status === "error" ? value.status : void 0,
4879
+ artifact: encodeNested(value.artifact),
4880
+ metadata: encodeNested(value.metadata),
4881
+ additionalKwargs: encodeNested(value.additional_kwargs),
4882
+ responseMetadata: encodeNested(value.response_metadata)
4883
+ };
4884
+ }
4885
+ return {
4886
+ [TOOL_RESULT_TAG]: "command",
4887
+ graph: isRecord(value) && typeof value.graph === "string" ? value.graph : void 0,
4888
+ update: isRecord(value) ? encodeNested(value.update) : void 0,
4889
+ resume: isRecord(value) ? encodeNested(value.resume) : void 0,
4890
+ goto: isRecord(value) ? encodeNested(value.goto) : void 0
4891
+ };
4892
+ }
4893
+ function finalizeToolResult(value) {
4894
+ return isToolMessage(value) || isCommand(value) ? encodeNativeToolResult(value) : value;
4895
+ }
4896
+ function isEncodedToolResult(value) {
4897
+ return isRecord(value) && typeof value[TOOL_RESULT_TAG] === "string";
4898
+ }
4899
+ async function loadLangChainCore() {
4900
+ try {
4901
+ return await importOptionalPeer([
4902
+ "@langchain",
4903
+ "core",
4904
+ "messages"
4905
+ ]);
4906
+ } catch {
4907
+ throw new BitfabError(
4908
+ "LangGraph tool replay requires @langchain/core. Install @langchain/langgraph before using getLangGraphIntegration().",
4909
+ "https://docs.bitfab.ai/frameworks/langgraph"
4910
+ );
4911
+ }
4912
+ }
4913
+ async function loadLangGraph() {
4914
+ try {
4915
+ return await importOptionalPeer([
4916
+ "@langchain",
4917
+ "langgraph"
4918
+ ]);
4919
+ } catch {
4920
+ throw new BitfabError(
4921
+ "Replaying a LangGraph Command requires @langchain/langgraph.",
4922
+ "https://docs.bitfab.ai/frameworks/langgraph"
4923
+ );
4924
+ }
4925
+ }
4926
+ async function reviveNested(value, toolCallId) {
4927
+ if (isEncodedToolResult(value)) {
4928
+ return reviveToolResult(value, toolCallId);
4929
+ }
4930
+ if (Array.isArray(value)) {
4931
+ return Promise.all(value.map((entry) => reviveNested(entry, toolCallId)));
4932
+ }
4933
+ if (isRecord(value)) {
4934
+ const entries = await Promise.all(
4935
+ Object.entries(value).map(async ([key, entry]) => [
4936
+ key,
4937
+ await reviveNested(entry, toolCallId)
4938
+ ])
4939
+ );
4940
+ return Object.fromEntries(entries);
4941
+ }
4942
+ return value;
4943
+ }
4944
+ async function reviveToolResult(value, toolCallId) {
4945
+ if (value[TOOL_RESULT_TAG] === "tool-message") {
4946
+ const { ToolMessage } = await loadLangChainCore();
4947
+ return new ToolMessage({
4948
+ content: value.content,
4949
+ tool_call_id: toolCallId,
4950
+ ...typeof value.name === "string" && { name: value.name },
4951
+ ...typeof value.id === "string" && { id: value.id },
4952
+ ...(value.status === "success" || value.status === "error") && {
4953
+ status: value.status
4954
+ },
4955
+ ...value.artifact !== void 0 && {
4956
+ artifact: await reviveNested(value.artifact, toolCallId)
4957
+ },
4958
+ ...isRecord(value.metadata) && {
4959
+ metadata: await reviveNested(value.metadata, toolCallId)
4960
+ },
4961
+ ...isRecord(value.additionalKwargs) && {
4962
+ additional_kwargs: await reviveNested(
4963
+ value.additionalKwargs,
4964
+ toolCallId
4965
+ )
4966
+ },
4967
+ ...isRecord(value.responseMetadata) && {
4968
+ response_metadata: await reviveNested(
4969
+ value.responseMetadata,
4970
+ toolCallId
4971
+ )
4972
+ }
4973
+ });
4974
+ }
4975
+ const { Command } = await loadLangGraph();
4976
+ return new Command({
4977
+ ...typeof value.graph === "string" && { graph: value.graph },
4978
+ ...value.update !== void 0 && {
4979
+ update: await reviveNested(value.update, toolCallId)
4980
+ },
4981
+ ...value.resume !== void 0 && {
4982
+ resume: await reviveNested(value.resume, toolCallId)
4983
+ },
4984
+ ...value.goto !== void 0 && {
4985
+ goto: await reviveNested(value.goto, toolCallId)
4986
+ }
4987
+ });
4988
+ }
4989
+ var BitfabLangGraphIntegration = class {
4990
+ constructor(config) {
4991
+ this.client = config.client;
4992
+ this.traceFunctionKey = config.traceFunctionKey;
4993
+ this.callbackHandler = config.callbackHandler;
4994
+ this.mockToolsOnReplay = config.options?.mockToolsOnReplay ?? true;
4995
+ }
4996
+ /**
4997
+ * Wrap tools before passing the same returned array to both
4998
+ * `model.bindTools()` and `new ToolNode()`. Each invocation becomes an
4999
+ * independently mockable child span.
5000
+ */
5001
+ wrapTools(tools) {
5002
+ return tools.map((tool) => this.wrapTool(tool));
5003
+ }
5004
+ /**
5005
+ * Create the normal graph entry point. The returned function adds Bitfab's
5006
+ * callback handler, preserves invocation config, and records only the graph
5007
+ * input as the replayable root input.
5008
+ *
5009
+ * @experimental This API may change before it is stable.
5010
+ */
5011
+ createInvoker(graph) {
5012
+ const configuredGraph = graph.withConfig({
5013
+ callbacks: [this.callbackHandler]
5014
+ });
5015
+ return (input, config) => {
5016
+ const invoke = this.wrapInvoke(
5017
+ (rootInput) => configuredGraph.invoke(rootInput, config)
5018
+ );
5019
+ return invoke(input);
5020
+ };
5021
+ }
5022
+ wrapTool(tool) {
5023
+ const toolName = tool.name;
5024
+ if (typeof toolName !== "string" || toolName.length === 0) {
5025
+ throw new BitfabError(
5026
+ "LangGraph replayable tools must have a name.",
5027
+ "https://docs.bitfab.ai/frameworks/langgraph"
5028
+ );
5029
+ }
5030
+ const mockToolsOnReplay = this.mockToolsOnReplay;
5031
+ const shouldMock = typeof mockToolsOnReplay === "boolean" ? mockToolsOnReplay : mockToolsOnReplay.includes(toolName);
5032
+ const originalInvoke = tool.invoke.bind(tool);
5033
+ return new Proxy(tool, {
5034
+ get: (target, property) => {
5035
+ if (property === "invoke") {
5036
+ return async (input, ...rest) => {
5037
+ const toolCallId = isRecord(input) && typeof input.id === "string" ? input.id : "";
5038
+ const args = isRecord(input) && "args" in input ? input.args : input;
5039
+ this.assertReplayToolResultExists(toolName, shouldMock);
5040
+ const execute = this.client.withSpan(
5041
+ this.traceFunctionKey,
5042
+ {
5043
+ name: toolName,
5044
+ type: "function",
5045
+ captureWhen: "nested",
5046
+ mockOnReplay: shouldMock,
5047
+ finalize: finalizeToolResult
5048
+ },
5049
+ async (_args) => await originalInvoke(input, ...rest)
5050
+ );
5051
+ const result = await execute(args);
5052
+ return isEncodedToolResult(result) ? await reviveToolResult(result, toolCallId) : result;
5053
+ };
5054
+ }
5055
+ const value = Reflect.get(target, property, target);
5056
+ return typeof value === "function" ? value.bind(target) : value;
5057
+ }
5058
+ });
5059
+ }
5060
+ assertReplayToolResultExists(toolName, shouldMock) {
5061
+ const replayContext = getReplayContext();
5062
+ if (!replayContext?.mockTree) {
5063
+ return;
5064
+ }
5065
+ const counterKey = `${this.traceFunctionKey}:${toolName}`;
5066
+ const callIndex = replayContext.callCounters?.get(counterKey) ?? 0;
5067
+ const mockSpan = replayContext.mockTree.spans.get(
5068
+ `${counterKey}:${callIndex}`
5069
+ );
5070
+ const hasMatchingOverride = replayContext.mockOverrides?.some(
5071
+ (override) => override.match({
5072
+ traceFunctionKey: this.traceFunctionKey,
5073
+ spanName: toolName,
5074
+ type: "function",
5075
+ originalSpanId: mockSpan?.sourceSpanId
5076
+ })
5077
+ );
5078
+ const expectsRecordedOutput = replayContext.mockStrategy === "all" || replayContext.mockStrategy === "marked" && shouldMock;
5079
+ if (hasMatchingOverride !== true && expectsRecordedOutput && !mockSpan) {
5080
+ throw new BitfabError(
5081
+ `No recorded LangGraph tool result for "${toolName}" at call ${callIndex + 1}; refusing to execute the live tool during replay.`,
5082
+ "https://docs.bitfab.ai/frameworks/langgraph"
5083
+ );
5084
+ }
5085
+ }
5086
+ /** Wrap the function that invokes the compiled graph as the replay root. */
5087
+ wrapInvoke(fn) {
5088
+ return this.client.withSpan(
5089
+ this.traceFunctionKey,
5090
+ { name: this.traceFunctionKey, type: "agent" },
5091
+ fn
5092
+ );
5093
+ }
5094
+ };
5095
+
4826
5096
  // src/client.ts
4827
5097
  init_mockOverride();
4828
5098
 
@@ -5673,8 +5943,9 @@ var Bitfab = class {
5673
5943
  * Decorate a class method as an automatically expanded trace root.
5674
5944
  *
5675
5945
  * Build instrumentation turns repository functions called beneath this
5676
- * method into nested spans. Every generated span preserves structure; only
5677
- * function IDs selected by the capture policy include inputs and output.
5946
+ * method into nested spans that capture inputs, outputs, and errors by
5947
+ * default. A confirmed capture policy can narrow rich capture to selected
5948
+ * function IDs.
5678
5949
  * Without a compatible build transform, this still records the decorated
5679
5950
  * method as a normal rich root span but cannot discover child calls.
5680
5951
  *
@@ -5884,7 +6155,7 @@ var Bitfab = class {
5884
6155
  type: nodeConfiguration?.type ?? "function",
5885
6156
  captureWhen: "nested",
5886
6157
  functionId: definition.id,
5887
- captureContent: nodeConfiguration !== void 0 || capturePolicy.has(definition.id),
6158
+ captureContent: nodeConfiguration !== void 0 || capturePolicy === void 0 || capturePolicy.has(definition.id),
5888
6159
  autoTraceDefinition: definition,
5889
6160
  ...nodeConfiguration?.testRunId !== void 0 && {
5890
6161
  testRunId: nodeConfiguration.testRunId
@@ -5949,7 +6220,11 @@ var Bitfab = class {
5949
6220
  const functionIds = Array.isArray(policy.functionIds) ? policy.functionIds.filter(
5950
6221
  (id) => typeof id === "string" && id.startsWith(`${AUTO_TRACE_PROTOCOL}:`)
5951
6222
  ).slice(0, DEFAULT_AUTO_TRACE_MAX_SPANS) : [];
5952
- __setBitfabAutoTraceCapturePolicy(this, traceFunctionKey, functionIds);
6223
+ __setBitfabAutoTraceCapturePolicy(
6224
+ this,
6225
+ traceFunctionKey,
6226
+ policy.revision === null ? void 0 : functionIds
6227
+ );
5953
6228
  state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_REFRESH_MS;
5954
6229
  }).catch(() => {
5955
6230
  state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
@@ -6208,6 +6483,37 @@ var Bitfab = class {
6208
6483
  getLangChainCallbackHandler(traceFunctionKey) {
6209
6484
  return this.getLangGraphCallbackHandler(traceFunctionKey);
6210
6485
  }
6486
+ /**
6487
+ * Get the first-class LangGraph integration for tracing and replaying tools
6488
+ * executed by `ToolNode`.
6489
+ *
6490
+ * The integration combines `wrapTools()` for per-tool replay interception
6491
+ * with `createInvoker()` for a callback-configured replayable graph entry
6492
+ * point. Lower-level callback and root wrappers remain available.
6493
+ *
6494
+ * @param traceFunctionKey - Groups traces under this key in Bitfab
6495
+ * @param options - Controls which tools are marked for replay mocking
6496
+ * @experimental This API may change before it is stable.
6497
+ */
6498
+ getLangGraphIntegration(traceFunctionKey, options) {
6499
+ const callbackHandler = new BitfabLangGraphCallbackHandler({
6500
+ apiKey: this.resolveApiKey(),
6501
+ traceFunctionKey,
6502
+ serviceUrl: this.serviceUrl,
6503
+ getActiveSpanContext: () => {
6504
+ const stack = getSpanStack();
6505
+ return stack[stack.length - 1] ?? null;
6506
+ },
6507
+ captureTools: false,
6508
+ _httpClient: this.httpClient
6509
+ });
6510
+ return new BitfabLangGraphIntegration({
6511
+ client: this,
6512
+ traceFunctionKey,
6513
+ callbackHandler,
6514
+ options
6515
+ });
6516
+ }
6211
6517
  /**
6212
6518
  * Get a Claude Agent SDK handler for tracing.
6213
6519
  *
@@ -7238,6 +7544,14 @@ var BitfabFunction = class {
7238
7544
  getLangChainCallbackHandler() {
7239
7545
  return this.client.getLangChainCallbackHandler(this.traceFunctionKey);
7240
7546
  }
7547
+ /**
7548
+ * Get the first-class LangGraph tool replay integration bound to this key.
7549
+ *
7550
+ * @experimental This API may change before it is stable.
7551
+ */
7552
+ getLangGraphIntegration(options) {
7553
+ return this.client.getLangGraphIntegration(this.traceFunctionKey, options);
7554
+ }
7241
7555
  /**
7242
7556
  * Wrap a BAML client method to automatically capture prompt and LLM metadata.
7243
7557
  * Delegates to the parent client's wrapBAML method.
@@ -7333,6 +7647,7 @@ function defineReplayRegistry(registry) {
7333
7647
  BitfabFunction,
7334
7648
  BitfabLangChainCallbackHandler,
7335
7649
  BitfabLangGraphCallbackHandler,
7650
+ BitfabLangGraphIntegration,
7336
7651
  BitfabOpenAIAgentHandler,
7337
7652
  BitfabOpenAITracingProcessor,
7338
7653
  BitfabVercelAiHandler,