@bitfab/sdk 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-GNHJKB5U.js → chunk-3STIE5QL.js} +113 -6
  2. package/dist/chunk-3STIE5QL.js.map +1 -0
  3. package/dist/{chunk-NONYCJ2E.js → chunk-4G3ZJBXQ.js} +3 -3
  4. package/dist/{chunk-GTDGXH7C.js → chunk-7DSNNK5I.js} +124 -54
  5. package/dist/chunk-7DSNNK5I.js.map +1 -0
  6. package/dist/{chunk-GRMGUSH4.js → chunk-PIF5HH3Z.js} +113 -6
  7. package/dist/chunk-PIF5HH3Z.js.map +1 -0
  8. package/dist/{chunk-QKZYQWUR.js → chunk-YH6YO2WS.js} +2 -2
  9. package/dist/{http-N4UKTUO7.js → http-36EP65LE.js} +2 -2
  10. package/dist/{http-LIAIPCJB.js → http-JQ4RXRWH.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-OFNZHVQZ.js → replay-HNSQHX52.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-GNHJKB5U.js.map +0 -1
  26. package/dist/chunk-GRMGUSH4.js.map +0 -1
  27. package/dist/chunk-GTDGXH7C.js.map +0 -1
  28. /package/dist/{chunk-NONYCJ2E.js.map → chunk-4G3ZJBXQ.js.map} +0 -0
  29. /package/dist/{chunk-QKZYQWUR.js.map → chunk-YH6YO2WS.js.map} +0 -0
  30. /package/dist/{http-LIAIPCJB.js.map → http-36EP65LE.js.map} +0 -0
  31. /package/dist/{http-N4UKTUO7.js.map → http-JQ4RXRWH.js.map} +0 -0
  32. /package/dist/{replay-OFNZHVQZ.js.map → replay-HNSQHX52.js.map} +0 -0
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.5";
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
  }
@@ -4228,45 +4342,6 @@ var AssertionCategoriesClient = class {
4228
4342
  }
4229
4343
  };
4230
4344
 
4231
- // src/assertions.ts
4232
- var ASSERTIONS_PATH = "/api/sdk/traces/assertions";
4233
- function traceAssertionsPath(traceId, suffix = "") {
4234
- return `/api/sdk/traces/${encodeURIComponent(traceId)}/assertions${suffix}`;
4235
- }
4236
- var TracesClient = class {
4237
- constructor(httpClient) {
4238
- this.httpClient = httpClient;
4239
- }
4240
- async getAssertions(traceId) {
4241
- return this.httpClient.get(
4242
- traceAssertionsPath(traceId)
4243
- );
4244
- }
4245
- async saveAssertions(params) {
4246
- return this.saveAssertionsAll({
4247
- updates: [{ traceId: params.traceId, assertions: params.assertions }],
4248
- source: params.source
4249
- });
4250
- }
4251
- async saveAssertionsAll(params) {
4252
- if (params.updates.length === 0) {
4253
- return [];
4254
- }
4255
- const response = await this.httpClient.request(ASSERTIONS_PATH, {
4256
- updates: params.updates,
4257
- source: params.source ?? "agent"
4258
- });
4259
- return response.assertions;
4260
- }
4261
- async archiveAssertions(params) {
4262
- const response = await this.httpClient.request(
4263
- traceAssertionsPath(params.traceId, "/archive"),
4264
- { assertionIds: params.assertionIds }
4265
- );
4266
- return response.archived;
4267
- }
4268
- };
4269
-
4270
4345
  // src/claudeAgentSdk.ts
4271
4346
  init_constants();
4272
4347
  init_http();
@@ -4494,6 +4569,7 @@ var BitfabClaudeAgentHandler = class {
4494
4569
  spanInfo.dropped = [...inputDropped];
4495
4570
  }
4496
4571
  this.runToSpan.set(spanId, spanInfo);
4572
+ this.httpClient.traceCompletion.start(spanInfo.traceId, spanInfo.spanId);
4497
4573
  return spanInfo;
4498
4574
  }
4499
4575
  completeSpan(spanId, output, error, extraContexts) {
@@ -4515,6 +4591,7 @@ var BitfabClaudeAgentHandler = class {
4515
4591
  spanInfo.contexts.push(extraContexts);
4516
4592
  }
4517
4593
  this.sendSpan(spanInfo);
4594
+ this.httpClient.traceCompletion.end(spanInfo.traceId, spanInfo.spanId);
4518
4595
  }
4519
4596
  sendSpan(spanInfo) {
4520
4597
  const spanData = {
@@ -6172,6 +6249,9 @@ var BitfabLangGraphCallbackHandler = class {
6172
6249
  spanInfo.hidden = true;
6173
6250
  }
6174
6251
  this.runToSpan.set(runId, spanInfo);
6252
+ if (spanInfo.hidden !== true) {
6253
+ this.httpClient.traceCompletion.start(spanInfo.traceId, spanInfo.spanId);
6254
+ }
6175
6255
  if (isRootInvocation) {
6176
6256
  this.sendTraceStart(spanInfo);
6177
6257
  }
@@ -6203,6 +6283,7 @@ var BitfabLangGraphCallbackHandler = class {
6203
6283
  this.sendTraceCompletion(spanInfo, invocation?.activeContext ?? null);
6204
6284
  this.invocations.delete(runId);
6205
6285
  }
6286
+ this.httpClient.traceCompletion.end(spanInfo.traceId, spanInfo.spanId);
6206
6287
  }
6207
6288
  sendSpan(spanInfo) {
6208
6289
  const spanData = {
@@ -6909,6 +6990,55 @@ var StreamFinalizationError = class extends Error {
6909
6990
  // src/client.ts
6910
6991
  init_traceMetadata();
6911
6992
 
6993
+ // src/traces.ts
6994
+ var ASSERTIONS_PATH = "/api/sdk/traces/assertions";
6995
+ var SEARCH_PATH = "/api/sdk/traces/search";
6996
+ function traceAssertionsPath(traceId, suffix = "") {
6997
+ return `/api/sdk/traces/${encodeURIComponent(traceId)}/assertions${suffix}`;
6998
+ }
6999
+ var TracesClient = class {
7000
+ constructor(httpClient) {
7001
+ this.httpClient = httpClient;
7002
+ }
7003
+ /**
7004
+ * Search traces by exact caller metadata.
7005
+ *
7006
+ * Keys and values are matched case-insensitively. Up to 10 supplied pairs
7007
+ * must match. Use `nextCursor` from the result to fetch another page.
7008
+ */
7009
+ async search(params) {
7010
+ return this.httpClient.request(SEARCH_PATH, params);
7011
+ }
7012
+ async getAssertions(traceId) {
7013
+ return this.httpClient.get(
7014
+ traceAssertionsPath(traceId)
7015
+ );
7016
+ }
7017
+ async saveAssertions(params) {
7018
+ return this.saveAssertionsAll({
7019
+ updates: [{ traceId: params.traceId, assertions: params.assertions }],
7020
+ source: params.source
7021
+ });
7022
+ }
7023
+ async saveAssertionsAll(params) {
7024
+ if (params.updates.length === 0) {
7025
+ return [];
7026
+ }
7027
+ const response = await this.httpClient.request(ASSERTIONS_PATH, {
7028
+ updates: params.updates,
7029
+ source: params.source ?? "agent"
7030
+ });
7031
+ return response.assertions;
7032
+ }
7033
+ async archiveAssertions(params) {
7034
+ const response = await this.httpClient.request(
7035
+ traceAssertionsPath(params.traceId, "/archive"),
7036
+ { assertionIds: params.assertionIds }
7037
+ );
7038
+ return response.archived;
7039
+ }
7040
+ };
7041
+
6912
7042
  // src/tracing.ts
6913
7043
  init_constants();
6914
7044
  init_http();
@@ -6924,6 +7054,8 @@ var BitfabOpenAITracingProcessor = class {
6924
7054
  this.activeTraces = {};
6925
7055
  this.activeSpanMappings = {};
6926
7056
  this.canonicalTraceIds = {};
7057
+ this.startedSpans = /* @__PURE__ */ new Map();
7058
+ this.endedTraces = /* @__PURE__ */ new Set();
6927
7059
  this.ownsHttpClient = config._httpClient === void 0;
6928
7060
  this.httpClient = config._httpClient ?? new HttpClient({
6929
7061
  apiKey: config.apiKey,
@@ -6962,6 +7094,10 @@ var BitfabOpenAITracingProcessor = class {
6962
7094
  }
6963
7095
  const canonicalTraceId = activeContext?.traceId ?? this.getCanonicalTraceId(trace.traceId);
6964
7096
  this.canonicalTraceIds[trace.traceId] = canonicalTraceId;
7097
+ this.httpClient.traceCompletion.hold(
7098
+ activeContext?.traceId ?? trace.traceId,
7099
+ `openai:${trace.traceId}`
7100
+ );
6965
7101
  this.sendTrace(trace, {
6966
7102
  id: canonicalTraceId,
6967
7103
  sourceTraceId: activeContext?.traceId
@@ -6979,16 +7115,33 @@ var BitfabOpenAITracingProcessor = class {
6979
7115
  id: mapping?.traceId ?? this.getCanonicalTraceId(trace.traceId),
6980
7116
  sourceTraceId: mapping?.traceId
6981
7117
  });
6982
- delete this.activeSpanMappings[trace.traceId];
6983
- delete this.canonicalTraceIds[trace.traceId];
6984
- delete this.activeTraces[trace.traceId];
7118
+ this.endedTraces.add(trace.traceId);
7119
+ this.httpClient.traceCompletion.end(
7120
+ mapping?.traceId ?? trace.traceId,
7121
+ `openai:${trace.traceId}`
7122
+ );
7123
+ this.cleanupTrace(trace.traceId);
7124
+ }
7125
+ cleanupTrace(traceId) {
7126
+ if (!this.endedTraces.has(traceId) || [...this.startedSpans.values()].includes(traceId)) {
7127
+ return;
7128
+ }
7129
+ this.endedTraces.delete(traceId);
7130
+ delete this.activeSpanMappings[traceId];
7131
+ delete this.canonicalTraceIds[traceId];
7132
+ delete this.activeTraces[traceId];
6985
7133
  }
6986
7134
  /**
6987
7135
  * Called when a span is started. Span payloads are authoritative completed
6988
7136
  * snapshots, so start notifications do not cross the transport boundary.
6989
7137
  */
6990
7138
  // biome-ignore lint/suspicious/noExplicitAny: OpenAI Agents SDK uses any for span data
6991
- async onSpanStart(_span) {
7139
+ async onSpanStart(span) {
7140
+ if (span.spanId !== void 0 && span.traceId !== null && span.traceId !== void 0) {
7141
+ this.startedSpans.set(span.spanId, span.traceId);
7142
+ const traceId = this.activeSpanMappings[span.traceId]?.traceId ?? span.traceId;
7143
+ this.httpClient.traceCompletion.start(traceId, span.spanId);
7144
+ }
6992
7145
  }
6993
7146
  /**
6994
7147
  * Called when a span is ended.
@@ -6997,7 +7150,17 @@ var BitfabOpenAITracingProcessor = class {
6997
7150
  */
6998
7151
  // biome-ignore lint/suspicious/noExplicitAny: OpenAI Agents SDK uses any for span data
6999
7152
  async onSpanEnd(span) {
7000
- this.sendSpan(span);
7153
+ const originalTraceId = span.traceId ?? "";
7154
+ const traceId = this.activeSpanMappings[originalTraceId]?.traceId ?? originalTraceId;
7155
+ try {
7156
+ this.sendSpan(span);
7157
+ } finally {
7158
+ if (span.spanId !== void 0) {
7159
+ this.httpClient.traceCompletion.end(traceId, span.spanId);
7160
+ this.startedSpans.delete(span.spanId);
7161
+ }
7162
+ this.cleanupTrace(originalTraceId);
7163
+ }
7001
7164
  }
7002
7165
  /**
7003
7166
  * Called when a trace is being flushed.
@@ -8703,6 +8866,7 @@ var Bitfab = class {
8703
8866
  let newStack;
8704
8867
  let executeWithContext;
8705
8868
  let registeredTraceId;
8869
+ let startedSpan;
8706
8870
  try {
8707
8871
  const currentStack = getSpanStack();
8708
8872
  const parentContext = currentStack[currentStack.length - 1];
@@ -8754,6 +8918,8 @@ var Bitfab = class {
8754
8918
  });
8755
8919
  registeredTraceId = traceId;
8756
8920
  }
8921
+ self.httpClient.traceCompletion.start(traceId, spanId);
8922
+ startedSpan = { traceId, spanId };
8757
8923
  const functionName = fn.name !== "" ? fn.name : void 0;
8758
8924
  const rootTraceFunctionKey = activeTraceStates.get(traceId)?.traceFunctionKey ?? traceFunctionKey;
8759
8925
  const baseSpanParams = {
@@ -8828,6 +8994,8 @@ var Bitfab = class {
8828
8994
  retireTraceMetadata(traceId);
8829
8995
  }
8830
8996
  } catch {
8997
+ } finally {
8998
+ self.httpClient.traceCompletion.end(traceId, spanId);
8831
8999
  }
8832
9000
  };
8833
9001
  const recordSpan = (result) => {
@@ -8844,6 +9012,14 @@ var Bitfab = class {
8844
9012
  void sendSpan({ result });
8845
9013
  }
8846
9014
  };
9015
+ const resolveMockOrAbort = async (resolve) => {
9016
+ try {
9017
+ return await resolve();
9018
+ } catch (error) {
9019
+ self.httpClient.traceCompletion.abort(traceId, spanId);
9020
+ throw error;
9021
+ }
9022
+ };
8847
9023
  executeWithContext = () => {
8848
9024
  let result;
8849
9025
  try {
@@ -8900,7 +9076,7 @@ var Bitfab = class {
8900
9076
  );
8901
9077
  }
8902
9078
  return (async () => {
8903
- const output = await pending;
9079
+ const output = await resolveMockOrAbort(() => pending);
8904
9080
  void sendSpan({
8905
9081
  result: output,
8906
9082
  mocked: true,
@@ -8970,7 +9146,7 @@ var Bitfab = class {
8970
9146
  );
8971
9147
  }
8972
9148
  return runWithSpanStack(newStack, async () => {
8973
- const resolved2 = await resolution;
9149
+ const resolved2 = await resolveMockOrAbort(() => resolution);
8974
9150
  if (resolved2.matched) {
8975
9151
  void sendSpan({
8976
9152
  result: resolved2.output,
@@ -8986,7 +9162,9 @@ var Bitfab = class {
8986
9162
  );
8987
9163
  }
8988
9164
  if (shouldMockWithBaseStrategy) {
8989
- const output = await resolveRecordedOutput();
9165
+ const output = await resolveMockOrAbort(
9166
+ () => resolveRecordedOutput()
9167
+ );
8990
9168
  void sendSpan({
8991
9169
  result: output,
8992
9170
  mocked: true,
@@ -9016,6 +9194,12 @@ var Bitfab = class {
9016
9194
  }
9017
9195
  }
9018
9196
  } catch (setupError) {
9197
+ if (startedSpan) {
9198
+ self.httpClient.traceCompletion.abort(
9199
+ startedSpan.traceId,
9200
+ startedSpan.spanId
9201
+ );
9202
+ }
9019
9203
  if (registeredTraceId) {
9020
9204
  activeTraceStates.delete(registeredTraceId);
9021
9205
  retireTraceMetadata(registeredTraceId);