@juspay/neurolink 11.16.3 → 11.17.1

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.
@@ -28,6 +28,8 @@ function sumUsage(a, b) {
28
28
  cacheReadTokens: (a.cacheReadTokens ?? 0) + (b.cacheReadTokens ?? 0) || undefined,
29
29
  cacheWriteTokens: (a.cacheWriteTokens ?? 0) + (b.cacheWriteTokens ?? 0) || undefined,
30
30
  reasoningTokens: (a.reasoningTokens ?? 0) + (b.reasoningTokens ?? 0) || undefined,
31
+ cacheWrite5mTokens: (a.cacheWrite5mTokens ?? 0) + (b.cacheWrite5mTokens ?? 0) || undefined,
32
+ cacheWrite1hTokens: (a.cacheWrite1hTokens ?? 0) + (b.cacheWrite1hTokens ?? 0) || undefined,
31
33
  };
32
34
  }
33
35
  /**
@@ -1567,7 +1567,7 @@ export class AnthropicProvider extends BaseProvider {
1567
1567
  content: [{ type: "text", text: ANTHROPIC_ELISION_NOTE }],
1568
1568
  });
1569
1569
  }
1570
- return rebuilt;
1570
+ return { conversation: rebuilt };
1571
1571
  };
1572
1572
  const buildParams = (conversation) => {
1573
1573
  // Mid-turn discovery sync: search_tools (tools.discovery) hydrates
@@ -1599,7 +1599,10 @@ export class AnthropicProvider extends BaseProvider {
1599
1599
  model: modelId,
1600
1600
  messages: cachedConversation,
1601
1601
  max_tokens: resolveClaudeMaxTokens(modelId, options.maxTokens),
1602
- stream: true,
1602
+ // No `stream: true` here: executeStep sets it when it calls
1603
+ // messages.create, so declaring it made the caller assert a literal
1604
+ // the adapter immediately overwrites — and forced this whole params
1605
+ // object into the streaming variant for a field it does not own.
1603
1606
  ...(payload.system ? { system: payload.system } : {}),
1604
1607
  ...(streamSamplingParams.temperature !== undefined
1605
1608
  ? { temperature: streamSamplingParams.temperature }
@@ -23,4 +23,4 @@
23
23
  */
24
24
  import type Anthropic from "@anthropic-ai/sdk";
25
25
  import type { AgenticLoopAdapter, AnthropicLoopAdapterConfig } from "../../types/index.js";
26
- export declare function createAnthropicLoopAdapter(config: AnthropicLoopAdapterConfig): AgenticLoopAdapter<Anthropic.Messages.MessageParam[], Anthropic.Messages.ContentBlockParam[]>;
26
+ export declare function createAnthropicLoopAdapter<TMessage = Anthropic.Messages.MessageParam>(config: AnthropicLoopAdapterConfig<TMessage>): AgenticLoopAdapter<TMessage[], Anthropic.Messages.ContentBlockParam[]>;
@@ -52,10 +52,12 @@ export function createAnthropicLoopAdapter(config) {
52
52
  */
53
53
  ...(config.planReclaim
54
54
  ? {
55
- planReclaim: (conversation, step) => {
56
- const reclaimed = config.planReclaim?.(conversation, step);
57
- return reclaimed ? { conversation: reclaimed } : undefined;
58
- },
55
+ // Passed straight through, INCLUDING `{ stop: true }`. Wrapping the
56
+ // return as `{ conversation }` swallowed the stop signal, so a guard
57
+ // that could not reclaim enough room had no way to end the turn and
58
+ // the loop kept sending oversized requests until the provider
59
+ // rejected one.
60
+ planReclaim: (conversation, step) => config.planReclaim?.(conversation, step),
59
61
  }
60
62
  : {}),
61
63
  resolveToolOnMiss: (name) => {
@@ -97,6 +99,12 @@ export function createAnthropicLoopAdapter(config) {
97
99
  let outputTokens = 0;
98
100
  let cacheReadTokens = 0;
99
101
  let cacheWriteTokens = 0;
102
+ // Reported alongside the total, not derivable from it: the two TTL
103
+ // tiers are priced differently, so a caller that reports them (the
104
+ // Claude-on-Vertex turn span does) cannot reconstruct the split from
105
+ // cacheWriteTokens alone.
106
+ let cacheWrite5mTokens = 0;
107
+ let cacheWrite1hTokens = 0;
100
108
  let stepOutputTokens = 0;
101
109
  for await (const rawEvent of events) {
102
110
  if (signal.aborted) {
@@ -118,6 +126,19 @@ export function createAnthropicLoopAdapter(config) {
118
126
  // accounting.
119
127
  cacheReadTokens += usage?.cache_read_input_tokens ?? 0;
120
128
  cacheWriteTokens += usage?.cache_creation_input_tokens ?? 0;
129
+ // BEST EFFORT, and the limit is worth stating. The nested TTL
130
+ // breakdown exists only on `Usage` (this event); `MessageDeltaUsage`
131
+ // carries the cache TOTALS but not the split, so message_start is
132
+ // the only place in the raw event stream it can come from. The
133
+ // pre-migration loop read it off `stream.finalMessage()` — the SDK's
134
+ // ACCUMULATED message — so if the API leaves `cache_creation` null
135
+ // here and fills it only on the assembled message, these two stay
136
+ // zero and the totals above remain correct regardless.
137
+ // Reported as undefined rather than a false zero when absent.
138
+ cacheWrite5mTokens +=
139
+ usage?.cache_creation?.ephemeral_5m_input_tokens ?? 0;
140
+ cacheWrite1hTokens +=
141
+ usage?.cache_creation?.ephemeral_1h_input_tokens ?? 0;
121
142
  // The guard calibrates from the FULL prompt size, not input_tokens
122
143
  // alone: on a cache hit the uncached remainder is tiny and using it
123
144
  // would let the guard drift far under the real cost.
@@ -297,6 +318,11 @@ export function createAnthropicLoopAdapter(config) {
297
318
  outputTokens,
298
319
  cacheReadTokens,
299
320
  cacheWriteTokens,
321
+ // Omitted entirely when the stream never reported a split, so a
322
+ // consumer can tell "no TTL breakdown available" from "zero tokens
323
+ // in that tier".
324
+ ...(cacheWrite5mTokens ? { cacheWrite5mTokens } : {}),
325
+ ...(cacheWrite1hTokens ? { cacheWrite1hTokens } : {}),
300
326
  },
301
327
  rawStopReason,
302
328
  raw: blocks,
@@ -305,7 +331,13 @@ export function createAnthropicLoopAdapter(config) {
305
331
  buildToolResultMessages(conversation, stepResult, toolResults) {
306
332
  const assistantMessage = {
307
333
  role: "assistant",
308
- content: stepResult.raw,
334
+ // server_tool_use blocks are stripped before the turn is replayed:
335
+ // the API emits them on the way out but REJECTS them on the way back
336
+ // in, so echoing one fails the next request outright rather than
337
+ // degrading. Both Claude-on-Vertex loops filtered these by hand; doing
338
+ // it here means a caller cannot forget to. A provider that never emits
339
+ // them sees no change.
340
+ content: stepResult.raw.filter((block) => block.type !== "server_tool_use"),
309
341
  };
310
342
  const resultMessage = {
311
343
  role: "user",
@@ -318,7 +350,17 @@ export function createAnthropicLoopAdapter(config) {
318
350
  ...(result.error ? { is_error: true } : {}),
319
351
  })),
320
352
  };
321
- return [...conversation, assistantMessage, resultMessage];
353
+ // The two messages are built in the SDK's own shape and handed back as
354
+ // TMessage. Every Anthropic-compatible message type accepts a plain
355
+ // assistant turn and a tool_result user turn — that is the wire format,
356
+ // not a dialect — and a caller's narrower type differs only in fields
357
+ // neither of these sets. One assertion, at the single point where the
358
+ // adapter authors content rather than passing it through.
359
+ return [
360
+ ...conversation,
361
+ assistantMessage,
362
+ resultMessage,
363
+ ];
322
364
  },
323
365
  mapFinishReason: mapAnthropicFinishReason,
324
366
  };
@@ -473,7 +473,11 @@ export function buildNativeToolDeclarations(tools, reservedNames) {
473
473
  */
474
474
  export function guardToolExecutor(name, execute, guards) {
475
475
  return async (args, opts) => {
476
- const call = () => Promise.resolve(execute(args, opts));
476
+ const invoke = () => Promise.resolve(execute(args, opts));
477
+ // The span wraps the CALL, not the guard: a timeout or an abort is a fact
478
+ // about this tool invocation and belongs inside its observation.
479
+ const wrapInSpan = guards.withToolSpan;
480
+ const call = wrapInSpan ? () => wrapInSpan(name, invoke) : invoke;
477
481
  guards.onProgress?.();
478
482
  try {
479
483
  const raced = guards.abortSignal