@bitfab/sdk 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
@@ -88,7 +88,7 @@ var __version__, __packageName__;
88
88
  var init_version_generated = __esm({
89
89
  "src/version.generated.ts"() {
90
90
  "use strict";
91
- __version__ = "0.53.0";
91
+ __version__ = "0.53.1";
92
92
  __packageName__ = "@bitfab/sdk";
93
93
  }
94
94
  });
@@ -514,8 +514,8 @@ function encodePayloadBody(payload) {
514
514
  const marker = { error: `payload_serialize_failed: ${message}` };
515
515
  return { body: JSON.stringify(marker), dropped, value: marker };
516
516
  }
517
- const isRecord2 = typeof sanitized === "object" && sanitized !== null && !Array.isArray(sanitized);
518
- if (dropped.length > 0 && isRecord2) {
517
+ const isRecord4 = typeof sanitized === "object" && sanitized !== null && !Array.isArray(sanitized);
518
+ if (dropped.length > 0 && isRecord4) {
519
519
  const obj = sanitized;
520
520
  const existing = Array.isArray(obj.errors) ? obj.errors : [];
521
521
  obj.errors = [
@@ -532,7 +532,7 @@ function encodePayloadBody(payload) {
532
532
  return {
533
533
  body: JSON.stringify(sanitized),
534
534
  dropped,
535
- value: isRecord2 ? sanitized : void 0
535
+ value: isRecord4 ? sanitized : void 0
536
536
  };
537
537
  }
538
538
  }
@@ -544,6 +544,456 @@ var init_serializePayload = __esm({
544
544
  }
545
545
  });
546
546
 
547
+ // src/policyRefresh.ts
548
+ var PolicyRefresh;
549
+ var init_policyRefresh = __esm({
550
+ "src/policyRefresh.ts"() {
551
+ "use strict";
552
+ PolicyRefresh = class {
553
+ constructor() {
554
+ this.refreshAfter = 0;
555
+ }
556
+ due() {
557
+ return this.inFlight === void 0 && Date.now() >= this.refreshAfter;
558
+ }
559
+ hold(durationMs) {
560
+ this.refreshAfter = Date.now() + durationMs;
561
+ }
562
+ releaseHold() {
563
+ this.refreshAfter = 0;
564
+ }
565
+ run(read2, onLoaded, onFailed) {
566
+ if (!this.due()) {
567
+ return;
568
+ }
569
+ let request;
570
+ try {
571
+ request = read2().then(onLoaded).catch(onFailed).finally(() => {
572
+ this.inFlight = void 0;
573
+ });
574
+ } catch (error) {
575
+ onFailed(error);
576
+ return;
577
+ }
578
+ this.inFlight = request;
579
+ }
580
+ };
581
+ }
582
+ });
583
+
584
+ // src/spanOrigin.ts
585
+ function isFrameworkInstrumentation(value) {
586
+ return typeof value === "string" && FRAMEWORK_INSTRUMENTATION_SET.has(value);
587
+ }
588
+ function makeSpanOrigin(instrumentation) {
589
+ return {
590
+ name: SPAN_ORIGIN_NAME,
591
+ version: __version__,
592
+ instrumentation: { name: instrumentation }
593
+ };
594
+ }
595
+ function isRecord(value) {
596
+ return typeof value === "object" && value !== null && !Array.isArray(value);
597
+ }
598
+ function spanOriginOf(payload) {
599
+ const rawSpan = payload.rawSpan;
600
+ if (!isRecord(rawSpan)) {
601
+ return void 0;
602
+ }
603
+ const origin = rawSpan.span_origin;
604
+ if (!isRecord(origin) || !isRecord(origin.instrumentation)) {
605
+ return void 0;
606
+ }
607
+ const { name, version } = origin;
608
+ const instrumentation = origin.instrumentation.name;
609
+ if (typeof name !== "string" || typeof version !== "string" || typeof instrumentation !== "string" || !SPAN_INSTRUMENTATIONS.includes(instrumentation)) {
610
+ return void 0;
611
+ }
612
+ return {
613
+ name,
614
+ version,
615
+ instrumentation: { name: instrumentation }
616
+ };
617
+ }
618
+ function spanInstrumentationOf(payload) {
619
+ return spanOriginOf(payload)?.instrumentation.name;
620
+ }
621
+ function recordedByFramework(payload) {
622
+ return isFrameworkInstrumentation(spanInstrumentationOf(payload));
623
+ }
624
+ var SPAN_ORIGIN_NAME, SPAN_INSTRUMENTATIONS, FRAMEWORK_INSTRUMENTATIONS, FRAMEWORK_INSTRUMENTATION_SET;
625
+ var init_spanOrigin = __esm({
626
+ "src/spanOrigin.ts"() {
627
+ "use strict";
628
+ init_constants();
629
+ SPAN_ORIGIN_NAME = "bitfab.sdk.typescript";
630
+ SPAN_INSTRUMENTATIONS = [
631
+ "span",
632
+ "trace",
633
+ "openai-agents",
634
+ "langgraph",
635
+ "claude-agent-sdk",
636
+ "vercel-ai"
637
+ ];
638
+ FRAMEWORK_INSTRUMENTATIONS = [
639
+ "openai-agents",
640
+ "langgraph",
641
+ "claude-agent-sdk",
642
+ "vercel-ai"
643
+ ];
644
+ FRAMEWORK_INSTRUMENTATION_SET = new Set(
645
+ FRAMEWORK_INSTRUMENTATIONS
646
+ );
647
+ }
648
+ });
649
+
650
+ // src/unrefTimer.ts
651
+ function unrefTimer(timer) {
652
+ const handle = timer;
653
+ if (typeof handle.unref === "function") {
654
+ handle.unref();
655
+ }
656
+ }
657
+ var init_unrefTimer = __esm({
658
+ "src/unrefTimer.ts"() {
659
+ "use strict";
660
+ }
661
+ });
662
+
663
+ // src/simulationPlan.ts
664
+ function planWaitSliceMs(timeoutMs) {
665
+ return Math.min(SIMULATION_PLAN_READ_TIMEOUT_MS, Math.max(timeoutMs, 0) / 2);
666
+ }
667
+ function parseSimulationPlan(body) {
668
+ if (typeof body !== "object" || body === null) {
669
+ return null;
670
+ }
671
+ const nodes = body.nodes;
672
+ if (!Array.isArray(nodes)) {
673
+ return null;
674
+ }
675
+ const contentOff = /* @__PURE__ */ new Map();
676
+ for (const node of nodes) {
677
+ if (typeof node !== "object" || node === null) {
678
+ continue;
679
+ }
680
+ const { traceFunctionKey, name, captureContent } = node;
681
+ if (typeof traceFunctionKey !== "string" || typeof name !== "string" || typeof captureContent !== "boolean") {
682
+ continue;
683
+ }
684
+ if (captureContent) {
685
+ continue;
686
+ }
687
+ const names = contentOff.get(traceFunctionKey) ?? /* @__PURE__ */ new Set();
688
+ names.add(name);
689
+ contentOff.set(traceFunctionKey, names);
690
+ }
691
+ return contentOff;
692
+ }
693
+ function traceIdOf(payload) {
694
+ const traceId = payload.traceId;
695
+ if (typeof traceId === "string") {
696
+ return traceId;
697
+ }
698
+ const id = payload.id;
699
+ return typeof id === "string" ? id : void 0;
700
+ }
701
+ function isRecord2(value) {
702
+ return typeof value === "object" && value !== null;
703
+ }
704
+ function rawSpanOf(payload) {
705
+ return isRecord2(payload.rawSpan) ? payload.rawSpan : void 0;
706
+ }
707
+ function spanDataOf(payload) {
708
+ const spanData = rawSpanOf(payload)?.span_data;
709
+ return isRecord2(spanData) ? spanData : void 0;
710
+ }
711
+ function spanNameOf(payload) {
712
+ const name = spanDataOf(payload)?.name;
713
+ return typeof name === "string" ? name : void 0;
714
+ }
715
+ function stripContent(payload) {
716
+ const rawSpan = rawSpanOf(payload);
717
+ const spanData = spanDataOf(payload);
718
+ if (rawSpan === void 0 || spanData === void 0) {
719
+ return payload;
720
+ }
721
+ const kept = { ...spanData };
722
+ for (const key of CONTENT_KEYS) {
723
+ delete kept[key];
724
+ }
725
+ kept[CONTENT_OFF_KEY] = true;
726
+ return { ...payload, rawSpan: { ...rawSpan, span_data: kept } };
727
+ }
728
+ function simulationPlanEnvDisabled() {
729
+ const value = readEnv(DISABLE_SIMULATION_PLAN_ENV);
730
+ return typeof value === "string" && value.trim() !== "";
731
+ }
732
+ function missingSimulationPlanEndpoint(error) {
733
+ return error instanceof BitfabError && error.status === 404;
734
+ }
735
+ 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;
736
+ var init_simulationPlan = __esm({
737
+ "src/simulationPlan.ts"() {
738
+ "use strict";
739
+ init_errors();
740
+ init_policyRefresh();
741
+ init_readEnv();
742
+ init_spanOrigin();
743
+ init_unrefTimer();
744
+ init_warnOnce();
745
+ SIMULATION_PLAN_REFRESH_MS = 6e4;
746
+ SIMULATION_PLAN_RETRY_MS = 1e4;
747
+ SIMULATION_PLAN_READ_TIMEOUT_MS = 5e3;
748
+ SIMULATION_PLAN_MAX_HELD = 1e3;
749
+ DISABLE_SIMULATION_PLAN_ENV = "BITFAB_DISABLE_SIM_PLAN";
750
+ ROOT_TRACE_FUNCTION_KEY_FIELD = "rootTraceFunctionKey";
751
+ CONTENT_OFF_KEY = "content_off_by_simulation_plan";
752
+ CONTENT_KEYS = ["input", "input_meta", "output", "output_meta"];
753
+ SimulationPlan = class {
754
+ constructor(source, enabled = true) {
755
+ this.source = source;
756
+ this.enabled = enabled;
757
+ this.policyRefresh = new PolicyRefresh();
758
+ this.retryPending = false;
759
+ this.waitingForFirstLoad = 0;
760
+ this.held = [];
761
+ this.droppedWhileHolding = 0;
762
+ this.stopped = false;
763
+ this.loaded = new Promise((resolve) => {
764
+ this.resolveLoaded = resolve;
765
+ });
766
+ }
767
+ disabled() {
768
+ return !this.enabled || simulationPlanEnvDisabled();
769
+ }
770
+ refresh() {
771
+ if (this.stopped || this.disabled()) {
772
+ return;
773
+ }
774
+ this.policyRefresh.run(
775
+ () => this.source.getSimulationPlan(),
776
+ (body) => {
777
+ const parsed = parseSimulationPlan(body);
778
+ if (parsed === null) {
779
+ this.scheduleRetry(
780
+ "sim-plan-unreadable",
781
+ "the sim plan response was not understood"
782
+ );
783
+ return;
784
+ }
785
+ this.markLoaded(parsed);
786
+ },
787
+ (error) => {
788
+ if (missingSimulationPlanEndpoint(error)) {
789
+ this.markLoaded(/* @__PURE__ */ new Map());
790
+ return;
791
+ }
792
+ this.scheduleRetry(
793
+ "sim-plan-unavailable",
794
+ `could not read the sim plan: ${error instanceof Error ? error.message : String(error)}`
795
+ );
796
+ }
797
+ );
798
+ }
799
+ markLoaded(parsed) {
800
+ if (this.stopped) {
801
+ return;
802
+ }
803
+ this.contentOffByKey = parsed;
804
+ this.policyRefresh.hold(SIMULATION_PLAN_REFRESH_MS);
805
+ this.retryPending = false;
806
+ this.clearRetryTimer();
807
+ this.resolveLoaded?.();
808
+ this.resolveLoaded = void 0;
809
+ this.releaseHeld();
810
+ }
811
+ scheduleRetry(warnKey, reason) {
812
+ if (this.stopped) {
813
+ return;
814
+ }
815
+ this.policyRefresh.hold(SIMULATION_PLAN_RETRY_MS);
816
+ if (this.contentOffByKey !== void 0) {
817
+ return;
818
+ }
819
+ this.retryPending = true;
820
+ warnOnce(
821
+ warnKey,
822
+ `${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.`
823
+ );
824
+ this.armRetry();
825
+ }
826
+ holdsWork() {
827
+ return this.held.length > 0 || this.waitingForFirstLoad > 0;
828
+ }
829
+ armRetry() {
830
+ if (this.stopped || !this.retryPending || this.retryTimer !== void 0 || !this.holdsWork()) {
831
+ return;
832
+ }
833
+ const timer = setTimeout(() => {
834
+ this.retryTimer = void 0;
835
+ this.policyRefresh.releaseHold();
836
+ this.refresh();
837
+ }, SIMULATION_PLAN_RETRY_MS);
838
+ unrefTimer(timer);
839
+ this.retryTimer = timer;
840
+ }
841
+ clearRetryTimer() {
842
+ if (this.retryTimer !== void 0) {
843
+ clearTimeout(this.retryTimer);
844
+ this.retryTimer = void 0;
845
+ }
846
+ }
847
+ syncRetryTimer() {
848
+ if (this.holdsWork()) {
849
+ return;
850
+ }
851
+ this.clearRetryTimer();
852
+ }
853
+ firstLoad() {
854
+ if (this.contentOffByKey !== void 0 || this.stopped || this.disabled()) {
855
+ return void 0;
856
+ }
857
+ return this.loaded;
858
+ }
859
+ send(payload, traceFunctionKey, submit) {
860
+ this.refresh();
861
+ if (this.stopped || this.disabled() || traceFunctionKey === void 0 || spanNameOf(payload) === void 0 || recordedByFramework(payload)) {
862
+ submit(payload);
863
+ return;
864
+ }
865
+ if (this.contentOffByKey === void 0) {
866
+ this.hold({ payload, traceFunctionKey, submit });
867
+ return;
868
+ }
869
+ this.submitEntry({ payload, traceFunctionKey, submit });
870
+ }
871
+ sendTrace(payload, submit) {
872
+ this.refresh();
873
+ if (this.stopped || this.disabled() || this.contentOffByKey !== void 0 || !this.holdsSpanOfTrace(traceIdOf(payload))) {
874
+ submit(payload);
875
+ return;
876
+ }
877
+ this.hold({ payload, traceFunctionKey: void 0, submit });
878
+ }
879
+ holdsSpanOfTrace(traceId) {
880
+ if (traceId === void 0) {
881
+ return false;
882
+ }
883
+ return this.held.some(
884
+ (entry) => entry.traceFunctionKey !== void 0 && traceIdOf(entry.payload) === traceId
885
+ );
886
+ }
887
+ hold(entry) {
888
+ this.held.push(entry);
889
+ while (this.held.length > SIMULATION_PLAN_MAX_HELD) {
890
+ this.held.shift();
891
+ this.droppedWhileHolding += 1;
892
+ }
893
+ this.armRetry();
894
+ }
895
+ submitEntry(entry) {
896
+ try {
897
+ entry.submit(
898
+ entry.traceFunctionKey === void 0 ? entry.payload : this.apply(entry.payload, entry.traceFunctionKey)
899
+ );
900
+ } catch (error) {
901
+ warnOnce(
902
+ "sim-plan-held-span-dropped",
903
+ `a span held for the sim plan was dropped when released: ${error instanceof Error ? error.message : String(error)}`
904
+ );
905
+ }
906
+ }
907
+ releaseHeld() {
908
+ const held = this.held;
909
+ this.held = [];
910
+ this.syncRetryTimer();
911
+ this.warnDropped();
912
+ for (const entry of held) {
913
+ this.submitEntry(entry);
914
+ }
915
+ }
916
+ warnDropped() {
917
+ if (this.droppedWhileHolding === 0) {
918
+ return;
919
+ }
920
+ const dropped = this.droppedWhileHolding;
921
+ this.droppedWhileHolding = 0;
922
+ warnOnce(
923
+ "sim-plan-held-overflow",
924
+ `${dropped} record(s) were dropped while the sim plan was still loading; at most ${SIMULATION_PLAN_MAX_HELD} are held per client.`
925
+ );
926
+ }
927
+ warnNeverLoaded() {
928
+ if (this.held.length === 0) {
929
+ return;
930
+ }
931
+ warnOnce(
932
+ "sim-plan-never-loaded",
933
+ `${this.held.length} record(s) were not sent because the sim plan never loaded`
934
+ );
935
+ }
936
+ async release(timeoutMs) {
937
+ this.refresh();
938
+ if (this.holdsWork()) {
939
+ await this.waitForFirstLoad(timeoutMs);
940
+ }
941
+ this.warnNeverLoaded();
942
+ this.warnDropped();
943
+ }
944
+ waitForFirstLoad(timeoutMs) {
945
+ const firstLoad = this.firstLoad();
946
+ if (firstLoad === void 0) {
947
+ return Promise.resolve();
948
+ }
949
+ this.waitingForFirstLoad += 1;
950
+ this.armRetry();
951
+ return new Promise((resolve) => {
952
+ let settled2 = false;
953
+ const finish = () => {
954
+ if (settled2) {
955
+ return;
956
+ }
957
+ settled2 = true;
958
+ this.waitingForFirstLoad -= 1;
959
+ this.syncRetryTimer();
960
+ resolve();
961
+ };
962
+ const timer = setTimeout(finish, Math.max(timeoutMs, 0));
963
+ void firstLoad.then(() => {
964
+ clearTimeout(timer);
965
+ finish();
966
+ });
967
+ });
968
+ }
969
+ stop() {
970
+ if (this.stopped) {
971
+ return;
972
+ }
973
+ this.stopped = true;
974
+ this.retryPending = false;
975
+ this.clearRetryTimer();
976
+ this.warnNeverLoaded();
977
+ this.held = [];
978
+ this.warnDropped();
979
+ }
980
+ contentOff(traceFunctionKey, spanName) {
981
+ return this.contentOffByKey?.get(traceFunctionKey)?.has(spanName) === true;
982
+ }
983
+ apply(payload, traceFunctionKey) {
984
+ if (recordedByFramework(payload)) {
985
+ return payload;
986
+ }
987
+ const name = spanNameOf(payload);
988
+ if (name === void 0 || !this.contentOff(traceFunctionKey, name)) {
989
+ return payload;
990
+ }
991
+ return stripContent(payload);
992
+ }
993
+ };
994
+ }
995
+ });
996
+
547
997
  // src/traceMetadata.ts
548
998
  function findRecord(traceId) {
549
999
  return activeRecords.get(traceId) ?? completedRecords.get(traceId);
@@ -660,19 +1110,6 @@ var init_transportTypes = __esm({
660
1110
  }
661
1111
  });
662
1112
 
663
- // src/unrefTimer.ts
664
- function unrefTimer(timer) {
665
- const handle = timer;
666
- if (typeof handle.unref === "function") {
667
- handle.unref();
668
- }
669
- }
670
- var init_unrefTimer = __esm({
671
- "src/unrefTimer.ts"() {
672
- "use strict";
673
- }
674
- });
675
-
676
1113
  // src/otel.ts
677
1114
  function readBoundedIntEnv(name, max, fallback, warnKey) {
678
1115
  const raw = readEnv(name);
@@ -1323,6 +1760,17 @@ __export(http_exports, {
1323
1760
  parseRetryAfterMs: () => parseRetryAfterMs,
1324
1761
  serializePayloadBody: () => serializePayloadBody
1325
1762
  });
1763
+ async function releaseHeldExternalSpans(timeoutMs) {
1764
+ const deadline = Date.now() + Math.max(timeoutMs, 0);
1765
+ for (const client of [...liveHttpClients]) {
1766
+ await client.releaseHeldExternalSpans?.(Math.max(0, deadline - Date.now()));
1767
+ }
1768
+ }
1769
+ function stopSimulationPlans() {
1770
+ for (const client of [...liveHttpClients]) {
1771
+ client.stopSimulationPlan?.();
1772
+ }
1773
+ }
1326
1774
  function awaitOnExit(promise) {
1327
1775
  pendingTracePromises.add(promise);
1328
1776
  void promise.finally(() => {
@@ -1333,7 +1781,10 @@ function awaitOnExit(promise) {
1333
1781
  }
1334
1782
  async function flushTraces(timeoutMs = 5e3) {
1335
1783
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1336
- const requestsFlushed = await awaitPendingRequests(timeoutMs);
1784
+ await releaseHeldExternalSpans(planWaitSliceMs(timeoutMs));
1785
+ const requestsFlushed = await awaitPendingRequests(
1786
+ Math.max(0, deadline - Date.now())
1787
+ );
1337
1788
  const transportsFlushed = await flushTraceTransports(
1338
1789
  Math.max(0, deadline - Date.now())
1339
1790
  );
@@ -1452,7 +1903,22 @@ function sourceTraceIdOf(payload) {
1452
1903
  const id = rawTrace?.id;
1453
1904
  return typeof id === "string" ? id : void 0;
1454
1905
  }
1455
- 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;
1906
+ function describeError(error) {
1907
+ return error instanceof Error ? error.message : String(error);
1908
+ }
1909
+ function warnDroppedExternalSpan(error) {
1910
+ warnOnce(
1911
+ "external-span-dropped",
1912
+ `a span was dropped because the send step failed: ${describeError(error)}`
1913
+ );
1914
+ }
1915
+ function warnDroppedExternalTrace(error) {
1916
+ warnOnce(
1917
+ "external-trace-dropped",
1918
+ `a trace was dropped because the send step failed: ${describeError(error)}`
1919
+ );
1920
+ }
1921
+ 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;
1456
1922
  var init_http = __esm({
1457
1923
  "src/http.ts"() {
1458
1924
  "use strict";
@@ -1461,6 +1927,7 @@ var init_http = __esm({
1461
1927
  init_errors();
1462
1928
  init_replayContext();
1463
1929
  init_serializePayload();
1930
+ init_simulationPlan();
1464
1931
  init_traceMetadata();
1465
1932
  init_transport();
1466
1933
  init_transportTypes();
@@ -1473,6 +1940,7 @@ var init_http = __esm({
1473
1940
  EXIT_FLUSH_TIMEOUT_MS = 5e3;
1474
1941
  DEFAULT_LIFECYCLE_TIMEOUT_MS2 = 3e4;
1475
1942
  pendingTracePromises = /* @__PURE__ */ new Set();
1943
+ liveHttpClients = /* @__PURE__ */ new Set();
1476
1944
  if (typeof process !== "undefined" && process.versions != null && process.versions.node != null) {
1477
1945
  let isFlushing = false;
1478
1946
  process.on("beforeExit", () => {
@@ -1480,12 +1948,27 @@ var init_http = __esm({
1480
1948
  return;
1481
1949
  }
1482
1950
  isFlushing = true;
1483
- void Promise.allSettled([
1484
- ...Array.from(pendingTracePromises).map((p) => p.catch(() => {
1485
- })),
1486
- shutdownTraceTransports(EXIT_FLUSH_TIMEOUT_MS).catch(() => false)
1487
- ]).then(() => {
1951
+ const planWaitMs = SIMULATION_PLAN_READ_TIMEOUT_MS;
1952
+ const stopFlushing = () => {
1488
1953
  isFlushing = false;
1954
+ };
1955
+ const deadline = setTimeout(
1956
+ stopFlushing,
1957
+ EXIT_FLUSH_TIMEOUT_MS + planWaitMs
1958
+ );
1959
+ unrefTimer(deadline);
1960
+ void releaseHeldExternalSpans(planWaitMs).catch(() => {
1961
+ }).then(() => {
1962
+ stopSimulationPlans();
1963
+ }).then(
1964
+ () => Promise.allSettled([
1965
+ ...Array.from(pendingTracePromises).map((p) => p.catch(() => {
1966
+ })),
1967
+ shutdownTraceTransports(EXIT_FLUSH_TIMEOUT_MS).catch(() => false)
1968
+ ])
1969
+ ).then(() => {
1970
+ clearTimeout(deadline);
1971
+ stopFlushing();
1489
1972
  });
1490
1973
  });
1491
1974
  }
@@ -1504,6 +1987,7 @@ var init_http = __esm({
1504
1987
  this.apiKey = config.apiKey;
1505
1988
  this.serviceUrl = config.serviceUrl;
1506
1989
  this.timeout = config.timeout ?? 12e4;
1990
+ liveHttpClients.add(this);
1507
1991
  }
1508
1992
  /**
1509
1993
  * Resolve the API key at the moment it is needed (request time), invoking
@@ -1701,9 +2185,14 @@ var init_http = __esm({
1701
2185
  * attributing its timeout here would fail a client whose own work succeeded.
1702
2186
  */
1703
2187
  async settleDeferredWork(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS2) {
2188
+ const deadline = Date.now() + Math.max(timeoutMs, 0);
2189
+ await this.releaseHeldExternalSpans?.(planWaitSliceMs(timeoutMs));
1704
2190
  await replayContextReady.catch(() => {
1705
2191
  });
1706
- return waitForPromises(Array.from(this.deferredWork), timeoutMs);
2192
+ return waitForPromises(
2193
+ Array.from(this.deferredWork),
2194
+ Math.max(0, deadline - Date.now())
2195
+ );
1707
2196
  }
1708
2197
  /**
1709
2198
  * Wait for spans queued by this client to be delivered, within one deadline.
@@ -1711,7 +2200,9 @@ var init_http = __esm({
1711
2200
  */
1712
2201
  async waitForPendingRequests(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS2) {
1713
2202
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1714
- const settled2 = await this.settleDeferredWork(timeoutMs);
2203
+ const settled2 = await this.settleDeferredWork(
2204
+ Math.max(0, deadline - Date.now())
2205
+ );
1715
2206
  const flushed = await this.traceTransport?.flush(Math.max(0, deadline - Date.now())) ?? true;
1716
2207
  return settled2 && flushed;
1717
2208
  }
@@ -1726,6 +2217,13 @@ var init_http = __esm({
1726
2217
  }
1727
2218
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1728
2219
  this.closing = (async () => {
2220
+ await this.releaseHeldExternalSpans?.(planWaitSliceMs(timeoutMs));
2221
+ this.stopSimulationPlan?.();
2222
+ this.externalSpanTransform = void 0;
2223
+ this.externalTraceTransform = void 0;
2224
+ this.releaseHeldExternalSpans = void 0;
2225
+ this.stopSimulationPlan = void 0;
2226
+ liveHttpClients.delete(this);
1729
2227
  const settled2 = await this.settleDeferredWork(
1730
2228
  Math.max(0, deadline - Date.now())
1731
2229
  );
@@ -1837,6 +2335,13 @@ var init_http = __esm({
1837
2335
  protocol
1838
2336
  });
1839
2337
  }
2338
+ async getSimulationPlan() {
2339
+ return this.get(
2340
+ "/api/sdk/sim-plan",
2341
+ SIMULATION_PLAN_READ_TIMEOUT_MS,
2342
+ { Connection: "close" }
2343
+ );
2344
+ }
1840
2345
  async getTraceSpan(traceId, lookup) {
1841
2346
  const searchParams = new URLSearchParams();
1842
2347
  if (lookup.id !== void 0) {
@@ -1853,14 +2358,18 @@ var init_http = __esm({
1853
2358
  * GET a JSON endpoint on the service with the client's API key. Throws a
1854
2359
  * `BitfabError` carrying the status text for any non-2xx response.
1855
2360
  */
1856
- async get(endpoint) {
2361
+ async get(endpoint, timeoutMs, extraHeaders) {
1857
2362
  const url = `${this.serviceUrl}${endpoint}`;
2363
+ const timeout = timeoutMs ?? this.timeout;
1858
2364
  const controller = new AbortController();
1859
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2365
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
1860
2366
  try {
1861
2367
  const response = await fetch(url, {
1862
2368
  method: "GET",
1863
- headers: { Authorization: `Bearer ${this.resolveApiKey() ?? ""}` },
2369
+ headers: {
2370
+ Authorization: `Bearer ${this.resolveApiKey() ?? ""}`,
2371
+ ...extraHeaders
2372
+ },
1864
2373
  signal: controller.signal
1865
2374
  });
1866
2375
  if (!response.ok) {
@@ -1879,7 +2388,7 @@ var init_http = __esm({
1879
2388
  }
1880
2389
  if (error instanceof Error) {
1881
2390
  if (error.name === "AbortError") {
1882
- throw new BitfabError(`Request timed out after ${this.timeout}ms`);
2391
+ throw new BitfabError(`Request timed out after ${timeout}ms`);
1883
2392
  }
1884
2393
  throw new BitfabError(error.message);
1885
2394
  }
@@ -1906,16 +2415,27 @@ var init_http = __esm({
1906
2415
  carrierMeta("internal_trace", body, void 0)
1907
2416
  );
1908
2417
  }
1909
- /**
1910
- * Queue an external span (from withSpan wrapper or OpenAI tracing) onto this
1911
- * client's batching transport. Fire-and-forget: the transport owns delivery,
1912
- * so callers await `flushTraces()` or `close()` rather than a per-span
1913
- * promise.
1914
- */
1915
2418
  sendExternalSpan(payload) {
2419
+ const gate = this.externalSpanTransform;
2420
+ if (gate === void 0) {
2421
+ this.submitExternalSpan(payload);
2422
+ return;
2423
+ }
2424
+ try {
2425
+ gate(payload, (ready) => this.submitExternalSpan(ready));
2426
+ } catch (error) {
2427
+ warnDroppedExternalSpan(error);
2428
+ }
2429
+ }
2430
+ submitExternalSpan(payload) {
2431
+ const body = {
2432
+ ...payload,
2433
+ sdkVersion: __version__
2434
+ };
2435
+ delete body[ROOT_TRACE_FUNCTION_KEY_FIELD];
1916
2436
  this.getTraceTransport()?.submit(
1917
2437
  "external_span",
1918
- { ...payload, sdkVersion: __version__ },
2438
+ body,
1919
2439
  this.recordedMeta("external_span", payload, carrierRef(payload))
1920
2440
  );
1921
2441
  }
@@ -1927,6 +2447,18 @@ var init_http = __esm({
1927
2447
  */
1928
2448
  sendExternalTrace(rawPayload) {
1929
2449
  const payload = mergeCallerMetadataIntoTracePayload(rawPayload);
2450
+ const gate = this.externalTraceTransform;
2451
+ if (gate === void 0) {
2452
+ this.submitExternalTrace(payload);
2453
+ return;
2454
+ }
2455
+ try {
2456
+ gate(payload, (ready) => this.submitExternalTrace(ready));
2457
+ } catch (error) {
2458
+ warnDroppedExternalTrace(error);
2459
+ }
2460
+ }
2461
+ submitExternalTrace(payload) {
1930
2462
  this.getTraceTransport()?.submit(
1931
2463
  "external_trace",
1932
2464
  {
@@ -3647,6 +4179,7 @@ function finalizeTracePayload(payload) {
3647
4179
  // src/claudeAgentSdk.ts
3648
4180
  init_randomUuid();
3649
4181
  init_serialize();
4182
+ init_spanOrigin();
3650
4183
 
3651
4184
  // src/timestamp.ts
3652
4185
  var lastTimestampMicros = 0;
@@ -3854,6 +4387,7 @@ var BitfabClaudeAgentHandler = class {
3854
4387
  trace_id: spanInfo.traceId,
3855
4388
  started_at: spanInfo.startedAt,
3856
4389
  ended_at: spanInfo.endedAt ?? nowIso(),
4390
+ span_origin: makeSpanOrigin("claude-agent-sdk"),
3857
4391
  span_data: spanData
3858
4392
  };
3859
4393
  if (spanInfo.parentId !== null) {
@@ -5165,6 +5699,7 @@ init_constants();
5165
5699
  init_http();
5166
5700
  init_randomUuid();
5167
5701
  init_serialize();
5702
+ init_spanOrigin();
5168
5703
  var LANGSMITH_HIDDEN_TAG = "langsmith:hidden";
5169
5704
  var CHAIN_RUN_TYPES = /* @__PURE__ */ new Set(["chain", "parser", "prompt"]);
5170
5705
  var LANGGRAPH_METADATA_KEYS = [
@@ -5519,6 +6054,7 @@ var BitfabLangGraphCallbackHandler = class {
5519
6054
  trace_id: spanInfo.traceId,
5520
6055
  started_at: spanInfo.startedAt,
5521
6056
  ended_at: spanInfo.endedAt ?? nowIso2(),
6057
+ span_origin: makeSpanOrigin("langgraph"),
5522
6058
  span_data: spanData
5523
6059
  };
5524
6060
  if (spanInfo.parentId !== null) {
@@ -5780,14 +6316,14 @@ var BitfabLangGraphCallbackHandler = class {
5780
6316
  init_http();
5781
6317
  init_replayContext();
5782
6318
  var TOOL_RESULT_TAG = "__bitfabLangGraphToolResult";
5783
- function isRecord(value) {
6319
+ function isRecord3(value) {
5784
6320
  return typeof value === "object" && value !== null;
5785
6321
  }
5786
6322
  function isToolMessage(value) {
5787
- return isRecord(value) && value.lc_direct_tool_output === true && value.type === "tool" && (typeof value.content === "string" || Array.isArray(value.content));
6323
+ return isRecord3(value) && value.lc_direct_tool_output === true && value.type === "tool" && (typeof value.content === "string" || Array.isArray(value.content));
5788
6324
  }
5789
6325
  function isCommand(value) {
5790
- return isRecord(value) && value.lg_name === "Command";
6326
+ return isRecord3(value) && value.lg_name === "Command";
5791
6327
  }
5792
6328
  function encodeNested(value) {
5793
6329
  if (isToolMessage(value) || isCommand(value)) {
@@ -5796,7 +6332,7 @@ function encodeNested(value) {
5796
6332
  if (Array.isArray(value)) {
5797
6333
  return value.map(encodeNested);
5798
6334
  }
5799
- if (isRecord(value)) {
6335
+ if (isRecord3(value)) {
5800
6336
  return Object.fromEntries(
5801
6337
  Object.entries(value).map(([key, entry]) => [key, encodeNested(entry)])
5802
6338
  );
@@ -5819,17 +6355,17 @@ function encodeNativeToolResult(value) {
5819
6355
  }
5820
6356
  return {
5821
6357
  [TOOL_RESULT_TAG]: "command",
5822
- graph: isRecord(value) && typeof value.graph === "string" ? value.graph : void 0,
5823
- update: isRecord(value) ? encodeNested(value.update) : void 0,
5824
- resume: isRecord(value) ? encodeNested(value.resume) : void 0,
5825
- goto: isRecord(value) ? encodeNested(value.goto) : void 0
6358
+ graph: isRecord3(value) && typeof value.graph === "string" ? value.graph : void 0,
6359
+ update: isRecord3(value) ? encodeNested(value.update) : void 0,
6360
+ resume: isRecord3(value) ? encodeNested(value.resume) : void 0,
6361
+ goto: isRecord3(value) ? encodeNested(value.goto) : void 0
5826
6362
  };
5827
6363
  }
5828
6364
  function finalizeToolResult(value) {
5829
6365
  return isToolMessage(value) || isCommand(value) ? encodeNativeToolResult(value) : value;
5830
6366
  }
5831
6367
  function isEncodedToolResult(value) {
5832
- return isRecord(value) && typeof value[TOOL_RESULT_TAG] === "string";
6368
+ return isRecord3(value) && typeof value[TOOL_RESULT_TAG] === "string";
5833
6369
  }
5834
6370
  async function loadLangChainCore() {
5835
6371
  try {
@@ -5865,7 +6401,7 @@ async function reviveNested(value, toolCallId) {
5865
6401
  if (Array.isArray(value)) {
5866
6402
  return Promise.all(value.map((entry) => reviveNested(entry, toolCallId)));
5867
6403
  }
5868
- if (isRecord(value)) {
6404
+ if (isRecord3(value)) {
5869
6405
  const entries = await Promise.all(
5870
6406
  Object.entries(value).map(async ([key, entry]) => [
5871
6407
  key,
@@ -5890,16 +6426,16 @@ async function reviveToolResult(value, toolCallId) {
5890
6426
  ...value.artifact !== void 0 && {
5891
6427
  artifact: await reviveNested(value.artifact, toolCallId)
5892
6428
  },
5893
- ...isRecord(value.metadata) && {
6429
+ ...isRecord3(value.metadata) && {
5894
6430
  metadata: await reviveNested(value.metadata, toolCallId)
5895
6431
  },
5896
- ...isRecord(value.additionalKwargs) && {
6432
+ ...isRecord3(value.additionalKwargs) && {
5897
6433
  additional_kwargs: await reviveNested(
5898
6434
  value.additionalKwargs,
5899
6435
  toolCallId
5900
6436
  )
5901
6437
  },
5902
- ...isRecord(value.responseMetadata) && {
6438
+ ...isRecord3(value.responseMetadata) && {
5903
6439
  response_metadata: await reviveNested(
5904
6440
  value.responseMetadata,
5905
6441
  toolCallId
@@ -5969,8 +6505,8 @@ var BitfabLangGraphIntegration = class {
5969
6505
  get: (target, property) => {
5970
6506
  if (property === "invoke") {
5971
6507
  return async (input, ...rest) => {
5972
- const toolCallId = isRecord(input) && typeof input.id === "string" ? input.id : "";
5973
- const args = isRecord(input) && "args" in input ? input.args : input;
6508
+ const toolCallId = isRecord3(input) && typeof input.id === "string" ? input.id : "";
6509
+ const args = isRecord3(input) && "args" in input ? input.args : input;
5974
6510
  this.assertReplayToolResultExists(toolName, shouldMock);
5975
6511
  const execute = this.client.withSpan(
5976
6512
  this.traceFunctionKey,
@@ -5980,7 +6516,8 @@ var BitfabLangGraphIntegration = class {
5980
6516
  captureWhen: "nested",
5981
6517
  mockOnReplay: shouldMock,
5982
6518
  finalize: finalizeToolResult,
5983
- surface: "inherit"
6519
+ surface: "inherit",
6520
+ instrumentation: "langgraph"
5984
6521
  },
5985
6522
  async (_args) => await originalInvoke(input, ...rest)
5986
6523
  );
@@ -6023,7 +6560,12 @@ var BitfabLangGraphIntegration = class {
6023
6560
  wrapInvoke(fn) {
6024
6561
  return this.client.withSpan(
6025
6562
  this.traceFunctionKey,
6026
- { name: this.traceFunctionKey, type: "agent", surface: "inherit" },
6563
+ {
6564
+ name: this.traceFunctionKey,
6565
+ type: "agent",
6566
+ surface: "inherit",
6567
+ instrumentation: "langgraph"
6568
+ },
6027
6569
  fn
6028
6570
  );
6029
6571
  }
@@ -6079,7 +6621,8 @@ var BitfabOpenAIAgentHandler = class {
6079
6621
  const options_ = {
6080
6622
  type: "agent",
6081
6623
  finalize,
6082
- surface: "inherit"
6624
+ surface: "inherit",
6625
+ instrumentation: "openai-agents"
6083
6626
  };
6084
6627
  const traced = this.withSpanFn(
6085
6628
  this.traceFunctionKey,
@@ -6095,6 +6638,7 @@ var BitfabOpenAIAgentHandler = class {
6095
6638
  };
6096
6639
 
6097
6640
  // src/client.ts
6641
+ init_policyRefresh();
6098
6642
  init_randomUuid();
6099
6643
  init_replay();
6100
6644
 
@@ -6178,12 +6722,15 @@ function runWithSeedContext(ctx, fn) {
6178
6722
 
6179
6723
  // src/client.ts
6180
6724
  init_serialize();
6725
+ init_simulationPlan();
6726
+ init_spanOrigin();
6181
6727
  init_traceMetadata();
6182
6728
 
6183
6729
  // src/tracing.ts
6184
6730
  init_constants();
6185
6731
  init_http();
6186
6732
  init_randomUuid();
6733
+ init_spanOrigin();
6187
6734
  var BitfabOpenAITracingProcessor = class {
6188
6735
  /**
6189
6736
  * Initialize the tracing processor.
@@ -6385,6 +6932,7 @@ var BitfabOpenAITracingProcessor = class {
6385
6932
  * Build span payload for the external spans API.
6386
6933
  */
6387
6934
  buildSpanPayload(serializedSpan, errors) {
6935
+ serializedSpan.span_origin = makeSpanOrigin("openai-agents");
6388
6936
  const payload = {
6389
6937
  id: randomUuid(),
6390
6938
  type: "openai",
@@ -6514,7 +7062,8 @@ var BitfabVercelAiHandler = class {
6514
7062
  {
6515
7063
  type: "llm",
6516
7064
  finalize: (result) => summarizeGenerate(result ?? {}, label),
6517
- surface: "inherit"
7065
+ surface: "inherit",
7066
+ instrumentation: "vercel-ai"
6518
7067
  },
6519
7068
  () => doGenerate()
6520
7069
  );
@@ -6532,7 +7081,12 @@ var BitfabVercelAiHandler = class {
6532
7081
  // The wrapped fn returns immediately with the live stream, so the span
6533
7082
  // output cannot be read from the return value. `finalize` instead
6534
7083
  // awaits the summary the accumulator resolves once the stream drains.
6535
- { type: "llm", finalize: () => summary, surface: "inherit" },
7084
+ {
7085
+ type: "llm",
7086
+ finalize: () => summary,
7087
+ surface: "inherit",
7088
+ instrumentation: "vercel-ai"
7089
+ },
6536
7090
  async () => {
6537
7091
  const result = await doStream();
6538
7092
  const stream = result.stream.pipeThrough(
@@ -6550,6 +7104,19 @@ var BitfabVercelAiHandler = class {
6550
7104
  // src/client.ts
6551
7105
  init_warnOnce();
6552
7106
  var activeTraceStates = /* @__PURE__ */ new Map();
7107
+ function rootTraceFunctionKeyOf(payload) {
7108
+ const captured = payload[ROOT_TRACE_FUNCTION_KEY_FIELD];
7109
+ if (typeof captured === "string") {
7110
+ return captured;
7111
+ }
7112
+ const traceId = payload.traceId;
7113
+ const live = typeof traceId === "string" ? activeTraceStates.get(traceId)?.traceFunctionKey : void 0;
7114
+ if (typeof live === "string") {
7115
+ return live;
7116
+ }
7117
+ const own = payload.traceFunctionKey;
7118
+ return typeof own === "string" ? own : void 0;
7119
+ }
6553
7120
  var asyncLocalStorage = null;
6554
7121
  var SPAN_CONTEXT_STORAGE_SYMBOL = /* @__PURE__ */ Symbol.for("bitfab.spanContextStorage");
6555
7122
  var initializeAsyncContext = () => {
@@ -6954,6 +7521,14 @@ var Bitfab = class {
6954
7521
  serviceUrl: this.serviceUrl,
6955
7522
  timeout: this.timeout
6956
7523
  });
7524
+ this.simulationPlan = new SimulationPlan(
7525
+ this.httpClient,
7526
+ config.simulationPlan ?? true
7527
+ );
7528
+ this.httpClient.externalSpanTransform = (payload, submit) => this.applySimulationPlan(payload, submit);
7529
+ this.httpClient.externalTraceTransform = (payload, submit) => this.simulationPlan.sendTrace(payload, submit);
7530
+ this.httpClient.releaseHeldExternalSpans = (timeoutMs) => this.simulationPlan.release(timeoutMs);
7531
+ this.httpClient.stopSimulationPlan = () => this.simulationPlan.stop();
6957
7532
  this.datasets = new DatasetsClient(this.httpClient);
6958
7533
  this.traces = new TracesClient(this.httpClient);
6959
7534
  this.labels = new LabelsClient(this.httpClient);
@@ -7104,6 +7679,7 @@ var Bitfab = class {
7104
7679
  }
7105
7680
  createAutoTraceRoot(traceFunctionKey, name, options, fn) {
7106
7681
  const self = this;
7682
+ self.simulationPlan.refresh();
7107
7683
  const maxDepth = autoTraceLimit(
7108
7684
  options.maxDepth,
7109
7685
  DEFAULT_AUTO_TRACE_MAX_DEPTH
@@ -7119,7 +7695,8 @@ var Bitfab = class {
7119
7695
  name: options.name,
7120
7696
  nameFor: rootNameFor,
7121
7697
  type: options.type ?? "custom",
7122
- surface: "opt-out"
7698
+ surface: "opt-out",
7699
+ instrumentation: "trace"
7123
7700
  };
7124
7701
  const buildTracedRoot = (spanOptions) => this.withSpan(
7125
7702
  traceFunctionKey,
@@ -7130,6 +7707,7 @@ var Bitfab = class {
7130
7707
  traceFunctionKey
7131
7708
  );
7132
7709
  self.refreshAutoTraceCapturePolicy(traceFunctionKey);
7710
+ self.simulationPlan.refresh();
7133
7711
  let spansUsed = 0;
7134
7712
  let truncated = false;
7135
7713
  const warnTruncated = () => {
@@ -7206,6 +7784,7 @@ var Bitfab = class {
7206
7784
  type: nodeConfiguration?.type ?? "function",
7207
7785
  captureWhen: "nested",
7208
7786
  surface: "opt-out",
7787
+ instrumentation: "trace",
7209
7788
  functionId: definition.id,
7210
7789
  captureContent: nodeConfiguration !== void 0 || capturePolicy === void 0 || capturePolicy.has(definition.id),
7211
7790
  autoTraceDefinition: definition,
@@ -7237,6 +7816,7 @@ var Bitfab = class {
7237
7816
  type: "function",
7238
7817
  captureWhen: "nested",
7239
7818
  surface: "opt-out",
7819
+ instrumentation: "trace",
7240
7820
  captureContent: true,
7241
7821
  ...link !== void 0 && { nestedTrace: link }
7242
7822
  };
@@ -7302,38 +7882,36 @@ var Bitfab = class {
7302
7882
  Object.defineProperty(autoTraceRoot, "_bitfabWrappedFn", { value: fn });
7303
7883
  return autoTraceRoot;
7304
7884
  }
7885
+ applySimulationPlan(payload, submit) {
7886
+ this.simulationPlan.send(payload, rootTraceFunctionKeyOf(payload), submit);
7887
+ }
7305
7888
  refreshAutoTraceCapturePolicy(traceFunctionKey) {
7306
- const now = Date.now();
7307
- const state = this.autoTracePolicyRefreshes.get(traceFunctionKey) ?? {
7308
- refreshAfter: 0
7309
- };
7310
- if (state.inFlight || now < state.refreshAfter) {
7311
- return;
7312
- }
7313
- const request = this.httpClient.getAutoTracePolicy(
7314
- traceFunctionKey,
7315
- AUTO_TRACE_PROTOCOL
7316
- ).then((policy) => {
7317
- if (policy.protocol !== AUTO_TRACE_PROTOCOL) {
7318
- state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
7319
- return;
7320
- }
7321
- const functionIds = Array.isArray(policy.functionIds) ? policy.functionIds.filter(
7322
- (id) => typeof id === "string" && id.startsWith(`${AUTO_TRACE_PROTOCOL}:`)
7323
- ).slice(0, DEFAULT_AUTO_TRACE_MAX_SPANS) : [];
7324
- __setBitfabAutoTraceCapturePolicy(
7325
- this,
7326
- traceFunctionKey,
7327
- policy.revision === null ? void 0 : functionIds
7328
- );
7329
- state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_REFRESH_MS;
7330
- }).catch(() => {
7331
- state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
7332
- }).finally(() => {
7333
- state.inFlight = void 0;
7334
- });
7335
- state.inFlight = request;
7889
+ const state = this.autoTracePolicyRefreshes.get(traceFunctionKey) ?? new PolicyRefresh();
7336
7890
  this.autoTracePolicyRefreshes.set(traceFunctionKey, state);
7891
+ state.run(
7892
+ () => this.httpClient.getAutoTracePolicy(
7893
+ traceFunctionKey,
7894
+ AUTO_TRACE_PROTOCOL
7895
+ ),
7896
+ (policy) => {
7897
+ if (policy.protocol !== AUTO_TRACE_PROTOCOL) {
7898
+ state.hold(AUTO_TRACE_POLICY_RETRY_MS);
7899
+ return;
7900
+ }
7901
+ const functionIds = Array.isArray(policy.functionIds) ? policy.functionIds.filter(
7902
+ (id) => typeof id === "string" && id.startsWith(`${AUTO_TRACE_PROTOCOL}:`)
7903
+ ).slice(0, DEFAULT_AUTO_TRACE_MAX_SPANS) : [];
7904
+ __setBitfabAutoTraceCapturePolicy(
7905
+ this,
7906
+ traceFunctionKey,
7907
+ policy.revision === null ? void 0 : functionIds
7908
+ );
7909
+ state.hold(AUTO_TRACE_POLICY_REFRESH_MS);
7910
+ },
7911
+ () => {
7912
+ state.hold(AUTO_TRACE_POLICY_RETRY_MS);
7913
+ }
7914
+ );
7337
7915
  }
7338
7916
  /**
7339
7917
  * Flush and permanently close this client's tracing resources: its pending
@@ -7817,6 +8395,7 @@ var Bitfab = class {
7817
8395
  * @returns A wrapped function with the same signature that creates spans for inputs and outputs
7818
8396
  */
7819
8397
  withSpan(traceFunctionKey, optionsOrFn, maybeFn) {
8398
+ this.simulationPlan.refresh();
7820
8399
  const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
7821
8400
  const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
7822
8401
  const self = this;
@@ -7908,8 +8487,10 @@ var Bitfab = class {
7908
8487
  const testRunId = replayCtxAtStart?.testRunId ?? options.testRunId;
7909
8488
  if (isRootSpan && !activeTraceStates.has(traceId)) {
7910
8489
  const dbSnapshotRef = buildSnapshotRef(self.dbSnapshot, startedAt);
8490
+ self.simulationPlan.refresh();
7911
8491
  activeTraceStates.set(traceId, {
7912
8492
  traceId,
8493
+ traceFunctionKey,
7913
8494
  startedAt,
7914
8495
  contexts: [],
7915
8496
  ...testRunId !== void 0 && { testRunId },
@@ -7924,8 +8505,10 @@ var Bitfab = class {
7924
8505
  registeredTraceId = traceId;
7925
8506
  }
7926
8507
  const functionName = fn.name !== "" ? fn.name : void 0;
8508
+ const rootTraceFunctionKey = activeTraceStates.get(traceId)?.traceFunctionKey ?? traceFunctionKey;
7927
8509
  const baseSpanParams = {
7928
8510
  traceFunctionKey,
8511
+ rootTraceFunctionKey,
7929
8512
  functionName,
7930
8513
  spanName: options.name ?? options.nameFor?.(this) ?? qualifiedSpanName(this, functionName) ?? traceFunctionKey,
7931
8514
  traceId,
@@ -7934,6 +8517,7 @@ var Bitfab = class {
7934
8517
  inputs,
7935
8518
  startedAt,
7936
8519
  spanType: options.type ?? "custom",
8520
+ instrumentation: options.instrumentation ?? "span",
7937
8521
  functionId: options.functionId,
7938
8522
  captureContent: options.captureContent ?? true,
7939
8523
  autoTraceDefinition: options.autoTraceDefinition,
@@ -8349,6 +8933,7 @@ var Bitfab = class {
8349
8933
  * @returns A BitfabFunction instance for wrapping functions
8350
8934
  */
8351
8935
  getFunction(traceFunctionKey) {
8936
+ this.simulationPlan.refresh();
8352
8937
  return new BitfabFunction(this, traceFunctionKey);
8353
8938
  }
8354
8939
  /**
@@ -8436,6 +9021,7 @@ var Bitfab = class {
8436
9021
  trace_id: params.traceId,
8437
9022
  started_at: params.startedAt,
8438
9023
  ended_at: params.endedAt,
9024
+ span_origin: makeSpanOrigin(params.instrumentation),
8439
9025
  span_data: {
8440
9026
  name: params.spanName,
8441
9027
  type: params.spanType,
@@ -8496,6 +9082,9 @@ var Bitfab = class {
8496
9082
  source: "typescript-sdk-function",
8497
9083
  sourceTraceId: params.traceId,
8498
9084
  traceFunctionKey: params.traceFunctionKey,
9085
+ ...params.rootTraceFunctionKey !== void 0 && {
9086
+ [ROOT_TRACE_FUNCTION_KEY_FIELD]: params.rootTraceFunctionKey
9087
+ },
8499
9088
  rawSpan: externalSpan,
8500
9089
  ...params.testRunId && { testRunId: params.testRunId },
8501
9090
  ...params.mocked && { mocked: true },
@@ -8564,6 +9153,7 @@ var Bitfab = class {
8564
9153
  }
8565
9154
  activeTraceStates.set(traceId, {
8566
9155
  traceId,
9156
+ traceFunctionKey,
8567
9157
  startedAt,
8568
9158
  contexts: [],
8569
9159
  ingestionType: "seeded",
@@ -8573,6 +9163,7 @@ var Bitfab = class {
8573
9163
  try {
8574
9164
  this.sendWrapperSpan({
8575
9165
  traceFunctionKey,
9166
+ rootTraceFunctionKey: traceFunctionKey,
8576
9167
  spanName: options.spanName ?? traceFunctionKey,
8577
9168
  traceId,
8578
9169
  spanId: randomUuid(),
@@ -8582,6 +9173,7 @@ var Bitfab = class {
8582
9173
  startedAt,
8583
9174
  endedAt: startedAt,
8584
9175
  spanType: options.spanType ?? "agent",
9176
+ instrumentation: "span",
8585
9177
  captureContent: true
8586
9178
  });
8587
9179
  this.sendTraceCompletion({
@@ -8627,6 +9219,7 @@ var Bitfab = class {
8627
9219
  }
8628
9220
  activeTraceStates.set(traceId, {
8629
9221
  traceId,
9222
+ traceFunctionKey,
8630
9223
  startedAt: nowIsoTimestamp(),
8631
9224
  contexts: [],
8632
9225
  ingestionType: "seeded",