@juspay/neurolink 11.15.7 → 11.15.9
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 +1 -5
- package/dist/browser/neurolink.min.js +362 -362
- package/dist/core/geminiLoopAdapter.js +35 -12
- package/dist/core/loopEngine.js +180 -96
- package/dist/providers/anthropic/client.js +2 -2
- package/dist/providers/googleAiStudio/client.js +18 -8
- package/dist/providers/googleNativeGemini3/utils.d.ts +3 -3
- package/dist/providers/googleNativeGemini3/utils.js +47 -10
- package/dist/providers/googleVertex/client.js +447 -788
- package/dist/types/loopEngine.d.ts +108 -5
- package/package.json +1 -1
|
@@ -46,12 +46,64 @@ export type AgenticLoopToolCallResult = AgenticLoopToolCall & {
|
|
|
46
46
|
};
|
|
47
47
|
export type AgenticLoopStepRequest = {
|
|
48
48
|
raw: unknown;
|
|
49
|
+
/**
|
|
50
|
+
* Tools that became callable while this step's request was being built —
|
|
51
|
+
* mid-turn discovery hydrating a name the model had already tried.
|
|
52
|
+
*
|
|
53
|
+
* The engine clears each one's failure strikes before dispatching, because
|
|
54
|
+
* TOOL_NOT_FOUND strikes accrued while a tool was deferred are snapshot
|
|
55
|
+
* artifacts rather than real failures. Clearing them at the miss-resolution
|
|
56
|
+
* path instead would be too late: the breaker is consulted BEFORE the
|
|
57
|
+
* lookup, so a tool already at the strike limit is refused without the
|
|
58
|
+
* resolution path ever running.
|
|
59
|
+
*/
|
|
60
|
+
hydratedToolNames?: string[];
|
|
49
61
|
};
|
|
50
62
|
export type AgenticLoopReclaimResult<TConversation> = {
|
|
51
|
-
conversation
|
|
63
|
+
conversation?: TConversation;
|
|
64
|
+
/**
|
|
65
|
+
* End the turn now, BEFORE this step's request is issued.
|
|
66
|
+
*
|
|
67
|
+
* A context guard does two things, and only one of them is "reclaim". When
|
|
68
|
+
* dropping old exchanges buys enough room the turn continues; when it does
|
|
69
|
+
* not, the guard has to stop rather than step into a provider rejection
|
|
70
|
+
* that would lose every completed step. Nothing else can express that: the
|
|
71
|
+
* hook returns a conversation, and an adapter cannot break the engine's
|
|
72
|
+
* loop.
|
|
73
|
+
*
|
|
74
|
+
* Aborting the caller's own signal from inside this hook does NOT work as a
|
|
75
|
+
* substitute — the engine checks for an abort at the TOP of the step, above
|
|
76
|
+
* this call, so the request would still be issued and the stop would not
|
|
77
|
+
* take effect until the following step.
|
|
78
|
+
*/
|
|
79
|
+
stop?: boolean;
|
|
52
80
|
};
|
|
53
81
|
export type AgenticLoopToolFailureBreaker = {
|
|
54
82
|
maxRetries: number;
|
|
83
|
+
/**
|
|
84
|
+
* Count CONSECUTIVE failures rather than lifetime ones: a clean result
|
|
85
|
+
* clears the strike count for that tool.
|
|
86
|
+
*
|
|
87
|
+
* Off by default because the two behaviours diverge for a tool that fails
|
|
88
|
+
* intermittently, and the providers already on this engine accumulate. What
|
|
89
|
+
* it protects is the argument-dependent soft error — a file-not-found on one
|
|
90
|
+
* path, fine on the next — which under lifetime counting disables a working
|
|
91
|
+
* tool for the rest of the turn.
|
|
92
|
+
*/
|
|
93
|
+
consecutive?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Decide whether a RESOLVED tool result is really a failure.
|
|
96
|
+
*
|
|
97
|
+
* Some tools report failure without throwing: MCP `isError` payloads, a
|
|
98
|
+
* proxy-blocked call returning `{ error }`. Counting only thrown errors lets
|
|
99
|
+
* the model grind on one of those for the entire step budget. Returning a
|
|
100
|
+
* non-empty string strikes the breaker exactly as a throw does; returning
|
|
101
|
+
* undefined leaves the result a success.
|
|
102
|
+
*
|
|
103
|
+
* Off by default — a provider whose loop never inspected results this way
|
|
104
|
+
* must not start doing so as a side effect of migrating.
|
|
105
|
+
*/
|
|
106
|
+
classifyResultFailure?: (output: unknown) => string | undefined;
|
|
55
107
|
};
|
|
56
108
|
/**
|
|
57
109
|
* DESIGN DECISION — mid-turn tool-discovery hydration (Plan 08 blocker 2,
|
|
@@ -114,13 +166,21 @@ export type AgenticLoopAdapter<TConversation = unknown, TRaw = unknown> = {
|
|
|
114
166
|
executeStep(request: AgenticLoopStepRequest, channel: {
|
|
115
167
|
push(chunk: AgenticLoopChunk): void;
|
|
116
168
|
}, signal: AbortSignal): Promise<AgenticLoopStepResult<TRaw>>;
|
|
117
|
-
|
|
169
|
+
/**
|
|
170
|
+
* `step` is the engine's own zero-based step index, not a count of times
|
|
171
|
+
* this hook ran. Adapters persist tool activity keyed by it, and the two
|
|
172
|
+
* numbers diverge: a malformed-call retry `continue`s before this hook is
|
|
173
|
+
* reached and still consumes a step, so an adapter counting its own
|
|
174
|
+
* invocations drifts by exactly the number of retries and mislabels every
|
|
175
|
+
* row after the first one.
|
|
176
|
+
*/
|
|
177
|
+
buildToolResultMessages(conversation: TConversation, stepResult: AgenticLoopStepResult<TRaw>, toolResults: AgenticLoopToolCallResult[], step: number): TConversation;
|
|
118
178
|
mapFinishReason(rawStopReason: string | undefined, hadToolCalls: boolean): string;
|
|
119
179
|
/** Optional: in-turn context-budget reclaim, called once per step before buildStepRequest. */
|
|
120
180
|
planReclaim?(conversation: TConversation, step: number): AgenticLoopReclaimResult<TConversation> | undefined;
|
|
121
181
|
/** Optional: Vertex+Gemini-only single-retry-on-malformed-call. */
|
|
122
182
|
isMalformedStep?(stepResult: AgenticLoopStepResult<TRaw>): boolean;
|
|
123
|
-
buildMalformedRetryNote?(conversation: TConversation): TConversation;
|
|
183
|
+
buildMalformedRetryNote?(conversation: TConversation, step: number): TConversation;
|
|
124
184
|
};
|
|
125
185
|
/**
|
|
126
186
|
* Construction input for `createAnthropicLoopAdapter`, shared by direct
|
|
@@ -184,6 +244,31 @@ export type AnthropicLoopAdapterConfig = {
|
|
|
184
244
|
noteObservedPromptTokens?: (promptTokens: number) => void;
|
|
185
245
|
abortSignal?: AbortSignal;
|
|
186
246
|
};
|
|
247
|
+
/**
|
|
248
|
+
* The three things a native Gemini loop wraps around every tool call that the
|
|
249
|
+
* shared engine does not do itself.
|
|
250
|
+
*
|
|
251
|
+
* All optional, and the whole object is optional, because the two Gemini
|
|
252
|
+
* providers differ here: Vertex bounds tool execution and runs a stall
|
|
253
|
+
* watchdog, AI Studio does neither. Passing nothing leaves an executor exactly
|
|
254
|
+
* as the caller supplied it, so this cannot quietly give AI Studio behaviour
|
|
255
|
+
* its hand-rolled loops never had.
|
|
256
|
+
*/
|
|
257
|
+
export type GeminiToolExecutionGuards = {
|
|
258
|
+
/** Upper bound on a single execute(); omit for no bound. */
|
|
259
|
+
toolTimeoutMs?: number;
|
|
260
|
+
/**
|
|
261
|
+
* Turn-level abort, raced against the call so a deadline or caller cancel is
|
|
262
|
+
* observed immediately instead of after the tool settles.
|
|
263
|
+
*/
|
|
264
|
+
abortSignal?: AbortSignal;
|
|
265
|
+
/**
|
|
266
|
+
* Stall-watchdog ping, called either side of the await. The watchdog is a
|
|
267
|
+
* whole-turn interval measuring wall-clock since the last mark, so a
|
|
268
|
+
* legitimately slow tool reads as a stalled turn without this.
|
|
269
|
+
*/
|
|
270
|
+
onProgress?: () => void;
|
|
271
|
+
};
|
|
187
272
|
/** What one Gemini step produced, carried to `buildToolResultMessages`. */
|
|
188
273
|
export type GeminiStepRaw = {
|
|
189
274
|
rawResponseParts: unknown[];
|
|
@@ -235,12 +320,30 @@ export type GeminiLoopAdapterCoreConfig = {
|
|
|
235
320
|
* bounding growth, so a migration that drops this overflows the context
|
|
236
321
|
* window mid-turn and loses every completed step.
|
|
237
322
|
*/
|
|
238
|
-
planReclaim?: (conversation: GeminiTurnContent[], step: number) => GeminiTurnContent[] | undefined;
|
|
323
|
+
planReclaim?: (conversation: GeminiTurnContent[], step: number) => AgenticLoopReclaimResult<GeminiTurnContent[]> | undefined;
|
|
239
324
|
/**
|
|
240
325
|
* Usage feedback for the provider's own context guard, called after each
|
|
241
326
|
* step with that step's real token counts.
|
|
242
327
|
*/
|
|
243
328
|
noteUsage?: (inputTokens: number, outputTokens: number) => void;
|
|
329
|
+
/**
|
|
330
|
+
* Name of the terminal structured-output tool when one is in play. A call
|
|
331
|
+
* to it ends the turn: its arguments ARE the answer, so it is reported as
|
|
332
|
+
* text and omitted from `toolCalls`, which routes it through the engine's
|
|
333
|
+
* ordinary zero-tool-calls exit — never dispatched, never counted against
|
|
334
|
+
* the breaker, never recorded as a tool execution.
|
|
335
|
+
*/
|
|
336
|
+
finalResultToolName?: string;
|
|
337
|
+
/**
|
|
338
|
+
* Called with the terminal tool's payload when one was actually detected.
|
|
339
|
+
*
|
|
340
|
+
* The caller cannot infer this from the turn's result: a structured turn
|
|
341
|
+
* ends with the payload in `text` when the model called the terminal tool,
|
|
342
|
+
* and with ordinary prose in `text` when it answered directly instead, and
|
|
343
|
+
* those two are indistinguishable downstream while being handled
|
|
344
|
+
* differently. Comparing strings to tell them apart would be guesswork.
|
|
345
|
+
*/
|
|
346
|
+
onTerminalResult?: (text: string) => void;
|
|
244
347
|
/**
|
|
245
348
|
* Fold one step's raw stream into the shape the adapter reports.
|
|
246
349
|
*
|
|
@@ -282,7 +385,7 @@ export type GeminiMalformedRetryConfig = {
|
|
|
282
385
|
* Provider-supplied because the note is written in the provider's own
|
|
283
386
|
* content shape.
|
|
284
387
|
*/
|
|
285
|
-
buildMalformedRetryNote: (conversation: GeminiTurnContent[]) => GeminiTurnContent[];
|
|
388
|
+
buildMalformedRetryNote: (conversation: GeminiTurnContent[], step: number) => GeminiTurnContent[];
|
|
286
389
|
} | {
|
|
287
390
|
enableMalformedRetry?: false;
|
|
288
391
|
buildMalformedRetryNote?: never;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "11.15.
|
|
3
|
+
"version": "11.15.9",
|
|
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": {
|