@juspay/neurolink 11.15.1 → 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.
- package/CHANGELOG.md +5 -1
- package/dist/browser/neurolink.min.js +300 -300
- package/dist/core/loopEngine.js +5 -2
- package/dist/providers/anthropic/client.js +8 -0
- package/dist/providers/googleAiStudio/client.js +7 -21
- package/dist/providers/googleNativeGemini3/utils.d.ts +19 -1
- package/dist/providers/googleNativeGemini3/utils.js +45 -0
- package/dist/types/loopEngine.d.ts +14 -0
- package/package.json +1 -1
package/dist/core/loopEngine.js
CHANGED
|
@@ -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
|
-
},
|
|
111
|
-
|
|
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
|
|
@@ -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
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
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
|
-
|
|
1155
|
-
|
|
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;
|
|
@@ -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.
|
|
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": {
|