@juspay/neurolink 11.15.2 → 11.15.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.
@@ -107,8 +107,11 @@ export function runAgenticLoop(adapter, initialConversation, options) {
107
107
  catch (err) {
108
108
  throw hasEmitted ? new PostEmissionStepError(err) : err;
109
109
  }
110
- }, undefined, // no OTel span threaded through the engine today; adapters instrument their own steps if they need span-level detail
111
- `${adapter.providerLabel}.step`);
110
+ },
111
+ // The caller's span, when it passes one. withProviderRetry writes
112
+ // gen_ai.provider.total_attempts here, so a loop that threaded a
113
+ // span before it moved onto this engine keeps emitting it.
114
+ options.span, `${adapter.providerLabel}.step`);
112
115
  }
113
116
  catch (err) {
114
117
  throw err instanceof PostEmissionStepError ? err.cause : err;
@@ -1697,9 +1697,17 @@ export class AnthropicProvider extends BaseProvider {
1697
1697
  },
1698
1698
  };
1699
1699
  }
1700
+ // The active span goes with it. Before this loop moved onto the shared
1701
+ // engine it called
1702
+ // withProviderRetry(fn, trace.getActiveSpan() ?? undefined, label)
1703
+ // and that span is where gen_ai.provider.total_attempts is recorded.
1704
+ // The engine passed `undefined` in its place, so the attribute silently
1705
+ // stopped being emitted for every native Anthropic turn.
1706
+ const activeSpan = trace.getActiveSpan();
1700
1707
  const { stream, resultPromise } = runAgenticLoop(adapter, payload.messages.slice(), {
1701
1708
  tools: engineTools,
1702
1709
  ...(abortSignal ? { abortSignal } : {}),
1710
+ ...(activeSpan ? { span: activeSpan } : {}),
1703
1711
  });
1704
1712
  // Structured turns buffer their text rather than streaming it: a caller
1705
1713
  // that passed a schema needs parseable JSON, and deltas emitted before
@@ -1,4 +1,5 @@
1
1
  import type Anthropic from "@anthropic-ai/sdk";
2
+ import type { Span } from "@opentelemetry/api";
2
3
  import type { Tool } from "./tools.js";
3
4
  import type { CollectedChunkResult, NativeFunctionCall, NativeToolDeclarationsResult } from "./providers.js";
4
5
  /**
@@ -292,6 +293,19 @@ export type AgenticLoopOptions = {
292
293
  execute?: (args: Record<string, unknown>, opts: unknown) => Promise<unknown>;
293
294
  }>;
294
295
  abortSignal?: AbortSignal;
296
+ /**
297
+ * Span the per-step provider retry annotates, via
298
+ * `withProviderRetry(..., span, ...)` — it records
299
+ * `gen_ai.provider.total_attempts` on every completed step, retried or not.
300
+ *
301
+ * Caller-supplied rather than read from the ambient context inside the
302
+ * engine. Reading it here would hand the attribute to every provider on the
303
+ * engine, including ones whose hand-rolled loops never emitted it, and a
304
+ * refactor that silently ADDS observable behaviour is the same defect as one
305
+ * that silently drops it. Today only the direct Anthropic loops set this,
306
+ * because only they threaded a span before moving onto the engine.
307
+ */
308
+ span?: Span;
295
309
  };
296
310
  export type AgenticLoopResult<TConversation> = {
297
311
  text: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "11.15.2",
3
+ "version": "11.15.3",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (connect any MCP server), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
6
6
  "author": {