bitfab 0.54.3 → 0.54.5

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.
Files changed (32) hide show
  1. package/dist/{chunk-DL4KHJON.js → chunk-3O5MS4XJ.js} +2 -2
  2. package/dist/{chunk-ZO4NEEUA.js → chunk-GVK7AES5.js} +113 -6
  3. package/dist/chunk-GVK7AES5.js.map +1 -0
  4. package/dist/{chunk-PELZFWPC.js → chunk-NATC7L2W.js} +124 -54
  5. package/dist/chunk-NATC7L2W.js.map +1 -0
  6. package/dist/{chunk-NI6B2BP4.js → chunk-RA3J6A6K.js} +113 -6
  7. package/dist/chunk-RA3J6A6K.js.map +1 -0
  8. package/dist/{chunk-4H7E2S27.js → chunk-VAHFHCBT.js} +3 -3
  9. package/dist/{http-6WMGO7GB.js → http-K2H4547F.js} +2 -2
  10. package/dist/{http-A5BXPX5R.js → http-RW2JO6TU.js} +2 -2
  11. package/dist/index.cjs +236 -52
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +114 -73
  14. package/dist/index.d.ts +114 -73
  15. package/dist/index.js +3 -3
  16. package/dist/node.cjs +236 -52
  17. package/dist/node.cjs.map +1 -1
  18. package/dist/node.d.cts +1 -1
  19. package/dist/node.d.ts +1 -1
  20. package/dist/node.js +3 -3
  21. package/dist/{replay-FOVT4PNE.js → replay-MHYULXCH.js} +3 -3
  22. package/dist/replayCli.js +2 -2
  23. package/dist/seedCli.js +2 -2
  24. package/package.json +1 -1
  25. package/dist/chunk-NI6B2BP4.js.map +0 -1
  26. package/dist/chunk-PELZFWPC.js.map +0 -1
  27. package/dist/chunk-ZO4NEEUA.js.map +0 -1
  28. /package/dist/{chunk-DL4KHJON.js.map → chunk-3O5MS4XJ.js.map} +0 -0
  29. /package/dist/{chunk-4H7E2S27.js.map → chunk-VAHFHCBT.js.map} +0 -0
  30. /package/dist/{http-6WMGO7GB.js.map → http-K2H4547F.js.map} +0 -0
  31. /package/dist/{http-A5BXPX5R.js.map → http-RW2JO6TU.js.map} +0 -0
  32. /package/dist/{replay-FOVT4PNE.js.map → replay-MHYULXCH.js.map} +0 -0
package/dist/node.cjs CHANGED
@@ -97,7 +97,7 @@ var __version__, __packageName__;
97
97
  var init_version_generated = __esm({
98
98
  "src/version.generated.ts"() {
99
99
  "use strict";
100
- __version__ = "0.54.3";
100
+ __version__ = "0.54.5";
101
101
  __packageName__ = "bitfab";
102
102
  }
103
103
  });
@@ -112,6 +112,99 @@ var init_constants = __esm({
112
112
  }
113
113
  });
114
114
 
115
+ // src/traceCompletion.ts
116
+ var TraceCompletion;
117
+ var init_traceCompletion = __esm({
118
+ "src/traceCompletion.ts"() {
119
+ "use strict";
120
+ TraceCompletion = class {
121
+ constructor() {
122
+ this.traces = /* @__PURE__ */ new Map();
123
+ this.closed = /* @__PURE__ */ new Map();
124
+ }
125
+ state(traceId) {
126
+ let state = this.traces.get(traceId);
127
+ if (state === void 0) {
128
+ state = { spanIds: /* @__PURE__ */ new Set(), active: /* @__PURE__ */ new Set() };
129
+ this.traces.set(traceId, state);
130
+ }
131
+ return state;
132
+ }
133
+ start(traceId, spanId) {
134
+ if (this.closed.has(traceId)) {
135
+ return;
136
+ }
137
+ const state = this.state(traceId);
138
+ state.spanIds.add(spanId);
139
+ state.active.add(spanId);
140
+ }
141
+ open(traceId) {
142
+ if (!this.closed.has(traceId)) {
143
+ this.state(traceId);
144
+ }
145
+ }
146
+ hold(traceId, key) {
147
+ this.state(traceId).active.add(key);
148
+ }
149
+ record(traceId, spanId) {
150
+ if (!this.closed.has(traceId)) {
151
+ this.state(traceId).spanIds.add(spanId);
152
+ }
153
+ }
154
+ end(traceId, spanId) {
155
+ const state = this.traces.get(traceId);
156
+ if (state !== void 0) {
157
+ state.active.delete(spanId);
158
+ this.drain(traceId, state);
159
+ }
160
+ }
161
+ abort(traceId, spanId) {
162
+ const state = this.traces.get(traceId);
163
+ if (state === void 0) {
164
+ return;
165
+ }
166
+ state.active.delete(spanId);
167
+ state.spanIds.delete(spanId);
168
+ if (state.active.size === 0 && state.spanIds.size === 0 && state.complete === void 0) {
169
+ this.traces.delete(traceId);
170
+ return;
171
+ }
172
+ this.drain(traceId, state);
173
+ }
174
+ close(traceId, complete, dropped = false) {
175
+ const count = this.closed.get(traceId);
176
+ if (count !== void 0) {
177
+ complete(count);
178
+ return;
179
+ }
180
+ const state = this.traces.get(traceId);
181
+ if (state === void 0) {
182
+ return;
183
+ }
184
+ state.complete = complete;
185
+ if (dropped) {
186
+ state.active.clear();
187
+ }
188
+ this.drain(traceId, state);
189
+ }
190
+ drain(traceId, state) {
191
+ if (state.active.size !== 0 || state.complete === void 0) {
192
+ return;
193
+ }
194
+ this.traces.delete(traceId);
195
+ this.closed.set(traceId, state.spanIds.size);
196
+ if (this.closed.size > 1024) {
197
+ const oldest = this.closed.keys().next().value;
198
+ if (oldest !== void 0) {
199
+ this.closed.delete(oldest);
200
+ }
201
+ }
202
+ state.complete(state.spanIds.size);
203
+ }
204
+ };
205
+ }
206
+ });
207
+
115
208
  // src/readEnv.ts
116
209
  function readEnv(name) {
117
210
  if (typeof process !== "undefined" && process.env) {
@@ -2159,6 +2252,7 @@ var REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS, REPLAY_COMPLETE_REQUEST_TIMEOUT_MS, OTL
2159
2252
  var init_http = __esm({
2160
2253
  "src/http.ts"() {
2161
2254
  "use strict";
2255
+ init_traceCompletion();
2162
2256
  init_compress();
2163
2257
  init_constants();
2164
2258
  init_errors();
@@ -2221,6 +2315,7 @@ var init_http = __esm({
2221
2315
  // must not wait on another client's slow finalize: a false `close()` failure
2222
2316
  // caused by unrelated work is worse than no signal at all.
2223
2317
  this.deferredWork = /* @__PURE__ */ new Set();
2318
+ this.traceCompletion = new TraceCompletion();
2224
2319
  this.closed = false;
2225
2320
  this.apiKey = config.apiKey;
2226
2321
  this.serviceUrl = config.serviceUrl;
@@ -2654,6 +2749,10 @@ var init_http = __esm({
2654
2749
  );
2655
2750
  }
2656
2751
  sendExternalSpan(payload) {
2752
+ const ref2 = carrierRef(payload);
2753
+ if (ref2?.spanId !== void 0) {
2754
+ this.traceCompletion.record(ref2.traceId, ref2.spanId);
2755
+ }
2657
2756
  const gate = this.externalSpanTransform;
2658
2757
  if (gate === void 0) {
2659
2758
  this.submitExternalSpan(payload);
@@ -2685,13 +2784,28 @@ var init_http = __esm({
2685
2784
  */
2686
2785
  sendExternalTrace(rawPayload) {
2687
2786
  const payload = mergeCallerMetadataIntoTracePayload(rawPayload);
2688
- const gate = this.externalTraceTransform;
2689
- if (gate === void 0) {
2690
- this.submitExternalTrace(payload);
2787
+ const traceId = sourceTraceIdOf(payload);
2788
+ if (payload.completed === true && traceId !== void 0) {
2789
+ this.traceCompletion.close(
2790
+ traceId,
2791
+ (expectedSpanCount) => this.sendCountedExternalTrace({ ...payload, expectedSpanCount }),
2792
+ payload.dropped === true
2793
+ );
2691
2794
  return;
2692
2795
  }
2796
+ if (traceId !== void 0) {
2797
+ this.traceCompletion.open(traceId);
2798
+ }
2799
+ this.sendCountedExternalTrace(payload);
2800
+ }
2801
+ sendCountedExternalTrace(payload) {
2693
2802
  try {
2694
- gate(payload, (ready) => this.submitExternalTrace(ready));
2803
+ const gate = this.externalTraceTransform;
2804
+ if (gate === void 0) {
2805
+ this.submitExternalTrace(payload);
2806
+ } else {
2807
+ gate(payload, (ready) => this.submitExternalTrace(ready));
2808
+ }
2695
2809
  } catch (error) {
2696
2810
  warnDroppedExternalTrace(error);
2697
2811
  }
@@ -4251,45 +4365,6 @@ var AssertionCategoriesClient = class {
4251
4365
  }
4252
4366
  };
4253
4367
 
4254
- // src/assertions.ts
4255
- var ASSERTIONS_PATH = "/api/sdk/traces/assertions";
4256
- function traceAssertionsPath(traceId, suffix = "") {
4257
- return `/api/sdk/traces/${encodeURIComponent(traceId)}/assertions${suffix}`;
4258
- }
4259
- var TracesClient = class {
4260
- constructor(httpClient) {
4261
- this.httpClient = httpClient;
4262
- }
4263
- async getAssertions(traceId) {
4264
- return this.httpClient.get(
4265
- traceAssertionsPath(traceId)
4266
- );
4267
- }
4268
- async saveAssertions(params) {
4269
- return this.saveAssertionsAll({
4270
- updates: [{ traceId: params.traceId, assertions: params.assertions }],
4271
- source: params.source
4272
- });
4273
- }
4274
- async saveAssertionsAll(params) {
4275
- if (params.updates.length === 0) {
4276
- return [];
4277
- }
4278
- const response = await this.httpClient.request(ASSERTIONS_PATH, {
4279
- updates: params.updates,
4280
- source: params.source ?? "agent"
4281
- });
4282
- return response.assertions;
4283
- }
4284
- async archiveAssertions(params) {
4285
- const response = await this.httpClient.request(
4286
- traceAssertionsPath(params.traceId, "/archive"),
4287
- { assertionIds: params.assertionIds }
4288
- );
4289
- return response.archived;
4290
- }
4291
- };
4292
-
4293
4368
  // src/claudeAgentSdk.ts
4294
4369
  init_constants();
4295
4370
  init_http();
@@ -4517,6 +4592,7 @@ var BitfabClaudeAgentHandler = class {
4517
4592
  spanInfo.dropped = [...inputDropped];
4518
4593
  }
4519
4594
  this.runToSpan.set(spanId, spanInfo);
4595
+ this.httpClient.traceCompletion.start(spanInfo.traceId, spanInfo.spanId);
4520
4596
  return spanInfo;
4521
4597
  }
4522
4598
  completeSpan(spanId, output, error, extraContexts) {
@@ -4538,6 +4614,7 @@ var BitfabClaudeAgentHandler = class {
4538
4614
  spanInfo.contexts.push(extraContexts);
4539
4615
  }
4540
4616
  this.sendSpan(spanInfo);
4617
+ this.httpClient.traceCompletion.end(spanInfo.traceId, spanInfo.spanId);
4541
4618
  }
4542
4619
  sendSpan(spanInfo) {
4543
4620
  const spanData = {
@@ -6195,6 +6272,9 @@ var BitfabLangGraphCallbackHandler = class {
6195
6272
  spanInfo.hidden = true;
6196
6273
  }
6197
6274
  this.runToSpan.set(runId, spanInfo);
6275
+ if (spanInfo.hidden !== true) {
6276
+ this.httpClient.traceCompletion.start(spanInfo.traceId, spanInfo.spanId);
6277
+ }
6198
6278
  if (isRootInvocation) {
6199
6279
  this.sendTraceStart(spanInfo);
6200
6280
  }
@@ -6226,6 +6306,7 @@ var BitfabLangGraphCallbackHandler = class {
6226
6306
  this.sendTraceCompletion(spanInfo, invocation?.activeContext ?? null);
6227
6307
  this.invocations.delete(runId);
6228
6308
  }
6309
+ this.httpClient.traceCompletion.end(spanInfo.traceId, spanInfo.spanId);
6229
6310
  }
6230
6311
  sendSpan(spanInfo) {
6231
6312
  const spanData = {
@@ -6932,6 +7013,55 @@ var StreamFinalizationError = class extends Error {
6932
7013
  // src/client.ts
6933
7014
  init_traceMetadata();
6934
7015
 
7016
+ // src/traces.ts
7017
+ var ASSERTIONS_PATH = "/api/sdk/traces/assertions";
7018
+ var SEARCH_PATH = "/api/sdk/traces/search";
7019
+ function traceAssertionsPath(traceId, suffix = "") {
7020
+ return `/api/sdk/traces/${encodeURIComponent(traceId)}/assertions${suffix}`;
7021
+ }
7022
+ var TracesClient = class {
7023
+ constructor(httpClient) {
7024
+ this.httpClient = httpClient;
7025
+ }
7026
+ /**
7027
+ * Search traces by exact caller metadata.
7028
+ *
7029
+ * Keys and values are matched case-insensitively. Up to 10 supplied pairs
7030
+ * must match. Use `nextCursor` from the result to fetch another page.
7031
+ */
7032
+ async search(params) {
7033
+ return this.httpClient.request(SEARCH_PATH, params);
7034
+ }
7035
+ async getAssertions(traceId) {
7036
+ return this.httpClient.get(
7037
+ traceAssertionsPath(traceId)
7038
+ );
7039
+ }
7040
+ async saveAssertions(params) {
7041
+ return this.saveAssertionsAll({
7042
+ updates: [{ traceId: params.traceId, assertions: params.assertions }],
7043
+ source: params.source
7044
+ });
7045
+ }
7046
+ async saveAssertionsAll(params) {
7047
+ if (params.updates.length === 0) {
7048
+ return [];
7049
+ }
7050
+ const response = await this.httpClient.request(ASSERTIONS_PATH, {
7051
+ updates: params.updates,
7052
+ source: params.source ?? "agent"
7053
+ });
7054
+ return response.assertions;
7055
+ }
7056
+ async archiveAssertions(params) {
7057
+ const response = await this.httpClient.request(
7058
+ traceAssertionsPath(params.traceId, "/archive"),
7059
+ { assertionIds: params.assertionIds }
7060
+ );
7061
+ return response.archived;
7062
+ }
7063
+ };
7064
+
6935
7065
  // src/tracing.ts
6936
7066
  init_constants();
6937
7067
  init_http();
@@ -6947,6 +7077,8 @@ var BitfabOpenAITracingProcessor = class {
6947
7077
  this.activeTraces = {};
6948
7078
  this.activeSpanMappings = {};
6949
7079
  this.canonicalTraceIds = {};
7080
+ this.startedSpans = /* @__PURE__ */ new Map();
7081
+ this.endedTraces = /* @__PURE__ */ new Set();
6950
7082
  this.ownsHttpClient = config._httpClient === void 0;
6951
7083
  this.httpClient = config._httpClient ?? new HttpClient({
6952
7084
  apiKey: config.apiKey,
@@ -6985,6 +7117,10 @@ var BitfabOpenAITracingProcessor = class {
6985
7117
  }
6986
7118
  const canonicalTraceId = activeContext?.traceId ?? this.getCanonicalTraceId(trace.traceId);
6987
7119
  this.canonicalTraceIds[trace.traceId] = canonicalTraceId;
7120
+ this.httpClient.traceCompletion.hold(
7121
+ activeContext?.traceId ?? trace.traceId,
7122
+ `openai:${trace.traceId}`
7123
+ );
6988
7124
  this.sendTrace(trace, {
6989
7125
  id: canonicalTraceId,
6990
7126
  sourceTraceId: activeContext?.traceId
@@ -7002,16 +7138,33 @@ var BitfabOpenAITracingProcessor = class {
7002
7138
  id: mapping?.traceId ?? this.getCanonicalTraceId(trace.traceId),
7003
7139
  sourceTraceId: mapping?.traceId
7004
7140
  });
7005
- delete this.activeSpanMappings[trace.traceId];
7006
- delete this.canonicalTraceIds[trace.traceId];
7007
- delete this.activeTraces[trace.traceId];
7141
+ this.endedTraces.add(trace.traceId);
7142
+ this.httpClient.traceCompletion.end(
7143
+ mapping?.traceId ?? trace.traceId,
7144
+ `openai:${trace.traceId}`
7145
+ );
7146
+ this.cleanupTrace(trace.traceId);
7147
+ }
7148
+ cleanupTrace(traceId) {
7149
+ if (!this.endedTraces.has(traceId) || [...this.startedSpans.values()].includes(traceId)) {
7150
+ return;
7151
+ }
7152
+ this.endedTraces.delete(traceId);
7153
+ delete this.activeSpanMappings[traceId];
7154
+ delete this.canonicalTraceIds[traceId];
7155
+ delete this.activeTraces[traceId];
7008
7156
  }
7009
7157
  /**
7010
7158
  * Called when a span is started. Span payloads are authoritative completed
7011
7159
  * snapshots, so start notifications do not cross the transport boundary.
7012
7160
  */
7013
7161
  // biome-ignore lint/suspicious/noExplicitAny: OpenAI Agents SDK uses any for span data
7014
- async onSpanStart(_span) {
7162
+ async onSpanStart(span) {
7163
+ if (span.spanId !== void 0 && span.traceId !== null && span.traceId !== void 0) {
7164
+ this.startedSpans.set(span.spanId, span.traceId);
7165
+ const traceId = this.activeSpanMappings[span.traceId]?.traceId ?? span.traceId;
7166
+ this.httpClient.traceCompletion.start(traceId, span.spanId);
7167
+ }
7015
7168
  }
7016
7169
  /**
7017
7170
  * Called when a span is ended.
@@ -7020,7 +7173,17 @@ var BitfabOpenAITracingProcessor = class {
7020
7173
  */
7021
7174
  // biome-ignore lint/suspicious/noExplicitAny: OpenAI Agents SDK uses any for span data
7022
7175
  async onSpanEnd(span) {
7023
- this.sendSpan(span);
7176
+ const originalTraceId = span.traceId ?? "";
7177
+ const traceId = this.activeSpanMappings[originalTraceId]?.traceId ?? originalTraceId;
7178
+ try {
7179
+ this.sendSpan(span);
7180
+ } finally {
7181
+ if (span.spanId !== void 0) {
7182
+ this.httpClient.traceCompletion.end(traceId, span.spanId);
7183
+ this.startedSpans.delete(span.spanId);
7184
+ }
7185
+ this.cleanupTrace(originalTraceId);
7186
+ }
7024
7187
  }
7025
7188
  /**
7026
7189
  * Called when a trace is being flushed.
@@ -8726,6 +8889,7 @@ var Bitfab = class {
8726
8889
  let newStack;
8727
8890
  let executeWithContext;
8728
8891
  let registeredTraceId;
8892
+ let startedSpan;
8729
8893
  try {
8730
8894
  const currentStack = getSpanStack();
8731
8895
  const parentContext = currentStack[currentStack.length - 1];
@@ -8777,6 +8941,8 @@ var Bitfab = class {
8777
8941
  });
8778
8942
  registeredTraceId = traceId;
8779
8943
  }
8944
+ self.httpClient.traceCompletion.start(traceId, spanId);
8945
+ startedSpan = { traceId, spanId };
8780
8946
  const functionName = fn.name !== "" ? fn.name : void 0;
8781
8947
  const rootTraceFunctionKey = activeTraceStates.get(traceId)?.traceFunctionKey ?? traceFunctionKey;
8782
8948
  const baseSpanParams = {
@@ -8851,6 +9017,8 @@ var Bitfab = class {
8851
9017
  retireTraceMetadata(traceId);
8852
9018
  }
8853
9019
  } catch {
9020
+ } finally {
9021
+ self.httpClient.traceCompletion.end(traceId, spanId);
8854
9022
  }
8855
9023
  };
8856
9024
  const recordSpan = (result) => {
@@ -8867,6 +9035,14 @@ var Bitfab = class {
8867
9035
  void sendSpan({ result });
8868
9036
  }
8869
9037
  };
9038
+ const resolveMockOrAbort = async (resolve) => {
9039
+ try {
9040
+ return await resolve();
9041
+ } catch (error) {
9042
+ self.httpClient.traceCompletion.abort(traceId, spanId);
9043
+ throw error;
9044
+ }
9045
+ };
8870
9046
  executeWithContext = () => {
8871
9047
  let result;
8872
9048
  try {
@@ -8923,7 +9099,7 @@ var Bitfab = class {
8923
9099
  );
8924
9100
  }
8925
9101
  return (async () => {
8926
- const output = await pending;
9102
+ const output = await resolveMockOrAbort(() => pending);
8927
9103
  void sendSpan({
8928
9104
  result: output,
8929
9105
  mocked: true,
@@ -8993,7 +9169,7 @@ var Bitfab = class {
8993
9169
  );
8994
9170
  }
8995
9171
  return runWithSpanStack(newStack, async () => {
8996
- const resolved2 = await resolution;
9172
+ const resolved2 = await resolveMockOrAbort(() => resolution);
8997
9173
  if (resolved2.matched) {
8998
9174
  void sendSpan({
8999
9175
  result: resolved2.output,
@@ -9009,7 +9185,9 @@ var Bitfab = class {
9009
9185
  );
9010
9186
  }
9011
9187
  if (shouldMockWithBaseStrategy) {
9012
- const output = await resolveRecordedOutput();
9188
+ const output = await resolveMockOrAbort(
9189
+ () => resolveRecordedOutput()
9190
+ );
9013
9191
  void sendSpan({
9014
9192
  result: output,
9015
9193
  mocked: true,
@@ -9039,6 +9217,12 @@ var Bitfab = class {
9039
9217
  }
9040
9218
  }
9041
9219
  } catch (setupError) {
9220
+ if (startedSpan) {
9221
+ self.httpClient.traceCompletion.abort(
9222
+ startedSpan.traceId,
9223
+ startedSpan.spanId
9224
+ );
9225
+ }
9042
9226
  if (registeredTraceId) {
9043
9227
  activeTraceStates.delete(registeredTraceId);
9044
9228
  retireTraceMetadata(registeredTraceId);