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/index.cjs CHANGED
@@ -51,7 +51,7 @@ var __version__, __packageName__;
51
51
  var init_version_generated = __esm({
52
52
  "src/version.generated.ts"() {
53
53
  "use strict";
54
- __version__ = "0.53.0";
54
+ __version__ = "0.53.1";
55
55
  __packageName__ = "bitfab";
56
56
  }
57
57
  });
@@ -516,8 +516,8 @@ function encodePayloadBody(payload) {
516
516
  const marker = { error: `payload_serialize_failed: ${message}` };
517
517
  return { body: JSON.stringify(marker), dropped, value: marker };
518
518
  }
519
- const isRecord2 = typeof sanitized === "object" && sanitized !== null && !Array.isArray(sanitized);
520
- if (dropped.length > 0 && isRecord2) {
519
+ const isRecord4 = typeof sanitized === "object" && sanitized !== null && !Array.isArray(sanitized);
520
+ if (dropped.length > 0 && isRecord4) {
521
521
  const obj = sanitized;
522
522
  const existing = Array.isArray(obj.errors) ? obj.errors : [];
523
523
  obj.errors = [
@@ -534,7 +534,7 @@ function encodePayloadBody(payload) {
534
534
  return {
535
535
  body: JSON.stringify(sanitized),
536
536
  dropped,
537
- value: isRecord2 ? sanitized : void 0
537
+ value: isRecord4 ? sanitized : void 0
538
538
  };
539
539
  }
540
540
  }
@@ -546,6 +546,456 @@ var init_serializePayload = __esm({
546
546
  }
547
547
  });
548
548
 
549
+ // src/policyRefresh.ts
550
+ var PolicyRefresh;
551
+ var init_policyRefresh = __esm({
552
+ "src/policyRefresh.ts"() {
553
+ "use strict";
554
+ PolicyRefresh = class {
555
+ constructor() {
556
+ this.refreshAfter = 0;
557
+ }
558
+ due() {
559
+ return this.inFlight === void 0 && Date.now() >= this.refreshAfter;
560
+ }
561
+ hold(durationMs) {
562
+ this.refreshAfter = Date.now() + durationMs;
563
+ }
564
+ releaseHold() {
565
+ this.refreshAfter = 0;
566
+ }
567
+ run(read2, onLoaded, onFailed) {
568
+ if (!this.due()) {
569
+ return;
570
+ }
571
+ let request;
572
+ try {
573
+ request = read2().then(onLoaded).catch(onFailed).finally(() => {
574
+ this.inFlight = void 0;
575
+ });
576
+ } catch (error) {
577
+ onFailed(error);
578
+ return;
579
+ }
580
+ this.inFlight = request;
581
+ }
582
+ };
583
+ }
584
+ });
585
+
586
+ // src/spanOrigin.ts
587
+ function isFrameworkInstrumentation(value) {
588
+ return typeof value === "string" && FRAMEWORK_INSTRUMENTATION_SET.has(value);
589
+ }
590
+ function makeSpanOrigin(instrumentation) {
591
+ return {
592
+ name: SPAN_ORIGIN_NAME,
593
+ version: __version__,
594
+ instrumentation: { name: instrumentation }
595
+ };
596
+ }
597
+ function isRecord(value) {
598
+ return typeof value === "object" && value !== null && !Array.isArray(value);
599
+ }
600
+ function spanOriginOf(payload) {
601
+ const rawSpan = payload.rawSpan;
602
+ if (!isRecord(rawSpan)) {
603
+ return void 0;
604
+ }
605
+ const origin = rawSpan.span_origin;
606
+ if (!isRecord(origin) || !isRecord(origin.instrumentation)) {
607
+ return void 0;
608
+ }
609
+ const { name, version } = origin;
610
+ const instrumentation = origin.instrumentation.name;
611
+ if (typeof name !== "string" || typeof version !== "string" || typeof instrumentation !== "string" || !SPAN_INSTRUMENTATIONS.includes(instrumentation)) {
612
+ return void 0;
613
+ }
614
+ return {
615
+ name,
616
+ version,
617
+ instrumentation: { name: instrumentation }
618
+ };
619
+ }
620
+ function spanInstrumentationOf(payload) {
621
+ return spanOriginOf(payload)?.instrumentation.name;
622
+ }
623
+ function recordedByFramework(payload) {
624
+ return isFrameworkInstrumentation(spanInstrumentationOf(payload));
625
+ }
626
+ var SPAN_ORIGIN_NAME, SPAN_INSTRUMENTATIONS, FRAMEWORK_INSTRUMENTATIONS, FRAMEWORK_INSTRUMENTATION_SET;
627
+ var init_spanOrigin = __esm({
628
+ "src/spanOrigin.ts"() {
629
+ "use strict";
630
+ init_constants();
631
+ SPAN_ORIGIN_NAME = "bitfab.sdk.typescript";
632
+ SPAN_INSTRUMENTATIONS = [
633
+ "span",
634
+ "trace",
635
+ "openai-agents",
636
+ "langgraph",
637
+ "claude-agent-sdk",
638
+ "vercel-ai"
639
+ ];
640
+ FRAMEWORK_INSTRUMENTATIONS = [
641
+ "openai-agents",
642
+ "langgraph",
643
+ "claude-agent-sdk",
644
+ "vercel-ai"
645
+ ];
646
+ FRAMEWORK_INSTRUMENTATION_SET = new Set(
647
+ FRAMEWORK_INSTRUMENTATIONS
648
+ );
649
+ }
650
+ });
651
+
652
+ // src/unrefTimer.ts
653
+ function unrefTimer(timer) {
654
+ const handle = timer;
655
+ if (typeof handle.unref === "function") {
656
+ handle.unref();
657
+ }
658
+ }
659
+ var init_unrefTimer = __esm({
660
+ "src/unrefTimer.ts"() {
661
+ "use strict";
662
+ }
663
+ });
664
+
665
+ // src/simulationPlan.ts
666
+ function planWaitSliceMs(timeoutMs) {
667
+ return Math.min(SIMULATION_PLAN_READ_TIMEOUT_MS, Math.max(timeoutMs, 0) / 2);
668
+ }
669
+ function parseSimulationPlan(body) {
670
+ if (typeof body !== "object" || body === null) {
671
+ return null;
672
+ }
673
+ const nodes = body.nodes;
674
+ if (!Array.isArray(nodes)) {
675
+ return null;
676
+ }
677
+ const contentOff = /* @__PURE__ */ new Map();
678
+ for (const node of nodes) {
679
+ if (typeof node !== "object" || node === null) {
680
+ continue;
681
+ }
682
+ const { traceFunctionKey, name, captureContent } = node;
683
+ if (typeof traceFunctionKey !== "string" || typeof name !== "string" || typeof captureContent !== "boolean") {
684
+ continue;
685
+ }
686
+ if (captureContent) {
687
+ continue;
688
+ }
689
+ const names = contentOff.get(traceFunctionKey) ?? /* @__PURE__ */ new Set();
690
+ names.add(name);
691
+ contentOff.set(traceFunctionKey, names);
692
+ }
693
+ return contentOff;
694
+ }
695
+ function traceIdOf(payload) {
696
+ const traceId = payload.traceId;
697
+ if (typeof traceId === "string") {
698
+ return traceId;
699
+ }
700
+ const id = payload.id;
701
+ return typeof id === "string" ? id : void 0;
702
+ }
703
+ function isRecord2(value) {
704
+ return typeof value === "object" && value !== null;
705
+ }
706
+ function rawSpanOf(payload) {
707
+ return isRecord2(payload.rawSpan) ? payload.rawSpan : void 0;
708
+ }
709
+ function spanDataOf(payload) {
710
+ const spanData = rawSpanOf(payload)?.span_data;
711
+ return isRecord2(spanData) ? spanData : void 0;
712
+ }
713
+ function spanNameOf(payload) {
714
+ const name = spanDataOf(payload)?.name;
715
+ return typeof name === "string" ? name : void 0;
716
+ }
717
+ function stripContent(payload) {
718
+ const rawSpan = rawSpanOf(payload);
719
+ const spanData = spanDataOf(payload);
720
+ if (rawSpan === void 0 || spanData === void 0) {
721
+ return payload;
722
+ }
723
+ const kept = { ...spanData };
724
+ for (const key of CONTENT_KEYS) {
725
+ delete kept[key];
726
+ }
727
+ kept[CONTENT_OFF_KEY] = true;
728
+ return { ...payload, rawSpan: { ...rawSpan, span_data: kept } };
729
+ }
730
+ function simulationPlanEnvDisabled() {
731
+ const value = readEnv(DISABLE_SIMULATION_PLAN_ENV);
732
+ return typeof value === "string" && value.trim() !== "";
733
+ }
734
+ function missingSimulationPlanEndpoint(error) {
735
+ return error instanceof BitfabError && error.status === 404;
736
+ }
737
+ 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;
738
+ var init_simulationPlan = __esm({
739
+ "src/simulationPlan.ts"() {
740
+ "use strict";
741
+ init_errors();
742
+ init_policyRefresh();
743
+ init_readEnv();
744
+ init_spanOrigin();
745
+ init_unrefTimer();
746
+ init_warnOnce();
747
+ SIMULATION_PLAN_REFRESH_MS = 6e4;
748
+ SIMULATION_PLAN_RETRY_MS = 1e4;
749
+ SIMULATION_PLAN_READ_TIMEOUT_MS = 5e3;
750
+ SIMULATION_PLAN_MAX_HELD = 1e3;
751
+ DISABLE_SIMULATION_PLAN_ENV = "BITFAB_DISABLE_SIM_PLAN";
752
+ ROOT_TRACE_FUNCTION_KEY_FIELD = "rootTraceFunctionKey";
753
+ CONTENT_OFF_KEY = "content_off_by_simulation_plan";
754
+ CONTENT_KEYS = ["input", "input_meta", "output", "output_meta"];
755
+ SimulationPlan = class {
756
+ constructor(source, enabled = true) {
757
+ this.source = source;
758
+ this.enabled = enabled;
759
+ this.policyRefresh = new PolicyRefresh();
760
+ this.retryPending = false;
761
+ this.waitingForFirstLoad = 0;
762
+ this.held = [];
763
+ this.droppedWhileHolding = 0;
764
+ this.stopped = false;
765
+ this.loaded = new Promise((resolve) => {
766
+ this.resolveLoaded = resolve;
767
+ });
768
+ }
769
+ disabled() {
770
+ return !this.enabled || simulationPlanEnvDisabled();
771
+ }
772
+ refresh() {
773
+ if (this.stopped || this.disabled()) {
774
+ return;
775
+ }
776
+ this.policyRefresh.run(
777
+ () => this.source.getSimulationPlan(),
778
+ (body) => {
779
+ const parsed = parseSimulationPlan(body);
780
+ if (parsed === null) {
781
+ this.scheduleRetry(
782
+ "sim-plan-unreadable",
783
+ "the sim plan response was not understood"
784
+ );
785
+ return;
786
+ }
787
+ this.markLoaded(parsed);
788
+ },
789
+ (error) => {
790
+ if (missingSimulationPlanEndpoint(error)) {
791
+ this.markLoaded(/* @__PURE__ */ new Map());
792
+ return;
793
+ }
794
+ this.scheduleRetry(
795
+ "sim-plan-unavailable",
796
+ `could not read the sim plan: ${error instanceof Error ? error.message : String(error)}`
797
+ );
798
+ }
799
+ );
800
+ }
801
+ markLoaded(parsed) {
802
+ if (this.stopped) {
803
+ return;
804
+ }
805
+ this.contentOffByKey = parsed;
806
+ this.policyRefresh.hold(SIMULATION_PLAN_REFRESH_MS);
807
+ this.retryPending = false;
808
+ this.clearRetryTimer();
809
+ this.resolveLoaded?.();
810
+ this.resolveLoaded = void 0;
811
+ this.releaseHeld();
812
+ }
813
+ scheduleRetry(warnKey, reason) {
814
+ if (this.stopped) {
815
+ return;
816
+ }
817
+ this.policyRefresh.hold(SIMULATION_PLAN_RETRY_MS);
818
+ if (this.contentOffByKey !== void 0) {
819
+ return;
820
+ }
821
+ this.retryPending = true;
822
+ warnOnce(
823
+ warnKey,
824
+ `${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.`
825
+ );
826
+ this.armRetry();
827
+ }
828
+ holdsWork() {
829
+ return this.held.length > 0 || this.waitingForFirstLoad > 0;
830
+ }
831
+ armRetry() {
832
+ if (this.stopped || !this.retryPending || this.retryTimer !== void 0 || !this.holdsWork()) {
833
+ return;
834
+ }
835
+ const timer = setTimeout(() => {
836
+ this.retryTimer = void 0;
837
+ this.policyRefresh.releaseHold();
838
+ this.refresh();
839
+ }, SIMULATION_PLAN_RETRY_MS);
840
+ unrefTimer(timer);
841
+ this.retryTimer = timer;
842
+ }
843
+ clearRetryTimer() {
844
+ if (this.retryTimer !== void 0) {
845
+ clearTimeout(this.retryTimer);
846
+ this.retryTimer = void 0;
847
+ }
848
+ }
849
+ syncRetryTimer() {
850
+ if (this.holdsWork()) {
851
+ return;
852
+ }
853
+ this.clearRetryTimer();
854
+ }
855
+ firstLoad() {
856
+ if (this.contentOffByKey !== void 0 || this.stopped || this.disabled()) {
857
+ return void 0;
858
+ }
859
+ return this.loaded;
860
+ }
861
+ send(payload, traceFunctionKey, submit) {
862
+ this.refresh();
863
+ if (this.stopped || this.disabled() || traceFunctionKey === void 0 || spanNameOf(payload) === void 0 || recordedByFramework(payload)) {
864
+ submit(payload);
865
+ return;
866
+ }
867
+ if (this.contentOffByKey === void 0) {
868
+ this.hold({ payload, traceFunctionKey, submit });
869
+ return;
870
+ }
871
+ this.submitEntry({ payload, traceFunctionKey, submit });
872
+ }
873
+ sendTrace(payload, submit) {
874
+ this.refresh();
875
+ if (this.stopped || this.disabled() || this.contentOffByKey !== void 0 || !this.holdsSpanOfTrace(traceIdOf(payload))) {
876
+ submit(payload);
877
+ return;
878
+ }
879
+ this.hold({ payload, traceFunctionKey: void 0, submit });
880
+ }
881
+ holdsSpanOfTrace(traceId) {
882
+ if (traceId === void 0) {
883
+ return false;
884
+ }
885
+ return this.held.some(
886
+ (entry) => entry.traceFunctionKey !== void 0 && traceIdOf(entry.payload) === traceId
887
+ );
888
+ }
889
+ hold(entry) {
890
+ this.held.push(entry);
891
+ while (this.held.length > SIMULATION_PLAN_MAX_HELD) {
892
+ this.held.shift();
893
+ this.droppedWhileHolding += 1;
894
+ }
895
+ this.armRetry();
896
+ }
897
+ submitEntry(entry) {
898
+ try {
899
+ entry.submit(
900
+ entry.traceFunctionKey === void 0 ? entry.payload : this.apply(entry.payload, entry.traceFunctionKey)
901
+ );
902
+ } catch (error) {
903
+ warnOnce(
904
+ "sim-plan-held-span-dropped",
905
+ `a span held for the sim plan was dropped when released: ${error instanceof Error ? error.message : String(error)}`
906
+ );
907
+ }
908
+ }
909
+ releaseHeld() {
910
+ const held = this.held;
911
+ this.held = [];
912
+ this.syncRetryTimer();
913
+ this.warnDropped();
914
+ for (const entry of held) {
915
+ this.submitEntry(entry);
916
+ }
917
+ }
918
+ warnDropped() {
919
+ if (this.droppedWhileHolding === 0) {
920
+ return;
921
+ }
922
+ const dropped = this.droppedWhileHolding;
923
+ this.droppedWhileHolding = 0;
924
+ warnOnce(
925
+ "sim-plan-held-overflow",
926
+ `${dropped} record(s) were dropped while the sim plan was still loading; at most ${SIMULATION_PLAN_MAX_HELD} are held per client.`
927
+ );
928
+ }
929
+ warnNeverLoaded() {
930
+ if (this.held.length === 0) {
931
+ return;
932
+ }
933
+ warnOnce(
934
+ "sim-plan-never-loaded",
935
+ `${this.held.length} record(s) were not sent because the sim plan never loaded`
936
+ );
937
+ }
938
+ async release(timeoutMs) {
939
+ this.refresh();
940
+ if (this.holdsWork()) {
941
+ await this.waitForFirstLoad(timeoutMs);
942
+ }
943
+ this.warnNeverLoaded();
944
+ this.warnDropped();
945
+ }
946
+ waitForFirstLoad(timeoutMs) {
947
+ const firstLoad = this.firstLoad();
948
+ if (firstLoad === void 0) {
949
+ return Promise.resolve();
950
+ }
951
+ this.waitingForFirstLoad += 1;
952
+ this.armRetry();
953
+ return new Promise((resolve) => {
954
+ let settled2 = false;
955
+ const finish = () => {
956
+ if (settled2) {
957
+ return;
958
+ }
959
+ settled2 = true;
960
+ this.waitingForFirstLoad -= 1;
961
+ this.syncRetryTimer();
962
+ resolve();
963
+ };
964
+ const timer = setTimeout(finish, Math.max(timeoutMs, 0));
965
+ void firstLoad.then(() => {
966
+ clearTimeout(timer);
967
+ finish();
968
+ });
969
+ });
970
+ }
971
+ stop() {
972
+ if (this.stopped) {
973
+ return;
974
+ }
975
+ this.stopped = true;
976
+ this.retryPending = false;
977
+ this.clearRetryTimer();
978
+ this.warnNeverLoaded();
979
+ this.held = [];
980
+ this.warnDropped();
981
+ }
982
+ contentOff(traceFunctionKey, spanName) {
983
+ return this.contentOffByKey?.get(traceFunctionKey)?.has(spanName) === true;
984
+ }
985
+ apply(payload, traceFunctionKey) {
986
+ if (recordedByFramework(payload)) {
987
+ return payload;
988
+ }
989
+ const name = spanNameOf(payload);
990
+ if (name === void 0 || !this.contentOff(traceFunctionKey, name)) {
991
+ return payload;
992
+ }
993
+ return stripContent(payload);
994
+ }
995
+ };
996
+ }
997
+ });
998
+
549
999
  // src/traceMetadata.ts
550
1000
  function findRecord(traceId) {
551
1001
  return activeRecords.get(traceId) ?? completedRecords.get(traceId);
@@ -662,19 +1112,6 @@ var init_transportTypes = __esm({
662
1112
  }
663
1113
  });
664
1114
 
665
- // src/unrefTimer.ts
666
- function unrefTimer(timer) {
667
- const handle = timer;
668
- if (typeof handle.unref === "function") {
669
- handle.unref();
670
- }
671
- }
672
- var init_unrefTimer = __esm({
673
- "src/unrefTimer.ts"() {
674
- "use strict";
675
- }
676
- });
677
-
678
1115
  // src/otel.ts
679
1116
  function readBoundedIntEnv(name, max, fallback, warnKey) {
680
1117
  const raw = readEnv(name);
@@ -1325,6 +1762,17 @@ __export(http_exports, {
1325
1762
  parseRetryAfterMs: () => parseRetryAfterMs,
1326
1763
  serializePayloadBody: () => serializePayloadBody
1327
1764
  });
1765
+ async function releaseHeldExternalSpans(timeoutMs) {
1766
+ const deadline = Date.now() + Math.max(timeoutMs, 0);
1767
+ for (const client of [...liveHttpClients]) {
1768
+ await client.releaseHeldExternalSpans?.(Math.max(0, deadline - Date.now()));
1769
+ }
1770
+ }
1771
+ function stopSimulationPlans() {
1772
+ for (const client of [...liveHttpClients]) {
1773
+ client.stopSimulationPlan?.();
1774
+ }
1775
+ }
1328
1776
  function awaitOnExit(promise) {
1329
1777
  pendingTracePromises.add(promise);
1330
1778
  void promise.finally(() => {
@@ -1335,7 +1783,10 @@ function awaitOnExit(promise) {
1335
1783
  }
1336
1784
  async function flushTraces(timeoutMs = 5e3) {
1337
1785
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1338
- const requestsFlushed = await awaitPendingRequests(timeoutMs);
1786
+ await releaseHeldExternalSpans(planWaitSliceMs(timeoutMs));
1787
+ const requestsFlushed = await awaitPendingRequests(
1788
+ Math.max(0, deadline - Date.now())
1789
+ );
1339
1790
  const transportsFlushed = await flushTraceTransports(
1340
1791
  Math.max(0, deadline - Date.now())
1341
1792
  );
@@ -1454,7 +1905,22 @@ function sourceTraceIdOf(payload) {
1454
1905
  const id = rawTrace?.id;
1455
1906
  return typeof id === "string" ? id : void 0;
1456
1907
  }
1457
- 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;
1908
+ function describeError(error) {
1909
+ return error instanceof Error ? error.message : String(error);
1910
+ }
1911
+ function warnDroppedExternalSpan(error) {
1912
+ warnOnce(
1913
+ "external-span-dropped",
1914
+ `a span was dropped because the send step failed: ${describeError(error)}`
1915
+ );
1916
+ }
1917
+ function warnDroppedExternalTrace(error) {
1918
+ warnOnce(
1919
+ "external-trace-dropped",
1920
+ `a trace was dropped because the send step failed: ${describeError(error)}`
1921
+ );
1922
+ }
1923
+ 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;
1458
1924
  var init_http = __esm({
1459
1925
  "src/http.ts"() {
1460
1926
  "use strict";
@@ -1463,6 +1929,7 @@ var init_http = __esm({
1463
1929
  init_errors();
1464
1930
  init_replayContext();
1465
1931
  init_serializePayload();
1932
+ init_simulationPlan();
1466
1933
  init_traceMetadata();
1467
1934
  init_transport();
1468
1935
  init_transportTypes();
@@ -1475,6 +1942,7 @@ var init_http = __esm({
1475
1942
  EXIT_FLUSH_TIMEOUT_MS = 5e3;
1476
1943
  DEFAULT_LIFECYCLE_TIMEOUT_MS2 = 3e4;
1477
1944
  pendingTracePromises = /* @__PURE__ */ new Set();
1945
+ liveHttpClients = /* @__PURE__ */ new Set();
1478
1946
  if (typeof process !== "undefined" && process.versions != null && process.versions.node != null) {
1479
1947
  let isFlushing = false;
1480
1948
  process.on("beforeExit", () => {
@@ -1482,12 +1950,27 @@ var init_http = __esm({
1482
1950
  return;
1483
1951
  }
1484
1952
  isFlushing = true;
1485
- void Promise.allSettled([
1486
- ...Array.from(pendingTracePromises).map((p) => p.catch(() => {
1487
- })),
1488
- shutdownTraceTransports(EXIT_FLUSH_TIMEOUT_MS).catch(() => false)
1489
- ]).then(() => {
1953
+ const planWaitMs = SIMULATION_PLAN_READ_TIMEOUT_MS;
1954
+ const stopFlushing = () => {
1490
1955
  isFlushing = false;
1956
+ };
1957
+ const deadline = setTimeout(
1958
+ stopFlushing,
1959
+ EXIT_FLUSH_TIMEOUT_MS + planWaitMs
1960
+ );
1961
+ unrefTimer(deadline);
1962
+ void releaseHeldExternalSpans(planWaitMs).catch(() => {
1963
+ }).then(() => {
1964
+ stopSimulationPlans();
1965
+ }).then(
1966
+ () => Promise.allSettled([
1967
+ ...Array.from(pendingTracePromises).map((p) => p.catch(() => {
1968
+ })),
1969
+ shutdownTraceTransports(EXIT_FLUSH_TIMEOUT_MS).catch(() => false)
1970
+ ])
1971
+ ).then(() => {
1972
+ clearTimeout(deadline);
1973
+ stopFlushing();
1491
1974
  });
1492
1975
  });
1493
1976
  }
@@ -1506,6 +1989,7 @@ var init_http = __esm({
1506
1989
  this.apiKey = config.apiKey;
1507
1990
  this.serviceUrl = config.serviceUrl;
1508
1991
  this.timeout = config.timeout ?? 12e4;
1992
+ liveHttpClients.add(this);
1509
1993
  }
1510
1994
  /**
1511
1995
  * Resolve the API key at the moment it is needed (request time), invoking
@@ -1703,9 +2187,14 @@ var init_http = __esm({
1703
2187
  * attributing its timeout here would fail a client whose own work succeeded.
1704
2188
  */
1705
2189
  async settleDeferredWork(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS2) {
2190
+ const deadline = Date.now() + Math.max(timeoutMs, 0);
2191
+ await this.releaseHeldExternalSpans?.(planWaitSliceMs(timeoutMs));
1706
2192
  await replayContextReady.catch(() => {
1707
2193
  });
1708
- return waitForPromises(Array.from(this.deferredWork), timeoutMs);
2194
+ return waitForPromises(
2195
+ Array.from(this.deferredWork),
2196
+ Math.max(0, deadline - Date.now())
2197
+ );
1709
2198
  }
1710
2199
  /**
1711
2200
  * Wait for spans queued by this client to be delivered, within one deadline.
@@ -1713,7 +2202,9 @@ var init_http = __esm({
1713
2202
  */
1714
2203
  async waitForPendingRequests(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS2) {
1715
2204
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1716
- const settled2 = await this.settleDeferredWork(timeoutMs);
2205
+ const settled2 = await this.settleDeferredWork(
2206
+ Math.max(0, deadline - Date.now())
2207
+ );
1717
2208
  const flushed = await this.traceTransport?.flush(Math.max(0, deadline - Date.now())) ?? true;
1718
2209
  return settled2 && flushed;
1719
2210
  }
@@ -1728,6 +2219,13 @@ var init_http = __esm({
1728
2219
  }
1729
2220
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1730
2221
  this.closing = (async () => {
2222
+ await this.releaseHeldExternalSpans?.(planWaitSliceMs(timeoutMs));
2223
+ this.stopSimulationPlan?.();
2224
+ this.externalSpanTransform = void 0;
2225
+ this.externalTraceTransform = void 0;
2226
+ this.releaseHeldExternalSpans = void 0;
2227
+ this.stopSimulationPlan = void 0;
2228
+ liveHttpClients.delete(this);
1731
2229
  const settled2 = await this.settleDeferredWork(
1732
2230
  Math.max(0, deadline - Date.now())
1733
2231
  );
@@ -1839,6 +2337,13 @@ var init_http = __esm({
1839
2337
  protocol
1840
2338
  });
1841
2339
  }
2340
+ async getSimulationPlan() {
2341
+ return this.get(
2342
+ "/api/sdk/sim-plan",
2343
+ SIMULATION_PLAN_READ_TIMEOUT_MS,
2344
+ { Connection: "close" }
2345
+ );
2346
+ }
1842
2347
  async getTraceSpan(traceId, lookup) {
1843
2348
  const searchParams = new URLSearchParams();
1844
2349
  if (lookup.id !== void 0) {
@@ -1855,14 +2360,18 @@ var init_http = __esm({
1855
2360
  * GET a JSON endpoint on the service with the client's API key. Throws a
1856
2361
  * `BitfabError` carrying the status text for any non-2xx response.
1857
2362
  */
1858
- async get(endpoint) {
2363
+ async get(endpoint, timeoutMs, extraHeaders) {
1859
2364
  const url = `${this.serviceUrl}${endpoint}`;
2365
+ const timeout = timeoutMs ?? this.timeout;
1860
2366
  const controller = new AbortController();
1861
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2367
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
1862
2368
  try {
1863
2369
  const response = await fetch(url, {
1864
2370
  method: "GET",
1865
- headers: { Authorization: `Bearer ${this.resolveApiKey() ?? ""}` },
2371
+ headers: {
2372
+ Authorization: `Bearer ${this.resolveApiKey() ?? ""}`,
2373
+ ...extraHeaders
2374
+ },
1866
2375
  signal: controller.signal
1867
2376
  });
1868
2377
  if (!response.ok) {
@@ -1881,7 +2390,7 @@ var init_http = __esm({
1881
2390
  }
1882
2391
  if (error instanceof Error) {
1883
2392
  if (error.name === "AbortError") {
1884
- throw new BitfabError(`Request timed out after ${this.timeout}ms`);
2393
+ throw new BitfabError(`Request timed out after ${timeout}ms`);
1885
2394
  }
1886
2395
  throw new BitfabError(error.message);
1887
2396
  }
@@ -1908,16 +2417,27 @@ var init_http = __esm({
1908
2417
  carrierMeta("internal_trace", body, void 0)
1909
2418
  );
1910
2419
  }
1911
- /**
1912
- * Queue an external span (from withSpan wrapper or OpenAI tracing) onto this
1913
- * client's batching transport. Fire-and-forget: the transport owns delivery,
1914
- * so callers await `flushTraces()` or `close()` rather than a per-span
1915
- * promise.
1916
- */
1917
2420
  sendExternalSpan(payload) {
2421
+ const gate = this.externalSpanTransform;
2422
+ if (gate === void 0) {
2423
+ this.submitExternalSpan(payload);
2424
+ return;
2425
+ }
2426
+ try {
2427
+ gate(payload, (ready) => this.submitExternalSpan(ready));
2428
+ } catch (error) {
2429
+ warnDroppedExternalSpan(error);
2430
+ }
2431
+ }
2432
+ submitExternalSpan(payload) {
2433
+ const body = {
2434
+ ...payload,
2435
+ sdkVersion: __version__
2436
+ };
2437
+ delete body[ROOT_TRACE_FUNCTION_KEY_FIELD];
1918
2438
  this.getTraceTransport()?.submit(
1919
2439
  "external_span",
1920
- { ...payload, sdkVersion: __version__ },
2440
+ body,
1921
2441
  this.recordedMeta("external_span", payload, carrierRef(payload))
1922
2442
  );
1923
2443
  }
@@ -1929,6 +2449,18 @@ var init_http = __esm({
1929
2449
  */
1930
2450
  sendExternalTrace(rawPayload) {
1931
2451
  const payload = mergeCallerMetadataIntoTracePayload(rawPayload);
2452
+ const gate = this.externalTraceTransform;
2453
+ if (gate === void 0) {
2454
+ this.submitExternalTrace(payload);
2455
+ return;
2456
+ }
2457
+ try {
2458
+ gate(payload, (ready) => this.submitExternalTrace(ready));
2459
+ } catch (error) {
2460
+ warnDroppedExternalTrace(error);
2461
+ }
2462
+ }
2463
+ submitExternalTrace(payload) {
1932
2464
  this.getTraceTransport()?.submit(
1933
2465
  "external_trace",
1934
2466
  {
@@ -3642,6 +4174,7 @@ function finalizeTracePayload(payload) {
3642
4174
  // src/claudeAgentSdk.ts
3643
4175
  init_randomUuid();
3644
4176
  init_serialize();
4177
+ init_spanOrigin();
3645
4178
 
3646
4179
  // src/timestamp.ts
3647
4180
  var lastTimestampMicros = 0;
@@ -3849,6 +4382,7 @@ var BitfabClaudeAgentHandler = class {
3849
4382
  trace_id: spanInfo.traceId,
3850
4383
  started_at: spanInfo.startedAt,
3851
4384
  ended_at: spanInfo.endedAt ?? nowIso(),
4385
+ span_origin: makeSpanOrigin("claude-agent-sdk"),
3852
4386
  span_data: spanData
3853
4387
  };
3854
4388
  if (spanInfo.parentId !== null) {
@@ -5160,6 +5694,7 @@ init_constants();
5160
5694
  init_http();
5161
5695
  init_randomUuid();
5162
5696
  init_serialize();
5697
+ init_spanOrigin();
5163
5698
  var LANGSMITH_HIDDEN_TAG = "langsmith:hidden";
5164
5699
  var CHAIN_RUN_TYPES = /* @__PURE__ */ new Set(["chain", "parser", "prompt"]);
5165
5700
  var LANGGRAPH_METADATA_KEYS = [
@@ -5514,6 +6049,7 @@ var BitfabLangGraphCallbackHandler = class {
5514
6049
  trace_id: spanInfo.traceId,
5515
6050
  started_at: spanInfo.startedAt,
5516
6051
  ended_at: spanInfo.endedAt ?? nowIso2(),
6052
+ span_origin: makeSpanOrigin("langgraph"),
5517
6053
  span_data: spanData
5518
6054
  };
5519
6055
  if (spanInfo.parentId !== null) {
@@ -5775,14 +6311,14 @@ var BitfabLangGraphCallbackHandler = class {
5775
6311
  init_http();
5776
6312
  init_replayContext();
5777
6313
  var TOOL_RESULT_TAG = "__bitfabLangGraphToolResult";
5778
- function isRecord(value) {
6314
+ function isRecord3(value) {
5779
6315
  return typeof value === "object" && value !== null;
5780
6316
  }
5781
6317
  function isToolMessage(value) {
5782
- return isRecord(value) && value.lc_direct_tool_output === true && value.type === "tool" && (typeof value.content === "string" || Array.isArray(value.content));
6318
+ return isRecord3(value) && value.lc_direct_tool_output === true && value.type === "tool" && (typeof value.content === "string" || Array.isArray(value.content));
5783
6319
  }
5784
6320
  function isCommand(value) {
5785
- return isRecord(value) && value.lg_name === "Command";
6321
+ return isRecord3(value) && value.lg_name === "Command";
5786
6322
  }
5787
6323
  function encodeNested(value) {
5788
6324
  if (isToolMessage(value) || isCommand(value)) {
@@ -5791,7 +6327,7 @@ function encodeNested(value) {
5791
6327
  if (Array.isArray(value)) {
5792
6328
  return value.map(encodeNested);
5793
6329
  }
5794
- if (isRecord(value)) {
6330
+ if (isRecord3(value)) {
5795
6331
  return Object.fromEntries(
5796
6332
  Object.entries(value).map(([key, entry]) => [key, encodeNested(entry)])
5797
6333
  );
@@ -5814,17 +6350,17 @@ function encodeNativeToolResult(value) {
5814
6350
  }
5815
6351
  return {
5816
6352
  [TOOL_RESULT_TAG]: "command",
5817
- graph: isRecord(value) && typeof value.graph === "string" ? value.graph : void 0,
5818
- update: isRecord(value) ? encodeNested(value.update) : void 0,
5819
- resume: isRecord(value) ? encodeNested(value.resume) : void 0,
5820
- goto: isRecord(value) ? encodeNested(value.goto) : void 0
6353
+ graph: isRecord3(value) && typeof value.graph === "string" ? value.graph : void 0,
6354
+ update: isRecord3(value) ? encodeNested(value.update) : void 0,
6355
+ resume: isRecord3(value) ? encodeNested(value.resume) : void 0,
6356
+ goto: isRecord3(value) ? encodeNested(value.goto) : void 0
5821
6357
  };
5822
6358
  }
5823
6359
  function finalizeToolResult(value) {
5824
6360
  return isToolMessage(value) || isCommand(value) ? encodeNativeToolResult(value) : value;
5825
6361
  }
5826
6362
  function isEncodedToolResult(value) {
5827
- return isRecord(value) && typeof value[TOOL_RESULT_TAG] === "string";
6363
+ return isRecord3(value) && typeof value[TOOL_RESULT_TAG] === "string";
5828
6364
  }
5829
6365
  async function loadLangChainCore() {
5830
6366
  try {
@@ -5860,7 +6396,7 @@ async function reviveNested(value, toolCallId) {
5860
6396
  if (Array.isArray(value)) {
5861
6397
  return Promise.all(value.map((entry) => reviveNested(entry, toolCallId)));
5862
6398
  }
5863
- if (isRecord(value)) {
6399
+ if (isRecord3(value)) {
5864
6400
  const entries = await Promise.all(
5865
6401
  Object.entries(value).map(async ([key, entry]) => [
5866
6402
  key,
@@ -5885,16 +6421,16 @@ async function reviveToolResult(value, toolCallId) {
5885
6421
  ...value.artifact !== void 0 && {
5886
6422
  artifact: await reviveNested(value.artifact, toolCallId)
5887
6423
  },
5888
- ...isRecord(value.metadata) && {
6424
+ ...isRecord3(value.metadata) && {
5889
6425
  metadata: await reviveNested(value.metadata, toolCallId)
5890
6426
  },
5891
- ...isRecord(value.additionalKwargs) && {
6427
+ ...isRecord3(value.additionalKwargs) && {
5892
6428
  additional_kwargs: await reviveNested(
5893
6429
  value.additionalKwargs,
5894
6430
  toolCallId
5895
6431
  )
5896
6432
  },
5897
- ...isRecord(value.responseMetadata) && {
6433
+ ...isRecord3(value.responseMetadata) && {
5898
6434
  response_metadata: await reviveNested(
5899
6435
  value.responseMetadata,
5900
6436
  toolCallId
@@ -5964,8 +6500,8 @@ var BitfabLangGraphIntegration = class {
5964
6500
  get: (target, property) => {
5965
6501
  if (property === "invoke") {
5966
6502
  return async (input, ...rest) => {
5967
- const toolCallId = isRecord(input) && typeof input.id === "string" ? input.id : "";
5968
- const args = isRecord(input) && "args" in input ? input.args : input;
6503
+ const toolCallId = isRecord3(input) && typeof input.id === "string" ? input.id : "";
6504
+ const args = isRecord3(input) && "args" in input ? input.args : input;
5969
6505
  this.assertReplayToolResultExists(toolName, shouldMock);
5970
6506
  const execute = this.client.withSpan(
5971
6507
  this.traceFunctionKey,
@@ -5975,7 +6511,8 @@ var BitfabLangGraphIntegration = class {
5975
6511
  captureWhen: "nested",
5976
6512
  mockOnReplay: shouldMock,
5977
6513
  finalize: finalizeToolResult,
5978
- surface: "inherit"
6514
+ surface: "inherit",
6515
+ instrumentation: "langgraph"
5979
6516
  },
5980
6517
  async (_args) => await originalInvoke(input, ...rest)
5981
6518
  );
@@ -6018,7 +6555,12 @@ var BitfabLangGraphIntegration = class {
6018
6555
  wrapInvoke(fn) {
6019
6556
  return this.client.withSpan(
6020
6557
  this.traceFunctionKey,
6021
- { name: this.traceFunctionKey, type: "agent", surface: "inherit" },
6558
+ {
6559
+ name: this.traceFunctionKey,
6560
+ type: "agent",
6561
+ surface: "inherit",
6562
+ instrumentation: "langgraph"
6563
+ },
6022
6564
  fn
6023
6565
  );
6024
6566
  }
@@ -6074,7 +6616,8 @@ var BitfabOpenAIAgentHandler = class {
6074
6616
  const options_ = {
6075
6617
  type: "agent",
6076
6618
  finalize,
6077
- surface: "inherit"
6619
+ surface: "inherit",
6620
+ instrumentation: "openai-agents"
6078
6621
  };
6079
6622
  const traced = this.withSpanFn(
6080
6623
  this.traceFunctionKey,
@@ -6090,6 +6633,7 @@ var BitfabOpenAIAgentHandler = class {
6090
6633
  };
6091
6634
 
6092
6635
  // src/client.ts
6636
+ init_policyRefresh();
6093
6637
  init_randomUuid();
6094
6638
  init_replay();
6095
6639
 
@@ -6173,12 +6717,15 @@ function runWithSeedContext(ctx, fn) {
6173
6717
 
6174
6718
  // src/client.ts
6175
6719
  init_serialize();
6720
+ init_simulationPlan();
6721
+ init_spanOrigin();
6176
6722
  init_traceMetadata();
6177
6723
 
6178
6724
  // src/tracing.ts
6179
6725
  init_constants();
6180
6726
  init_http();
6181
6727
  init_randomUuid();
6728
+ init_spanOrigin();
6182
6729
  var BitfabOpenAITracingProcessor = class {
6183
6730
  /**
6184
6731
  * Initialize the tracing processor.
@@ -6380,6 +6927,7 @@ var BitfabOpenAITracingProcessor = class {
6380
6927
  * Build span payload for the external spans API.
6381
6928
  */
6382
6929
  buildSpanPayload(serializedSpan, errors) {
6930
+ serializedSpan.span_origin = makeSpanOrigin("openai-agents");
6383
6931
  const payload = {
6384
6932
  id: randomUuid(),
6385
6933
  type: "openai",
@@ -6509,7 +7057,8 @@ var BitfabVercelAiHandler = class {
6509
7057
  {
6510
7058
  type: "llm",
6511
7059
  finalize: (result) => summarizeGenerate(result ?? {}, label),
6512
- surface: "inherit"
7060
+ surface: "inherit",
7061
+ instrumentation: "vercel-ai"
6513
7062
  },
6514
7063
  () => doGenerate()
6515
7064
  );
@@ -6527,7 +7076,12 @@ var BitfabVercelAiHandler = class {
6527
7076
  // The wrapped fn returns immediately with the live stream, so the span
6528
7077
  // output cannot be read from the return value. `finalize` instead
6529
7078
  // awaits the summary the accumulator resolves once the stream drains.
6530
- { type: "llm", finalize: () => summary, surface: "inherit" },
7079
+ {
7080
+ type: "llm",
7081
+ finalize: () => summary,
7082
+ surface: "inherit",
7083
+ instrumentation: "vercel-ai"
7084
+ },
6531
7085
  async () => {
6532
7086
  const result = await doStream();
6533
7087
  const stream = result.stream.pipeThrough(
@@ -6545,6 +7099,19 @@ var BitfabVercelAiHandler = class {
6545
7099
  // src/client.ts
6546
7100
  init_warnOnce();
6547
7101
  var activeTraceStates = /* @__PURE__ */ new Map();
7102
+ function rootTraceFunctionKeyOf(payload) {
7103
+ const captured = payload[ROOT_TRACE_FUNCTION_KEY_FIELD];
7104
+ if (typeof captured === "string") {
7105
+ return captured;
7106
+ }
7107
+ const traceId = payload.traceId;
7108
+ const live = typeof traceId === "string" ? activeTraceStates.get(traceId)?.traceFunctionKey : void 0;
7109
+ if (typeof live === "string") {
7110
+ return live;
7111
+ }
7112
+ const own = payload.traceFunctionKey;
7113
+ return typeof own === "string" ? own : void 0;
7114
+ }
6548
7115
  var asyncLocalStorage = null;
6549
7116
  var SPAN_CONTEXT_STORAGE_SYMBOL = /* @__PURE__ */ Symbol.for("bitfab.spanContextStorage");
6550
7117
  var initializeAsyncContext = () => {
@@ -6949,6 +7516,14 @@ var Bitfab = class {
6949
7516
  serviceUrl: this.serviceUrl,
6950
7517
  timeout: this.timeout
6951
7518
  });
7519
+ this.simulationPlan = new SimulationPlan(
7520
+ this.httpClient,
7521
+ config.simulationPlan ?? true
7522
+ );
7523
+ this.httpClient.externalSpanTransform = (payload, submit) => this.applySimulationPlan(payload, submit);
7524
+ this.httpClient.externalTraceTransform = (payload, submit) => this.simulationPlan.sendTrace(payload, submit);
7525
+ this.httpClient.releaseHeldExternalSpans = (timeoutMs) => this.simulationPlan.release(timeoutMs);
7526
+ this.httpClient.stopSimulationPlan = () => this.simulationPlan.stop();
6952
7527
  this.datasets = new DatasetsClient(this.httpClient);
6953
7528
  this.traces = new TracesClient(this.httpClient);
6954
7529
  this.labels = new LabelsClient(this.httpClient);
@@ -7099,6 +7674,7 @@ var Bitfab = class {
7099
7674
  }
7100
7675
  createAutoTraceRoot(traceFunctionKey, name, options, fn) {
7101
7676
  const self = this;
7677
+ self.simulationPlan.refresh();
7102
7678
  const maxDepth = autoTraceLimit(
7103
7679
  options.maxDepth,
7104
7680
  DEFAULT_AUTO_TRACE_MAX_DEPTH
@@ -7114,7 +7690,8 @@ var Bitfab = class {
7114
7690
  name: options.name,
7115
7691
  nameFor: rootNameFor,
7116
7692
  type: options.type ?? "custom",
7117
- surface: "opt-out"
7693
+ surface: "opt-out",
7694
+ instrumentation: "trace"
7118
7695
  };
7119
7696
  const buildTracedRoot = (spanOptions) => this.withSpan(
7120
7697
  traceFunctionKey,
@@ -7125,6 +7702,7 @@ var Bitfab = class {
7125
7702
  traceFunctionKey
7126
7703
  );
7127
7704
  self.refreshAutoTraceCapturePolicy(traceFunctionKey);
7705
+ self.simulationPlan.refresh();
7128
7706
  let spansUsed = 0;
7129
7707
  let truncated = false;
7130
7708
  const warnTruncated = () => {
@@ -7201,6 +7779,7 @@ var Bitfab = class {
7201
7779
  type: nodeConfiguration?.type ?? "function",
7202
7780
  captureWhen: "nested",
7203
7781
  surface: "opt-out",
7782
+ instrumentation: "trace",
7204
7783
  functionId: definition.id,
7205
7784
  captureContent: nodeConfiguration !== void 0 || capturePolicy === void 0 || capturePolicy.has(definition.id),
7206
7785
  autoTraceDefinition: definition,
@@ -7232,6 +7811,7 @@ var Bitfab = class {
7232
7811
  type: "function",
7233
7812
  captureWhen: "nested",
7234
7813
  surface: "opt-out",
7814
+ instrumentation: "trace",
7235
7815
  captureContent: true,
7236
7816
  ...link !== void 0 && { nestedTrace: link }
7237
7817
  };
@@ -7297,38 +7877,36 @@ var Bitfab = class {
7297
7877
  Object.defineProperty(autoTraceRoot, "_bitfabWrappedFn", { value: fn });
7298
7878
  return autoTraceRoot;
7299
7879
  }
7880
+ applySimulationPlan(payload, submit) {
7881
+ this.simulationPlan.send(payload, rootTraceFunctionKeyOf(payload), submit);
7882
+ }
7300
7883
  refreshAutoTraceCapturePolicy(traceFunctionKey) {
7301
- const now = Date.now();
7302
- const state = this.autoTracePolicyRefreshes.get(traceFunctionKey) ?? {
7303
- refreshAfter: 0
7304
- };
7305
- if (state.inFlight || now < state.refreshAfter) {
7306
- return;
7307
- }
7308
- const request = this.httpClient.getAutoTracePolicy(
7309
- traceFunctionKey,
7310
- AUTO_TRACE_PROTOCOL
7311
- ).then((policy) => {
7312
- if (policy.protocol !== AUTO_TRACE_PROTOCOL) {
7313
- state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
7314
- return;
7315
- }
7316
- const functionIds = Array.isArray(policy.functionIds) ? policy.functionIds.filter(
7317
- (id) => typeof id === "string" && id.startsWith(`${AUTO_TRACE_PROTOCOL}:`)
7318
- ).slice(0, DEFAULT_AUTO_TRACE_MAX_SPANS) : [];
7319
- __setBitfabAutoTraceCapturePolicy(
7320
- this,
7321
- traceFunctionKey,
7322
- policy.revision === null ? void 0 : functionIds
7323
- );
7324
- state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_REFRESH_MS;
7325
- }).catch(() => {
7326
- state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
7327
- }).finally(() => {
7328
- state.inFlight = void 0;
7329
- });
7330
- state.inFlight = request;
7884
+ const state = this.autoTracePolicyRefreshes.get(traceFunctionKey) ?? new PolicyRefresh();
7331
7885
  this.autoTracePolicyRefreshes.set(traceFunctionKey, state);
7886
+ state.run(
7887
+ () => this.httpClient.getAutoTracePolicy(
7888
+ traceFunctionKey,
7889
+ AUTO_TRACE_PROTOCOL
7890
+ ),
7891
+ (policy) => {
7892
+ if (policy.protocol !== AUTO_TRACE_PROTOCOL) {
7893
+ state.hold(AUTO_TRACE_POLICY_RETRY_MS);
7894
+ return;
7895
+ }
7896
+ const functionIds = Array.isArray(policy.functionIds) ? policy.functionIds.filter(
7897
+ (id) => typeof id === "string" && id.startsWith(`${AUTO_TRACE_PROTOCOL}:`)
7898
+ ).slice(0, DEFAULT_AUTO_TRACE_MAX_SPANS) : [];
7899
+ __setBitfabAutoTraceCapturePolicy(
7900
+ this,
7901
+ traceFunctionKey,
7902
+ policy.revision === null ? void 0 : functionIds
7903
+ );
7904
+ state.hold(AUTO_TRACE_POLICY_REFRESH_MS);
7905
+ },
7906
+ () => {
7907
+ state.hold(AUTO_TRACE_POLICY_RETRY_MS);
7908
+ }
7909
+ );
7332
7910
  }
7333
7911
  /**
7334
7912
  * Flush and permanently close this client's tracing resources: its pending
@@ -7812,6 +8390,7 @@ var Bitfab = class {
7812
8390
  * @returns A wrapped function with the same signature that creates spans for inputs and outputs
7813
8391
  */
7814
8392
  withSpan(traceFunctionKey, optionsOrFn, maybeFn) {
8393
+ this.simulationPlan.refresh();
7815
8394
  const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
7816
8395
  const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
7817
8396
  const self = this;
@@ -7903,8 +8482,10 @@ var Bitfab = class {
7903
8482
  const testRunId = replayCtxAtStart?.testRunId ?? options.testRunId;
7904
8483
  if (isRootSpan && !activeTraceStates.has(traceId)) {
7905
8484
  const dbSnapshotRef = buildSnapshotRef(self.dbSnapshot, startedAt);
8485
+ self.simulationPlan.refresh();
7906
8486
  activeTraceStates.set(traceId, {
7907
8487
  traceId,
8488
+ traceFunctionKey,
7908
8489
  startedAt,
7909
8490
  contexts: [],
7910
8491
  ...testRunId !== void 0 && { testRunId },
@@ -7919,8 +8500,10 @@ var Bitfab = class {
7919
8500
  registeredTraceId = traceId;
7920
8501
  }
7921
8502
  const functionName = fn.name !== "" ? fn.name : void 0;
8503
+ const rootTraceFunctionKey = activeTraceStates.get(traceId)?.traceFunctionKey ?? traceFunctionKey;
7922
8504
  const baseSpanParams = {
7923
8505
  traceFunctionKey,
8506
+ rootTraceFunctionKey,
7924
8507
  functionName,
7925
8508
  spanName: options.name ?? options.nameFor?.(this) ?? qualifiedSpanName(this, functionName) ?? traceFunctionKey,
7926
8509
  traceId,
@@ -7929,6 +8512,7 @@ var Bitfab = class {
7929
8512
  inputs,
7930
8513
  startedAt,
7931
8514
  spanType: options.type ?? "custom",
8515
+ instrumentation: options.instrumentation ?? "span",
7932
8516
  functionId: options.functionId,
7933
8517
  captureContent: options.captureContent ?? true,
7934
8518
  autoTraceDefinition: options.autoTraceDefinition,
@@ -8344,6 +8928,7 @@ var Bitfab = class {
8344
8928
  * @returns A BitfabFunction instance for wrapping functions
8345
8929
  */
8346
8930
  getFunction(traceFunctionKey) {
8931
+ this.simulationPlan.refresh();
8347
8932
  return new BitfabFunction(this, traceFunctionKey);
8348
8933
  }
8349
8934
  /**
@@ -8431,6 +9016,7 @@ var Bitfab = class {
8431
9016
  trace_id: params.traceId,
8432
9017
  started_at: params.startedAt,
8433
9018
  ended_at: params.endedAt,
9019
+ span_origin: makeSpanOrigin(params.instrumentation),
8434
9020
  span_data: {
8435
9021
  name: params.spanName,
8436
9022
  type: params.spanType,
@@ -8491,6 +9077,9 @@ var Bitfab = class {
8491
9077
  source: "typescript-sdk-function",
8492
9078
  sourceTraceId: params.traceId,
8493
9079
  traceFunctionKey: params.traceFunctionKey,
9080
+ ...params.rootTraceFunctionKey !== void 0 && {
9081
+ [ROOT_TRACE_FUNCTION_KEY_FIELD]: params.rootTraceFunctionKey
9082
+ },
8494
9083
  rawSpan: externalSpan,
8495
9084
  ...params.testRunId && { testRunId: params.testRunId },
8496
9085
  ...params.mocked && { mocked: true },
@@ -8559,6 +9148,7 @@ var Bitfab = class {
8559
9148
  }
8560
9149
  activeTraceStates.set(traceId, {
8561
9150
  traceId,
9151
+ traceFunctionKey,
8562
9152
  startedAt,
8563
9153
  contexts: [],
8564
9154
  ingestionType: "seeded",
@@ -8568,6 +9158,7 @@ var Bitfab = class {
8568
9158
  try {
8569
9159
  this.sendWrapperSpan({
8570
9160
  traceFunctionKey,
9161
+ rootTraceFunctionKey: traceFunctionKey,
8571
9162
  spanName: options.spanName ?? traceFunctionKey,
8572
9163
  traceId,
8573
9164
  spanId: randomUuid(),
@@ -8577,6 +9168,7 @@ var Bitfab = class {
8577
9168
  startedAt,
8578
9169
  endedAt: startedAt,
8579
9170
  spanType: options.spanType ?? "agent",
9171
+ instrumentation: "span",
8580
9172
  captureContent: true
8581
9173
  });
8582
9174
  this.sendTraceCompletion({
@@ -8622,6 +9214,7 @@ var Bitfab = class {
8622
9214
  }
8623
9215
  activeTraceStates.set(traceId, {
8624
9216
  traceId,
9217
+ traceFunctionKey,
8625
9218
  startedAt: nowIsoTimestamp(),
8626
9219
  contexts: [],
8627
9220
  ingestionType: "seeded",