@juspay/neurolink 11.15.1 → 11.15.2

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.
@@ -17,7 +17,7 @@ import { withTimeout } from "../../utils/async/index.js";
17
17
  import { estimateTokens } from "../../utils/tokenEstimation.js";
18
18
  import { transformToolExecutions } from "../../utils/transformationUtils.js";
19
19
  import { resolveToolExecutionRecords } from "../../core/toolExecutionRecorder.js";
20
- import { buildGeminiResponseSchema, buildNativeConfig, computeMaxSteps, createContextGuard, buildUserPartsWithMultimodal, extractThoughtSignature, handleMaxStepsTermination, prependConversationMessages, } from "../googleNativeGemini3/index.js";
20
+ import { buildDedupedEngineTools, buildGeminiResponseSchema, buildNativeConfig, computeMaxSteps, createContextGuard, buildUserPartsWithMultimodal, extractThoughtSignature, handleMaxStepsTermination, prependConversationMessages, } from "../googleNativeGemini3/index.js";
21
21
  import { createStreamChannel } from "../../core/streamChannel.js";
22
22
  import { toNativeToolDeclarations } from "../../core/nativeToolFormat.js";
23
23
  import { warnGoogleSdkIgnoresProxy } from "../../proxy/proxyFetch.js";
@@ -835,16 +835,10 @@ export class GoogleAIStudioProvider extends BaseProvider {
835
835
  return next;
836
836
  },
837
837
  };
838
- const engineTools = {};
839
- for (const [name, tool] of Object.entries(options.tools ?? {})) {
840
- const execute = tool?.execute;
841
- if (!execute) {
842
- continue;
843
- }
844
- engineTools[name] = {
845
- execute: async (args, opts) => execute(args, opts),
846
- };
847
- }
838
+ // Through the turn's DedupExecuteMap, NOT the raw executors:
839
+ // `.get()` returns the dedup wrapper that answers an identical
840
+ // repeated {name, args} from the per-turn cache (BZ-3327).
841
+ const engineTools = buildDedupedEngineTools(declarationsResult, options.tools);
848
842
  const { stream: engineStream, resultPromise } = runAgenticLoop(adapter, currentContents, {
849
843
  tools: engineTools,
850
844
  ...(composedSignal ? { abortSignal: composedSignal } : {}),
@@ -1151,16 +1145,8 @@ export class GoogleAIStudioProvider extends BaseProvider {
1151
1145
  return next;
1152
1146
  },
1153
1147
  };
1154
- const engineTools = {};
1155
- for (const [name, tool] of Object.entries(options.tools ?? {})) {
1156
- const execute = tool?.execute;
1157
- if (!execute) {
1158
- continue;
1159
- }
1160
- engineTools[name] = {
1161
- execute: async (args, opts) => execute(args, opts),
1162
- };
1163
- }
1148
+ // Same dedup routing as the streaming twin above.
1149
+ const engineTools = buildDedupedEngineTools(declarationsResult, options.tools);
1164
1150
  const { stream: engineStream, resultPromise } = runAgenticLoop(adapter, currentContents, {
1165
1151
  tools: engineTools,
1166
1152
  ...(composedSignal ? { abortSignal: composedSignal } : {}),
@@ -8,7 +8,7 @@
8
8
  * This module extracts the functions that are duplicated between the two
9
9
  * providers so they can share a single implementation.
10
10
  */
11
- import type { GenerateStopReason, ThinkingConfig, ChatMessage, CollectedChunkResult, MinimalChatMessage, NativeFunctionCall, NativeFunctionResponse, NativeToolDeclarationsResult, NativeToolsConfig, StreamChannel, VertexNativePart, GeminiMultimodalInput, MultimodalAudioEntry } from "../../types/index.js";
11
+ import type { GenerateStopReason, ThinkingConfig, AgenticLoopOptions, ChatMessage, CollectedChunkResult, MinimalChatMessage, NativeFunctionCall, NativeFunctionResponse, NativeToolDeclarationsResult, NativeToolsConfig, StreamChannel, VertexNativePart, GeminiMultimodalInput, MultimodalAudioEntry } from "../../types/index.js";
12
12
  import type { Tool } from "../../types/index.js";
13
13
  /**
14
14
  * A per-turn tool execute map that deduplicates identical tool calls.
@@ -91,6 +91,24 @@ export declare function buildNativeToolDeclarations(tools: Record<string, Tool>,
91
91
  * TOOL_NOT_FOUND. Mutates the snapshot in place — the request config holds
92
92
  * `toolsConfig` by reference — and returns true when anything was added.
93
93
  */
94
+ /**
95
+ * Build the tool record handed to `runAgenticLoop`, routed through the turn's
96
+ * DedupExecuteMap.
97
+ *
98
+ * The engine looks tools up by the name the adapter reports, which is the
99
+ * ORIGINAL caller-facing name; `executeMap` is keyed by the SANITIZED wire
100
+ * name Google actually declares. `originalNameMap` is the bridge, and it
101
+ * carries an entry for every converted tool (identity mappings included), so
102
+ * iterating it yields exactly the declared, executable set.
103
+ *
104
+ * Going through `executeMap.get()` rather than the raw `tool.execute` is the
105
+ * entire point: `.get()` returns the dedup wrapper, so an identical
106
+ * {name, args} repeated within one turn is answered from the per-turn cache
107
+ * instead of running the tool again (BZ-3327). Passing the raw executor looks
108
+ * identical in every test that calls a tool once, and silently reintroduces
109
+ * duplicate side effects the moment the model repeats itself.
110
+ */
111
+ export declare function buildDedupedEngineTools(declarations: NativeToolDeclarationsResult | undefined, tools: Record<string, Tool> | undefined): NonNullable<AgenticLoopOptions["tools"]>;
94
112
  export declare function refreshNativeToolDeclarations(liveTools: Record<string, Tool> | undefined, current: NativeToolDeclarationsResult): boolean;
95
113
  /**
96
114
  * Build the native @google/genai config object shared by stream and generate.
@@ -455,6 +455,51 @@ export function buildNativeToolDeclarations(tools, reservedNames) {
455
455
  * TOOL_NOT_FOUND. Mutates the snapshot in place — the request config holds
456
456
  * `toolsConfig` by reference — and returns true when anything was added.
457
457
  */
458
+ /**
459
+ * Build the tool record handed to `runAgenticLoop`, routed through the turn's
460
+ * DedupExecuteMap.
461
+ *
462
+ * The engine looks tools up by the name the adapter reports, which is the
463
+ * ORIGINAL caller-facing name; `executeMap` is keyed by the SANITIZED wire
464
+ * name Google actually declares. `originalNameMap` is the bridge, and it
465
+ * carries an entry for every converted tool (identity mappings included), so
466
+ * iterating it yields exactly the declared, executable set.
467
+ *
468
+ * Going through `executeMap.get()` rather than the raw `tool.execute` is the
469
+ * entire point: `.get()` returns the dedup wrapper, so an identical
470
+ * {name, args} repeated within one turn is answered from the per-turn cache
471
+ * instead of running the tool again (BZ-3327). Passing the raw executor looks
472
+ * identical in every test that calls a tool once, and silently reintroduces
473
+ * duplicate side effects the moment the model repeats itself.
474
+ */
475
+ export function buildDedupedEngineTools(declarations, tools) {
476
+ const engineTools = {};
477
+ if (declarations) {
478
+ for (const [safeName, originalName] of declarations.originalNameMap) {
479
+ const execute = declarations.executeMap.get(safeName);
480
+ if (!execute) {
481
+ continue;
482
+ }
483
+ engineTools[originalName] = {
484
+ execute: async (args, opts) => execute(args, opts),
485
+ };
486
+ }
487
+ return engineTools;
488
+ }
489
+ // No declarations were built (no tools, or a path that skips the snapshot).
490
+ // Fall back to the caller's own executors so this helper can never REMOVE a
491
+ // tool that would otherwise have been callable.
492
+ for (const [name, tool] of Object.entries(tools ?? {})) {
493
+ const execute = tool?.execute;
494
+ if (!execute) {
495
+ continue;
496
+ }
497
+ engineTools[name] = {
498
+ execute: async (args, opts) => execute(args, opts),
499
+ };
500
+ }
501
+ return engineTools;
502
+ }
458
503
  export function refreshNativeToolDeclarations(liveTools, current) {
459
504
  if (!liveTools) {
460
505
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "11.15.1",
3
+ "version": "11.15.2",
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": {