neatlogs 1.1.17 → 1.1.18

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
@@ -4549,6 +4549,7 @@ var NeatlogsSpanProcessor = class {
4549
4549
  unifiedProcessor;
4550
4550
  perfStats;
4551
4551
  _retrieversToSuppress;
4552
+ _activeSpans;
4552
4553
  // File logging
4553
4554
  _logRawSpansEnabled;
4554
4555
  _logProcessedSpansEnabled;
@@ -4574,6 +4575,7 @@ var NeatlogsSpanProcessor = class {
4574
4575
  spansExported: 0
4575
4576
  };
4576
4577
  this._retrieversToSuppress = /* @__PURE__ */ new Set();
4578
+ this._activeSpans = /* @__PURE__ */ new Map();
4577
4579
  }
4578
4580
  // ── File logging init ─────────────────────────────────
4579
4581
  _initFileLogging() {
@@ -4606,6 +4608,10 @@ var NeatlogsSpanProcessor = class {
4606
4608
  onStart(span2, parentContext) {
4607
4609
  const startTime = import_node_perf_hooks.performance.now();
4608
4610
  try {
4611
+ const scopeName = span2.instrumentationLibrary?.name ?? "";
4612
+ if (scopeName.startsWith("neatlogs") || span2.parentSpanId !== void 0 && this._activeSpans.has(span2.parentSpanId)) {
4613
+ this._activeSpans.set(span2.spanContext().spanId, span2);
4614
+ }
4609
4615
  if (!span2.parentSpanId) {
4610
4616
  applySessionAttributes(span2, void 0, true);
4611
4617
  applyEndUserAttributes(span2, void 0, void 0, true);
@@ -4682,6 +4688,7 @@ var NeatlogsSpanProcessor = class {
4682
4688
  }
4683
4689
  // ── SpanProcessor.onEnd ───────────────────────────────
4684
4690
  onEnd(span2) {
4691
+ this._activeSpans.delete(span2.spanContext().spanId);
4685
4692
  if (span2.name === "neatlogs.trace.complete") {
4686
4693
  return;
4687
4694
  }
@@ -4860,6 +4867,47 @@ var NeatlogsSpanProcessor = class {
4860
4867
  this.perfStats.onEndTime += import_node_perf_hooks.performance.now() - startTime;
4861
4868
  }
4862
4869
  }
4870
+ /**
4871
+ * End active Neatlogs-owned spans child-first before provider shutdown.
4872
+ * Ending the actual root through the normal lifecycle emits the completion
4873
+ * marker; interruption attributes keep the termination explicit.
4874
+ */
4875
+ endActiveSpans(reason = "shutdown") {
4876
+ const activeById = this._activeSpans;
4877
+ this._activeSpans = /* @__PURE__ */ new Map();
4878
+ const active = [...activeById.values()];
4879
+ if (active.length === 0) return 0;
4880
+ const activeIds = new Set(active.map((span2) => span2.spanContext().spanId));
4881
+ const depth = (span2) => {
4882
+ let current = span2;
4883
+ const seen = /* @__PURE__ */ new Set();
4884
+ let value = 0;
4885
+ while (current?.parentSpanId && activeIds.has(current.parentSpanId)) {
4886
+ const parentId = current.parentSpanId;
4887
+ if (seen.has(parentId)) break;
4888
+ seen.add(parentId);
4889
+ value += 1;
4890
+ current = activeById.get(parentId);
4891
+ }
4892
+ return value;
4893
+ };
4894
+ const cleanReason = String(reason || "shutdown").slice(0, 256);
4895
+ let ended = 0;
4896
+ for (const span2 of active.sort((a, b) => depth(b) - depth(a))) {
4897
+ try {
4898
+ if (!span2.isRecording()) continue;
4899
+ span2.setAttribute("neatlogs.trace.interrupted", true);
4900
+ span2.setAttribute("neatlogs.trace.termination.reason", cleanReason);
4901
+ span2.end();
4902
+ ended += 1;
4903
+ } catch (error) {
4904
+ logger10.warn(
4905
+ `Failed to end active span during ${cleanReason}: ${error}`
4906
+ );
4907
+ }
4908
+ }
4909
+ return ended;
4910
+ }
4863
4911
  // ── Completion marker ─────────────────────────────────
4864
4912
  _emitCompletionMarker(rootSpan, traceId, resourceAttrs) {
4865
4913
  try {
@@ -6106,7 +6154,7 @@ function _resetMastraCache() {
6106
6154
  }
6107
6155
 
6108
6156
  // src/version.ts
6109
- var __version__ = "1.1.17";
6157
+ var __version__ = "1.1.18";
6110
6158
 
6111
6159
  // src/init.ts
6112
6160
  var logger13 = getLogger();
@@ -6118,8 +6166,24 @@ var _spanProcessor = null;
6118
6166
  var _debugMode2 = false;
6119
6167
  var _instrumentationManager = null;
6120
6168
  var _sigHandlersRegistered = false;
6121
- var _shutdownOnSignal = () => {
6122
- shutdown().catch(() => {
6169
+ var _signalShutdownStarted = false;
6170
+ var _shutdownPromise = null;
6171
+ var _shutdownBeforeExit = () => {
6172
+ void shutdown("beforeExit").catch((error) => {
6173
+ logger13.error(`Error shutting down before exit: ${error}`);
6174
+ });
6175
+ };
6176
+ var _shutdownOnSignal = (signal) => {
6177
+ if (_signalShutdownStarted) return;
6178
+ _signalShutdownStarted = true;
6179
+ void shutdown(signal).catch((error) => {
6180
+ logger13.error(`Error shutting down after ${signal}: ${error}`);
6181
+ }).finally(() => {
6182
+ try {
6183
+ process.kill(process.pid, signal);
6184
+ } catch {
6185
+ process.exitCode = signal === "SIGINT" ? 130 : 143;
6186
+ }
6123
6187
  });
6124
6188
  };
6125
6189
  function _resolveWorkflowName(workflowName) {
@@ -6284,7 +6348,7 @@ async function init(options = {}) {
6284
6348
  }
6285
6349
  const registerShutdownHandlers = options.registerShutdownHandlers ?? _ownsTracerProvider;
6286
6350
  if (registerShutdownHandlers && !_sigHandlersRegistered) {
6287
- process.on("beforeExit", _shutdownOnSignal);
6351
+ process.on("beforeExit", _shutdownBeforeExit);
6288
6352
  process.on("SIGTERM", _shutdownOnSignal);
6289
6353
  process.on("SIGINT", _shutdownOnSignal);
6290
6354
  _sigHandlersRegistered = true;
@@ -6326,14 +6390,32 @@ async function flush() {
6326
6390
  }
6327
6391
  return success;
6328
6392
  }
6329
- async function shutdown() {
6393
+ function shutdown(terminationReason = "shutdown") {
6394
+ if (_shutdownPromise) return _shutdownPromise;
6395
+ const currentShutdown = _performShutdown(terminationReason);
6396
+ _shutdownPromise = currentShutdown;
6397
+ const clearCurrentShutdown = () => {
6398
+ if (_shutdownPromise === currentShutdown) _shutdownPromise = null;
6399
+ };
6400
+ void currentShutdown.then(clearCurrentShutdown, clearCurrentShutdown);
6401
+ return currentShutdown;
6402
+ }
6403
+ async function _performShutdown(terminationReason) {
6330
6404
  if (_sigHandlersRegistered) {
6331
- process.removeListener("beforeExit", _shutdownOnSignal);
6405
+ process.removeListener("beforeExit", _shutdownBeforeExit);
6332
6406
  process.removeListener("SIGTERM", _shutdownOnSignal);
6333
6407
  process.removeListener("SIGINT", _shutdownOnSignal);
6334
6408
  _sigHandlersRegistered = false;
6335
6409
  }
6336
6410
  let success = true;
6411
+ if (_spanProcessor) {
6412
+ const ended = _spanProcessor.endActiveSpans(terminationReason);
6413
+ if (ended > 0) {
6414
+ logger13.info(
6415
+ `Ended ${ended} active Neatlogs span(s) during ${terminationReason}`
6416
+ );
6417
+ }
6418
+ }
6337
6419
  _instrumentationManager?.disable();
6338
6420
  _instrumentationManager = null;
6339
6421
  _resetMastraCache();
@@ -6372,6 +6454,7 @@ async function shutdown() {
6372
6454
  _logProvider = null;
6373
6455
  _spanProcessor = null;
6374
6456
  _debugMode2 = false;
6457
+ _signalShutdownStarted = false;
6375
6458
  _setSessionConfig({});
6376
6459
  logger13.info("Neatlogs SDK shutdown complete");
6377
6460
  return success;
@@ -7030,29 +7113,25 @@ function tracedResponsesCreate(original) {
7030
7113
  return function(opts, ...rest) {
7031
7114
  const tracer = getProviderTracer(TRACER_NAME3);
7032
7115
  const model = opts?.model ?? "";
7116
+ const isStream = opts?.stream === true;
7033
7117
  const span2 = tracer.startSpan("openai.responses.create", {
7034
7118
  attributes: {
7035
7119
  "neatlogs.span.kind": "LLM",
7036
7120
  "neatlogs.llm.provider": "openai",
7037
7121
  "neatlogs.llm.system": "openai",
7038
7122
  "neatlogs.llm.model_name": model,
7123
+ "neatlogs.llm.is_streaming": isStream,
7039
7124
  "input.value": safeStringify3(opts?.input ?? "")
7040
7125
  }
7041
7126
  }, getNeatlogsParentContext());
7127
+ setInvocationParams(span2, opts);
7042
7128
  const promise = withNeatlogsSpan(span2, () => original(opts, ...rest));
7043
7129
  return promise.then(
7044
7130
  (response) => {
7045
- if (response?.output_text) {
7046
- span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
7047
- span2.setAttribute("neatlogs.llm.output_messages.0.content", response.output_text);
7048
- }
7049
- if (response?.model) span2.setAttribute("neatlogs.llm.model_name", response.model);
7050
- if (response?.usage) {
7051
- if (response.usage.input_tokens != null) span2.setAttribute("neatlogs.llm.token_count.prompt", response.usage.input_tokens);
7052
- if (response.usage.output_tokens != null) span2.setAttribute("neatlogs.llm.token_count.completion", response.usage.output_tokens);
7131
+ if (isStream) {
7132
+ return wrapResponsesAsyncIterableStream(response, span2);
7053
7133
  }
7054
- span2.setStatus({ code: import_api10.SpanStatusCode.OK });
7055
- span2.end();
7134
+ finalizeResponsesResponse(span2, response);
7056
7135
  return response;
7057
7136
  },
7058
7137
  (err) => {
@@ -7062,6 +7141,110 @@ function tracedResponsesCreate(original) {
7062
7141
  );
7063
7142
  };
7064
7143
  }
7144
+ function wrapResponsesAsyncIterableStream(stream, span2) {
7145
+ const originalAsyncIterator = stream?.[Symbol.asyncIterator]?.bind(stream);
7146
+ if (!originalAsyncIterator) {
7147
+ finalizeResponsesResponse(span2, stream);
7148
+ return stream;
7149
+ }
7150
+ const textParts = [];
7151
+ let completedResponse;
7152
+ let finalized = false;
7153
+ const finalize = () => {
7154
+ if (finalized) return;
7155
+ finalized = true;
7156
+ finalizeResponsesResponse(span2, completedResponse, textParts.join(""));
7157
+ };
7158
+ return new Proxy(stream, {
7159
+ get(target, prop) {
7160
+ if (prop === Symbol.asyncIterator) {
7161
+ return () => {
7162
+ const iterator = originalAsyncIterator();
7163
+ return {
7164
+ async next() {
7165
+ try {
7166
+ const result = await iterator.next();
7167
+ if (result.done) {
7168
+ finalize();
7169
+ return result;
7170
+ }
7171
+ const event = result.value;
7172
+ if (event?.type === "response.output_text.delta" && typeof event.delta === "string") {
7173
+ textParts.push(event.delta);
7174
+ } else if (event?.type === "response.completed") {
7175
+ completedResponse = event.response;
7176
+ }
7177
+ return result;
7178
+ } catch (err) {
7179
+ if (!finalized) {
7180
+ finalized = true;
7181
+ recordError(span2, err);
7182
+ }
7183
+ throw err;
7184
+ }
7185
+ },
7186
+ async return(value2) {
7187
+ try {
7188
+ return await (iterator.return?.(value2) ?? { done: true, value: value2 });
7189
+ } finally {
7190
+ finalize();
7191
+ }
7192
+ },
7193
+ async throw(err) {
7194
+ if (!finalized) {
7195
+ finalized = true;
7196
+ recordError(span2, err);
7197
+ }
7198
+ if (iterator.throw) return iterator.throw(err);
7199
+ throw err;
7200
+ }
7201
+ };
7202
+ };
7203
+ }
7204
+ const value = Reflect.get(target, prop, target);
7205
+ return typeof value === "function" ? value.bind(target) : value;
7206
+ }
7207
+ });
7208
+ }
7209
+ function finalizeResponsesResponse(span2, response, streamedText = "") {
7210
+ const text = response?.output_text || streamedText || extractResponsesOutputText(response?.output);
7211
+ if (text) {
7212
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
7213
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", text);
7214
+ span2.setAttribute("output.value", text);
7215
+ } else if (response?.output) {
7216
+ span2.setAttribute("output.value", safeStringify3(response.output));
7217
+ }
7218
+ if (response?.model) span2.setAttribute("neatlogs.llm.model_name", response.model);
7219
+ if (response?.status) span2.setAttribute("neatlogs.llm.finish_reason", response.status);
7220
+ const usage = response?.usage;
7221
+ if (usage) {
7222
+ if (usage.input_tokens != null) span2.setAttribute("neatlogs.llm.token_count.prompt", usage.input_tokens);
7223
+ if (usage.output_tokens != null) span2.setAttribute("neatlogs.llm.token_count.completion", usage.output_tokens);
7224
+ if (usage.total_tokens != null) span2.setAttribute("neatlogs.llm.token_count.total", usage.total_tokens);
7225
+ if (usage.input_tokens_details?.cached_tokens != null) {
7226
+ span2.setAttribute("neatlogs.llm.token_count.cache_read", usage.input_tokens_details.cached_tokens);
7227
+ }
7228
+ if (usage.output_tokens_details?.reasoning_tokens != null) {
7229
+ span2.setAttribute("neatlogs.llm.token_count.reasoning", usage.output_tokens_details.reasoning_tokens);
7230
+ }
7231
+ }
7232
+ span2.setStatus({ code: import_api10.SpanStatusCode.OK });
7233
+ span2.end();
7234
+ }
7235
+ function extractResponsesOutputText(output) {
7236
+ if (!Array.isArray(output)) return "";
7237
+ const parts = [];
7238
+ for (const item of output) {
7239
+ if (item?.type !== "message" || !Array.isArray(item.content)) continue;
7240
+ for (const content of item.content) {
7241
+ if (content?.type === "output_text" && typeof content.text === "string") {
7242
+ parts.push(content.text);
7243
+ }
7244
+ }
7245
+ }
7246
+ return parts.join("");
7247
+ }
7065
7248
  function wrapAsyncIterableStream(stream, span2) {
7066
7249
  const chunks = [];
7067
7250
  const originalAsyncIterator = stream[Symbol.asyncIterator]?.bind(stream);