@juspay/neurolink 11.6.1 → 11.7.0
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 +47 -47
- package/dist/core/loopEngine.js +10 -1
- package/dist/lib/core/loopEngine.js +10 -1
- package/dist/lib/types/loopEngine.d.ts +52 -0
- package/dist/types/loopEngine.d.ts +52 -0
- package/package.json +1 -1
package/dist/core/loopEngine.js
CHANGED
|
@@ -156,7 +156,16 @@ export function runAgenticLoop(adapter, initialConversation, options) {
|
|
|
156
156
|
});
|
|
157
157
|
continue;
|
|
158
158
|
}
|
|
159
|
-
|
|
159
|
+
// Second lookup path for adapters that discover tools mid-turn.
|
|
160
|
+
// The miss is defined as "nothing executable under this name"
|
|
161
|
+
// rather than "no key under this name", because the guard directly
|
|
162
|
+
// below already treats a present-but-unexecutable entry as absent —
|
|
163
|
+
// a deferred-catalog placeholder is exactly that shape, and it is
|
|
164
|
+
// precisely what hydration exists to resolve.
|
|
165
|
+
const declaredTool = options.tools?.[call.name];
|
|
166
|
+
const tool = declaredTool?.execute
|
|
167
|
+
? declaredTool
|
|
168
|
+
: (adapter.resolveToolOnMiss?.(call.name) ?? declaredTool);
|
|
160
169
|
if (!tool?.execute) {
|
|
161
170
|
const output = breaker
|
|
162
171
|
? {
|
|
@@ -156,7 +156,16 @@ export function runAgenticLoop(adapter, initialConversation, options) {
|
|
|
156
156
|
});
|
|
157
157
|
continue;
|
|
158
158
|
}
|
|
159
|
-
|
|
159
|
+
// Second lookup path for adapters that discover tools mid-turn.
|
|
160
|
+
// The miss is defined as "nothing executable under this name"
|
|
161
|
+
// rather than "no key under this name", because the guard directly
|
|
162
|
+
// below already treats a present-but-unexecutable entry as absent —
|
|
163
|
+
// a deferred-catalog placeholder is exactly that shape, and it is
|
|
164
|
+
// precisely what hydration exists to resolve.
|
|
165
|
+
const declaredTool = options.tools?.[call.name];
|
|
166
|
+
const tool = declaredTool?.execute
|
|
167
|
+
? declaredTool
|
|
168
|
+
: (adapter.resolveToolOnMiss?.(call.name) ?? declaredTool);
|
|
160
169
|
if (!tool?.execute) {
|
|
161
170
|
const output = breaker
|
|
162
171
|
? {
|
|
@@ -35,6 +35,46 @@ export type AgenticLoopReclaimResult<TConversation> = {
|
|
|
35
35
|
export type AgenticLoopToolFailureBreaker = {
|
|
36
36
|
maxRetries: number;
|
|
37
37
|
};
|
|
38
|
+
/**
|
|
39
|
+
* DESIGN DECISION — mid-turn tool-discovery hydration (Plan 08 blocker 2,
|
|
40
|
+
* Task 7): resolved by the single optional `resolveToolOnMiss` field below,
|
|
41
|
+
* NOT by a broader `dispatchTools?` full-dispatch override. A full-dispatch
|
|
42
|
+
* override would let an adapter replace the engine's entire per-call
|
|
43
|
+
* dispatch — breaker bookkeeping, execution, toolExecutions aggregation — so
|
|
44
|
+
* every adapter needing hydration would have to reimplement that bookkeeping,
|
|
45
|
+
* and any later engine-level fix to dispatch would silently not apply to the
|
|
46
|
+
* adapters using the override. `resolveToolOnMiss` plugs into the existing
|
|
47
|
+
* dispatch at the one decision point that needs a second lookup, leaving
|
|
48
|
+
* breaker bookkeeping, retries and aggregation engine-owned for every
|
|
49
|
+
* provider, hydrated or not.
|
|
50
|
+
*
|
|
51
|
+
* DESIGN DECISION — originalNameMap propagation (blocker 3): needs ZERO
|
|
52
|
+
* engine or type change. Google's function-name sanitization is a translation
|
|
53
|
+
* concern between the wire (sanitized names out, sanitized names back on
|
|
54
|
+
* tool_call.name) and the engine's shape, which only ever sees plain string
|
|
55
|
+
* names. An adapter that needs the map threads it as a constructor-time
|
|
56
|
+
* closure and translates inside its own `executeStep` /
|
|
57
|
+
* `buildToolResultMessages`, before those names cross the engine boundary.
|
|
58
|
+
*
|
|
59
|
+
* DESIGN DECISION — reserved-step + forced finalization (blocker 1, part 2):
|
|
60
|
+
* stays OUTSIDE `runAgenticLoop`, in Vertex+Claude's own wrapper around
|
|
61
|
+
* `resultPromise`. The reserved step needs no engine change at all — an
|
|
62
|
+
* adapter declaring `maxSteps: requested - 1` means the engine's own loop
|
|
63
|
+
* never touches the reserved slot. The forced call is a one-shot action taken
|
|
64
|
+
* on the RESULT of a turn, not a repeatable step within one, so folding it in
|
|
65
|
+
* would teach the engine a family-specific concept (forced tool_choice, a
|
|
66
|
+
* distinguished terminal tool name) that every other adapter would then carry
|
|
67
|
+
* and never set.
|
|
68
|
+
*
|
|
69
|
+
* DESIGN DECISION — terminal tool-call marking (blocker 1, part 1): needs
|
|
70
|
+
* ZERO engine or type change. An adapter treats a detected terminal call as
|
|
71
|
+
* terminal by omitting it from `toolCalls` and putting its parsed payload in
|
|
72
|
+
* `text`. The engine already ends a turn the moment a step yields zero tool
|
|
73
|
+
* calls, so such a step is indistinguishable from an ordinary final text
|
|
74
|
+
* turn: never looked up in `options.tools`, never reaching TOOL_NOT_FOUND,
|
|
75
|
+
* never counted against the breaker. Proven by a case in the loop-engine
|
|
76
|
+
* suite rather than asserted here.
|
|
77
|
+
*/
|
|
38
78
|
export type AgenticLoopAdapter<TConversation = unknown, TRaw = unknown> = {
|
|
39
79
|
readonly providerLabel: string;
|
|
40
80
|
readonly maxSteps: number;
|
|
@@ -43,6 +83,18 @@ export type AgenticLoopAdapter<TConversation = unknown, TRaw = unknown> = {
|
|
|
43
83
|
readonly stallTimeoutMs?: number;
|
|
44
84
|
/** Set only for adapter instances whose client has the TOOL_NOT_FOUND strike breaker today: both Gemini adapters (AI Studio, Vertex+Gemini) AND the Vertex+Claude call to createAnthropicLoopAdapter — NOT the native-Anthropic call to that same factory, and not Bedrock. See Verified Fact 4. */
|
|
45
85
|
readonly toolFailureBreaker?: AgenticLoopToolFailureBreaker;
|
|
86
|
+
/**
|
|
87
|
+
* Second lookup path, consulted when a tool call names nothing executable
|
|
88
|
+
* in the caller's `options.tools` — used by adapters supporting mid-turn
|
|
89
|
+
* discovery to hydrate a tool the model just found via `search_tools`, or a
|
|
90
|
+
* deferred-catalog tool called by its advertised name, before the engine
|
|
91
|
+
* falls through to TOOL_NOT_FOUND and the breaker strike. See the design
|
|
92
|
+
* decision above for why this is a narrow lookup and not a dispatch
|
|
93
|
+
* override.
|
|
94
|
+
*/
|
|
95
|
+
readonly resolveToolOnMiss?: (name: string) => {
|
|
96
|
+
execute: (args: Record<string, unknown>, opts: unknown) => Promise<unknown>;
|
|
97
|
+
} | undefined;
|
|
46
98
|
buildStepRequest(conversation: TConversation, step: number): AgenticLoopStepRequest;
|
|
47
99
|
executeStep(request: AgenticLoopStepRequest, channel: {
|
|
48
100
|
push(chunk: {
|
|
@@ -35,6 +35,46 @@ export type AgenticLoopReclaimResult<TConversation> = {
|
|
|
35
35
|
export type AgenticLoopToolFailureBreaker = {
|
|
36
36
|
maxRetries: number;
|
|
37
37
|
};
|
|
38
|
+
/**
|
|
39
|
+
* DESIGN DECISION — mid-turn tool-discovery hydration (Plan 08 blocker 2,
|
|
40
|
+
* Task 7): resolved by the single optional `resolveToolOnMiss` field below,
|
|
41
|
+
* NOT by a broader `dispatchTools?` full-dispatch override. A full-dispatch
|
|
42
|
+
* override would let an adapter replace the engine's entire per-call
|
|
43
|
+
* dispatch — breaker bookkeeping, execution, toolExecutions aggregation — so
|
|
44
|
+
* every adapter needing hydration would have to reimplement that bookkeeping,
|
|
45
|
+
* and any later engine-level fix to dispatch would silently not apply to the
|
|
46
|
+
* adapters using the override. `resolveToolOnMiss` plugs into the existing
|
|
47
|
+
* dispatch at the one decision point that needs a second lookup, leaving
|
|
48
|
+
* breaker bookkeeping, retries and aggregation engine-owned for every
|
|
49
|
+
* provider, hydrated or not.
|
|
50
|
+
*
|
|
51
|
+
* DESIGN DECISION — originalNameMap propagation (blocker 3): needs ZERO
|
|
52
|
+
* engine or type change. Google's function-name sanitization is a translation
|
|
53
|
+
* concern between the wire (sanitized names out, sanitized names back on
|
|
54
|
+
* tool_call.name) and the engine's shape, which only ever sees plain string
|
|
55
|
+
* names. An adapter that needs the map threads it as a constructor-time
|
|
56
|
+
* closure and translates inside its own `executeStep` /
|
|
57
|
+
* `buildToolResultMessages`, before those names cross the engine boundary.
|
|
58
|
+
*
|
|
59
|
+
* DESIGN DECISION — reserved-step + forced finalization (blocker 1, part 2):
|
|
60
|
+
* stays OUTSIDE `runAgenticLoop`, in Vertex+Claude's own wrapper around
|
|
61
|
+
* `resultPromise`. The reserved step needs no engine change at all — an
|
|
62
|
+
* adapter declaring `maxSteps: requested - 1` means the engine's own loop
|
|
63
|
+
* never touches the reserved slot. The forced call is a one-shot action taken
|
|
64
|
+
* on the RESULT of a turn, not a repeatable step within one, so folding it in
|
|
65
|
+
* would teach the engine a family-specific concept (forced tool_choice, a
|
|
66
|
+
* distinguished terminal tool name) that every other adapter would then carry
|
|
67
|
+
* and never set.
|
|
68
|
+
*
|
|
69
|
+
* DESIGN DECISION — terminal tool-call marking (blocker 1, part 1): needs
|
|
70
|
+
* ZERO engine or type change. An adapter treats a detected terminal call as
|
|
71
|
+
* terminal by omitting it from `toolCalls` and putting its parsed payload in
|
|
72
|
+
* `text`. The engine already ends a turn the moment a step yields zero tool
|
|
73
|
+
* calls, so such a step is indistinguishable from an ordinary final text
|
|
74
|
+
* turn: never looked up in `options.tools`, never reaching TOOL_NOT_FOUND,
|
|
75
|
+
* never counted against the breaker. Proven by a case in the loop-engine
|
|
76
|
+
* suite rather than asserted here.
|
|
77
|
+
*/
|
|
38
78
|
export type AgenticLoopAdapter<TConversation = unknown, TRaw = unknown> = {
|
|
39
79
|
readonly providerLabel: string;
|
|
40
80
|
readonly maxSteps: number;
|
|
@@ -43,6 +83,18 @@ export type AgenticLoopAdapter<TConversation = unknown, TRaw = unknown> = {
|
|
|
43
83
|
readonly stallTimeoutMs?: number;
|
|
44
84
|
/** Set only for adapter instances whose client has the TOOL_NOT_FOUND strike breaker today: both Gemini adapters (AI Studio, Vertex+Gemini) AND the Vertex+Claude call to createAnthropicLoopAdapter — NOT the native-Anthropic call to that same factory, and not Bedrock. See Verified Fact 4. */
|
|
45
85
|
readonly toolFailureBreaker?: AgenticLoopToolFailureBreaker;
|
|
86
|
+
/**
|
|
87
|
+
* Second lookup path, consulted when a tool call names nothing executable
|
|
88
|
+
* in the caller's `options.tools` — used by adapters supporting mid-turn
|
|
89
|
+
* discovery to hydrate a tool the model just found via `search_tools`, or a
|
|
90
|
+
* deferred-catalog tool called by its advertised name, before the engine
|
|
91
|
+
* falls through to TOOL_NOT_FOUND and the breaker strike. See the design
|
|
92
|
+
* decision above for why this is a narrow lookup and not a dispatch
|
|
93
|
+
* override.
|
|
94
|
+
*/
|
|
95
|
+
readonly resolveToolOnMiss?: (name: string) => {
|
|
96
|
+
execute: (args: Record<string, unknown>, opts: unknown) => Promise<unknown>;
|
|
97
|
+
} | undefined;
|
|
46
98
|
buildStepRequest(conversation: TConversation, step: number): AgenticLoopStepRequest;
|
|
47
99
|
executeStep(request: AgenticLoopStepRequest, channel: {
|
|
48
100
|
push(chunk: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.7.0",
|
|
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": {
|