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/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.54.3";
54
+ __version__ = "0.54.5";
55
55
  __packageName__ = "bitfab";
56
56
  }
57
57
  });
@@ -66,6 +66,99 @@ var init_constants = __esm({
66
66
  }
67
67
  });
68
68
 
69
+ // src/traceCompletion.ts
70
+ var TraceCompletion;
71
+ var init_traceCompletion = __esm({
72
+ "src/traceCompletion.ts"() {
73
+ "use strict";
74
+ TraceCompletion = class {
75
+ constructor() {
76
+ this.traces = /* @__PURE__ */ new Map();
77
+ this.closed = /* @__PURE__ */ new Map();
78
+ }
79
+ state(traceId) {
80
+ let state = this.traces.get(traceId);
81
+ if (state === void 0) {
82
+ state = { spanIds: /* @__PURE__ */ new Set(), active: /* @__PURE__ */ new Set() };
83
+ this.traces.set(traceId, state);
84
+ }
85
+ return state;
86
+ }
87
+ start(traceId, spanId) {
88
+ if (this.closed.has(traceId)) {
89
+ return;
90
+ }
91
+ const state = this.state(traceId);
92
+ state.spanIds.add(spanId);
93
+ state.active.add(spanId);
94
+ }
95
+ open(traceId) {
96
+ if (!this.closed.has(traceId)) {
97
+ this.state(traceId);
98
+ }
99
+ }
100
+ hold(traceId, key) {
101
+ this.state(traceId).active.add(key);
102
+ }
103
+ record(traceId, spanId) {
104
+ if (!this.closed.has(traceId)) {
105
+ this.state(traceId).spanIds.add(spanId);
106
+ }
107
+ }
108
+ end(traceId, spanId) {
109
+ const state = this.traces.get(traceId);
110
+ if (state !== void 0) {
111
+ state.active.delete(spanId);
112
+ this.drain(traceId, state);
113
+ }
114
+ }
115
+ abort(traceId, spanId) {
116
+ const state = this.traces.get(traceId);
117
+ if (state === void 0) {
118
+ return;
119
+ }
120
+ state.active.delete(spanId);
121
+ state.spanIds.delete(spanId);
122
+ if (state.active.size === 0 && state.spanIds.size === 0 && state.complete === void 0) {
123
+ this.traces.delete(traceId);
124
+ return;
125
+ }
126
+ this.drain(traceId, state);
127
+ }
128
+ close(traceId, complete, dropped = false) {
129
+ const count = this.closed.get(traceId);
130
+ if (count !== void 0) {
131
+ complete(count);
132
+ return;
133
+ }
134
+ const state = this.traces.get(traceId);
135
+ if (state === void 0) {
136
+ return;
137
+ }
138
+ state.complete = complete;
139
+ if (dropped) {
140
+ state.active.clear();
141
+ }
142
+ this.drain(traceId, state);
143
+ }
144
+ drain(traceId, state) {
145
+ if (state.active.size !== 0 || state.complete === void 0) {
146
+ return;
147
+ }
148
+ this.traces.delete(traceId);
149
+ this.closed.set(traceId, state.spanIds.size);
150
+ if (this.closed.size > 1024) {
151
+ const oldest = this.closed.keys().next().value;
152
+ if (oldest !== void 0) {
153
+ this.closed.delete(oldest);
154
+ }
155
+ }
156
+ state.complete(state.spanIds.size);
157
+ }
158
+ };
159
+ }
160
+ });
161
+
69
162
  // src/readEnv.ts
70
163
  function readEnv(name) {
71
164
  if (typeof process !== "undefined" && process.env) {
@@ -2152,6 +2245,7 @@ var REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS, REPLAY_COMPLETE_REQUEST_TIMEOUT_MS, OTL
2152
2245
  var init_http = __esm({
2153
2246
  "src/http.ts"() {
2154
2247
  "use strict";
2248
+ init_traceCompletion();
2155
2249
  init_compress();
2156
2250
  init_constants();
2157
2251
  init_errors();
@@ -2214,6 +2308,7 @@ var init_http = __esm({
2214
2308
  // must not wait on another client's slow finalize: a false `close()` failure
2215
2309
  // caused by unrelated work is worse than no signal at all.
2216
2310
  this.deferredWork = /* @__PURE__ */ new Set();
2311
+ this.traceCompletion = new TraceCompletion();
2217
2312
  this.closed = false;
2218
2313
  this.apiKey = config.apiKey;
2219
2314
  this.serviceUrl = config.serviceUrl;
@@ -2647,6 +2742,10 @@ var init_http = __esm({
2647
2742
  );
2648
2743
  }
2649
2744
  sendExternalSpan(payload) {
2745
+ const ref2 = carrierRef(payload);
2746
+ if (ref2?.spanId !== void 0) {
2747
+ this.traceCompletion.record(ref2.traceId, ref2.spanId);
2748
+ }
2650
2749
  const gate = this.externalSpanTransform;
2651
2750
  if (gate === void 0) {
2652
2751
  this.submitExternalSpan(payload);
@@ -2678,13 +2777,28 @@ var init_http = __esm({
2678
2777
  */
2679
2778
  sendExternalTrace(rawPayload) {
2680
2779
  const payload = mergeCallerMetadataIntoTracePayload(rawPayload);
2681
- const gate = this.externalTraceTransform;
2682
- if (gate === void 0) {
2683
- this.submitExternalTrace(payload);
2780
+ const traceId = sourceTraceIdOf(payload);
2781
+ if (payload.completed === true && traceId !== void 0) {
2782
+ this.traceCompletion.close(
2783
+ traceId,
2784
+ (expectedSpanCount) => this.sendCountedExternalTrace({ ...payload, expectedSpanCount }),
2785
+ payload.dropped === true
2786
+ );
2684
2787
  return;
2685
2788
  }
2789
+ if (traceId !== void 0) {
2790
+ this.traceCompletion.open(traceId);
2791
+ }
2792
+ this.sendCountedExternalTrace(payload);
2793
+ }
2794
+ sendCountedExternalTrace(payload) {
2686
2795
  try {
2687
- gate(payload, (ready) => this.submitExternalTrace(ready));
2796
+ const gate = this.externalTraceTransform;
2797
+ if (gate === void 0) {
2798
+ this.submitExternalTrace(payload);
2799
+ } else {
2800
+ gate(payload, (ready) => this.submitExternalTrace(ready));
2801
+ }
2688
2802
  } catch (error) {
2689
2803
  warnDroppedExternalTrace(error);
2690
2804
  }
@@ -4237,45 +4351,6 @@ var AssertionCategoriesClient = class {
4237
4351
  }
4238
4352
  };
4239
4353
 
4240
- // src/assertions.ts
4241
- var ASSERTIONS_PATH = "/api/sdk/traces/assertions";
4242
- function traceAssertionsPath(traceId, suffix = "") {
4243
- return `/api/sdk/traces/${encodeURIComponent(traceId)}/assertions${suffix}`;
4244
- }
4245
- var TracesClient = class {
4246
- constructor(httpClient) {
4247
- this.httpClient = httpClient;
4248
- }
4249
- async getAssertions(traceId) {
4250
- return this.httpClient.get(
4251
- traceAssertionsPath(traceId)
4252
- );
4253
- }
4254
- async saveAssertions(params) {
4255
- return this.saveAssertionsAll({
4256
- updates: [{ traceId: params.traceId, assertions: params.assertions }],
4257
- source: params.source
4258
- });
4259
- }
4260
- async saveAssertionsAll(params) {
4261
- if (params.updates.length === 0) {
4262
- return [];
4263
- }
4264
- const response = await this.httpClient.request(ASSERTIONS_PATH, {
4265
- updates: params.updates,
4266
- source: params.source ?? "agent"
4267
- });
4268
- return response.assertions;
4269
- }
4270
- async archiveAssertions(params) {
4271
- const response = await this.httpClient.request(
4272
- traceAssertionsPath(params.traceId, "/archive"),
4273
- { assertionIds: params.assertionIds }
4274
- );
4275
- return response.archived;
4276
- }
4277
- };
4278
-
4279
4354
  // src/claudeAgentSdk.ts
4280
4355
  init_constants();
4281
4356
  init_http();
@@ -4503,6 +4578,7 @@ var BitfabClaudeAgentHandler = class {
4503
4578
  spanInfo.dropped = [...inputDropped];
4504
4579
  }
4505
4580
  this.runToSpan.set(spanId, spanInfo);
4581
+ this.httpClient.traceCompletion.start(spanInfo.traceId, spanInfo.spanId);
4506
4582
  return spanInfo;
4507
4583
  }
4508
4584
  completeSpan(spanId, output, error, extraContexts) {
@@ -4524,6 +4600,7 @@ var BitfabClaudeAgentHandler = class {
4524
4600
  spanInfo.contexts.push(extraContexts);
4525
4601
  }
4526
4602
  this.sendSpan(spanInfo);
4603
+ this.httpClient.traceCompletion.end(spanInfo.traceId, spanInfo.spanId);
4527
4604
  }
4528
4605
  sendSpan(spanInfo) {
4529
4606
  const spanData = {
@@ -6181,6 +6258,9 @@ var BitfabLangGraphCallbackHandler = class {
6181
6258
  spanInfo.hidden = true;
6182
6259
  }
6183
6260
  this.runToSpan.set(runId, spanInfo);
6261
+ if (spanInfo.hidden !== true) {
6262
+ this.httpClient.traceCompletion.start(spanInfo.traceId, spanInfo.spanId);
6263
+ }
6184
6264
  if (isRootInvocation) {
6185
6265
  this.sendTraceStart(spanInfo);
6186
6266
  }
@@ -6212,6 +6292,7 @@ var BitfabLangGraphCallbackHandler = class {
6212
6292
  this.sendTraceCompletion(spanInfo, invocation?.activeContext ?? null);
6213
6293
  this.invocations.delete(runId);
6214
6294
  }
6295
+ this.httpClient.traceCompletion.end(spanInfo.traceId, spanInfo.spanId);
6215
6296
  }
6216
6297
  sendSpan(spanInfo) {
6217
6298
  const spanData = {
@@ -6918,6 +6999,55 @@ var StreamFinalizationError = class extends Error {
6918
6999
  // src/client.ts
6919
7000
  init_traceMetadata();
6920
7001
 
7002
+ // src/traces.ts
7003
+ var ASSERTIONS_PATH = "/api/sdk/traces/assertions";
7004
+ var SEARCH_PATH = "/api/sdk/traces/search";
7005
+ function traceAssertionsPath(traceId, suffix = "") {
7006
+ return `/api/sdk/traces/${encodeURIComponent(traceId)}/assertions${suffix}`;
7007
+ }
7008
+ var TracesClient = class {
7009
+ constructor(httpClient) {
7010
+ this.httpClient = httpClient;
7011
+ }
7012
+ /**
7013
+ * Search traces by exact caller metadata.
7014
+ *
7015
+ * Keys and values are matched case-insensitively. Up to 10 supplied pairs
7016
+ * must match. Use `nextCursor` from the result to fetch another page.
7017
+ */
7018
+ async search(params) {
7019
+ return this.httpClient.request(SEARCH_PATH, params);
7020
+ }
7021
+ async getAssertions(traceId) {
7022
+ return this.httpClient.get(
7023
+ traceAssertionsPath(traceId)
7024
+ );
7025
+ }
7026
+ async saveAssertions(params) {
7027
+ return this.saveAssertionsAll({
7028
+ updates: [{ traceId: params.traceId, assertions: params.assertions }],
7029
+ source: params.source
7030
+ });
7031
+ }
7032
+ async saveAssertionsAll(params) {
7033
+ if (params.updates.length === 0) {
7034
+ return [];
7035
+ }
7036
+ const response = await this.httpClient.request(ASSERTIONS_PATH, {
7037
+ updates: params.updates,
7038
+ source: params.source ?? "agent"
7039
+ });
7040
+ return response.assertions;
7041
+ }
7042
+ async archiveAssertions(params) {
7043
+ const response = await this.httpClient.request(
7044
+ traceAssertionsPath(params.traceId, "/archive"),
7045
+ { assertionIds: params.assertionIds }
7046
+ );
7047
+ return response.archived;
7048
+ }
7049
+ };
7050
+
6921
7051
  // src/tracing.ts
6922
7052
  init_constants();
6923
7053
  init_http();
@@ -6933,6 +7063,8 @@ var BitfabOpenAITracingProcessor = class {
6933
7063
  this.activeTraces = {};
6934
7064
  this.activeSpanMappings = {};
6935
7065
  this.canonicalTraceIds = {};
7066
+ this.startedSpans = /* @__PURE__ */ new Map();
7067
+ this.endedTraces = /* @__PURE__ */ new Set();
6936
7068
  this.ownsHttpClient = config._httpClient === void 0;
6937
7069
  this.httpClient = config._httpClient ?? new HttpClient({
6938
7070
  apiKey: config.apiKey,
@@ -6971,6 +7103,10 @@ var BitfabOpenAITracingProcessor = class {
6971
7103
  }
6972
7104
  const canonicalTraceId = activeContext?.traceId ?? this.getCanonicalTraceId(trace.traceId);
6973
7105
  this.canonicalTraceIds[trace.traceId] = canonicalTraceId;
7106
+ this.httpClient.traceCompletion.hold(
7107
+ activeContext?.traceId ?? trace.traceId,
7108
+ `openai:${trace.traceId}`
7109
+ );
6974
7110
  this.sendTrace(trace, {
6975
7111
  id: canonicalTraceId,
6976
7112
  sourceTraceId: activeContext?.traceId
@@ -6988,16 +7124,33 @@ var BitfabOpenAITracingProcessor = class {
6988
7124
  id: mapping?.traceId ?? this.getCanonicalTraceId(trace.traceId),
6989
7125
  sourceTraceId: mapping?.traceId
6990
7126
  });
6991
- delete this.activeSpanMappings[trace.traceId];
6992
- delete this.canonicalTraceIds[trace.traceId];
6993
- delete this.activeTraces[trace.traceId];
7127
+ this.endedTraces.add(trace.traceId);
7128
+ this.httpClient.traceCompletion.end(
7129
+ mapping?.traceId ?? trace.traceId,
7130
+ `openai:${trace.traceId}`
7131
+ );
7132
+ this.cleanupTrace(trace.traceId);
7133
+ }
7134
+ cleanupTrace(traceId) {
7135
+ if (!this.endedTraces.has(traceId) || [...this.startedSpans.values()].includes(traceId)) {
7136
+ return;
7137
+ }
7138
+ this.endedTraces.delete(traceId);
7139
+ delete this.activeSpanMappings[traceId];
7140
+ delete this.canonicalTraceIds[traceId];
7141
+ delete this.activeTraces[traceId];
6994
7142
  }
6995
7143
  /**
6996
7144
  * Called when a span is started. Span payloads are authoritative completed
6997
7145
  * snapshots, so start notifications do not cross the transport boundary.
6998
7146
  */
6999
7147
  // biome-ignore lint/suspicious/noExplicitAny: OpenAI Agents SDK uses any for span data
7000
- async onSpanStart(_span) {
7148
+ async onSpanStart(span) {
7149
+ if (span.spanId !== void 0 && span.traceId !== null && span.traceId !== void 0) {
7150
+ this.startedSpans.set(span.spanId, span.traceId);
7151
+ const traceId = this.activeSpanMappings[span.traceId]?.traceId ?? span.traceId;
7152
+ this.httpClient.traceCompletion.start(traceId, span.spanId);
7153
+ }
7001
7154
  }
7002
7155
  /**
7003
7156
  * Called when a span is ended.
@@ -7006,7 +7159,17 @@ var BitfabOpenAITracingProcessor = class {
7006
7159
  */
7007
7160
  // biome-ignore lint/suspicious/noExplicitAny: OpenAI Agents SDK uses any for span data
7008
7161
  async onSpanEnd(span) {
7009
- this.sendSpan(span);
7162
+ const originalTraceId = span.traceId ?? "";
7163
+ const traceId = this.activeSpanMappings[originalTraceId]?.traceId ?? originalTraceId;
7164
+ try {
7165
+ this.sendSpan(span);
7166
+ } finally {
7167
+ if (span.spanId !== void 0) {
7168
+ this.httpClient.traceCompletion.end(traceId, span.spanId);
7169
+ this.startedSpans.delete(span.spanId);
7170
+ }
7171
+ this.cleanupTrace(originalTraceId);
7172
+ }
7010
7173
  }
7011
7174
  /**
7012
7175
  * Called when a trace is being flushed.
@@ -8712,6 +8875,7 @@ var Bitfab = class {
8712
8875
  let newStack;
8713
8876
  let executeWithContext;
8714
8877
  let registeredTraceId;
8878
+ let startedSpan;
8715
8879
  try {
8716
8880
  const currentStack = getSpanStack();
8717
8881
  const parentContext = currentStack[currentStack.length - 1];
@@ -8763,6 +8927,8 @@ var Bitfab = class {
8763
8927
  });
8764
8928
  registeredTraceId = traceId;
8765
8929
  }
8930
+ self.httpClient.traceCompletion.start(traceId, spanId);
8931
+ startedSpan = { traceId, spanId };
8766
8932
  const functionName = fn.name !== "" ? fn.name : void 0;
8767
8933
  const rootTraceFunctionKey = activeTraceStates.get(traceId)?.traceFunctionKey ?? traceFunctionKey;
8768
8934
  const baseSpanParams = {
@@ -8837,6 +9003,8 @@ var Bitfab = class {
8837
9003
  retireTraceMetadata(traceId);
8838
9004
  }
8839
9005
  } catch {
9006
+ } finally {
9007
+ self.httpClient.traceCompletion.end(traceId, spanId);
8840
9008
  }
8841
9009
  };
8842
9010
  const recordSpan = (result) => {
@@ -8853,6 +9021,14 @@ var Bitfab = class {
8853
9021
  void sendSpan({ result });
8854
9022
  }
8855
9023
  };
9024
+ const resolveMockOrAbort = async (resolve) => {
9025
+ try {
9026
+ return await resolve();
9027
+ } catch (error) {
9028
+ self.httpClient.traceCompletion.abort(traceId, spanId);
9029
+ throw error;
9030
+ }
9031
+ };
8856
9032
  executeWithContext = () => {
8857
9033
  let result;
8858
9034
  try {
@@ -8909,7 +9085,7 @@ var Bitfab = class {
8909
9085
  );
8910
9086
  }
8911
9087
  return (async () => {
8912
- const output = await pending;
9088
+ const output = await resolveMockOrAbort(() => pending);
8913
9089
  void sendSpan({
8914
9090
  result: output,
8915
9091
  mocked: true,
@@ -8979,7 +9155,7 @@ var Bitfab = class {
8979
9155
  );
8980
9156
  }
8981
9157
  return runWithSpanStack(newStack, async () => {
8982
- const resolved2 = await resolution;
9158
+ const resolved2 = await resolveMockOrAbort(() => resolution);
8983
9159
  if (resolved2.matched) {
8984
9160
  void sendSpan({
8985
9161
  result: resolved2.output,
@@ -8995,7 +9171,9 @@ var Bitfab = class {
8995
9171
  );
8996
9172
  }
8997
9173
  if (shouldMockWithBaseStrategy) {
8998
- const output = await resolveRecordedOutput();
9174
+ const output = await resolveMockOrAbort(
9175
+ () => resolveRecordedOutput()
9176
+ );
8999
9177
  void sendSpan({
9000
9178
  result: output,
9001
9179
  mocked: true,
@@ -9025,6 +9203,12 @@ var Bitfab = class {
9025
9203
  }
9026
9204
  }
9027
9205
  } catch (setupError) {
9206
+ if (startedSpan) {
9207
+ self.httpClient.traceCompletion.abort(
9208
+ startedSpan.traceId,
9209
+ startedSpan.spanId
9210
+ );
9211
+ }
9028
9212
  if (registeredTraceId) {
9029
9213
  activeTraceStates.delete(registeredTraceId);
9030
9214
  retireTraceMetadata(registeredTraceId);