bitfab 0.68.7 → 0.68.9

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.
@@ -1,6 +1,6 @@
1
1
  const require_bamlPeer = require("./bamlPeer-5Ohpq8q9.cjs");
2
- const require_http = require("./http-DAMAcv_J.cjs");
3
- const require_autoTrace = require("./autoTrace-DUmR1KJ8.cjs");
2
+ const require_http = require("./http-BB9wDcLm.cjs");
3
+ const require_autoTrace = require("./autoTrace-DPWV1Xzr.cjs");
4
4
  const require_optionalPeer = require("./optionalPeer-CUH756lt.cjs");
5
5
  let superjson = require("superjson");
6
6
  superjson = require_bamlPeer.__toESM(superjson, 1);
@@ -1412,11 +1412,11 @@ var GradersClient = class {
1412
1412
  const JEV_PROVIDER = "typesafe";
1413
1413
  const JEV_WATCH_STORAGE_SYMBOL = Symbol.for("bitfab.jevWatchStorage");
1414
1414
  const repliesRecordedByAutoTrace = /* @__PURE__ */ new WeakSet();
1415
- function isRecord$4(value) {
1415
+ function isRecord$5(value) {
1416
1416
  return typeof value === "object" && value !== null;
1417
1417
  }
1418
1418
  function isJevReply(value) {
1419
- return isRecord$4(value) && typeof value.model === "string" && isRecord$4(value.usage);
1419
+ return isRecord$5(value) && typeof value.model === "string" && isRecord$5(value.usage);
1420
1420
  }
1421
1421
  function tokenCount(usage, key) {
1422
1422
  const count = usage[key];
@@ -1475,7 +1475,7 @@ function recordWatchedJevReply(span, watch, reply, durationMs) {
1475
1475
  markEnclosingWatches(watch);
1476
1476
  }
1477
1477
  function isRecordedByAutoTrace(reply) {
1478
- return isRecord$4(reply) && repliesRecordedByAutoTrace.has(reply);
1478
+ return isRecord$5(reply) && repliesRecordedByAutoTrace.has(reply);
1479
1479
  }
1480
1480
  function recordAutoTracedJev(invokeFn, span) {
1481
1481
  const startedAt = Date.now();
@@ -1988,7 +1988,7 @@ var BitfabLangGraphCallbackHandler = class {
1988
1988
  //#region src/integrationFixture.ts
1989
1989
  const INTEGRATION_FIXTURE_CONTEXT_KEY = "__bitfabIntegrationFixture";
1990
1990
  const INTEGRATION_FIXTURE_VERSION = 1;
1991
- function isRecord$3(value) {
1991
+ function isRecord$4(value) {
1992
1992
  return typeof value === "object" && value !== null && !Array.isArray(value);
1993
1993
  }
1994
1994
  function createIntegrationFixtureContext(name, value) {
@@ -2002,8 +2002,8 @@ function createIntegrationFixtureContext(name, value) {
2002
2002
  }
2003
2003
  function hasIntegrationFixture(contexts, name) {
2004
2004
  return contexts.some((context) => {
2005
- const fixture = isRecord$3(context) ? context[INTEGRATION_FIXTURE_CONTEXT_KEY] : void 0;
2006
- return isRecord$3(fixture) && fixture.version === INTEGRATION_FIXTURE_VERSION && fixture.name === name;
2005
+ const fixture = isRecord$4(context) ? context[INTEGRATION_FIXTURE_CONTEXT_KEY] : void 0;
2006
+ return isRecord$4(fixture) && fixture.version === INTEGRATION_FIXTURE_VERSION && fixture.name === name;
2007
2007
  });
2008
2008
  }
2009
2009
  function extractIntegrationFixtures(spanData) {
@@ -2011,9 +2011,9 @@ function extractIntegrationFixtures(spanData) {
2011
2011
  if (!Array.isArray(contexts)) return;
2012
2012
  const fixtures = /* @__PURE__ */ new Map();
2013
2013
  for (const context of contexts) {
2014
- if (!isRecord$3(context)) continue;
2014
+ if (!isRecord$4(context)) continue;
2015
2015
  const fixture = context[INTEGRATION_FIXTURE_CONTEXT_KEY];
2016
- if (!isRecord$3(fixture) || fixture.version !== INTEGRATION_FIXTURE_VERSION || typeof fixture.name !== "string" || fixtures.has(fixture.name)) continue;
2016
+ if (!isRecord$4(fixture) || fixture.version !== INTEGRATION_FIXTURE_VERSION || typeof fixture.name !== "string" || fixtures.has(fixture.name)) continue;
2017
2017
  fixtures.set(fixture.name, deserializeValue({
2018
2018
  json: fixture.value,
2019
2019
  ...fixture.valueMeta !== void 0 && { meta: fixture.valueMeta }
@@ -2032,7 +2032,7 @@ const THREAD_CONFIG_KEYS = [
2032
2032
  "checkpoint_ns",
2033
2033
  "checkpoint_id"
2034
2034
  ];
2035
- function isRecord$2(value) {
2035
+ function isRecord$3(value) {
2036
2036
  return typeof value === "object" && value !== null;
2037
2037
  }
2038
2038
  function toBase64(bytes) {
@@ -2059,12 +2059,12 @@ async function newMemorySaver() {
2059
2059
  return new MemorySaver();
2060
2060
  }
2061
2061
  async function unstoredDeltaChannels(graph, tuple) {
2062
- const channels = isRecord$2(graph) ? graph.channels : void 0;
2063
- if (!isRecord$2(channels)) return [];
2062
+ const channels = isRecord$3(graph) ? graph.channels : void 0;
2063
+ if (!isRecord$3(channels)) return [];
2064
2064
  const { DeltaChannel } = await loadLangGraphPeer();
2065
2065
  if (DeltaChannel === void 0) return [];
2066
- const versions = isRecord$2(tuple.checkpoint.channel_versions) ? tuple.checkpoint.channel_versions : {};
2067
- const values = isRecord$2(tuple.checkpoint.channel_values) ? tuple.checkpoint.channel_values : {};
2066
+ const versions = isRecord$3(tuple.checkpoint.channel_versions) ? tuple.checkpoint.channel_versions : {};
2067
+ const values = isRecord$3(tuple.checkpoint.channel_values) ? tuple.checkpoint.channel_values : {};
2068
2068
  return Object.entries(channels).filter(([name, spec]) => spec instanceof DeltaChannel && name in versions && !(name in values)).map(([name]) => name);
2069
2069
  }
2070
2070
  async function selfContained(graph, checkpointer, tuple) {
@@ -2077,27 +2077,27 @@ async function selfContained(graph, checkpointer, tuple) {
2077
2077
  checkpoint: {
2078
2078
  ...tuple.checkpoint,
2079
2079
  channel_values: {
2080
- ...isRecord$2(tuple.checkpoint.channel_values) ? tuple.checkpoint.channel_values : {},
2080
+ ...isRecord$3(tuple.checkpoint.channel_values) ? tuple.checkpoint.channel_values : {},
2081
2081
  ...Object.fromEntries(names.filter((name) => name in values).map((name) => [name, values[name]]))
2082
2082
  }
2083
2083
  }
2084
2084
  };
2085
2085
  }
2086
2086
  function savingCheckpointer(graph) {
2087
- const own = isRecord$2(graph) ? graph.checkpointer : void 0;
2088
- const inner = isRecord$2(graph) && isRecord$2(graph.graph) ? graph.graph.checkpointer : void 0;
2087
+ const own = isRecord$3(graph) ? graph.checkpointer : void 0;
2088
+ const inner = isRecord$3(graph) && isRecord$3(graph.graph) ? graph.graph.checkpointer : void 0;
2089
2089
  const checkpointer = own ?? inner;
2090
- return isRecord$2(checkpointer) && typeof checkpointer.getTuple === "function" ? checkpointer : null;
2090
+ return isRecord$3(checkpointer) && typeof checkpointer.getTuple === "function" ? checkpointer : null;
2091
2091
  }
2092
2092
  function threadConfig(config) {
2093
- const configurable = isRecord$2(config?.configurable) ? config.configurable : {};
2093
+ const configurable = isRecord$3(config?.configurable) ? config.configurable : {};
2094
2094
  return Object.fromEntries(THREAD_CONFIG_KEYS.filter((key) => key in configurable).map((key) => [key, configurable[key]]));
2095
2095
  }
2096
2096
  function withConfigurable(config, values) {
2097
2097
  return {
2098
2098
  ...config ?? {},
2099
2099
  configurable: {
2100
- ...isRecord$2(config?.configurable) ? config.configurable : {},
2100
+ ...isRecord$3(config?.configurable) ? config.configurable : {},
2101
2101
  ...values
2102
2102
  }
2103
2103
  };
@@ -2234,7 +2234,7 @@ var GraphRun = class {
2234
2234
  }
2235
2235
  async restoreThread(replay) {
2236
2236
  const { saver, thread } = await restoredCheckpointer(replay.integrationFixtures?.get(this.fixtureName) ?? null);
2237
- const configurable = isRecord$2(this.config?.configurable) ? this.config.configurable : {};
2237
+ const configurable = isRecord$3(this.config?.configurable) ? this.config.configurable : {};
2238
2238
  return {
2239
2239
  saver,
2240
2240
  thread: {
@@ -2248,19 +2248,19 @@ var GraphRun = class {
2248
2248
  //#region src/langgraphIntegration.ts
2249
2249
  const TOOL_RESULT_TAG = "__bitfabLangGraphToolResult";
2250
2250
  const AGENT_MIDDLEWARE_BRAND = Symbol.for("AgentMiddleware");
2251
- function isRecord$1(value) {
2251
+ function isRecord$2(value) {
2252
2252
  return typeof value === "object" && value !== null;
2253
2253
  }
2254
2254
  function isToolMessage(value) {
2255
- return isRecord$1(value) && value.lc_direct_tool_output === true && value.type === "tool" && (typeof value.content === "string" || Array.isArray(value.content));
2255
+ return isRecord$2(value) && value.lc_direct_tool_output === true && value.type === "tool" && (typeof value.content === "string" || Array.isArray(value.content));
2256
2256
  }
2257
2257
  function isCommand(value) {
2258
- return isRecord$1(value) && value.lg_name === "Command";
2258
+ return isRecord$2(value) && value.lg_name === "Command";
2259
2259
  }
2260
2260
  function encodeNested(value) {
2261
2261
  if (isToolMessage(value) || isCommand(value)) return encodeNativeToolResult(value);
2262
2262
  if (Array.isArray(value)) return value.map(encodeNested);
2263
- if (isRecord$1(value)) return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, encodeNested(entry)]));
2263
+ if (isRecord$2(value)) return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, encodeNested(entry)]));
2264
2264
  return value;
2265
2265
  }
2266
2266
  function encodeNativeToolResult(value) {
@@ -2277,17 +2277,17 @@ function encodeNativeToolResult(value) {
2277
2277
  };
2278
2278
  return {
2279
2279
  [TOOL_RESULT_TAG]: "command",
2280
- graph: isRecord$1(value) && typeof value.graph === "string" ? value.graph : void 0,
2281
- update: isRecord$1(value) ? encodeNested(value.update) : void 0,
2282
- resume: isRecord$1(value) ? encodeNested(value.resume) : void 0,
2283
- goto: isRecord$1(value) ? encodeNested(value.goto) : void 0
2280
+ graph: isRecord$2(value) && typeof value.graph === "string" ? value.graph : void 0,
2281
+ update: isRecord$2(value) ? encodeNested(value.update) : void 0,
2282
+ resume: isRecord$2(value) ? encodeNested(value.resume) : void 0,
2283
+ goto: isRecord$2(value) ? encodeNested(value.goto) : void 0
2284
2284
  };
2285
2285
  }
2286
2286
  function finalizeToolResult(value) {
2287
2287
  return isToolMessage(value) || isCommand(value) ? encodeNativeToolResult(value) : value;
2288
2288
  }
2289
2289
  function isEncodedToolResult(value) {
2290
- return isRecord$1(value) && typeof value[TOOL_RESULT_TAG] === "string";
2290
+ return isRecord$2(value) && typeof value[TOOL_RESULT_TAG] === "string";
2291
2291
  }
2292
2292
  async function loadPeer(specifierParts, packageName, docsPath) {
2293
2293
  try {
@@ -2317,7 +2317,7 @@ async function loadLangGraph() {
2317
2317
  async function reviveNested(value, toolCallId) {
2318
2318
  if (isEncodedToolResult(value)) return reviveToolResult(value, toolCallId);
2319
2319
  if (Array.isArray(value)) return Promise.all(value.map((entry) => reviveNested(entry, toolCallId)));
2320
- if (isRecord$1(value)) {
2320
+ if (isRecord$2(value)) {
2321
2321
  const entries = await Promise.all(Object.entries(value).map(async ([key, entry]) => [key, await reviveNested(entry, toolCallId)]));
2322
2322
  return Object.fromEntries(entries);
2323
2323
  }
@@ -2333,9 +2333,9 @@ async function reviveToolResult(value, toolCallId) {
2333
2333
  ...typeof value.id === "string" && { id: value.id },
2334
2334
  ...(value.status === "success" || value.status === "error") && { status: value.status },
2335
2335
  ...value.artifact !== void 0 && { artifact: await reviveNested(value.artifact, toolCallId) },
2336
- ...isRecord$1(value.metadata) && { metadata: await reviveNested(value.metadata, toolCallId) },
2337
- ...isRecord$1(value.additionalKwargs) && { additional_kwargs: await reviveNested(value.additionalKwargs, toolCallId) },
2338
- ...isRecord$1(value.responseMetadata) && { response_metadata: await reviveNested(value.responseMetadata, toolCallId) }
2336
+ ...isRecord$2(value.metadata) && { metadata: await reviveNested(value.metadata, toolCallId) },
2337
+ ...isRecord$2(value.additionalKwargs) && { additional_kwargs: await reviveNested(value.additionalKwargs, toolCallId) },
2338
+ ...isRecord$2(value.responseMetadata) && { response_metadata: await reviveNested(value.responseMetadata, toolCallId) }
2339
2339
  });
2340
2340
  }
2341
2341
  const { Command } = await loadLangGraph();
@@ -2412,7 +2412,7 @@ var BitfabLangGraphIntegration = class {
2412
2412
  return middleware.includes(this.middleware) ? [...middleware] : [...middleware, this.middleware];
2413
2413
  }
2414
2414
  withSubagentMiddleware(spec) {
2415
- if (!isRecord$1(spec) || "runnable" in spec || "graphId" in spec) return spec;
2415
+ if (!isRecord$2(spec) || "runnable" in spec || "graphId" in spec) return spec;
2416
2416
  return {
2417
2417
  ...spec,
2418
2418
  middleware: this.withMiddleware(Array.isArray(spec.middleware) ? spec.middleware : [])
@@ -2429,7 +2429,7 @@ var BitfabLangGraphIntegration = class {
2429
2429
  return await this.runClaimedToolCall(traceId, toolCallId, toolName, shouldMock, request.toolCall.args, async () => await handler(request), stepSpanId);
2430
2430
  }
2431
2431
  stepSpanIdFor(config, traceId) {
2432
- const namespace = isRecord$1(config) && isRecord$1(config.configurable) ? config.configurable.checkpoint_ns : void 0;
2432
+ const namespace = isRecord$2(config) && isRecord$2(config.configurable) ? config.configurable.checkpoint_ns : void 0;
2433
2433
  return typeof namespace === "string" ? this.callbackHandler.visibleStepSpanId(namespace, traceId) : null;
2434
2434
  }
2435
2435
  recordingTraceId(toolName) {
@@ -2476,8 +2476,8 @@ var BitfabLangGraphIntegration = class {
2476
2476
  const originalInvoke = tool.invoke.bind(tool);
2477
2477
  return new Proxy(tool, { get: (target, property) => {
2478
2478
  if (property === "invoke") return async (input, ...rest) => {
2479
- const toolCallId = isRecord$1(input) && typeof input.id === "string" ? input.id : "";
2480
- const args = isRecord$1(input) && "args" in input ? input.args : input;
2479
+ const toolCallId = isRecord$2(input) && typeof input.id === "string" ? input.id : "";
2480
+ const args = isRecord$2(input) && "args" in input ? input.args : input;
2481
2481
  this.assertReplayToolResultExists(toolName, shouldMock);
2482
2482
  const traceId = this.getActiveSpan()?.traceId ?? null;
2483
2483
  const run = async () => await originalInvoke(input, ...rest);
@@ -2587,6 +2587,415 @@ var OrganizationMembersClient = class {
2587
2587
  }
2588
2588
  };
2589
2589
  //#endregion
2590
+ //#region src/piIntegration.ts
2591
+ const STREAM_FN_PROPERTY_NAMES_BY_RELEASE = /* @__PURE__ */ new Set(["streamFunction", "streamFn"]);
2592
+ const STATE_PROPERTIES = /* @__PURE__ */ new Set(["state", "_state"]);
2593
+ const HOOKS_RETURNING_CONTEXT = /* @__PURE__ */ new Set([
2594
+ "prepareRequest",
2595
+ "prepareNextTurn",
2596
+ "prepareNextTurnWithContext"
2597
+ ]);
2598
+ const FAILED_STOP_REASONS = /* @__PURE__ */ new Set(["error", "aborted"]);
2599
+ const replayFailuresHiddenByPi = /* @__PURE__ */ new WeakMap();
2600
+ const instrumentedByAnyIntegration = /* @__PURE__ */ new WeakSet();
2601
+ const wrappersByAnyIntegration = /* @__PURE__ */ new WeakSet();
2602
+ const replayItemsWithRestoredTranscript = /* @__PURE__ */ new WeakSet();
2603
+ function transcriptFixtureName(traceFunctionKey) {
2604
+ return `pi-transcript:${traceFunctionKey}`;
2605
+ }
2606
+ function isTranscriptFixture(value) {
2607
+ return isRecord$1(value) && (value.method === "prompt" || value.method === "continue") && Array.isArray(value.messages);
2608
+ }
2609
+ function conversationMessages(messages) {
2610
+ return messages.filter((message) => message?.role !== "system");
2611
+ }
2612
+ function leadingSystemMessages(messages) {
2613
+ const firstConversation = messages.findIndex((message) => message?.role !== "system");
2614
+ return firstConversation === -1 ? messages.slice() : messages.slice(0, firstConversation);
2615
+ }
2616
+ function serializedBytes(value) {
2617
+ try {
2618
+ return JSON.stringify(value)?.length;
2619
+ } catch {
2620
+ return;
2621
+ }
2622
+ }
2623
+ const TRANSCRIPT_BUDGET_BYTES = Math.floor(require_http.MAX_SPAN_CARRIER_BYTES * .7);
2624
+ function mostRecentTurnsWithinBudget(messages) {
2625
+ const sizes = messages.map((message) => serializedBytes(message) ?? 0);
2626
+ let total = sizes.reduce((sum, size) => sum + size, 0);
2627
+ let start = 0;
2628
+ while (start < messages.length && total > TRANSCRIPT_BUDGET_BYTES) {
2629
+ total -= sizes[start] ?? 0;
2630
+ start += 1;
2631
+ }
2632
+ while (start < messages.length && messages[start]?.role !== "user") start += 1;
2633
+ return {
2634
+ kept: messages.slice(start),
2635
+ dropped: start
2636
+ };
2637
+ }
2638
+ function callsWithoutArguments(args) {
2639
+ return args.every((arg) => arg === void 0);
2640
+ }
2641
+ function spanNameForModel(model) {
2642
+ if (typeof model?.id !== "string") return "llm";
2643
+ return typeof model.provider === "string" ? `${model.provider}/${model.id}` : model.id;
2644
+ }
2645
+ function keepReplayFailure(error) {
2646
+ const replay = require_http.getReplayContext();
2647
+ if (replay !== null && error instanceof require_http.BitfabError) {
2648
+ if (!replayFailuresHiddenByPi.has(replay)) replayFailuresHiddenByPi.set(replay, error);
2649
+ }
2650
+ }
2651
+ function throwKeptReplayFailure() {
2652
+ const replay = require_http.getReplayContext();
2653
+ if (replay !== null && replayFailuresHiddenByPi.has(replay)) {
2654
+ const error = replayFailuresHiddenByPi.get(replay);
2655
+ replayFailuresHiddenByPi.delete(replay);
2656
+ throw error;
2657
+ }
2658
+ }
2659
+ async function rethrowingKept(work) {
2660
+ try {
2661
+ return await work();
2662
+ } catch (error) {
2663
+ keepReplayFailure(error);
2664
+ throw error;
2665
+ }
2666
+ }
2667
+ function isRecord$1(value) {
2668
+ return typeof value === "object" && value !== null;
2669
+ }
2670
+ function isAgentLike(value) {
2671
+ return isRecord$1(value) && typeof value.prompt === "function" && typeof value.continue === "function" && isRecord$1(value.state) && Array.isArray(value.state.messages);
2672
+ }
2673
+ function isSessionLike(value) {
2674
+ return isRecord$1(value) && typeof value.prompt === "function" && isAgentLike(value.agent);
2675
+ }
2676
+ function isEventStream(value) {
2677
+ return isRecord$1(value) && typeof value.result === "function" && typeof value[Symbol.asyncIterator] === "function";
2678
+ }
2679
+ function failed(message) {
2680
+ return typeof message?.stopReason === "string" && FAILED_STOP_REASONS.has(message.stopReason);
2681
+ }
2682
+ function messageText(message) {
2683
+ const content = message?.content;
2684
+ if (typeof content === "string") return content;
2685
+ if (!Array.isArray(content)) return "";
2686
+ return content.filter((block) => block?.type === "text" && typeof block.text === "string").map((block) => block.text).join("");
2687
+ }
2688
+ function asCount(value) {
2689
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
2690
+ }
2691
+ function wholePromptTokens(usage) {
2692
+ const uncachedInput = asCount(usage.input);
2693
+ const cacheRead = asCount(usage.cacheRead);
2694
+ if (uncachedInput === void 0 && cacheRead === void 0) return;
2695
+ return (uncachedInput ?? 0) + (cacheRead ?? 0) + (asCount(usage.cacheWrite) ?? 0);
2696
+ }
2697
+ function pricedCost(usage) {
2698
+ const cost = asCount(usage.cost?.total);
2699
+ return cost !== void 0 && cost > 0 ? cost : void 0;
2700
+ }
2701
+ function usageContext(message, model) {
2702
+ const context = {};
2703
+ const modelName = message.model ?? model.id;
2704
+ if (typeof modelName === "string") context.model = modelName;
2705
+ const usage = message.usage;
2706
+ if (!isRecord$1(usage)) return context;
2707
+ const entries = {
2708
+ inputTokens: wholePromptTokens(usage),
2709
+ outputTokens: asCount(usage.output),
2710
+ cachedInputTokens: asCount(usage.cacheRead),
2711
+ costUsd: pricedCost(usage)
2712
+ };
2713
+ for (const [name, value] of Object.entries(entries)) if (value !== void 0) context[name] = value;
2714
+ return context;
2715
+ }
2716
+ function toolDeclarations(tools) {
2717
+ return tools.filter(isRecord$1).map((tool) => ({
2718
+ name: tool.name,
2719
+ description: tool.description,
2720
+ parameters: tool.parameters
2721
+ }));
2722
+ }
2723
+ function llmRequest(model, context, options) {
2724
+ const request = { model: {
2725
+ id: model.id,
2726
+ provider: model.provider,
2727
+ api: model.api
2728
+ } };
2729
+ if (typeof context.systemPrompt === "string") request.systemPrompt = context.systemPrompt;
2730
+ request.messages = context.messages;
2731
+ if (Array.isArray(context.tools)) request.tools = toolDeclarations(context.tools);
2732
+ for (const setting of [
2733
+ "reasoning",
2734
+ "maxTokens",
2735
+ "temperature"
2736
+ ]) if (options?.[setting] !== void 0) request[setting] = options[setting];
2737
+ return request;
2738
+ }
2739
+ function streamOfRecordedMessage(message) {
2740
+ const reason = message.stopReason ?? "stop";
2741
+ const terminalEvent = failed(message) ? {
2742
+ type: "error",
2743
+ reason,
2744
+ error: message
2745
+ } : {
2746
+ type: "done",
2747
+ reason,
2748
+ message
2749
+ };
2750
+ return {
2751
+ async *[Symbol.asyncIterator]() {
2752
+ yield terminalEvent;
2753
+ },
2754
+ result: () => Promise.resolve(message)
2755
+ };
2756
+ }
2757
+ function lastAssistantMessageSince(state, start) {
2758
+ const assistantMessages = state.messages.slice(start).filter((message) => message?.role === "assistant");
2759
+ return assistantMessages[assistantMessages.length - 1];
2760
+ }
2761
+ var BitfabPiIntegration = class {
2762
+ constructor(config) {
2763
+ this.instrumented = /* @__PURE__ */ new WeakMap();
2764
+ this.toolArrays = /* @__PURE__ */ new WeakMap();
2765
+ this.wrappedStreamFns = /* @__PURE__ */ new WeakMap();
2766
+ this.wrappedTools = /* @__PURE__ */ new WeakMap();
2767
+ this.originalTools = /* @__PURE__ */ new WeakMap();
2768
+ this.wrappedHooks = /* @__PURE__ */ new WeakMap();
2769
+ this.host = config.host;
2770
+ this.traceFunctionKey = config.traceFunctionKey;
2771
+ this.mockToolsOnReplay = config.options?.mockToolsOnReplay ?? true;
2772
+ }
2773
+ instrument(target) {
2774
+ if (instrumentedByAnyIntegration.has(target)) return target;
2775
+ const existing = this.instrumented.get(target);
2776
+ if (existing !== void 0) return existing;
2777
+ const proxy = this.proxyFor(target);
2778
+ this.instrumented.set(target, proxy);
2779
+ instrumentedByAnyIntegration.add(proxy);
2780
+ return proxy;
2781
+ }
2782
+ proxyFor(target) {
2783
+ if (isAgentLike(target)) return this.instrumentAgent(target);
2784
+ if (isSessionLike(target)) return this.instrumentSession(target);
2785
+ throw new require_http.BitfabError("getPiIntegration().instrument() expects a Pi Agent (from @earendil-works/pi-agent-core) or an AgentSession (from createAgentSession)", "https://docs.bitfab.ai/frameworks/pi");
2786
+ }
2787
+ instrumentAgent(agent) {
2788
+ const proxy = new Proxy(agent, { get: (target, property) => {
2789
+ if (property === "prompt" || property === "continue") return (...args) => this.runRoot(property, target, proxy, args, {
2790
+ state: () => target.state,
2791
+ sessionId: () => target.sessionId,
2792
+ restoreConversation: (messages) => {
2793
+ target.state.messages = [...leadingSystemMessages(target.state.messages), ...messages];
2794
+ }
2795
+ });
2796
+ const value = Reflect.get(target, property, proxy);
2797
+ if (STREAM_FN_PROPERTY_NAMES_BY_RELEASE.has(property) && typeof value === "function") return this.wrapStreamFn(value);
2798
+ if (STATE_PROPERTIES.has(property) && isRecord$1(value)) return this.toolWrappingState(value);
2799
+ if (HOOKS_RETURNING_CONTEXT.has(property) && typeof value === "function") return this.toolWrappingHook(value);
2800
+ return value;
2801
+ } });
2802
+ return proxy;
2803
+ }
2804
+ instrumentSession(session) {
2805
+ const proxy = new Proxy(session, { get: (target, property) => {
2806
+ if (property === "prompt") return (...args) => this.runRoot("prompt", target, proxy, args, {
2807
+ state: () => target.agent.state,
2808
+ sessionId: () => target.sessionId,
2809
+ restoreConversation: (messages) => this.restoreIntoSession(target, messages)
2810
+ });
2811
+ const value = Reflect.get(target, property, proxy);
2812
+ if (property === "agent" && isAgentLike(value)) return this.instrument(value);
2813
+ return value;
2814
+ } });
2815
+ return proxy;
2816
+ }
2817
+ toolWrappingHook(hook) {
2818
+ const existing = this.wrappedHooks.get(hook);
2819
+ if (existing !== void 0) return existing;
2820
+ const wrapped = async (...args) => {
2821
+ const update = await hook(...args);
2822
+ if (!isRecord$1(update) || !isRecord$1(update.context)) return update;
2823
+ const tools = update.context.tools;
2824
+ if (!Array.isArray(tools)) return update;
2825
+ return {
2826
+ ...update,
2827
+ context: {
2828
+ ...update.context,
2829
+ tools: tools.map((tool) => this.wrapTool(tool))
2830
+ }
2831
+ };
2832
+ };
2833
+ this.wrappedHooks.set(hook, wrapped);
2834
+ return wrapped;
2835
+ }
2836
+ restoreIntoSession(session, messages) {
2837
+ const store = session.sessionManager;
2838
+ if (store?.isPersisted?.() !== false || typeof store.appendMessage !== "function") {
2839
+ require_autoTrace.warnOnce(`pi-replay-session-persisted:${this.traceFunctionKey}`, `A replayed "${this.traceFunctionKey}" run used an AgentSession saved to disk, so Bitfab did not restore the recorded conversation into it. Build the session in your replay function with SessionManager.inMemory() to replay each turn with its history.`);
2840
+ return;
2841
+ }
2842
+ for (const message of messages) store.appendMessage(message);
2843
+ }
2844
+ toolWrappingState(state) {
2845
+ const existing = this.instrumented.get(state);
2846
+ if (existing !== void 0) return existing;
2847
+ const proxy = new Proxy(state, {
2848
+ get: (target, property) => {
2849
+ const value = Reflect.get(target, property, target);
2850
+ if (property === "tools" && Array.isArray(value)) return this.toolWrappingArray(value);
2851
+ return value;
2852
+ },
2853
+ set: (target, property, value) => Reflect.set(target, property, property === "tools" && Array.isArray(value) ? value.map((tool) => this.unwrapTool(tool)) : value, target)
2854
+ });
2855
+ this.instrumented.set(state, proxy);
2856
+ return proxy;
2857
+ }
2858
+ toolWrappingArray(tools) {
2859
+ const existing = this.toolArrays.get(tools);
2860
+ if (existing !== void 0) return existing;
2861
+ const proxy = new Proxy(tools, {
2862
+ get: (target, property, receiver) => {
2863
+ const value = Reflect.get(target, property, receiver);
2864
+ if (typeof property === "string" && /^\d+$/.test(property)) return this.wrapTool(value);
2865
+ return value;
2866
+ },
2867
+ set: (target, property, value) => Reflect.set(target, property, this.unwrapTool(value))
2868
+ });
2869
+ this.toolArrays.set(tools, proxy);
2870
+ return proxy;
2871
+ }
2872
+ recordTranscript(method, state) {
2873
+ const contexts = this.host.traceRootContexts();
2874
+ const name = transcriptFixtureName(this.traceFunctionKey);
2875
+ if (contexts === null || hasIntegrationFixture(contexts, name)) return;
2876
+ const messages = conversationMessages(state.messages);
2877
+ if (method === "prompt" && messages.length === 0) return;
2878
+ const { kept, dropped } = mostRecentTurnsWithinBudget(messages);
2879
+ if (dropped > 0) this.warnConversationTrimmed(messages, kept);
2880
+ contexts.push(createIntegrationFixtureContext(name, {
2881
+ method,
2882
+ messages: kept,
2883
+ ...dropped > 0 && { droppedMessages: dropped }
2884
+ }));
2885
+ }
2886
+ warnConversationTrimmed(messages, kept) {
2887
+ const megabytes = ((serializedBytes(messages) ?? 0) / 1e6).toFixed(1);
2888
+ require_autoTrace.warnOnce(`pi-conversation-too-large:${this.traceFunctionKey}`, `The conversation before a "${this.traceFunctionKey}" prompt is ${megabytes} MB, more than one span can carry, so Bitfab recorded only its most recent ${kept.length} of ${messages.length} messages. A replay of that turn starts from those. Prune agent.state.messages (or the session) to replay long conversations in full.`);
2889
+ }
2890
+ restoredTranscript(run) {
2891
+ const replay = require_http.getReplayContext();
2892
+ if (replay === null || replayItemsWithRestoredTranscript.has(replay)) return;
2893
+ const fixture = replay.integrationFixtures?.get(transcriptFixtureName(this.traceFunctionKey));
2894
+ if (!isTranscriptFixture(fixture)) {
2895
+ if (fixture !== void 0) require_autoTrace.warnOnce(`pi-replay-conversation-unavailable:${this.traceFunctionKey}`, `A replayed "${this.traceFunctionKey}" turn had a recorded conversation that was too large to keep, so it replays without the earlier turns.`);
2896
+ return;
2897
+ }
2898
+ replayItemsWithRestoredTranscript.add(replay);
2899
+ if ((fixture.droppedMessages ?? 0) > 0) require_autoTrace.warnOnce(`pi-replay-conversation-trimmed:${this.traceFunctionKey}`, `A replayed "${this.traceFunctionKey}" turn had a conversation too large to record in full, so it replays with only the most recent ${fixture.messages.length} messages.`);
2900
+ run.restoreConversation(fixture.messages);
2901
+ return fixture;
2902
+ }
2903
+ runRoot(method, target, receiver, args, run) {
2904
+ const call = async (...callArgs) => {
2905
+ const replaysContinue = this.restoredTranscript(run)?.method === "continue" && callsWithoutArguments(callArgs);
2906
+ const calledMethod = replaysContinue ? "continue" : method;
2907
+ if (require_http.getReplayContext() === null) this.recordTranscript(method, run.state());
2908
+ await Reflect.get(target, calledMethod, target).apply(receiver, replaysContinue ? [] : callArgs);
2909
+ throwKeptReplayFailure();
2910
+ };
2911
+ if (this.host.activeRootTraceFunctionKey() === this.traceFunctionKey) return call(...args);
2912
+ const callReturningFinalMessage = async (...callArgs) => {
2913
+ const sessionId = run.sessionId();
2914
+ if (typeof sessionId === "string" && sessionId.length > 0) this.host.setTraceSessionId(sessionId);
2915
+ const start = run.state().messages.length;
2916
+ await call(...callArgs);
2917
+ return lastAssistantMessageSince(run.state(), start);
2918
+ };
2919
+ return this.host.withSpan(this.traceFunctionKey, {
2920
+ name: this.traceFunctionKey,
2921
+ type: "agent",
2922
+ surface: "inherit",
2923
+ instrumentation: "pi",
2924
+ finalize: (result) => {
2925
+ const finalMessage = result;
2926
+ const text = messageText(finalMessage);
2927
+ if (failed(finalMessage)) throw new StreamFinalizationError(finalMessage?.errorMessage ?? `Agent run ${finalMessage?.stopReason}`, text);
2928
+ return text;
2929
+ }
2930
+ }, callReturningFinalMessage)(...args).then(() => void 0);
2931
+ }
2932
+ warnIfOutsideRun(what) {
2933
+ if (this.host.activeRootTraceFunctionKey() !== void 0) return;
2934
+ require_autoTrace.warnOnce(`pi-call-outside-run:${this.traceFunctionKey}`, `A Pi ${what} for "${this.traceFunctionKey}" ran outside any traced run, so it was not recorded. Run the agent through getPiIntegration("${this.traceFunctionKey}").instrument(agent).prompt() so its model requests and tool calls are traced.`);
2935
+ }
2936
+ wrapStreamFn(streamFn) {
2937
+ if (wrappersByAnyIntegration.has(streamFn)) return streamFn;
2938
+ const existing = this.wrappedStreamFns.get(streamFn);
2939
+ if (existing !== void 0) return existing;
2940
+ const wrapped = async (model, context, options) => {
2941
+ this.warnIfOutsideRun("model request");
2942
+ let llmSpan;
2943
+ const recordFinalMessage = async (result) => {
2944
+ const message = await result.result();
2945
+ llmSpan?.addContext(usageContext(message, model));
2946
+ if (failed(message)) throw new StreamFinalizationError(message.errorMessage ?? `Model request ${message.stopReason}`, message);
2947
+ return message;
2948
+ };
2949
+ const traced = this.host.withSpan(this.traceFunctionKey, {
2950
+ name: spanNameForModel(model),
2951
+ type: "llm",
2952
+ captureWhen: "nested",
2953
+ surface: "inherit",
2954
+ instrumentation: "pi",
2955
+ finalize: recordFinalMessage
2956
+ }, async (_request) => {
2957
+ llmSpan = this.host.currentSpan();
2958
+ return streamFn(model, context, options);
2959
+ });
2960
+ const result = await rethrowingKept(() => traced(llmRequest(model, context, options)));
2961
+ return isEventStream(result) ? result : streamOfRecordedMessage(result ?? {});
2962
+ };
2963
+ this.wrappedStreamFns.set(streamFn, wrapped);
2964
+ wrappersByAnyIntegration.add(wrapped);
2965
+ return wrapped;
2966
+ }
2967
+ mocksTool(name) {
2968
+ return Array.isArray(this.mockToolsOnReplay) ? this.mockToolsOnReplay.includes(name) : this.mockToolsOnReplay === true;
2969
+ }
2970
+ unwrapTool(tool) {
2971
+ return this.originalTools.get(tool) ?? tool;
2972
+ }
2973
+ wrapTool(tool) {
2974
+ if (!isRecord$1(tool) || typeof tool.execute !== "function" || wrappersByAnyIntegration.has(tool)) return tool;
2975
+ const existing = this.wrappedTools.get(tool);
2976
+ if (existing !== void 0) return existing;
2977
+ const execute = tool.execute;
2978
+ const executeName = execute.name || "execute";
2979
+ const spanOptions = {
2980
+ name: tool.name,
2981
+ type: "function",
2982
+ captureWhen: "nested",
2983
+ mockOnReplay: this.mocksTool(tool.name),
2984
+ surface: "inherit",
2985
+ instrumentation: "pi"
2986
+ };
2987
+ const tracedExecute = (toolCallId, params, signal, onUpdate) => {
2988
+ this.warnIfOutsideRun("tool call");
2989
+ return rethrowingKept(() => this.host.withSpan(this.traceFunctionKey, spanOptions, async (args) => this.host.withDiscoveredCallsUnderCurrentSpan(() => require_autoTrace.runAsAutoTraceRootFunction(executeName, () => execute.call(tool, toolCallId, args, signal, onUpdate))))(params));
2990
+ };
2991
+ const wrapped = new Proxy(tool, { get: (target, property, receiver) => property === "execute" ? tracedExecute : Reflect.get(target, property, receiver) });
2992
+ this.wrappedTools.set(tool, wrapped);
2993
+ this.originalTools.set(wrapped, tool);
2994
+ wrappersByAnyIntegration.add(wrapped);
2995
+ return wrapped;
2996
+ }
2997
+ };
2998
+ //#endregion
2590
2999
  //#region src/codeChange.ts
2591
3000
  const MAX_FILES = 60;
2592
3001
  const MAX_FILE_BYTES = 5e5;
@@ -4599,6 +5008,9 @@ var TracesClient = class {
4599
5008
  async getScenario(traceId) {
4600
5009
  return (await this.httpClient.get(traceScenarioPath(traceId))).scenario;
4601
5010
  }
5011
+ async generateScenario(traceId) {
5012
+ return (await this.httpClient.request(`${traceScenarioPath(traceId)}/generate`, {})).generation;
5013
+ }
4602
5014
  async saveScenario({ traceId, ...edit }) {
4603
5015
  return (await this.httpClient.request(traceScenarioPath(traceId), withoutDataRecords(edit))).scenario;
4604
5016
  }
@@ -5808,6 +6220,24 @@ var Bitfab = class {
5808
6220
  }
5809
6221
  }, options);
5810
6222
  }
6223
+ getPiIntegration(traceFunctionKey, options) {
6224
+ this.prepareFrameworkIntegration();
6225
+ return new BitfabPiIntegration({
6226
+ traceFunctionKey,
6227
+ options,
6228
+ host: {
6229
+ withSpan: (key, spanOptions, fn) => this.withSpan(key, spanOptions, fn),
6230
+ activeRootTraceFunctionKey: () => {
6231
+ const stack = getSpanStack();
6232
+ return stack[stack.length - 1]?.rootTraceFunctionKey;
6233
+ },
6234
+ currentSpan: () => getCurrentSpan(),
6235
+ traceRootContexts: () => currentTraceRootSpan()?.details.contexts ?? null,
6236
+ setTraceSessionId: (sessionId) => getCurrentTrace().setSessionId(sessionId),
6237
+ withDiscoveredCallsUnderCurrentSpan: (fn) => require_autoTrace.runWithAutoTraceFramesAt(getSpanStack(), fn)
6238
+ }
6239
+ });
6240
+ }
5811
6241
  getClaudeAgentHandler(traceFunctionKey) {
5812
6242
  this.prepareFrameworkIntegration();
5813
6243
  return new BitfabClaudeAgentHandler({
@@ -6573,7 +7003,7 @@ var Bitfab = class {
6573
7003
  await runWithSeedContext({ traceId }, async () => target(...args));
6574
7004
  } finally {
6575
7005
  try {
6576
- const { flushTraces } = await Promise.resolve().then(() => require("./http-DAMAcv_J.cjs")).then((n) => n.http_exports);
7006
+ const { flushTraces } = await Promise.resolve().then(() => require("./http-BB9wDcLm.cjs")).then((n) => n.http_exports);
6577
7007
  await flushTraces(3e4);
6578
7008
  } finally {
6579
7009
  unrecorded = activeTraceStates.delete(traceId);
@@ -6656,6 +7086,9 @@ var BitfabFunction = class {
6656
7086
  getDeepAgentsIntegration(options) {
6657
7087
  return this.client.getDeepAgentsIntegration(this.traceFunctionKey, options);
6658
7088
  }
7089
+ getPiIntegration(options) {
7090
+ return this.client.getPiIntegration(this.traceFunctionKey, options);
7091
+ }
6659
7092
  getRivetIntegration(options) {
6660
7093
  return this.client.getRivetIntegration(this.traceFunctionKey, options);
6661
7094
  }
@@ -6776,7 +7209,7 @@ async function seedFromRegistry(registry, pipeline, cases, options = {}) {
6776
7209
  metadata: seedCase.metadata,
6777
7210
  sessionId: seedCase.sessionId
6778
7211
  }));
6779
- const { flushTraces } = await Promise.resolve().then(() => require("./http-DAMAcv_J.cjs")).then((n) => n.http_exports);
7212
+ const { flushTraces } = await Promise.resolve().then(() => require("./http-BB9wDcLm.cjs")).then((n) => n.http_exports);
6780
7213
  await flushTraces(3e4);
6781
7214
  return {
6782
7215
  pipeline,
@@ -6857,6 +7290,12 @@ Object.defineProperty(exports, "BitfabOpenAITracingProcessor", {
6857
7290
  return BitfabOpenAITracingProcessor;
6858
7291
  }
6859
7292
  });
7293
+ Object.defineProperty(exports, "BitfabPiIntegration", {
7294
+ enumerable: true,
7295
+ get: function() {
7296
+ return BitfabPiIntegration;
7297
+ }
7298
+ });
6860
7299
  Object.defineProperty(exports, "BitfabRivetIntegration", {
6861
7300
  enumerable: true,
6862
7301
  get: function() {
@@ -7020,4 +7459,4 @@ Object.defineProperty(exports, "serializeReplayResult", {
7020
7459
  }
7021
7460
  });
7022
7461
 
7023
- //# sourceMappingURL=src-B7_GnVaZ.cjs.map
7462
+ //# sourceMappingURL=src-BOmu6a4v.cjs.map