@bitfab/sdk 0.54.3 → 0.54.4

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
@@ -42,7 +42,7 @@ var __version__, __packageName__;
42
42
  var init_version_generated = __esm({
43
43
  "src/version.generated.ts"() {
44
44
  "use strict";
45
- __version__ = "0.54.3";
45
+ __version__ = "0.54.4";
46
46
  __packageName__ = "@bitfab/sdk";
47
47
  }
48
48
  });
@@ -57,6 +57,99 @@ var init_constants = __esm({
57
57
  }
58
58
  });
59
59
 
60
+ // src/traceCompletion.ts
61
+ var TraceCompletion;
62
+ var init_traceCompletion = __esm({
63
+ "src/traceCompletion.ts"() {
64
+ "use strict";
65
+ TraceCompletion = class {
66
+ constructor() {
67
+ this.traces = /* @__PURE__ */ new Map();
68
+ this.closed = /* @__PURE__ */ new Map();
69
+ }
70
+ state(traceId) {
71
+ let state = this.traces.get(traceId);
72
+ if (state === void 0) {
73
+ state = { spanIds: /* @__PURE__ */ new Set(), active: /* @__PURE__ */ new Set() };
74
+ this.traces.set(traceId, state);
75
+ }
76
+ return state;
77
+ }
78
+ start(traceId, spanId) {
79
+ if (this.closed.has(traceId)) {
80
+ return;
81
+ }
82
+ const state = this.state(traceId);
83
+ state.spanIds.add(spanId);
84
+ state.active.add(spanId);
85
+ }
86
+ open(traceId) {
87
+ if (!this.closed.has(traceId)) {
88
+ this.state(traceId);
89
+ }
90
+ }
91
+ hold(traceId, key) {
92
+ this.state(traceId).active.add(key);
93
+ }
94
+ record(traceId, spanId) {
95
+ if (!this.closed.has(traceId)) {
96
+ this.state(traceId).spanIds.add(spanId);
97
+ }
98
+ }
99
+ end(traceId, spanId) {
100
+ const state = this.traces.get(traceId);
101
+ if (state !== void 0) {
102
+ state.active.delete(spanId);
103
+ this.drain(traceId, state);
104
+ }
105
+ }
106
+ abort(traceId, spanId) {
107
+ const state = this.traces.get(traceId);
108
+ if (state === void 0) {
109
+ return;
110
+ }
111
+ state.active.delete(spanId);
112
+ state.spanIds.delete(spanId);
113
+ if (state.active.size === 0 && state.spanIds.size === 0 && state.complete === void 0) {
114
+ this.traces.delete(traceId);
115
+ return;
116
+ }
117
+ this.drain(traceId, state);
118
+ }
119
+ close(traceId, complete, dropped = false) {
120
+ const count = this.closed.get(traceId);
121
+ if (count !== void 0) {
122
+ complete(count);
123
+ return;
124
+ }
125
+ const state = this.traces.get(traceId);
126
+ if (state === void 0) {
127
+ return;
128
+ }
129
+ state.complete = complete;
130
+ if (dropped) {
131
+ state.active.clear();
132
+ }
133
+ this.drain(traceId, state);
134
+ }
135
+ drain(traceId, state) {
136
+ if (state.active.size !== 0 || state.complete === void 0) {
137
+ return;
138
+ }
139
+ this.traces.delete(traceId);
140
+ this.closed.set(traceId, state.spanIds.size);
141
+ if (this.closed.size > 1024) {
142
+ const oldest = this.closed.keys().next().value;
143
+ if (oldest !== void 0) {
144
+ this.closed.delete(oldest);
145
+ }
146
+ }
147
+ state.complete(state.spanIds.size);
148
+ }
149
+ };
150
+ }
151
+ });
152
+
60
153
  // src/readEnv.ts
61
154
  function readEnv(name) {
62
155
  if (typeof process !== "undefined" && process.env) {
@@ -2143,6 +2236,7 @@ var REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS, REPLAY_COMPLETE_REQUEST_TIMEOUT_MS, OTL
2143
2236
  var init_http = __esm({
2144
2237
  "src/http.ts"() {
2145
2238
  "use strict";
2239
+ init_traceCompletion();
2146
2240
  init_compress();
2147
2241
  init_constants();
2148
2242
  init_errors();
@@ -2205,6 +2299,7 @@ var init_http = __esm({
2205
2299
  // must not wait on another client's slow finalize: a false `close()` failure
2206
2300
  // caused by unrelated work is worse than no signal at all.
2207
2301
  this.deferredWork = /* @__PURE__ */ new Set();
2302
+ this.traceCompletion = new TraceCompletion();
2208
2303
  this.closed = false;
2209
2304
  this.apiKey = config.apiKey;
2210
2305
  this.serviceUrl = config.serviceUrl;
@@ -2638,6 +2733,10 @@ var init_http = __esm({
2638
2733
  );
2639
2734
  }
2640
2735
  sendExternalSpan(payload) {
2736
+ const ref2 = carrierRef(payload);
2737
+ if (ref2?.spanId !== void 0) {
2738
+ this.traceCompletion.record(ref2.traceId, ref2.spanId);
2739
+ }
2641
2740
  const gate = this.externalSpanTransform;
2642
2741
  if (gate === void 0) {
2643
2742
  this.submitExternalSpan(payload);
@@ -2669,13 +2768,28 @@ var init_http = __esm({
2669
2768
  */
2670
2769
  sendExternalTrace(rawPayload) {
2671
2770
  const payload = mergeCallerMetadataIntoTracePayload(rawPayload);
2672
- const gate = this.externalTraceTransform;
2673
- if (gate === void 0) {
2674
- this.submitExternalTrace(payload);
2771
+ const traceId = sourceTraceIdOf(payload);
2772
+ if (payload.completed === true && traceId !== void 0) {
2773
+ this.traceCompletion.close(
2774
+ traceId,
2775
+ (expectedSpanCount) => this.sendCountedExternalTrace({ ...payload, expectedSpanCount }),
2776
+ payload.dropped === true
2777
+ );
2675
2778
  return;
2676
2779
  }
2780
+ if (traceId !== void 0) {
2781
+ this.traceCompletion.open(traceId);
2782
+ }
2783
+ this.sendCountedExternalTrace(payload);
2784
+ }
2785
+ sendCountedExternalTrace(payload) {
2677
2786
  try {
2678
- gate(payload, (ready) => this.submitExternalTrace(ready));
2787
+ const gate = this.externalTraceTransform;
2788
+ if (gate === void 0) {
2789
+ this.submitExternalTrace(payload);
2790
+ } else {
2791
+ gate(payload, (ready) => this.submitExternalTrace(ready));
2792
+ }
2679
2793
  } catch (error) {
2680
2794
  warnDroppedExternalTrace(error);
2681
2795
  }
@@ -4494,6 +4608,7 @@ var BitfabClaudeAgentHandler = class {
4494
4608
  spanInfo.dropped = [...inputDropped];
4495
4609
  }
4496
4610
  this.runToSpan.set(spanId, spanInfo);
4611
+ this.httpClient.traceCompletion.start(spanInfo.traceId, spanInfo.spanId);
4497
4612
  return spanInfo;
4498
4613
  }
4499
4614
  completeSpan(spanId, output, error, extraContexts) {
@@ -4515,6 +4630,7 @@ var BitfabClaudeAgentHandler = class {
4515
4630
  spanInfo.contexts.push(extraContexts);
4516
4631
  }
4517
4632
  this.sendSpan(spanInfo);
4633
+ this.httpClient.traceCompletion.end(spanInfo.traceId, spanInfo.spanId);
4518
4634
  }
4519
4635
  sendSpan(spanInfo) {
4520
4636
  const spanData = {
@@ -6172,6 +6288,9 @@ var BitfabLangGraphCallbackHandler = class {
6172
6288
  spanInfo.hidden = true;
6173
6289
  }
6174
6290
  this.runToSpan.set(runId, spanInfo);
6291
+ if (spanInfo.hidden !== true) {
6292
+ this.httpClient.traceCompletion.start(spanInfo.traceId, spanInfo.spanId);
6293
+ }
6175
6294
  if (isRootInvocation) {
6176
6295
  this.sendTraceStart(spanInfo);
6177
6296
  }
@@ -6203,6 +6322,7 @@ var BitfabLangGraphCallbackHandler = class {
6203
6322
  this.sendTraceCompletion(spanInfo, invocation?.activeContext ?? null);
6204
6323
  this.invocations.delete(runId);
6205
6324
  }
6325
+ this.httpClient.traceCompletion.end(spanInfo.traceId, spanInfo.spanId);
6206
6326
  }
6207
6327
  sendSpan(spanInfo) {
6208
6328
  const spanData = {
@@ -6924,6 +7044,8 @@ var BitfabOpenAITracingProcessor = class {
6924
7044
  this.activeTraces = {};
6925
7045
  this.activeSpanMappings = {};
6926
7046
  this.canonicalTraceIds = {};
7047
+ this.startedSpans = /* @__PURE__ */ new Map();
7048
+ this.endedTraces = /* @__PURE__ */ new Set();
6927
7049
  this.ownsHttpClient = config._httpClient === void 0;
6928
7050
  this.httpClient = config._httpClient ?? new HttpClient({
6929
7051
  apiKey: config.apiKey,
@@ -6962,6 +7084,10 @@ var BitfabOpenAITracingProcessor = class {
6962
7084
  }
6963
7085
  const canonicalTraceId = activeContext?.traceId ?? this.getCanonicalTraceId(trace.traceId);
6964
7086
  this.canonicalTraceIds[trace.traceId] = canonicalTraceId;
7087
+ this.httpClient.traceCompletion.hold(
7088
+ activeContext?.traceId ?? trace.traceId,
7089
+ `openai:${trace.traceId}`
7090
+ );
6965
7091
  this.sendTrace(trace, {
6966
7092
  id: canonicalTraceId,
6967
7093
  sourceTraceId: activeContext?.traceId
@@ -6979,16 +7105,33 @@ var BitfabOpenAITracingProcessor = class {
6979
7105
  id: mapping?.traceId ?? this.getCanonicalTraceId(trace.traceId),
6980
7106
  sourceTraceId: mapping?.traceId
6981
7107
  });
6982
- delete this.activeSpanMappings[trace.traceId];
6983
- delete this.canonicalTraceIds[trace.traceId];
6984
- delete this.activeTraces[trace.traceId];
7108
+ this.endedTraces.add(trace.traceId);
7109
+ this.httpClient.traceCompletion.end(
7110
+ mapping?.traceId ?? trace.traceId,
7111
+ `openai:${trace.traceId}`
7112
+ );
7113
+ this.cleanupTrace(trace.traceId);
7114
+ }
7115
+ cleanupTrace(traceId) {
7116
+ if (!this.endedTraces.has(traceId) || [...this.startedSpans.values()].includes(traceId)) {
7117
+ return;
7118
+ }
7119
+ this.endedTraces.delete(traceId);
7120
+ delete this.activeSpanMappings[traceId];
7121
+ delete this.canonicalTraceIds[traceId];
7122
+ delete this.activeTraces[traceId];
6985
7123
  }
6986
7124
  /**
6987
7125
  * Called when a span is started. Span payloads are authoritative completed
6988
7126
  * snapshots, so start notifications do not cross the transport boundary.
6989
7127
  */
6990
7128
  // biome-ignore lint/suspicious/noExplicitAny: OpenAI Agents SDK uses any for span data
6991
- async onSpanStart(_span) {
7129
+ async onSpanStart(span) {
7130
+ if (span.spanId !== void 0 && span.traceId !== null && span.traceId !== void 0) {
7131
+ this.startedSpans.set(span.spanId, span.traceId);
7132
+ const traceId = this.activeSpanMappings[span.traceId]?.traceId ?? span.traceId;
7133
+ this.httpClient.traceCompletion.start(traceId, span.spanId);
7134
+ }
6992
7135
  }
6993
7136
  /**
6994
7137
  * Called when a span is ended.
@@ -6997,7 +7140,17 @@ var BitfabOpenAITracingProcessor = class {
6997
7140
  */
6998
7141
  // biome-ignore lint/suspicious/noExplicitAny: OpenAI Agents SDK uses any for span data
6999
7142
  async onSpanEnd(span) {
7000
- this.sendSpan(span);
7143
+ const originalTraceId = span.traceId ?? "";
7144
+ const traceId = this.activeSpanMappings[originalTraceId]?.traceId ?? originalTraceId;
7145
+ try {
7146
+ this.sendSpan(span);
7147
+ } finally {
7148
+ if (span.spanId !== void 0) {
7149
+ this.httpClient.traceCompletion.end(traceId, span.spanId);
7150
+ this.startedSpans.delete(span.spanId);
7151
+ }
7152
+ this.cleanupTrace(originalTraceId);
7153
+ }
7001
7154
  }
7002
7155
  /**
7003
7156
  * Called when a trace is being flushed.
@@ -8703,6 +8856,7 @@ var Bitfab = class {
8703
8856
  let newStack;
8704
8857
  let executeWithContext;
8705
8858
  let registeredTraceId;
8859
+ let startedSpan;
8706
8860
  try {
8707
8861
  const currentStack = getSpanStack();
8708
8862
  const parentContext = currentStack[currentStack.length - 1];
@@ -8754,6 +8908,8 @@ var Bitfab = class {
8754
8908
  });
8755
8909
  registeredTraceId = traceId;
8756
8910
  }
8911
+ self.httpClient.traceCompletion.start(traceId, spanId);
8912
+ startedSpan = { traceId, spanId };
8757
8913
  const functionName = fn.name !== "" ? fn.name : void 0;
8758
8914
  const rootTraceFunctionKey = activeTraceStates.get(traceId)?.traceFunctionKey ?? traceFunctionKey;
8759
8915
  const baseSpanParams = {
@@ -8828,6 +8984,8 @@ var Bitfab = class {
8828
8984
  retireTraceMetadata(traceId);
8829
8985
  }
8830
8986
  } catch {
8987
+ } finally {
8988
+ self.httpClient.traceCompletion.end(traceId, spanId);
8831
8989
  }
8832
8990
  };
8833
8991
  const recordSpan = (result) => {
@@ -8844,6 +9002,14 @@ var Bitfab = class {
8844
9002
  void sendSpan({ result });
8845
9003
  }
8846
9004
  };
9005
+ const resolveMockOrAbort = async (resolve) => {
9006
+ try {
9007
+ return await resolve();
9008
+ } catch (error) {
9009
+ self.httpClient.traceCompletion.abort(traceId, spanId);
9010
+ throw error;
9011
+ }
9012
+ };
8847
9013
  executeWithContext = () => {
8848
9014
  let result;
8849
9015
  try {
@@ -8900,7 +9066,7 @@ var Bitfab = class {
8900
9066
  );
8901
9067
  }
8902
9068
  return (async () => {
8903
- const output = await pending;
9069
+ const output = await resolveMockOrAbort(() => pending);
8904
9070
  void sendSpan({
8905
9071
  result: output,
8906
9072
  mocked: true,
@@ -8970,7 +9136,7 @@ var Bitfab = class {
8970
9136
  );
8971
9137
  }
8972
9138
  return runWithSpanStack(newStack, async () => {
8973
- const resolved2 = await resolution;
9139
+ const resolved2 = await resolveMockOrAbort(() => resolution);
8974
9140
  if (resolved2.matched) {
8975
9141
  void sendSpan({
8976
9142
  result: resolved2.output,
@@ -8986,7 +9152,9 @@ var Bitfab = class {
8986
9152
  );
8987
9153
  }
8988
9154
  if (shouldMockWithBaseStrategy) {
8989
- const output = await resolveRecordedOutput();
9155
+ const output = await resolveMockOrAbort(
9156
+ () => resolveRecordedOutput()
9157
+ );
8990
9158
  void sendSpan({
8991
9159
  result: output,
8992
9160
  mocked: true,
@@ -9016,6 +9184,12 @@ var Bitfab = class {
9016
9184
  }
9017
9185
  }
9018
9186
  } catch (setupError) {
9187
+ if (startedSpan) {
9188
+ self.httpClient.traceCompletion.abort(
9189
+ startedSpan.traceId,
9190
+ startedSpan.spanId
9191
+ );
9192
+ }
9019
9193
  if (registeredTraceId) {
9020
9194
  activeTraceStates.delete(registeredTraceId);
9021
9195
  retireTraceMetadata(registeredTraceId);