bitfab 0.53.0 → 0.53.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/node.cjs CHANGED
@@ -97,7 +97,7 @@ var __version__, __packageName__;
97
97
  var init_version_generated = __esm({
98
98
  "src/version.generated.ts"() {
99
99
  "use strict";
100
- __version__ = "0.53.0";
100
+ __version__ = "0.53.1";
101
101
  __packageName__ = "bitfab";
102
102
  }
103
103
  });
@@ -523,8 +523,8 @@ function encodePayloadBody(payload) {
523
523
  const marker = { error: `payload_serialize_failed: ${message}` };
524
524
  return { body: JSON.stringify(marker), dropped, value: marker };
525
525
  }
526
- const isRecord2 = typeof sanitized === "object" && sanitized !== null && !Array.isArray(sanitized);
527
- if (dropped.length > 0 && isRecord2) {
526
+ const isRecord4 = typeof sanitized === "object" && sanitized !== null && !Array.isArray(sanitized);
527
+ if (dropped.length > 0 && isRecord4) {
528
528
  const obj = sanitized;
529
529
  const existing = Array.isArray(obj.errors) ? obj.errors : [];
530
530
  obj.errors = [
@@ -541,7 +541,7 @@ function encodePayloadBody(payload) {
541
541
  return {
542
542
  body: JSON.stringify(sanitized),
543
543
  dropped,
544
- value: isRecord2 ? sanitized : void 0
544
+ value: isRecord4 ? sanitized : void 0
545
545
  };
546
546
  }
547
547
  }
@@ -553,6 +553,456 @@ var init_serializePayload = __esm({
553
553
  }
554
554
  });
555
555
 
556
+ // src/policyRefresh.ts
557
+ var PolicyRefresh;
558
+ var init_policyRefresh = __esm({
559
+ "src/policyRefresh.ts"() {
560
+ "use strict";
561
+ PolicyRefresh = class {
562
+ constructor() {
563
+ this.refreshAfter = 0;
564
+ }
565
+ due() {
566
+ return this.inFlight === void 0 && Date.now() >= this.refreshAfter;
567
+ }
568
+ hold(durationMs) {
569
+ this.refreshAfter = Date.now() + durationMs;
570
+ }
571
+ releaseHold() {
572
+ this.refreshAfter = 0;
573
+ }
574
+ run(read2, onLoaded, onFailed) {
575
+ if (!this.due()) {
576
+ return;
577
+ }
578
+ let request;
579
+ try {
580
+ request = read2().then(onLoaded).catch(onFailed).finally(() => {
581
+ this.inFlight = void 0;
582
+ });
583
+ } catch (error) {
584
+ onFailed(error);
585
+ return;
586
+ }
587
+ this.inFlight = request;
588
+ }
589
+ };
590
+ }
591
+ });
592
+
593
+ // src/spanOrigin.ts
594
+ function isFrameworkInstrumentation(value) {
595
+ return typeof value === "string" && FRAMEWORK_INSTRUMENTATION_SET.has(value);
596
+ }
597
+ function makeSpanOrigin(instrumentation) {
598
+ return {
599
+ name: SPAN_ORIGIN_NAME,
600
+ version: __version__,
601
+ instrumentation: { name: instrumentation }
602
+ };
603
+ }
604
+ function isRecord(value) {
605
+ return typeof value === "object" && value !== null && !Array.isArray(value);
606
+ }
607
+ function spanOriginOf(payload) {
608
+ const rawSpan = payload.rawSpan;
609
+ if (!isRecord(rawSpan)) {
610
+ return void 0;
611
+ }
612
+ const origin = rawSpan.span_origin;
613
+ if (!isRecord(origin) || !isRecord(origin.instrumentation)) {
614
+ return void 0;
615
+ }
616
+ const { name, version } = origin;
617
+ const instrumentation = origin.instrumentation.name;
618
+ if (typeof name !== "string" || typeof version !== "string" || typeof instrumentation !== "string" || !SPAN_INSTRUMENTATIONS.includes(instrumentation)) {
619
+ return void 0;
620
+ }
621
+ return {
622
+ name,
623
+ version,
624
+ instrumentation: { name: instrumentation }
625
+ };
626
+ }
627
+ function spanInstrumentationOf(payload) {
628
+ return spanOriginOf(payload)?.instrumentation.name;
629
+ }
630
+ function recordedByFramework(payload) {
631
+ return isFrameworkInstrumentation(spanInstrumentationOf(payload));
632
+ }
633
+ var SPAN_ORIGIN_NAME, SPAN_INSTRUMENTATIONS, FRAMEWORK_INSTRUMENTATIONS, FRAMEWORK_INSTRUMENTATION_SET;
634
+ var init_spanOrigin = __esm({
635
+ "src/spanOrigin.ts"() {
636
+ "use strict";
637
+ init_constants();
638
+ SPAN_ORIGIN_NAME = "bitfab.sdk.typescript";
639
+ SPAN_INSTRUMENTATIONS = [
640
+ "span",
641
+ "trace",
642
+ "openai-agents",
643
+ "langgraph",
644
+ "claude-agent-sdk",
645
+ "vercel-ai"
646
+ ];
647
+ FRAMEWORK_INSTRUMENTATIONS = [
648
+ "openai-agents",
649
+ "langgraph",
650
+ "claude-agent-sdk",
651
+ "vercel-ai"
652
+ ];
653
+ FRAMEWORK_INSTRUMENTATION_SET = new Set(
654
+ FRAMEWORK_INSTRUMENTATIONS
655
+ );
656
+ }
657
+ });
658
+
659
+ // src/unrefTimer.ts
660
+ function unrefTimer(timer) {
661
+ const handle = timer;
662
+ if (typeof handle.unref === "function") {
663
+ handle.unref();
664
+ }
665
+ }
666
+ var init_unrefTimer = __esm({
667
+ "src/unrefTimer.ts"() {
668
+ "use strict";
669
+ }
670
+ });
671
+
672
+ // src/simulationPlan.ts
673
+ function planWaitSliceMs(timeoutMs) {
674
+ return Math.min(SIMULATION_PLAN_READ_TIMEOUT_MS, Math.max(timeoutMs, 0) / 2);
675
+ }
676
+ function parseSimulationPlan(body) {
677
+ if (typeof body !== "object" || body === null) {
678
+ return null;
679
+ }
680
+ const nodes = body.nodes;
681
+ if (!Array.isArray(nodes)) {
682
+ return null;
683
+ }
684
+ const contentOff = /* @__PURE__ */ new Map();
685
+ for (const node of nodes) {
686
+ if (typeof node !== "object" || node === null) {
687
+ continue;
688
+ }
689
+ const { traceFunctionKey, name, captureContent } = node;
690
+ if (typeof traceFunctionKey !== "string" || typeof name !== "string" || typeof captureContent !== "boolean") {
691
+ continue;
692
+ }
693
+ if (captureContent) {
694
+ continue;
695
+ }
696
+ const names = contentOff.get(traceFunctionKey) ?? /* @__PURE__ */ new Set();
697
+ names.add(name);
698
+ contentOff.set(traceFunctionKey, names);
699
+ }
700
+ return contentOff;
701
+ }
702
+ function traceIdOf(payload) {
703
+ const traceId = payload.traceId;
704
+ if (typeof traceId === "string") {
705
+ return traceId;
706
+ }
707
+ const id = payload.id;
708
+ return typeof id === "string" ? id : void 0;
709
+ }
710
+ function isRecord2(value) {
711
+ return typeof value === "object" && value !== null;
712
+ }
713
+ function rawSpanOf(payload) {
714
+ return isRecord2(payload.rawSpan) ? payload.rawSpan : void 0;
715
+ }
716
+ function spanDataOf(payload) {
717
+ const spanData = rawSpanOf(payload)?.span_data;
718
+ return isRecord2(spanData) ? spanData : void 0;
719
+ }
720
+ function spanNameOf(payload) {
721
+ const name = spanDataOf(payload)?.name;
722
+ return typeof name === "string" ? name : void 0;
723
+ }
724
+ function stripContent(payload) {
725
+ const rawSpan = rawSpanOf(payload);
726
+ const spanData = spanDataOf(payload);
727
+ if (rawSpan === void 0 || spanData === void 0) {
728
+ return payload;
729
+ }
730
+ const kept = { ...spanData };
731
+ for (const key of CONTENT_KEYS) {
732
+ delete kept[key];
733
+ }
734
+ kept[CONTENT_OFF_KEY] = true;
735
+ return { ...payload, rawSpan: { ...rawSpan, span_data: kept } };
736
+ }
737
+ function simulationPlanEnvDisabled() {
738
+ const value = readEnv(DISABLE_SIMULATION_PLAN_ENV);
739
+ return typeof value === "string" && value.trim() !== "";
740
+ }
741
+ function missingSimulationPlanEndpoint(error) {
742
+ return error instanceof BitfabError && error.status === 404;
743
+ }
744
+ var SIMULATION_PLAN_REFRESH_MS, SIMULATION_PLAN_RETRY_MS, SIMULATION_PLAN_READ_TIMEOUT_MS, SIMULATION_PLAN_MAX_HELD, DISABLE_SIMULATION_PLAN_ENV, ROOT_TRACE_FUNCTION_KEY_FIELD, CONTENT_OFF_KEY, CONTENT_KEYS, SimulationPlan;
745
+ var init_simulationPlan = __esm({
746
+ "src/simulationPlan.ts"() {
747
+ "use strict";
748
+ init_errors();
749
+ init_policyRefresh();
750
+ init_readEnv();
751
+ init_spanOrigin();
752
+ init_unrefTimer();
753
+ init_warnOnce();
754
+ SIMULATION_PLAN_REFRESH_MS = 6e4;
755
+ SIMULATION_PLAN_RETRY_MS = 1e4;
756
+ SIMULATION_PLAN_READ_TIMEOUT_MS = 5e3;
757
+ SIMULATION_PLAN_MAX_HELD = 1e3;
758
+ DISABLE_SIMULATION_PLAN_ENV = "BITFAB_DISABLE_SIM_PLAN";
759
+ ROOT_TRACE_FUNCTION_KEY_FIELD = "rootTraceFunctionKey";
760
+ CONTENT_OFF_KEY = "content_off_by_simulation_plan";
761
+ CONTENT_KEYS = ["input", "input_meta", "output", "output_meta"];
762
+ SimulationPlan = class {
763
+ constructor(source, enabled = true) {
764
+ this.source = source;
765
+ this.enabled = enabled;
766
+ this.policyRefresh = new PolicyRefresh();
767
+ this.retryPending = false;
768
+ this.waitingForFirstLoad = 0;
769
+ this.held = [];
770
+ this.droppedWhileHolding = 0;
771
+ this.stopped = false;
772
+ this.loaded = new Promise((resolve) => {
773
+ this.resolveLoaded = resolve;
774
+ });
775
+ }
776
+ disabled() {
777
+ return !this.enabled || simulationPlanEnvDisabled();
778
+ }
779
+ refresh() {
780
+ if (this.stopped || this.disabled()) {
781
+ return;
782
+ }
783
+ this.policyRefresh.run(
784
+ () => this.source.getSimulationPlan(),
785
+ (body) => {
786
+ const parsed = parseSimulationPlan(body);
787
+ if (parsed === null) {
788
+ this.scheduleRetry(
789
+ "sim-plan-unreadable",
790
+ "the sim plan response was not understood"
791
+ );
792
+ return;
793
+ }
794
+ this.markLoaded(parsed);
795
+ },
796
+ (error) => {
797
+ if (missingSimulationPlanEndpoint(error)) {
798
+ this.markLoaded(/* @__PURE__ */ new Map());
799
+ return;
800
+ }
801
+ this.scheduleRetry(
802
+ "sim-plan-unavailable",
803
+ `could not read the sim plan: ${error instanceof Error ? error.message : String(error)}`
804
+ );
805
+ }
806
+ );
807
+ }
808
+ markLoaded(parsed) {
809
+ if (this.stopped) {
810
+ return;
811
+ }
812
+ this.contentOffByKey = parsed;
813
+ this.policyRefresh.hold(SIMULATION_PLAN_REFRESH_MS);
814
+ this.retryPending = false;
815
+ this.clearRetryTimer();
816
+ this.resolveLoaded?.();
817
+ this.resolveLoaded = void 0;
818
+ this.releaseHeld();
819
+ }
820
+ scheduleRetry(warnKey, reason) {
821
+ if (this.stopped) {
822
+ return;
823
+ }
824
+ this.policyRefresh.hold(SIMULATION_PLAN_RETRY_MS);
825
+ if (this.contentOffByKey !== void 0) {
826
+ return;
827
+ }
828
+ this.retryPending = true;
829
+ warnOnce(
830
+ warnKey,
831
+ `${reason}. Spans are held until the first read succeeds; while a record is held it is retried every ${SIMULATION_PLAN_RETRY_MS / 1e3}s, otherwise on the next span.`
832
+ );
833
+ this.armRetry();
834
+ }
835
+ holdsWork() {
836
+ return this.held.length > 0 || this.waitingForFirstLoad > 0;
837
+ }
838
+ armRetry() {
839
+ if (this.stopped || !this.retryPending || this.retryTimer !== void 0 || !this.holdsWork()) {
840
+ return;
841
+ }
842
+ const timer = setTimeout(() => {
843
+ this.retryTimer = void 0;
844
+ this.policyRefresh.releaseHold();
845
+ this.refresh();
846
+ }, SIMULATION_PLAN_RETRY_MS);
847
+ unrefTimer(timer);
848
+ this.retryTimer = timer;
849
+ }
850
+ clearRetryTimer() {
851
+ if (this.retryTimer !== void 0) {
852
+ clearTimeout(this.retryTimer);
853
+ this.retryTimer = void 0;
854
+ }
855
+ }
856
+ syncRetryTimer() {
857
+ if (this.holdsWork()) {
858
+ return;
859
+ }
860
+ this.clearRetryTimer();
861
+ }
862
+ firstLoad() {
863
+ if (this.contentOffByKey !== void 0 || this.stopped || this.disabled()) {
864
+ return void 0;
865
+ }
866
+ return this.loaded;
867
+ }
868
+ send(payload, traceFunctionKey, submit) {
869
+ this.refresh();
870
+ if (this.stopped || this.disabled() || traceFunctionKey === void 0 || spanNameOf(payload) === void 0 || recordedByFramework(payload)) {
871
+ submit(payload);
872
+ return;
873
+ }
874
+ if (this.contentOffByKey === void 0) {
875
+ this.hold({ payload, traceFunctionKey, submit });
876
+ return;
877
+ }
878
+ this.submitEntry({ payload, traceFunctionKey, submit });
879
+ }
880
+ sendTrace(payload, submit) {
881
+ this.refresh();
882
+ if (this.stopped || this.disabled() || this.contentOffByKey !== void 0 || !this.holdsSpanOfTrace(traceIdOf(payload))) {
883
+ submit(payload);
884
+ return;
885
+ }
886
+ this.hold({ payload, traceFunctionKey: void 0, submit });
887
+ }
888
+ holdsSpanOfTrace(traceId) {
889
+ if (traceId === void 0) {
890
+ return false;
891
+ }
892
+ return this.held.some(
893
+ (entry) => entry.traceFunctionKey !== void 0 && traceIdOf(entry.payload) === traceId
894
+ );
895
+ }
896
+ hold(entry) {
897
+ this.held.push(entry);
898
+ while (this.held.length > SIMULATION_PLAN_MAX_HELD) {
899
+ this.held.shift();
900
+ this.droppedWhileHolding += 1;
901
+ }
902
+ this.armRetry();
903
+ }
904
+ submitEntry(entry) {
905
+ try {
906
+ entry.submit(
907
+ entry.traceFunctionKey === void 0 ? entry.payload : this.apply(entry.payload, entry.traceFunctionKey)
908
+ );
909
+ } catch (error) {
910
+ warnOnce(
911
+ "sim-plan-held-span-dropped",
912
+ `a span held for the sim plan was dropped when released: ${error instanceof Error ? error.message : String(error)}`
913
+ );
914
+ }
915
+ }
916
+ releaseHeld() {
917
+ const held = this.held;
918
+ this.held = [];
919
+ this.syncRetryTimer();
920
+ this.warnDropped();
921
+ for (const entry of held) {
922
+ this.submitEntry(entry);
923
+ }
924
+ }
925
+ warnDropped() {
926
+ if (this.droppedWhileHolding === 0) {
927
+ return;
928
+ }
929
+ const dropped = this.droppedWhileHolding;
930
+ this.droppedWhileHolding = 0;
931
+ warnOnce(
932
+ "sim-plan-held-overflow",
933
+ `${dropped} record(s) were dropped while the sim plan was still loading; at most ${SIMULATION_PLAN_MAX_HELD} are held per client.`
934
+ );
935
+ }
936
+ warnNeverLoaded() {
937
+ if (this.held.length === 0) {
938
+ return;
939
+ }
940
+ warnOnce(
941
+ "sim-plan-never-loaded",
942
+ `${this.held.length} record(s) were not sent because the sim plan never loaded`
943
+ );
944
+ }
945
+ async release(timeoutMs) {
946
+ this.refresh();
947
+ if (this.holdsWork()) {
948
+ await this.waitForFirstLoad(timeoutMs);
949
+ }
950
+ this.warnNeverLoaded();
951
+ this.warnDropped();
952
+ }
953
+ waitForFirstLoad(timeoutMs) {
954
+ const firstLoad = this.firstLoad();
955
+ if (firstLoad === void 0) {
956
+ return Promise.resolve();
957
+ }
958
+ this.waitingForFirstLoad += 1;
959
+ this.armRetry();
960
+ return new Promise((resolve) => {
961
+ let settled2 = false;
962
+ const finish = () => {
963
+ if (settled2) {
964
+ return;
965
+ }
966
+ settled2 = true;
967
+ this.waitingForFirstLoad -= 1;
968
+ this.syncRetryTimer();
969
+ resolve();
970
+ };
971
+ const timer = setTimeout(finish, Math.max(timeoutMs, 0));
972
+ void firstLoad.then(() => {
973
+ clearTimeout(timer);
974
+ finish();
975
+ });
976
+ });
977
+ }
978
+ stop() {
979
+ if (this.stopped) {
980
+ return;
981
+ }
982
+ this.stopped = true;
983
+ this.retryPending = false;
984
+ this.clearRetryTimer();
985
+ this.warnNeverLoaded();
986
+ this.held = [];
987
+ this.warnDropped();
988
+ }
989
+ contentOff(traceFunctionKey, spanName) {
990
+ return this.contentOffByKey?.get(traceFunctionKey)?.has(spanName) === true;
991
+ }
992
+ apply(payload, traceFunctionKey) {
993
+ if (recordedByFramework(payload)) {
994
+ return payload;
995
+ }
996
+ const name = spanNameOf(payload);
997
+ if (name === void 0 || !this.contentOff(traceFunctionKey, name)) {
998
+ return payload;
999
+ }
1000
+ return stripContent(payload);
1001
+ }
1002
+ };
1003
+ }
1004
+ });
1005
+
556
1006
  // src/traceMetadata.ts
557
1007
  function findRecord(traceId) {
558
1008
  return activeRecords.get(traceId) ?? completedRecords.get(traceId);
@@ -669,19 +1119,6 @@ var init_transportTypes = __esm({
669
1119
  }
670
1120
  });
671
1121
 
672
- // src/unrefTimer.ts
673
- function unrefTimer(timer) {
674
- const handle = timer;
675
- if (typeof handle.unref === "function") {
676
- handle.unref();
677
- }
678
- }
679
- var init_unrefTimer = __esm({
680
- "src/unrefTimer.ts"() {
681
- "use strict";
682
- }
683
- });
684
-
685
1122
  // src/otel.ts
686
1123
  function readBoundedIntEnv(name, max, fallback, warnKey) {
687
1124
  const raw = readEnv(name);
@@ -1332,6 +1769,17 @@ __export(http_exports, {
1332
1769
  parseRetryAfterMs: () => parseRetryAfterMs,
1333
1770
  serializePayloadBody: () => serializePayloadBody
1334
1771
  });
1772
+ async function releaseHeldExternalSpans(timeoutMs) {
1773
+ const deadline = Date.now() + Math.max(timeoutMs, 0);
1774
+ for (const client of [...liveHttpClients]) {
1775
+ await client.releaseHeldExternalSpans?.(Math.max(0, deadline - Date.now()));
1776
+ }
1777
+ }
1778
+ function stopSimulationPlans() {
1779
+ for (const client of [...liveHttpClients]) {
1780
+ client.stopSimulationPlan?.();
1781
+ }
1782
+ }
1335
1783
  function awaitOnExit(promise) {
1336
1784
  pendingTracePromises.add(promise);
1337
1785
  void promise.finally(() => {
@@ -1342,7 +1790,10 @@ function awaitOnExit(promise) {
1342
1790
  }
1343
1791
  async function flushTraces(timeoutMs = 5e3) {
1344
1792
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1345
- const requestsFlushed = await awaitPendingRequests(timeoutMs);
1793
+ await releaseHeldExternalSpans(planWaitSliceMs(timeoutMs));
1794
+ const requestsFlushed = await awaitPendingRequests(
1795
+ Math.max(0, deadline - Date.now())
1796
+ );
1346
1797
  const transportsFlushed = await flushTraceTransports(
1347
1798
  Math.max(0, deadline - Date.now())
1348
1799
  );
@@ -1461,7 +1912,22 @@ function sourceTraceIdOf(payload) {
1461
1912
  const id = rawTrace?.id;
1462
1913
  return typeof id === "string" ? id : void 0;
1463
1914
  }
1464
- var REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS, REPLAY_COMPLETE_REQUEST_TIMEOUT_MS, OTLP_TRACES_ENDPOINT, RETRYABLE_STATUSES, EXIT_FLUSH_TIMEOUT_MS, DEFAULT_LIFECYCLE_TIMEOUT_MS2, pendingTracePromises, carrierSeq, HttpClient;
1915
+ function describeError(error) {
1916
+ return error instanceof Error ? error.message : String(error);
1917
+ }
1918
+ function warnDroppedExternalSpan(error) {
1919
+ warnOnce(
1920
+ "external-span-dropped",
1921
+ `a span was dropped because the send step failed: ${describeError(error)}`
1922
+ );
1923
+ }
1924
+ function warnDroppedExternalTrace(error) {
1925
+ warnOnce(
1926
+ "external-trace-dropped",
1927
+ `a trace was dropped because the send step failed: ${describeError(error)}`
1928
+ );
1929
+ }
1930
+ var REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS, REPLAY_COMPLETE_REQUEST_TIMEOUT_MS, OTLP_TRACES_ENDPOINT, RETRYABLE_STATUSES, EXIT_FLUSH_TIMEOUT_MS, DEFAULT_LIFECYCLE_TIMEOUT_MS2, pendingTracePromises, liveHttpClients, carrierSeq, HttpClient;
1465
1931
  var init_http = __esm({
1466
1932
  "src/http.ts"() {
1467
1933
  "use strict";
@@ -1470,6 +1936,7 @@ var init_http = __esm({
1470
1936
  init_errors();
1471
1937
  init_replayContext();
1472
1938
  init_serializePayload();
1939
+ init_simulationPlan();
1473
1940
  init_traceMetadata();
1474
1941
  init_transport();
1475
1942
  init_transportTypes();
@@ -1482,6 +1949,7 @@ var init_http = __esm({
1482
1949
  EXIT_FLUSH_TIMEOUT_MS = 5e3;
1483
1950
  DEFAULT_LIFECYCLE_TIMEOUT_MS2 = 3e4;
1484
1951
  pendingTracePromises = /* @__PURE__ */ new Set();
1952
+ liveHttpClients = /* @__PURE__ */ new Set();
1485
1953
  if (typeof process !== "undefined" && process.versions != null && process.versions.node != null) {
1486
1954
  let isFlushing = false;
1487
1955
  process.on("beforeExit", () => {
@@ -1489,12 +1957,27 @@ var init_http = __esm({
1489
1957
  return;
1490
1958
  }
1491
1959
  isFlushing = true;
1492
- void Promise.allSettled([
1493
- ...Array.from(pendingTracePromises).map((p) => p.catch(() => {
1494
- })),
1495
- shutdownTraceTransports(EXIT_FLUSH_TIMEOUT_MS).catch(() => false)
1496
- ]).then(() => {
1960
+ const planWaitMs = SIMULATION_PLAN_READ_TIMEOUT_MS;
1961
+ const stopFlushing = () => {
1497
1962
  isFlushing = false;
1963
+ };
1964
+ const deadline = setTimeout(
1965
+ stopFlushing,
1966
+ EXIT_FLUSH_TIMEOUT_MS + planWaitMs
1967
+ );
1968
+ unrefTimer(deadline);
1969
+ void releaseHeldExternalSpans(planWaitMs).catch(() => {
1970
+ }).then(() => {
1971
+ stopSimulationPlans();
1972
+ }).then(
1973
+ () => Promise.allSettled([
1974
+ ...Array.from(pendingTracePromises).map((p) => p.catch(() => {
1975
+ })),
1976
+ shutdownTraceTransports(EXIT_FLUSH_TIMEOUT_MS).catch(() => false)
1977
+ ])
1978
+ ).then(() => {
1979
+ clearTimeout(deadline);
1980
+ stopFlushing();
1498
1981
  });
1499
1982
  });
1500
1983
  }
@@ -1513,6 +1996,7 @@ var init_http = __esm({
1513
1996
  this.apiKey = config.apiKey;
1514
1997
  this.serviceUrl = config.serviceUrl;
1515
1998
  this.timeout = config.timeout ?? 12e4;
1999
+ liveHttpClients.add(this);
1516
2000
  }
1517
2001
  /**
1518
2002
  * Resolve the API key at the moment it is needed (request time), invoking
@@ -1710,9 +2194,14 @@ var init_http = __esm({
1710
2194
  * attributing its timeout here would fail a client whose own work succeeded.
1711
2195
  */
1712
2196
  async settleDeferredWork(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS2) {
2197
+ const deadline = Date.now() + Math.max(timeoutMs, 0);
2198
+ await this.releaseHeldExternalSpans?.(planWaitSliceMs(timeoutMs));
1713
2199
  await replayContextReady.catch(() => {
1714
2200
  });
1715
- return waitForPromises(Array.from(this.deferredWork), timeoutMs);
2201
+ return waitForPromises(
2202
+ Array.from(this.deferredWork),
2203
+ Math.max(0, deadline - Date.now())
2204
+ );
1716
2205
  }
1717
2206
  /**
1718
2207
  * Wait for spans queued by this client to be delivered, within one deadline.
@@ -1720,7 +2209,9 @@ var init_http = __esm({
1720
2209
  */
1721
2210
  async waitForPendingRequests(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS2) {
1722
2211
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1723
- const settled2 = await this.settleDeferredWork(timeoutMs);
2212
+ const settled2 = await this.settleDeferredWork(
2213
+ Math.max(0, deadline - Date.now())
2214
+ );
1724
2215
  const flushed = await this.traceTransport?.flush(Math.max(0, deadline - Date.now())) ?? true;
1725
2216
  return settled2 && flushed;
1726
2217
  }
@@ -1735,6 +2226,13 @@ var init_http = __esm({
1735
2226
  }
1736
2227
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1737
2228
  this.closing = (async () => {
2229
+ await this.releaseHeldExternalSpans?.(planWaitSliceMs(timeoutMs));
2230
+ this.stopSimulationPlan?.();
2231
+ this.externalSpanTransform = void 0;
2232
+ this.externalTraceTransform = void 0;
2233
+ this.releaseHeldExternalSpans = void 0;
2234
+ this.stopSimulationPlan = void 0;
2235
+ liveHttpClients.delete(this);
1738
2236
  const settled2 = await this.settleDeferredWork(
1739
2237
  Math.max(0, deadline - Date.now())
1740
2238
  );
@@ -1846,6 +2344,13 @@ var init_http = __esm({
1846
2344
  protocol
1847
2345
  });
1848
2346
  }
2347
+ async getSimulationPlan() {
2348
+ return this.get(
2349
+ "/api/sdk/sim-plan",
2350
+ SIMULATION_PLAN_READ_TIMEOUT_MS,
2351
+ { Connection: "close" }
2352
+ );
2353
+ }
1849
2354
  async getTraceSpan(traceId, lookup) {
1850
2355
  const searchParams = new URLSearchParams();
1851
2356
  if (lookup.id !== void 0) {
@@ -1862,14 +2367,18 @@ var init_http = __esm({
1862
2367
  * GET a JSON endpoint on the service with the client's API key. Throws a
1863
2368
  * `BitfabError` carrying the status text for any non-2xx response.
1864
2369
  */
1865
- async get(endpoint) {
2370
+ async get(endpoint, timeoutMs, extraHeaders) {
1866
2371
  const url = `${this.serviceUrl}${endpoint}`;
2372
+ const timeout = timeoutMs ?? this.timeout;
1867
2373
  const controller = new AbortController();
1868
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2374
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
1869
2375
  try {
1870
2376
  const response = await fetch(url, {
1871
2377
  method: "GET",
1872
- headers: { Authorization: `Bearer ${this.resolveApiKey() ?? ""}` },
2378
+ headers: {
2379
+ Authorization: `Bearer ${this.resolveApiKey() ?? ""}`,
2380
+ ...extraHeaders
2381
+ },
1873
2382
  signal: controller.signal
1874
2383
  });
1875
2384
  if (!response.ok) {
@@ -1888,7 +2397,7 @@ var init_http = __esm({
1888
2397
  }
1889
2398
  if (error instanceof Error) {
1890
2399
  if (error.name === "AbortError") {
1891
- throw new BitfabError(`Request timed out after ${this.timeout}ms`);
2400
+ throw new BitfabError(`Request timed out after ${timeout}ms`);
1892
2401
  }
1893
2402
  throw new BitfabError(error.message);
1894
2403
  }
@@ -1915,16 +2424,27 @@ var init_http = __esm({
1915
2424
  carrierMeta("internal_trace", body, void 0)
1916
2425
  );
1917
2426
  }
1918
- /**
1919
- * Queue an external span (from withSpan wrapper or OpenAI tracing) onto this
1920
- * client's batching transport. Fire-and-forget: the transport owns delivery,
1921
- * so callers await `flushTraces()` or `close()` rather than a per-span
1922
- * promise.
1923
- */
1924
2427
  sendExternalSpan(payload) {
2428
+ const gate = this.externalSpanTransform;
2429
+ if (gate === void 0) {
2430
+ this.submitExternalSpan(payload);
2431
+ return;
2432
+ }
2433
+ try {
2434
+ gate(payload, (ready) => this.submitExternalSpan(ready));
2435
+ } catch (error) {
2436
+ warnDroppedExternalSpan(error);
2437
+ }
2438
+ }
2439
+ submitExternalSpan(payload) {
2440
+ const body = {
2441
+ ...payload,
2442
+ sdkVersion: __version__
2443
+ };
2444
+ delete body[ROOT_TRACE_FUNCTION_KEY_FIELD];
1925
2445
  this.getTraceTransport()?.submit(
1926
2446
  "external_span",
1927
- { ...payload, sdkVersion: __version__ },
2447
+ body,
1928
2448
  this.recordedMeta("external_span", payload, carrierRef(payload))
1929
2449
  );
1930
2450
  }
@@ -1936,6 +2456,18 @@ var init_http = __esm({
1936
2456
  */
1937
2457
  sendExternalTrace(rawPayload) {
1938
2458
  const payload = mergeCallerMetadataIntoTracePayload(rawPayload);
2459
+ const gate = this.externalTraceTransform;
2460
+ if (gate === void 0) {
2461
+ this.submitExternalTrace(payload);
2462
+ return;
2463
+ }
2464
+ try {
2465
+ gate(payload, (ready) => this.submitExternalTrace(ready));
2466
+ } catch (error) {
2467
+ warnDroppedExternalTrace(error);
2468
+ }
2469
+ }
2470
+ submitExternalTrace(payload) {
1939
2471
  this.getTraceTransport()?.submit(
1940
2472
  "external_trace",
1941
2473
  {
@@ -3656,6 +4188,7 @@ function finalizeTracePayload(payload) {
3656
4188
  // src/claudeAgentSdk.ts
3657
4189
  init_randomUuid();
3658
4190
  init_serialize();
4191
+ init_spanOrigin();
3659
4192
 
3660
4193
  // src/timestamp.ts
3661
4194
  var lastTimestampMicros = 0;
@@ -3863,6 +4396,7 @@ var BitfabClaudeAgentHandler = class {
3863
4396
  trace_id: spanInfo.traceId,
3864
4397
  started_at: spanInfo.startedAt,
3865
4398
  ended_at: spanInfo.endedAt ?? nowIso(),
4399
+ span_origin: makeSpanOrigin("claude-agent-sdk"),
3866
4400
  span_data: spanData
3867
4401
  };
3868
4402
  if (spanInfo.parentId !== null) {
@@ -5174,6 +5708,7 @@ init_constants();
5174
5708
  init_http();
5175
5709
  init_randomUuid();
5176
5710
  init_serialize();
5711
+ init_spanOrigin();
5177
5712
  var LANGSMITH_HIDDEN_TAG = "langsmith:hidden";
5178
5713
  var CHAIN_RUN_TYPES = /* @__PURE__ */ new Set(["chain", "parser", "prompt"]);
5179
5714
  var LANGGRAPH_METADATA_KEYS = [
@@ -5528,6 +6063,7 @@ var BitfabLangGraphCallbackHandler = class {
5528
6063
  trace_id: spanInfo.traceId,
5529
6064
  started_at: spanInfo.startedAt,
5530
6065
  ended_at: spanInfo.endedAt ?? nowIso2(),
6066
+ span_origin: makeSpanOrigin("langgraph"),
5531
6067
  span_data: spanData
5532
6068
  };
5533
6069
  if (spanInfo.parentId !== null) {
@@ -5789,14 +6325,14 @@ var BitfabLangGraphCallbackHandler = class {
5789
6325
  init_http();
5790
6326
  init_replayContext();
5791
6327
  var TOOL_RESULT_TAG = "__bitfabLangGraphToolResult";
5792
- function isRecord(value) {
6328
+ function isRecord3(value) {
5793
6329
  return typeof value === "object" && value !== null;
5794
6330
  }
5795
6331
  function isToolMessage(value) {
5796
- return isRecord(value) && value.lc_direct_tool_output === true && value.type === "tool" && (typeof value.content === "string" || Array.isArray(value.content));
6332
+ return isRecord3(value) && value.lc_direct_tool_output === true && value.type === "tool" && (typeof value.content === "string" || Array.isArray(value.content));
5797
6333
  }
5798
6334
  function isCommand(value) {
5799
- return isRecord(value) && value.lg_name === "Command";
6335
+ return isRecord3(value) && value.lg_name === "Command";
5800
6336
  }
5801
6337
  function encodeNested(value) {
5802
6338
  if (isToolMessage(value) || isCommand(value)) {
@@ -5805,7 +6341,7 @@ function encodeNested(value) {
5805
6341
  if (Array.isArray(value)) {
5806
6342
  return value.map(encodeNested);
5807
6343
  }
5808
- if (isRecord(value)) {
6344
+ if (isRecord3(value)) {
5809
6345
  return Object.fromEntries(
5810
6346
  Object.entries(value).map(([key, entry]) => [key, encodeNested(entry)])
5811
6347
  );
@@ -5828,17 +6364,17 @@ function encodeNativeToolResult(value) {
5828
6364
  }
5829
6365
  return {
5830
6366
  [TOOL_RESULT_TAG]: "command",
5831
- graph: isRecord(value) && typeof value.graph === "string" ? value.graph : void 0,
5832
- update: isRecord(value) ? encodeNested(value.update) : void 0,
5833
- resume: isRecord(value) ? encodeNested(value.resume) : void 0,
5834
- goto: isRecord(value) ? encodeNested(value.goto) : void 0
6367
+ graph: isRecord3(value) && typeof value.graph === "string" ? value.graph : void 0,
6368
+ update: isRecord3(value) ? encodeNested(value.update) : void 0,
6369
+ resume: isRecord3(value) ? encodeNested(value.resume) : void 0,
6370
+ goto: isRecord3(value) ? encodeNested(value.goto) : void 0
5835
6371
  };
5836
6372
  }
5837
6373
  function finalizeToolResult(value) {
5838
6374
  return isToolMessage(value) || isCommand(value) ? encodeNativeToolResult(value) : value;
5839
6375
  }
5840
6376
  function isEncodedToolResult(value) {
5841
- return isRecord(value) && typeof value[TOOL_RESULT_TAG] === "string";
6377
+ return isRecord3(value) && typeof value[TOOL_RESULT_TAG] === "string";
5842
6378
  }
5843
6379
  async function loadLangChainCore() {
5844
6380
  try {
@@ -5874,7 +6410,7 @@ async function reviveNested(value, toolCallId) {
5874
6410
  if (Array.isArray(value)) {
5875
6411
  return Promise.all(value.map((entry) => reviveNested(entry, toolCallId)));
5876
6412
  }
5877
- if (isRecord(value)) {
6413
+ if (isRecord3(value)) {
5878
6414
  const entries = await Promise.all(
5879
6415
  Object.entries(value).map(async ([key, entry]) => [
5880
6416
  key,
@@ -5899,16 +6435,16 @@ async function reviveToolResult(value, toolCallId) {
5899
6435
  ...value.artifact !== void 0 && {
5900
6436
  artifact: await reviveNested(value.artifact, toolCallId)
5901
6437
  },
5902
- ...isRecord(value.metadata) && {
6438
+ ...isRecord3(value.metadata) && {
5903
6439
  metadata: await reviveNested(value.metadata, toolCallId)
5904
6440
  },
5905
- ...isRecord(value.additionalKwargs) && {
6441
+ ...isRecord3(value.additionalKwargs) && {
5906
6442
  additional_kwargs: await reviveNested(
5907
6443
  value.additionalKwargs,
5908
6444
  toolCallId
5909
6445
  )
5910
6446
  },
5911
- ...isRecord(value.responseMetadata) && {
6447
+ ...isRecord3(value.responseMetadata) && {
5912
6448
  response_metadata: await reviveNested(
5913
6449
  value.responseMetadata,
5914
6450
  toolCallId
@@ -5978,8 +6514,8 @@ var BitfabLangGraphIntegration = class {
5978
6514
  get: (target, property) => {
5979
6515
  if (property === "invoke") {
5980
6516
  return async (input, ...rest) => {
5981
- const toolCallId = isRecord(input) && typeof input.id === "string" ? input.id : "";
5982
- const args = isRecord(input) && "args" in input ? input.args : input;
6517
+ const toolCallId = isRecord3(input) && typeof input.id === "string" ? input.id : "";
6518
+ const args = isRecord3(input) && "args" in input ? input.args : input;
5983
6519
  this.assertReplayToolResultExists(toolName, shouldMock);
5984
6520
  const execute = this.client.withSpan(
5985
6521
  this.traceFunctionKey,
@@ -5989,7 +6525,8 @@ var BitfabLangGraphIntegration = class {
5989
6525
  captureWhen: "nested",
5990
6526
  mockOnReplay: shouldMock,
5991
6527
  finalize: finalizeToolResult,
5992
- surface: "inherit"
6528
+ surface: "inherit",
6529
+ instrumentation: "langgraph"
5993
6530
  },
5994
6531
  async (_args) => await originalInvoke(input, ...rest)
5995
6532
  );
@@ -6032,7 +6569,12 @@ var BitfabLangGraphIntegration = class {
6032
6569
  wrapInvoke(fn) {
6033
6570
  return this.client.withSpan(
6034
6571
  this.traceFunctionKey,
6035
- { name: this.traceFunctionKey, type: "agent", surface: "inherit" },
6572
+ {
6573
+ name: this.traceFunctionKey,
6574
+ type: "agent",
6575
+ surface: "inherit",
6576
+ instrumentation: "langgraph"
6577
+ },
6036
6578
  fn
6037
6579
  );
6038
6580
  }
@@ -6088,7 +6630,8 @@ var BitfabOpenAIAgentHandler = class {
6088
6630
  const options_ = {
6089
6631
  type: "agent",
6090
6632
  finalize,
6091
- surface: "inherit"
6633
+ surface: "inherit",
6634
+ instrumentation: "openai-agents"
6092
6635
  };
6093
6636
  const traced = this.withSpanFn(
6094
6637
  this.traceFunctionKey,
@@ -6104,6 +6647,7 @@ var BitfabOpenAIAgentHandler = class {
6104
6647
  };
6105
6648
 
6106
6649
  // src/client.ts
6650
+ init_policyRefresh();
6107
6651
  init_randomUuid();
6108
6652
  init_replay();
6109
6653
 
@@ -6187,12 +6731,15 @@ function runWithSeedContext(ctx, fn) {
6187
6731
 
6188
6732
  // src/client.ts
6189
6733
  init_serialize();
6734
+ init_simulationPlan();
6735
+ init_spanOrigin();
6190
6736
  init_traceMetadata();
6191
6737
 
6192
6738
  // src/tracing.ts
6193
6739
  init_constants();
6194
6740
  init_http();
6195
6741
  init_randomUuid();
6742
+ init_spanOrigin();
6196
6743
  var BitfabOpenAITracingProcessor = class {
6197
6744
  /**
6198
6745
  * Initialize the tracing processor.
@@ -6394,6 +6941,7 @@ var BitfabOpenAITracingProcessor = class {
6394
6941
  * Build span payload for the external spans API.
6395
6942
  */
6396
6943
  buildSpanPayload(serializedSpan, errors) {
6944
+ serializedSpan.span_origin = makeSpanOrigin("openai-agents");
6397
6945
  const payload = {
6398
6946
  id: randomUuid(),
6399
6947
  type: "openai",
@@ -6523,7 +7071,8 @@ var BitfabVercelAiHandler = class {
6523
7071
  {
6524
7072
  type: "llm",
6525
7073
  finalize: (result) => summarizeGenerate(result ?? {}, label),
6526
- surface: "inherit"
7074
+ surface: "inherit",
7075
+ instrumentation: "vercel-ai"
6527
7076
  },
6528
7077
  () => doGenerate()
6529
7078
  );
@@ -6541,7 +7090,12 @@ var BitfabVercelAiHandler = class {
6541
7090
  // The wrapped fn returns immediately with the live stream, so the span
6542
7091
  // output cannot be read from the return value. `finalize` instead
6543
7092
  // awaits the summary the accumulator resolves once the stream drains.
6544
- { type: "llm", finalize: () => summary, surface: "inherit" },
7093
+ {
7094
+ type: "llm",
7095
+ finalize: () => summary,
7096
+ surface: "inherit",
7097
+ instrumentation: "vercel-ai"
7098
+ },
6545
7099
  async () => {
6546
7100
  const result = await doStream();
6547
7101
  const stream = result.stream.pipeThrough(
@@ -6559,6 +7113,19 @@ var BitfabVercelAiHandler = class {
6559
7113
  // src/client.ts
6560
7114
  init_warnOnce();
6561
7115
  var activeTraceStates = /* @__PURE__ */ new Map();
7116
+ function rootTraceFunctionKeyOf(payload) {
7117
+ const captured = payload[ROOT_TRACE_FUNCTION_KEY_FIELD];
7118
+ if (typeof captured === "string") {
7119
+ return captured;
7120
+ }
7121
+ const traceId = payload.traceId;
7122
+ const live = typeof traceId === "string" ? activeTraceStates.get(traceId)?.traceFunctionKey : void 0;
7123
+ if (typeof live === "string") {
7124
+ return live;
7125
+ }
7126
+ const own = payload.traceFunctionKey;
7127
+ return typeof own === "string" ? own : void 0;
7128
+ }
6562
7129
  var asyncLocalStorage = null;
6563
7130
  var SPAN_CONTEXT_STORAGE_SYMBOL = /* @__PURE__ */ Symbol.for("bitfab.spanContextStorage");
6564
7131
  var initializeAsyncContext = () => {
@@ -6963,6 +7530,14 @@ var Bitfab = class {
6963
7530
  serviceUrl: this.serviceUrl,
6964
7531
  timeout: this.timeout
6965
7532
  });
7533
+ this.simulationPlan = new SimulationPlan(
7534
+ this.httpClient,
7535
+ config.simulationPlan ?? true
7536
+ );
7537
+ this.httpClient.externalSpanTransform = (payload, submit) => this.applySimulationPlan(payload, submit);
7538
+ this.httpClient.externalTraceTransform = (payload, submit) => this.simulationPlan.sendTrace(payload, submit);
7539
+ this.httpClient.releaseHeldExternalSpans = (timeoutMs) => this.simulationPlan.release(timeoutMs);
7540
+ this.httpClient.stopSimulationPlan = () => this.simulationPlan.stop();
6966
7541
  this.datasets = new DatasetsClient(this.httpClient);
6967
7542
  this.traces = new TracesClient(this.httpClient);
6968
7543
  this.labels = new LabelsClient(this.httpClient);
@@ -7113,6 +7688,7 @@ var Bitfab = class {
7113
7688
  }
7114
7689
  createAutoTraceRoot(traceFunctionKey, name, options, fn) {
7115
7690
  const self = this;
7691
+ self.simulationPlan.refresh();
7116
7692
  const maxDepth = autoTraceLimit(
7117
7693
  options.maxDepth,
7118
7694
  DEFAULT_AUTO_TRACE_MAX_DEPTH
@@ -7128,7 +7704,8 @@ var Bitfab = class {
7128
7704
  name: options.name,
7129
7705
  nameFor: rootNameFor,
7130
7706
  type: options.type ?? "custom",
7131
- surface: "opt-out"
7707
+ surface: "opt-out",
7708
+ instrumentation: "trace"
7132
7709
  };
7133
7710
  const buildTracedRoot = (spanOptions) => this.withSpan(
7134
7711
  traceFunctionKey,
@@ -7139,6 +7716,7 @@ var Bitfab = class {
7139
7716
  traceFunctionKey
7140
7717
  );
7141
7718
  self.refreshAutoTraceCapturePolicy(traceFunctionKey);
7719
+ self.simulationPlan.refresh();
7142
7720
  let spansUsed = 0;
7143
7721
  let truncated = false;
7144
7722
  const warnTruncated = () => {
@@ -7215,6 +7793,7 @@ var Bitfab = class {
7215
7793
  type: nodeConfiguration?.type ?? "function",
7216
7794
  captureWhen: "nested",
7217
7795
  surface: "opt-out",
7796
+ instrumentation: "trace",
7218
7797
  functionId: definition.id,
7219
7798
  captureContent: nodeConfiguration !== void 0 || capturePolicy === void 0 || capturePolicy.has(definition.id),
7220
7799
  autoTraceDefinition: definition,
@@ -7246,6 +7825,7 @@ var Bitfab = class {
7246
7825
  type: "function",
7247
7826
  captureWhen: "nested",
7248
7827
  surface: "opt-out",
7828
+ instrumentation: "trace",
7249
7829
  captureContent: true,
7250
7830
  ...link !== void 0 && { nestedTrace: link }
7251
7831
  };
@@ -7311,38 +7891,36 @@ var Bitfab = class {
7311
7891
  Object.defineProperty(autoTraceRoot, "_bitfabWrappedFn", { value: fn });
7312
7892
  return autoTraceRoot;
7313
7893
  }
7894
+ applySimulationPlan(payload, submit) {
7895
+ this.simulationPlan.send(payload, rootTraceFunctionKeyOf(payload), submit);
7896
+ }
7314
7897
  refreshAutoTraceCapturePolicy(traceFunctionKey) {
7315
- const now = Date.now();
7316
- const state = this.autoTracePolicyRefreshes.get(traceFunctionKey) ?? {
7317
- refreshAfter: 0
7318
- };
7319
- if (state.inFlight || now < state.refreshAfter) {
7320
- return;
7321
- }
7322
- const request = this.httpClient.getAutoTracePolicy(
7323
- traceFunctionKey,
7324
- AUTO_TRACE_PROTOCOL
7325
- ).then((policy) => {
7326
- if (policy.protocol !== AUTO_TRACE_PROTOCOL) {
7327
- state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
7328
- return;
7329
- }
7330
- const functionIds = Array.isArray(policy.functionIds) ? policy.functionIds.filter(
7331
- (id) => typeof id === "string" && id.startsWith(`${AUTO_TRACE_PROTOCOL}:`)
7332
- ).slice(0, DEFAULT_AUTO_TRACE_MAX_SPANS) : [];
7333
- __setBitfabAutoTraceCapturePolicy(
7334
- this,
7335
- traceFunctionKey,
7336
- policy.revision === null ? void 0 : functionIds
7337
- );
7338
- state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_REFRESH_MS;
7339
- }).catch(() => {
7340
- state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
7341
- }).finally(() => {
7342
- state.inFlight = void 0;
7343
- });
7344
- state.inFlight = request;
7898
+ const state = this.autoTracePolicyRefreshes.get(traceFunctionKey) ?? new PolicyRefresh();
7345
7899
  this.autoTracePolicyRefreshes.set(traceFunctionKey, state);
7900
+ state.run(
7901
+ () => this.httpClient.getAutoTracePolicy(
7902
+ traceFunctionKey,
7903
+ AUTO_TRACE_PROTOCOL
7904
+ ),
7905
+ (policy) => {
7906
+ if (policy.protocol !== AUTO_TRACE_PROTOCOL) {
7907
+ state.hold(AUTO_TRACE_POLICY_RETRY_MS);
7908
+ return;
7909
+ }
7910
+ const functionIds = Array.isArray(policy.functionIds) ? policy.functionIds.filter(
7911
+ (id) => typeof id === "string" && id.startsWith(`${AUTO_TRACE_PROTOCOL}:`)
7912
+ ).slice(0, DEFAULT_AUTO_TRACE_MAX_SPANS) : [];
7913
+ __setBitfabAutoTraceCapturePolicy(
7914
+ this,
7915
+ traceFunctionKey,
7916
+ policy.revision === null ? void 0 : functionIds
7917
+ );
7918
+ state.hold(AUTO_TRACE_POLICY_REFRESH_MS);
7919
+ },
7920
+ () => {
7921
+ state.hold(AUTO_TRACE_POLICY_RETRY_MS);
7922
+ }
7923
+ );
7346
7924
  }
7347
7925
  /**
7348
7926
  * Flush and permanently close this client's tracing resources: its pending
@@ -7826,6 +8404,7 @@ var Bitfab = class {
7826
8404
  * @returns A wrapped function with the same signature that creates spans for inputs and outputs
7827
8405
  */
7828
8406
  withSpan(traceFunctionKey, optionsOrFn, maybeFn) {
8407
+ this.simulationPlan.refresh();
7829
8408
  const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
7830
8409
  const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
7831
8410
  const self = this;
@@ -7917,8 +8496,10 @@ var Bitfab = class {
7917
8496
  const testRunId = replayCtxAtStart?.testRunId ?? options.testRunId;
7918
8497
  if (isRootSpan && !activeTraceStates.has(traceId)) {
7919
8498
  const dbSnapshotRef = buildSnapshotRef(self.dbSnapshot, startedAt);
8499
+ self.simulationPlan.refresh();
7920
8500
  activeTraceStates.set(traceId, {
7921
8501
  traceId,
8502
+ traceFunctionKey,
7922
8503
  startedAt,
7923
8504
  contexts: [],
7924
8505
  ...testRunId !== void 0 && { testRunId },
@@ -7933,8 +8514,10 @@ var Bitfab = class {
7933
8514
  registeredTraceId = traceId;
7934
8515
  }
7935
8516
  const functionName = fn.name !== "" ? fn.name : void 0;
8517
+ const rootTraceFunctionKey = activeTraceStates.get(traceId)?.traceFunctionKey ?? traceFunctionKey;
7936
8518
  const baseSpanParams = {
7937
8519
  traceFunctionKey,
8520
+ rootTraceFunctionKey,
7938
8521
  functionName,
7939
8522
  spanName: options.name ?? options.nameFor?.(this) ?? qualifiedSpanName(this, functionName) ?? traceFunctionKey,
7940
8523
  traceId,
@@ -7943,6 +8526,7 @@ var Bitfab = class {
7943
8526
  inputs,
7944
8527
  startedAt,
7945
8528
  spanType: options.type ?? "custom",
8529
+ instrumentation: options.instrumentation ?? "span",
7946
8530
  functionId: options.functionId,
7947
8531
  captureContent: options.captureContent ?? true,
7948
8532
  autoTraceDefinition: options.autoTraceDefinition,
@@ -8358,6 +8942,7 @@ var Bitfab = class {
8358
8942
  * @returns A BitfabFunction instance for wrapping functions
8359
8943
  */
8360
8944
  getFunction(traceFunctionKey) {
8945
+ this.simulationPlan.refresh();
8361
8946
  return new BitfabFunction(this, traceFunctionKey);
8362
8947
  }
8363
8948
  /**
@@ -8445,6 +9030,7 @@ var Bitfab = class {
8445
9030
  trace_id: params.traceId,
8446
9031
  started_at: params.startedAt,
8447
9032
  ended_at: params.endedAt,
9033
+ span_origin: makeSpanOrigin(params.instrumentation),
8448
9034
  span_data: {
8449
9035
  name: params.spanName,
8450
9036
  type: params.spanType,
@@ -8505,6 +9091,9 @@ var Bitfab = class {
8505
9091
  source: "typescript-sdk-function",
8506
9092
  sourceTraceId: params.traceId,
8507
9093
  traceFunctionKey: params.traceFunctionKey,
9094
+ ...params.rootTraceFunctionKey !== void 0 && {
9095
+ [ROOT_TRACE_FUNCTION_KEY_FIELD]: params.rootTraceFunctionKey
9096
+ },
8508
9097
  rawSpan: externalSpan,
8509
9098
  ...params.testRunId && { testRunId: params.testRunId },
8510
9099
  ...params.mocked && { mocked: true },
@@ -8573,6 +9162,7 @@ var Bitfab = class {
8573
9162
  }
8574
9163
  activeTraceStates.set(traceId, {
8575
9164
  traceId,
9165
+ traceFunctionKey,
8576
9166
  startedAt,
8577
9167
  contexts: [],
8578
9168
  ingestionType: "seeded",
@@ -8582,6 +9172,7 @@ var Bitfab = class {
8582
9172
  try {
8583
9173
  this.sendWrapperSpan({
8584
9174
  traceFunctionKey,
9175
+ rootTraceFunctionKey: traceFunctionKey,
8585
9176
  spanName: options.spanName ?? traceFunctionKey,
8586
9177
  traceId,
8587
9178
  spanId: randomUuid(),
@@ -8591,6 +9182,7 @@ var Bitfab = class {
8591
9182
  startedAt,
8592
9183
  endedAt: startedAt,
8593
9184
  spanType: options.spanType ?? "agent",
9185
+ instrumentation: "span",
8594
9186
  captureContent: true
8595
9187
  });
8596
9188
  this.sendTraceCompletion({
@@ -8636,6 +9228,7 @@ var Bitfab = class {
8636
9228
  }
8637
9229
  activeTraceStates.set(traceId, {
8638
9230
  traceId,
9231
+ traceFunctionKey,
8639
9232
  startedAt: nowIsoTimestamp(),
8640
9233
  contexts: [],
8641
9234
  ingestionType: "seeded",