@juspay/neurolink 12.34.1 → 12.34.3

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.
@@ -1812,6 +1812,20 @@ export class OpenAIChatCompletionsProvider extends BaseProvider {
1812
1812
  // `loopPromise` is undefined when a middleware blocked the request
1813
1813
  // before `doStream` ran, in which case there is no loop to surface.
1814
1814
  await loopPromise;
1815
+ // Record the terminal finish reason on the metadata object this
1816
+ // provider returns by reference (`result.metadata`). A rejected
1817
+ // `loopPromise` throws out of this `await` straight into the `catch`
1818
+ // below, so reaching this line means `runStreamLoop` returned
1819
+ // normally and already called `resolveFinish` with the wire value —
1820
+ // `finishPromise` is settled, not pending.
1821
+ //
1822
+ // `rawFinishReason` is the verbatim vendor value (e.g. "stop",
1823
+ // "length", "tool_calls", "content_filter") and is accurate the
1824
+ // moment the wire stream itself finished, independent of whatever
1825
+ // post-stream work follows. The graded `finishReason` is set later,
1826
+ // once that post-stream work (the structured-output re-ask below)
1827
+ // has actually succeeded — see the assignment after that block.
1828
+ streamMetadata.rawFinishReason = await finishPromise;
1815
1829
  // Structured output for a `stream({ schema })` turn. Runs HERE —
1816
1830
  // after the stream is fully drained — so a tool-free re-ask (when the
1817
1831
  // streamed answer isn't already schema-valid) never reaches
@@ -1853,6 +1867,12 @@ export class OpenAIChatCompletionsProvider extends BaseProvider {
1853
1867
  });
1854
1868
  }
1855
1869
  }
1870
+ // Only reached once the structured-output re-ask above (when there
1871
+ // was one) has resolved without throwing. A caller abort during that
1872
+ // re-ask rejects `resolveStreamStructuredData` and skips this line
1873
+ // entirely, so `metadata.finishReason` never claims "stop" for a
1874
+ // turn that actually failed after the wire stream itself finished.
1875
+ streamMetadata.finishReason = "stop";
1856
1876
  // No-output path: stream completed normally but yielded zero text.
1857
1877
  // Build an enriched sentinel + stamp the active OTel span so
1858
1878
  // Pipeline B (ContextEnricher) surfaces a WARNING-level Langfuse
@@ -51,6 +51,11 @@ export declare function initializeOpenTelemetry(config: LangfuseConfig): Promise
51
51
  export declare function flushOpenTelemetry(): Promise<void>;
52
52
  /**
53
53
  * Shutdown OpenTelemetry and Langfuse span processor
54
+ *
55
+ * Concurrent callers share one in-flight teardown, the same way concurrent
56
+ * initializers share one in-flight `initializeOpenTelemetry`: a second
57
+ * shutdown call joins the first instead of tearing down the same provider
58
+ * instances a second time.
54
59
  */
55
60
  export declare function shutdownOpenTelemetry(): Promise<void>;
56
61
  /**
@@ -106,6 +106,7 @@ let loggerProvider = null;
106
106
  let langfuseProcessor = null;
107
107
  let isInitialized = false;
108
108
  let initializationPromise = null;
109
+ let shutdownPromise = null;
109
110
  let isCredentialsValid = false;
110
111
  let currentConfig = null;
111
112
  let usingExternalProvider = false;
@@ -841,6 +842,15 @@ async function initializeStandaloneOpenTelemetryMode(config, resource, otlpEndpo
841
842
  * flush or shutdown wait for the same initialization before touching providers.
842
843
  */
843
844
  export async function initializeOpenTelemetry(config) {
845
+ if (shutdownPromise) {
846
+ // A shutdown already in flight is what made isInitialized/
847
+ // initializationPromise true or null in the first place; either reading
848
+ // is stale until it actually finishes. Waiting here means this call sees
849
+ // the settled post-teardown state — nothing initialized, nothing
850
+ // pending — and falls through to build fresh providers, rather than
851
+ // returning early on a flag that is about to flip out from under it.
852
+ await shutdownPromise;
853
+ }
844
854
  if (isInitialized) {
845
855
  currentConfig = config;
846
856
  logger.debug(`${LOG_PREFIX} Already initialized, config updated`, {
@@ -991,8 +1001,29 @@ export async function flushOpenTelemetry() {
991
1001
  }
992
1002
  /**
993
1003
  * Shutdown OpenTelemetry and Langfuse span processor
1004
+ *
1005
+ * Concurrent callers share one in-flight teardown, the same way concurrent
1006
+ * initializers share one in-flight `initializeOpenTelemetry`: a second
1007
+ * shutdown call joins the first instead of tearing down the same provider
1008
+ * instances a second time.
994
1009
  */
995
1010
  export async function shutdownOpenTelemetry() {
1011
+ if (shutdownPromise) {
1012
+ await shutdownPromise;
1013
+ return;
1014
+ }
1015
+ const pending = shutdownOpenTelemetryOnce();
1016
+ shutdownPromise = pending;
1017
+ try {
1018
+ await pending;
1019
+ }
1020
+ finally {
1021
+ if (shutdownPromise === pending) {
1022
+ shutdownPromise = null;
1023
+ }
1024
+ }
1025
+ }
1026
+ async function shutdownOpenTelemetryOnce() {
996
1027
  if (initializationPromise) {
997
1028
  try {
998
1029
  await initializationPromise;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "12.34.1",
3
+ "version": "12.34.3",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002/call) for routing, tool selection and context budgeting. MCP-native (4 transports), voice TTS/STT/realtime, RAG, agents, memory, compaction, 9 observability exporters. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · TypeSafe Jev and more.",
6
6
  "author": {